Use PHP Socket to create your own chat room server. read how to use PHP Socket to create your own chat room server ,? PHP/*** patServer * PHPsocketserverbaseclass * Eventsthatcanbehandled: ** onStart ** onConnect ** onConne
/**
* PatServer
* PHP socket server base class
* Events that can be handled:
** OnStart
** OnConnect
** OnConnectionRefused
** OnClose
** OnShutdown
** OnReceiveData
*
* @ Version 1.1
* @ Author Stephen an Schmidt
* @ Package patServer
*/
Class patServer {
/**
* Information about the project
* @ Var array $ systemVars
*/
Var $ systemVars = array (
"AppName" => "patServer ",
"AppVersion" => "1.1 ",
"Author" => array ("Stephen Schmidt ",)
);
/**
* 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 = "\ n ";
/**
* 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 ++ ){
If (! Isset ($ this-> clientFD [$ I])
Continue;
If (in_array ($ this-> clientFD [$ I], $ readFDs )){
$ Data = $ this-> readFromSocket ($ I );
// Empty data => connection was closed
If (! $ Data ){
$ This-> sendDebugMessage ("Connection closed by peer ");
$ This-> closeConnection ($ I );
} Else {
$ This-> sendDebugMessage ("Received". trim ($ data). "from". $ I );
If (method_exists ($ this, "onReceiveData "))
$ This-> onReceiveData ($ I, $ data );
}
}
}
}
}
/**
* Read from a socket
*
* @ Access private
* @ Param integer $ clientId internal id of the client to read from
* @ Return string $ data that was read
*/
Function readFromSocket ($ clientId ){
// Start with empty string
$ Data = "";
// Read data from socket
While ($ buf = socket_read ($ this-> clientFD [$ clientId], $ this-> readBufferSize )){
$ Data. = $ buf;
$ EndString = substr ($ buf,-strlen ($ this-> readEndCharacter ));
If ($ endString = $ this-> readEndCharacter)
Break;
If ($ buf = NULL)
Break;
}
If ($ buf = false)
$ This-> sendDebugMessage ("cocould not read from client ". $ clientId. "(". $ this-> getLastSocketError ($ this-> clientFD [$ clientId]). "). ");
Return $ data;
}
/**
* Accept a new connection
*
* @ Access public
* @ Param resource & $ socket that has ed the new connection
* @ Return int $ clientID internal ID of the client
*/
Function acceptConnection (& $ socket ){
For ($ I = 0; $ I <= count ($ this-> clientFD); $ I ++ ){
If (! Isset ($ this-> clientFD [$ I]) | $ this-> clientFD [$ I] = NULL ){
$ This-> clientFD [$ I] = socket_accept ($ socket );
Socket_setopt ($ this-> clientFD [$ I], SOL_SOCKET, SO_REUSEADDR, 1 );
$ Peer_host = "";
$ Peer_port = "";
Socket_getpeername ($ this-> clientFD [$ I], $ peer_host, $ peer_port );
$ This-> clientInfo [$ I] = array (
"Host" => $ peer_host,
"Port" => $ peer_port,
"ConnectOn" => time ()
);
$ This-> clients ++;
$ This-> sendDebugMessage ("New connection (". $ I. ") from". $ peer_host. "on port". $ peer_port );
If (method_exists ($ this, "onConnect "))
$ This-> onConnect ($ I );
Return $ I;
}
}
}
/**
* Check, whether a client is still connected
*
* @ Access public
* @ Param integer $ id client id
* @ Return boolean $ connected true if client is connected, false otherwise
*/
Function isConnected ($ id ){
If (! Isset ($ this-> clientFD [$ id])
Return false;
Return true;
}
/**
* Close connection to a client
*
* @ Access public
* @ Param int $ clientID internal ID of the client
*/
Function closeConnection ($ id ){
If (! Isset ($ this-> clientFD [$ id])
Return false;
If (method_exists ($ this, "onClose "))
$ This-> onClose ($ id );
$ This-> sendDebugMessage ("Closed connection (". $ id. ") from ". $ this-> clientInfo [$ id] ["host"]. "on port ". $ this-> clientInfo [$ id] ["port"]);
@ Socket_close ($ this-> clientFD [$ id]);
$ This-> clientFD [$ id] = NULL;
Unset ($ this-> clientInfo [$ id]);
$ This-> clients --;
}
/**
* Shutdown server
*
* @ Access public
*/
Function shutDown (){
If ($ GLOBALS ["_ patServerStatus"]! = "Running ")
Exit;
$ GLOBALS ["_ patServerStatus"] = "stopped ";
If (method_exists ($ this, "onShutdown "))
$ This-> onShutdown ();
$ MaxFD = count ($ this-> clientFD );
For ($ I = 0; $ I <$ maxFD; $ I ++)
$ This-> closeConnection ($ I );
@ Socket_close ($ this-> initFD );
$ This-> sendDebugMessage ("Shutdown server .");
Exit;
}
/**
* Get current amount of clients
*
* @ Access public
* @ Return int $ clients amount of clients
*/
Function getClients (){
Return $ this-> clients;
}
/**
* Send data to a client
*
* @ Access public
* @ Param int $ clientId ID of the client
* @ Param string $ data to send
* @ Param boolean $ debugData flag to indicate whether data that is written to socket shoshould also be sent as debug message
*/
Function sendData ($ clientId, $ data, $ debugData = true ){
If (! Isset ($ this-> clientFD [$ clientId]) | $ this-> clientFD [$ clientId] = NULL)
Return false;
If ($ debugData)
$ This-> sendDebugMessage ("sending: \" ". $ data." \ "to: $ clientId ");
If (! @ Socket_write ($ this-> clientFD [$ clientId], $ data ))
$ This-> sendDebugMessage ("cocould not write '". $ data. "'Client ". $ clientId. "(". $ this-> getLastSocketError ($ this-> clientFD [$ clientId]). "). ");
}
/**
* Send data to all clients
*
* @ Access public
* @ Param string $ data to send
* @ Param array $ exclude client ids to exclude
*/
Function broadcastData ($ data, $ exclude = array (), $ debugData = true ){
If (! Empty ($ exclude )&&! Is_array ($ exclude ))
$ Exclude = array ($ exclude );
For ($ I = 0; $ I <count ($ this-> clientFD); $ I ++ ){
If (isset ($ this-> clientFD [$ I]) & $ this-> clientFD [$ I]! = NULL &&! In_array ($ I, $ exclude )){
If ($ debugData)
$ This-> sendDebugMessage ("sending: \" ". $ data." \ "to: $ I ");
If (! @ Socket_write ($ this-> clientFD [$ I], $ data ))
$ This-> sendDebugMessage ("cocould not write '". $ data. "'Client ". $ I. "(". $ this-> getLastSocketError ($ this-> clientFD [$ I]). "). ");
}
}
}
/**
* Get current information about a client
*
* @ Access public
* @ Param int $ clientId ID of the client
* @ Return array $ info information about the client
*/
Function getClientInfo ($ clientId ){
If (! Isset ($ this-> clientFD [$ clientId]) | $ this-> clientFD [$ clientId] = NULL)
Return false;
Return $ this-> clientInfo [$ clientId];
}
/**
* Send a debug message
*
* @ Access private
* @ Param string $ msg message to debug
*/
Function sendDebugMessage ($ msg ){
If (! $ This-> debug)
Return false;
$ Msg = date ("Y-m-d H: I: s", time (). "". $ msg;
Switch ($ this-> debugMode ){
Case "text ":
$ Msg = $ msg. "\ n ";
Break;
Case "html ":
$ Msg = htmlspecialchars ($ msg )."
\ N ";
Break;
}
If ($ this-> debugDest = "stdout" | empty ($ this-> debugDest )){
Echo $ msg;
Flush ();
Return true;
}
Error_log ($ msg, 3, $ this-> debugDest );
Return true;
}
/**
* Return string for last socket error
*
* @ Access public
* @ Return string $ error last error
*/
Function getLastSocketError (& $ fd ){
$ LastError = socket_last_error ($ fd );
Return "msg:". socket_strerror ($ lastError). "/Code:". $ lastError;
}
Function onReceiveData ($ ip, $ data ){
$ This-> broadcastData ($ data, array (), true );
}
}
$ PatServer = new patServer ();
$ PatServer-> start ();
?>