Location: PHPKode > scripts > PHP-Simple-Daemon > fastest963-PHP-Simple-Daemon-9f3e1b3/daemon.php
#!/usr/bin/php -q 
<?php 
error_reporting(E_ALL); //report all errors
set_time_limit(0); //run forever
declare(ticks = 1); 

/* You may edit any values below this line */
// TRAILING SLASHES REQUIRED
$conf['masterdir'] = "/home/james/PHP-Simple-Daemon/"; //the folder in which this file exists
$conf['piddir'] = "/home/james/PHP-Simple-Daemon/"; //a folder that contains PIDs (must be 777)
$conf['logfile'] = $conf['masterdir']."server.log"; //blank ("") for no logging
// you need super-user or root privleges to change the uid and gid
$conf['uid'] = ""; //the UID of the daemon to run (blank for no change)
$conf['gid'] = ""; //group ID of the daemon to run (blank for no change)
$conf['IP'] = "0.0.0.0"; // IP for the daemon to run on
$conf['port'] = 16644; //port to run daemon on
$conf['timeout'] = 5; //seconds to wait with NO activity until client is closed
$conf['welcome'] = "\nWelcome to my PHP Daemon.\nTo end your session, type 'end'.\n"; //welcome message
$conf['login'] = array('user' => 'pass', 'user2' => 'pass2');

// here is your function:
// it is called whenever someone enters text
function userfunc($sent){ //keep the function name the same!
		$msg = "You said '$sent'.\n";
		socket_write($sock, $msg, strlen($msg));
}

/* You should really be careful editting anything below this line! :P */

$__mpid = daemonme(); //store the master pid

//set the gid first
if (!empty($conf['gid'])){
if( !posix_setgid($conf['gid']) ){ 
  file_put_contents($conf['logfile'], "[".posix_getpid()."] Unable to setgid!\n", FILE_APPEND); 
  echo "[".posix_getpid()."] Unable to setgid!\n";
  exit(0); 
}
}
//set the uid
if (!empty($conf['uid'])){
if( !posix_setuid($conf['uid']) ){ 
  file_put_contents($conf['logfile'], "[".posix_getpid()."] Unable to setuid!\n", FILE_APPEND); 
  echo "[".posix_getpid()."] Unable to setuid!\n";
  exit(0); 
}
}

//make sure log is writable
if (!is_writable($conf['logfile']) && !is_writable(substr($conf['logfile'], 0, -1*strlen(basename($conf['logfile']))))){
	echo "[".posix_getpid()."] Log File and Directory are not writable\n";
	clearstatcache(); //cleanup
	exit(0);
}

//make sure pids is writable
if (!is_writable($conf['piddir'])){
	echo "[".posix_getpid()."] PID Directory is not writable\n";
	clearstatcache(); //cleanup
	exit(0);
}

clearstatcache(); //cleanup

//define global vars
$__list = true;
$__gsoc = false;
$__csoc = false;

//handle system calls and send to signal()
pcntl_signal(SIGTERM, 'signal'); 
pcntl_signal(SIGINT, 'signal'); 
pcntl_signal(SIGCHLD, 'signal');
pcntl_signal(SIGHUP, "signal");

//start socket

file_put_contents($conf['logfile'], "\n****************\n* Daemon Start *\n****************\nTime: ".date("r")."\n", FILE_APPEND); 

$__gsoc = begin($conf['IP'], $conf['port']);

//daemonize
function daemonme(){ 
    $pid = pcntl_fork();    
    if ($pid == -1){ 
        file_put_contents($conf['logfile'],  "[".posix_getpid()."] initial fork failure!\n", FILE_APPEND);
		echo "[".posix_getpid()."] initial fork failure!";
        exit(); 
    }elseif ($pid){ // we are in parent
        exit(0); 
    }else{ 
        posix_setsid(); 
        chdir('/');
        umask(0);				
		sdClients(false); // remove all current pids		
        return posix_getpid();
    } 
} 

