<?php

// This is a very simple, naive and crude PHP implementation of a minimalist
// gopher server. It only opens a socket, awaits for a (single) client and
// displays back an informational screen.
//
// It is meant as a dumb (simplest possible) example of a gopher server for
// students and hobbyists to fiddle with and possibly build upon.
//
// Written by Mateusz Viste, who released it to the public domain (see below).
// ---------------------------------------------------------------------------
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// In jurisdictions that recognize copyright laws, the author or authors of
// this software dedicate any and all copyright interest in the software to
// the public domain. We make this dedication for the benefit of the public at
// large and to the detriment of our heirs and successors. We intend this
// dedication to be an overt act of relinquishment in perpetuity of all
// present and future rights to this software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org/>
// ---------------------------------------------------------------------------
//
// CHANGELOG
// 20210603: public release
//


// change this to make the server listen on another port (ports below 1024 may require root privileges!)
$PORT = 7070;


// helper function that builds a menu entry line
function infoline($txt, $type = 'i', $res = '', $host = 'localhost') {
  global $PORT;
  return($type . $txt . "\t{$res}\t{$host}\t$PORT\r\n");
}


// make sure the socket-related functions are present in this PHP install
if (!function_exists('socket_create')) {
  echo "ERROR: your PHP installation is missing support for sockets. Perhaps you should install something like php-sockets or alike.\n";
  exit(1);
}

// initialize a socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// bind the socket to 0.0.0.0 so it will accept connections from all local interfaces
socket_bind($sock, '0.0.0.0', $PORT);

// switch the socket into listening mode (only 1 client at a time)
socket_listen($sock, 1);

echo "phpgoph is running now and listens on port {$PORT}\n";

// processing loop
for (;;) {

  // wait for a client
  $clisock = socket_accept($sock);

  // who is the client?
  socket_getpeername($clisock, $client, $cliport);

  // what is my own IP address?
  socket_getsockname($clisock, $selfip);

  echo "accepted connection from {$client}:{$cliport}\n";

  // read a single line from stdin - ie. the gopher client's query (max 512 bytes)
  $req = trim(socket_read($clisock, 512, PHP_NORMAL_READ));

  if ($req == 'alphabet') {
    socket_write($clisock, "abcdefghijklmnopqrstuvwxyz\r\n");
    socket_write($clisock, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
    socket_write($clisock, ".\r\n");

  } else if ($req == 'random') {
    $r = rand(1, 10);
    socket_write($clisock, "Your random number is " . $r);
    socket_write($clisock, ".\r\n");

  } else {
    socket_write($clisock, infoline('Welcome to PHPGOPH - a crude gopher server implementation written in PHP'));
    socket_write($clisock, infoline(''));
    socket_write($clisock, infoline("Today is " . date('l \t\h\e jS')));
    socket_write($clisock, infoline(''));
    socket_write($clisock, infoline("Your IP is {$client}"));
    socket_write($clisock, infoline("This server's IP is {$selfip}"));
    socket_write($clisock, infoline(''));
    socket_write($clisock, infoline('Would you like to see the alphabet?', '0', 'alphabet', $selfip));
    socket_write($clisock, infoline('Here you will get a random number (1-10)', '0', 'random', $selfip));
    socket_write($clisock, ".\r\n");
  }

  socket_close($clisock);

}
