<? PHP
/**
* PatServer
* PHP socket server base class
* Events that can be handled:
** OnStart
** OnConnect
** OnConnectionRefused
** OnClose
** OnShutdown
** OnReceiveData
*
* @ Version 1.1
* @ Author STEPHEN an Schmidt <schst@php-tools.de>
* @ Package patServer
*/
Class patServer {
/**
* Information about the project
* @ Var array $ systemVars
*/
Var $ systemVars = array (
"AppName" => "patServer ",
"AppVersion" => "1.1 ",
"Author" => array ("Stephen Schmidt <schst@php-tools.de> ",)
);
/**
* Port to listen
* @ Var integer $ port
*/
Var $ port = 10000;
/**
* Domain to bind
* @ Var string $ domain
*/
Var $ domain = "localhost ";
/**
* Maximum amount of clients
* @ Var integer $ maxClients
*/
Var $ maxClients =-1;
/**
* Buffer size for socket_read
* @ Var integer $ readBufferSize
*/
Var $ readBufferSize = 128;
/**
* End character for socket_read
* @ Var integer $ readEndCharacter
*/
Var $ readEndCharacter = "";
/**
* Maximum of backlog in queue
* @ Var integer $ maxQueue
*/
Var $ maxQueue = 500;
/**
* Debug mode
* @ Var boolean $ debug
*/
Var $ debug = true;
/**
* Debug mode
* @ Var string $ debugMode
*/
Var $ debugMode = "text ";
/**
* Debug destination (filename or stdout)
* @ Var string $ debugDest
*/
Var $ debugDest = "stdout ";
/**
* Empty array, used for socket_select
* @ Var array $ null
*/
Var $ null = array ();
/**
* All file descriptors are stored here
* @ Var array $ clientFD
*/
Var $ clientFD = array ();
/**
* Needed to store client information
* @ Var array $ clientInfo
*/
Var $ clientInfo = array ();
/**
* Needed to store server information
* @ Var array $ serverInfo
*/
Var $ serverInfo = array ();
/**
* Amount of clients
* @ Var integer $ clients
*/
Var $ clients = 0;
/**
* Create a new socket server
*
* @ Access public
* @ Param string $ domain to bind
* @ Param integer $ port to listen
*/
Function patServer ($ domain = "localhost", $ port = 10000 ){
$ This-> domain = $ domain;
$ This-> port = $ port;
$ This-> serverInfo ["domain"] = $ domain;
$ This-> serverInfo ["port"] = $ port;
$ This-> serverInfo ["servername"] = $ this-> systemVars ["appName"];
$ This-> serverInfo ["serverversion"] = $ this-> systemVars ["appVersion"];
Set_time_limit (0 );
}
/**
* Set maximum amount of simultaneous connections
*
* @ Access public
* @ Param int $ maxClients
*/
Function setMaxClients ($ maxClients ){
$ This-> maxClients = $ maxClients;
}
/**
* Set debug mode
*
* @ Access public
* @ Param mixed $ debug [text | htmlfalse]
* @ Param string $ dest destination of debug message (stdout to output or filename if log shocould be written)
*/
Function setDebugMode ($ debug, $ dest = "stdout "){
If ($ debug = false ){
$ This-> debug = false;
Return true;
}
$ This-> debug = true;
$ This-> debugMode = $ debug;
$ This-> debugDest = $ dest;
}
/**
* Start the server
*
* @ Access public
* @ Param int $ maxClients
*/
Function start (){
$ This-> initFD = @ socket_create (AF_INET, SOCK_STREAM, 0 );
If (! $ This-> initFD)
Die ("patServer: cocould not create socket .");
// Adress may be reused
Socket_setopt ($ this-> initFD, SOL_SOCKET, SO_REUSEADDR, 1 );
// Bind the socket
If (! @ Socket_bind ($ this-> initFD, $ this-> domain, $ this-> port )){
@ Socket_close ($ this-> initFD );
Die ("patServer: cocould not bind socket ". $ this-> domain. "on port ". $ this-> port. "(". $ this-> getLastSocketError ($ this-> initFd ). "). ");
}
// Listen on selected port
If (! @ Socket_listen ($ this-> initFD, $ this-> maxQueue ))
Die ("patServer: cocould not listen (". $ this-> getLastSocketError ($ this-> initFd ).").");
$ This-> sendDebugMessage ("Listening on port ". $ this-> port. ". server started ". date ("H: I: s", time ()));
// This allows the shutdown function to check whether the server is already shut down
$ GLOBALS ["_ patServerStatus"] = "running ";
// This ensures that the server will be susudown correctly
Register_shutdown_function (array ($ this, "shutdown "));
If (method_exists ($ this, "onStart "))
$ This-> onStart ();
$ This-> serverInfo ["started"] = time ();
$ This-> serverInfo ["status"] = "running ";
While (true ){
$ ReadFDs = array ();
Array_push ($ readFDs, $ this-> initFD );
// Fetch all clients that are awaiting connections
For ($ I = 0; $ I <count ($ this-> clientFD); $ I ++)
If (isset ($ this-> clientFD [$ I])
Array_push ($ readFDs, $ this-> clientFD [$ I]);
// Block and wait for data or new connection
$ Ready = @ socket_select ($ readFDs, $ this-> null, $ this-> null, NULL );
If ($ ready = false ){
$ This-> sendDebugMessage ("socket_select failed .");
$ This-> shutdown ();
}
// Check for new connection
If (in_array ($ this-> initFD, $ readFDs )){
$ NewClient = $ this-> acceptConnection ($ this-> initFD );
// Check for maximum amount of connections
If ($ this-> maxClients> 0 ){
If ($ this-> clients> $ this-> maxClients ){
$ This-> sendDebugMessage ("Too many connections .");
If (method_exists ($ this, "onConnectionRefused "))
$ This-> onConnectionRefused ($ newClient );
$ This-> closeConnection ($ newClient );
}
}
If (-- $ ready <= 0)
Continue;
}
// Check all clients for incoming data
For ($ I = 0; $ I <count ($ this-> clientFD); $ I ++) {<