//starts socket and begins
function begin($ip, $p){ 
    global $__list, $__gsoc, $__mpid, $conf; 

	//create socket
    if(($__gsoc = socket_create(AF_INET, SOCK_STREAM, 0))===false){ 
		file_put_contents($conf['logfile'], "[".posix_getpid()."] failed to create socket: ".socket_strerror(socket_last_error())."\n", FILE_APPEND);
		echo "[".posix_getpid()."] failed to create socket: ".socket_strerror(socket_last_error())."\n";
        exit(0); 
    }
	
    // reuse socket if its already open (prevents errors on restart)
    if(socket_set_option($__gsoc, SOL_SOCKET, SO_REUSEADDR, 1)===false){
		file_put_contents($conf['logfile'], "[".posix_getpid()."] failed to set SO_REUSEADDR socket: ".socket_strerror(socket_last_error())."\n", FILE_APPEND);
		echo "[".posix_getpid()."] failed to set SO_REUSEADDR socket: ".socket_strerror(socket_last_error())."\n";
        exit(0); 
    } 

	// bind socket to IP and port
    if(@socket_bind($__gsoc, $ip, $p)===false){ 
		file_put_contents($conf['logfile'], "[".posix_getpid()."] failed to bind socket: ".socket_strerror(socket_last_error())."\n", FILE_APPEND);
		echo "[".posix_getpid()."] failed to bind socket: ".socket_strerror(socket_last_error())."\n";
        exit(0); 
    } 

	// start listening with no backlog
    if(socket_listen($__gsoc, 0)===false){ 
		file_put_contents($conf['logfile'], "[".posix_getpid()."] failed to listen to socket: ".socket_strerror(socket_last_error())."\n", FILE_APPEND);
		echo "[".posix_getpid()."] failed to listen to socket: ".socket_strerror(socket_last_error())."\n";
        exit(0); 
    }
	//set the socket to non-blocking mode
    socket_set_nonblock($__gsoc); 

	file_put_contents($conf['logfile'], "[".posix_getpid()."] daemon connected and waiting...\n", FILE_APPEND);
	//echo "[".posix_getpid()."] daemon connected and waiting...\n";
	
    while ($__list){ 
        $conn = @socket_accept($__gsoc); 
        if ($conn === false)
            usleep(100); 
        elseif ($conn > 0)
            handle_client($__gsoc, $conn); 
        else{ 
            file_put_contents($conf['logfile'], "[".posix_getpid()."] socket_accept() error: ".socket_strerror(socket_last_error()), FILE_APPEND); 
            exit(0); 
        } 
    }
    return $sock;
}

//shutdown clients
function sdClients ($b=true){
	global $conf;
    $hand = opendir($conf['piddir']);
    while ($f = readdir($hand)) {
        if ($f!='.' && $f!='..' && substr($f,-4)==".pid"){
			if($b===true) file_put_contents($conf['logfile'], "[".posix_getpid()."]  killed client PID:".basename($file, ".pid")."\n", FILE_APPEND);
            unlink($conf['piddir'].$file);
        }
    }
    closedir($hand);
	unset($f, $hand);
}

//handle system signals
function signal($sig) {
	global $__list, $__gsoc, $__mpid, $conf;
    switch($sig){
        case SIGTERM: //shutdown 
        case SIGINT:
			if (posix_getpid() == $__mpid){ // if we are the master
				file_put_contents($conf['logfile'], "[".posix_getpid()."] server shutdown...!\n", FILE_APPEND);
				sdClients();
				sleep(1); //hold on
				$__list = false;
			    socket_shutdown($__gsoc, 2); //force end reading and writing
			    socket_close($__gsoc);
				file_put_contents($conf['logfile'], "[".posix_getpid()."] disconnected!\n", FILE_APPEND);
				unset($__gsoc);
				exit(0);
			}else{ // we are in a client
				//delete pid file				
				unlink($conf['piddir'].posix_getpid().".pid");
				exit(0);
			}			
        break;			
		case SIGHUP: //restart
			if (posix_getpid() == $__mpid){ // if we are the master
				file_put_contents($conf['logfile'], "[".posix_getpid()."] server restarting...!\n", FILE_APPEND);
				sdClients();
				sleep(1); //hold on
				$__list = false;
			    socket_shutdown($__gsoc, 2); //force end reading and writing
			    socket_close($__gsoc);
				file_put_contents($conf['logfile'], "[".posix_getpid()."] disconnected and new process being started!\n", FILE_APPEND);
				unset($__gsoc);	
				exec('bash -c "exec nohup setsid '.__FILE__.' > /dev/null 2>&1 &"'); //non-blocking exec (thanks to @miorel)
				//executes subprocess in null environment...
				//file_put_contents($conf['logfile'], "new process created, shutdown!\n", FILE_APPEND);	
				exit(0);
			}else //we are in client, just close, no restart possible						
				exit(0);
		break;
        case SIGCHLD: //child process terminated
            pcntl_waitpid(-1, $s); // wait for child to close and continue
        break; 
    } 
} 

//handle a client connection, fork and continue
function handle_client($gsoc, $__csoc){ 
    GLOBAL $__list, $__mpid, $conf; 
    $pid = pcntl_fork(); // we could use the pid later?	
    if ($pid == -1){ 
		file_put_contents($conf['logfile'], "[".posix_getpid()."] handle_client() fork failure!\n", FILE_APPEND);
        exit(0); 
    }elseif ($pid == 0){ // we are in the child        
        $__list = false;
        socket_close($gsoc);
		file_put_contents($conf['piddir'].posix_getpid().".pid", "true", LOCK_EX); //store pid file
		cont($__csoc); // start talking with server
	 	socket_shutdown($__csoc, 2);
        socket_close($__csoc);
		//delete pid file
		@unlink($conf['piddir'].posix_getpid().".pid");
		exit(0);
    }else{ 
        socket_close($__csoc);
    }	
} 

