<?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 
} 
 
?>
 
 |