Location: PHPKode > scripts > Daemon Emulation > daemon-emulation/daemon.class.php
<?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
}

?>
Return current item: Daemon Emulation