//take client and interact
function cont($sock){
	global $__mpid, $conf;
	
    $msg = $conf['welcome'];
	if(!empty($msg))
		socket_write($sock, $msg, strlen($msg));
	unset($msg);
	
	$usr = false; //var for user login
	$pas = false; //var for password
	$logn = false; //login mode
	$admn = false;	//if user is admin
	$shutdown = false; //shutdown
	$idl = false;
	$time = time(); //get inital time
	
	do {
		$chg = 0;
		$buf = "";
		$chg = socket_select($read=array($sock), $write=null, $except=null, 0, 250); //wait 250 ms
	    if ($chg>0) {
	  		if (false === ($buf = socket_read($sock, 2048, PHP_NORMAL_READ))) {
				file_put_contents($conf['logfile'], "[".posix_getpid()."] socket_read() error: " . socket_strerror(socket_last_error()) . "\n", FILE_APPEND);
				break;
			}
		}elseif($chg===false){//something went wrong
			file_put_contents($conf['logfile'], "[".posix_getpid()."] socket_select() error: " . socket_strerror(socket_last_error()) . "\n", FILE_APPEND);
			break;
		}
		unset($chg);
		
		$buf = trim($buf);
		$sbuf = strtolower($buf);
		if (!empty($buf)){
			$time = time(); //reset time
			switch($sbuf){ 
				case 'login':
					$logn = true;
					$msg = "User: ";
					$usr = true;
					socket_write($sock, $msg, strlen($msg));
					break;
				case 'quit':
				case 'end':
					unset($logn, $msg, $usr, $buf, $idl, $admn, $shutdown);
					break 2; // break out were done
				case 'shutdown':
					if ($admn===true){
						$msg = "Shutting down master server!\nMaster PID: $__mpid\n";
						socket_write($sock, $msg, strlen($msg));
						posix_kill($__mpid, SIGTERM); //send shutdown signal
						$shutdown = true;
						unset($logn, $msg, $usr, $buf, $idl, $admn);
						break 2;
					}else{
						$msg = "Woah! Who said you could do that?\n";
						socket_write($sock, $msg, strlen($msg));
						break 2;
					}
				case 'process list':
					if ($admn===true){
						$msg = "List Of Running PIDs\nMaster PID: $mpid\n";
						$hand = opendir($conf['piddir']);
						while ($f = readdir($hand)) {
							if ($f!='.' && $f!='..' && substr($f, -4)==".pid")
								$msg .= basename($f, ".pid")."\n";
						}
						closedir($hand);						
						socket_write($sock, $msg, strlen($msg));	
						unset($f, $msg, $hand);
					}else{
						$msg = "Woah! Who said you could do that?\n";
						socket_write($sock, $msg, strlen($msg));
					}
					break;
				case 'restart':			
					if ($admn===true){
						$msg = "Restarting master server!\nMaster PID: $__mpid\n";						
						socket_write($sock, $msg, strlen($msg));
						posix_kill($__mpid, SIGHUP); //send restart signal
						$shutdown = true;
						unset($logn, $msg, $usr, $buf, $idl, $admn);
						break 2;
					}else{
						$msg = "Woah! Who said you could do that?\n";
						socket_write($sock, $msg, strlen($msg));
						break 2;
					}
				default:
					if ($logn===true){
						$logn = false; //prevent looping
						if ($usr===true){
							$usr = false; //prevent looping
							if (empty($buf)){
								$msg = "\nInvalid User\n";
								socket_write($sock, $msg, strlen($msg));
								break;
							}else{
								$usr = $buf;
								$msg = "Pass: ";
								$pas = true;
								$logn = true;
								socket_write($sock, $msg, strlen($msg));
								break;
							}
						}
						if ($pas===true){
							if (isset($conf['login'][$usr]) && $buf==$conf['login'][$usr]){
								$msg = "\n**************\nWelcome $usr!\n**************\n";
								socket_write($sock, $msg, strlen($msg));
								//we are done with login so make all false
									$usr = false;
									$pas = false;
									$logn = false;
								$admn = true;								
								break;
							}
							//we are done with login so make all false
								$usr = false;
								$pas = false;
								$logn = false;
							$msg = "**Invalid User/Pass**\n\n";
							socket_write($sock, $msg, strlen($msg));
							break;
						}
					}else{
						// this is where the user can define functions, etc
						userfunc($buf);
					}
					break;
			}
		}else{ // buf is empty
			if (time()-$time > $conf['timeout']){ //uh oh user has timed out
				$idl = true;
				break;
			}
		}
		unset($msg);
	} while (file_exists($conf['piddir'].posix_getpid().".pid"));
	
	if (!file_exists($conf['piddir'].posix_getpid().".pid") && isset($shutdown) && $shutdown === false){ //we were shutdown!
		$msg = "Remote server shutdown...!\n";
		socket_write($sock, $msg, strlen($msg));
		return;
	}	
	if (isset($idl) && $idl===true){ //idle process
		$msg = "**Idle Process**\n";
		socket_write($sock, $msg, strlen($msg));
		return;
	}
	return;
} 

?>
Return current item: PHP-Simple-Daemon