| 
<?php/* This code is writed by Grigori A. Kochanov.
 * The script can be used, modified and redistributed freely
 * under the terms and conditions of the BSD public license.
 *
 * Requirements:  PHP 5 CLI compiled with --enable-pcntl, POSIX functions not disabled
 * UNIX-style systems only
 *
 * version: 1
 */
 
 class Daemon{
 
 //show demonstration messages
 const DEBUG_MODE = true;
 
 //exit if sleeping more then MAX_SLEEP_HOURS
 const MAX_SLEEP_HOURS = 6;
 
 //path to the pid file
 const PID_FILE_PATH='daemon.pid';
 
 //service parameters
 const i_sleep = 1;
 const i_run = 2;
 const i_exit = 3;
 private $role;
 private $child_pid;
 
 /**
 * Checks the configuration, register signal handler and start the multi-process daemon emulation
 *
 */
 public function __construct(){
 //check the PHP configuration
 if (!defined('SIGHUP')){
 trigger_error('PHP is compiled without --enable-pcntl directive',E_USER_ERROR);
 }
 //check if the pid file is writable
 if (file_exists(self::PID_FILE_PATH ) && !is_writable(self::PID_FILE_PATH) ||
 !file_exists(self::PID_FILE_PATH ) && !is_writable(dirname(self::PID_FILE_PATH))
 ){
 trigger_error('can not open PID file '.self::PID_FILE_PATH.' for writing', E_USER_ERROR);
 }
 
 // tick required as of PHP 4.3.0
 declare(ticks = 2);
 
 // setup signal handlers
 pcntl_signal(SIGTERM,array($this,'sigTermHandler'));
 pcntl_signal(SIGCONT,array($this,'sigContHandler'));
 pcntl_signal(SIGALRM,array($this,'sigAlrmHandler'));
 
 //register the shutdown function to waken the child
 register_shutdown_function(array($this,'wakeUpChild'));
 
 //the parent will work
 $this->role = self::i_run;
 
 if (self::DEBUG_MODE){
 echo "Root PID: ".posix_getpid()."\n";
 }
 do{
 //child sleeps
 if ($this->role == self::i_sleep ){
 if (self::DEBUG_MODE){
 echo 'process ', $pid," will sleep\n";
 }
 sleep(0xFFFFFFFF);
 }
 
 //if we are asked to exit - let's do it
 if ($this->role == self::i_exit ){
 @unlink(self::PID_FILE_PATH );
 exit;
 }
 if ($this->role == self::i_run){
 //spawn a child and continue the work
 $this->child_pid = pcntl_fork();
 $pid = posix_getpid();
 if (!$this->child_pid){
 //it's a child - go to bed
 $this->role = self::i_sleep;
 pcntl_alarm(3600*self::MAX_SLEEP_HOURS); // max time to sleep, then exit
 }
 }
 }while ($this->role == self::i_sleep);
 
 //write the PID
 file_put_contents(self::PID_FILE_PATH,$pid);
 
 if (self::DEBUG_MODE){
 echo 'process ',$pid, " continues opertions\n";
 }
 }
 
 /**
 * Catch the SIGTERM signal
 *
 */
 private function sigTermHandler(){
 if (self::DEBUG_MODE){
 echo "SIGTERM CAUGHT\n";
 }
 // I was asked to exit - pass the call to the child and remove the PID file
 if ($this->child_pid){
 posix_kill($this->child_pid, SIGTERM);
 @unlink(self::PID_FILE_PATH );
 }
 exit;
 }
 
 /**
 * Catch the SIGCONT signal
 *
 */
 private function sigContHandler(){
 // I am waken up to run
 $this->role = self::i_run;
 }
 
 /**
 * Catch the SIGALRM signal
 *
 */
 private function sigAlrmHandler(){
 //time is out
 $this->role = self::i_exit;
 }
 
 /**
 * Send the signal to a child to wake him up to continue the work
 *
 */
 public function wakeUpChild(){
 if ($this->child_pid){
 posix_kill($this->child_pid, SIGCONT);
 }
 }
 
 /**
 * Send the SIGTERM to the process and the child
 *
 */
 public function terminate(){
 posix_kill(posix_getpid(), SIGTERM);
 }
 
 //end of the class
 }
 
 ?>
 |