Code Courtesy: lars at opdenkamp dot eu
A socket server written in PHP. This can accept multiple connections and runs as a daemon.
pcntl_fork() is thing here that is making this all possible.
<?php
/**
* Listens for requests and forks on each connection
*/
$__server_listening = true;
//error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
declare(ticks = 1);
become_daemon();
/* nobody/nogroup, change to your host's uid/gid of the non-priv user */
change_identity(1000, 1000);
/* handle signals */
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, 'sig_handler');
/* change this to your own host / port */
server_loop("192.168.0.1", 1250);
/**
* Change the identity to a non-priv user
*/
function change_identity( $uid, $gid )
{
if( !posix_setgid( $gid ) )
{
print "Unable to setgid to " . $gid . "!\n";
exit;
}
if( !posix_setuid( $uid ) )
{
print "Unable to setuid to " . $uid . "!\n";
exit;
}
}
/**
* Creates a server socket and listens for incoming client connections
* @param string $address The address to listen on
* @param int $port The port to listen on
*/
function server_loop($address, $port)
{
GLOBAL $__server_listening;
if(($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
{
echo "failed to create socket: ".socket_strerror($sock)."\n";
exit();
}
if(($ret = socket_bind($sock, $address, $port)) < 0)
{
echo "failed to bind socket: ".socket_strerror($ret)."\n";
exit();
}
if( ( $ret = socket_listen( $sock, 0 ) ) < 0 )
{
echo "failed to listen to socket: ".socket_strerror($ret)."\n";
exit();
}
socket_set_nonblock($sock);
echo "waiting for clients to connect\n";
while ($__server_listening)
{
$connection = @socket_accept($sock);
if ($connection === false)
{
usleep(100);
}elseif ($connection > 0)
{
handle_client($sock, $connection);
}else
{
echo "error: ".socket_strerror($connection);
die;
}
}
}
/**
* Signal handler
*/
function sig_handler($sig)
{
switch($sig)
{
case SIGTERM:
case SIGINT:
exit();
break;
case SIGCHLD:
pcntl_waitpid(-1, $status);
break;
}
}
/**
* Handle a new client connection
*/
function handle_client($ssock, $csock)
{
GLOBAL $__server_listening;
$pid = pcntl_fork();
if ($pid == -1)
{
/* fork failed */
echo "fork failure!\n";
die;
}elseif ($pid == 0)
{
/* child process */
$__server_listening = false;
socket_close($ssock);
interact($csock);
socket_close($csock);
}else
{
socket_close($csock);
}
}
function interact($socket)
{
$conn = mysql_connect("localhost","xxxxxxxx","xxxxxxxxxxx");
if(!$conn)
{
echo "Error: failed to connect DB";
die();
}
if(!mysql_select_db("xxxxxxxx",$conn))
{
echo "Error: failed to connect DB";
die();
}
// read client input
$input = socket_read($socket, 1024, PHP_NORMAL_READ);
$buff = explode("|",$input);
$len = count($buff);
$temp = explode("=",$buff[0]);
$temp[1] = intval($temp[1]);
if($temp[0]!="action" && ($temp[1]!=1 || $temp[1]!=2 )) //1=read 2=write -- these are just random numbers and has no other significance.
{
$output = "Error\r\n";
}
if($temp[1] == 1)
{
$result = mysql_query("select * from led_status");
$rows = mysql_fetch_array($result);
$output = "led_1=".$rows['led_1']."|led_2=".$rows['led_2']."\r\n";
}
if($temp[1] == 2)
{
$queryW = "insert into weather set ";
$queryL = "update led_status set ";
for($i=1; $i<$len; $i++)
{
$temp = explode("=",$buff[$i]);
switch($temp[0])
{
case 'temp':
$queryW .= "temperature=" . floatval($temp[1]).", ";
break;
case 'paH':
$queryW .= "paH=" . floatval($temp[1]) .", ";
break;
case 'paM':
$queryW .= "paM=" . floatval($temp[1]).", ";
break;
case 'led_1':
$queryL .= "led_1" . floatval($temp[1]) .", ";
break;
case 'led_2':
$queryL .= "led_2=" . float_val($temp[1]).", ";
}
}
$queryW .= " time=".time();
$queryL .= " time=".time();
mysql_query($queryL);
mysql_query($queryW);
$output = "Update Success\r\n";
}
/* TALK TO YOUR CLIENT */
socket_write($socket,$output, strlen($output));
mysql_close();
}
/**
* Become a daemon by forking and closing the parent
*/
function become_daemon()
{
$pid = pcntl_fork();
if ($pid == -1)
{
/* fork failed */
echo "fork failure!\n";
exit();
}elseif ($pid)
{
/* close the parent */
exit();
}else
{
/* child becomes our daemon */
posix_setsid();
chdir('/');
umask(0);
return posix_getpid();
}
}
?>