Not every problem can be solved with an aid of a cronjob. Sometimes a real time background process is required. The most common approach is to create an ordinary script and run it from command line with “&” character at the end.
I’m sure many PHP programmers asked themselves a question, is that the right way of doing it? What is the correct way? We usually don’t deal with the low level programming, but the C programmers do. I found the answer in the Advance Programming in the UNIX Environment book. There is a chapter about creating a deamon in C. It let me to create the below library which can be included into any PHP deamon script.
/** * _demonlib.php */ defined('DEAMON_LOCK_FILE') || define('DEAMON_LOCK_FILE', 'run/deamon.pid'); if($_SERVER['argc'] >= 2 && $_SERVER['argv'][1] == 'kill') { $fh = fopen(realpath(__DIR__) . '/' . DEAMON_LOCK_FILE, 'r'); $pid = fread($fh, 8); if( $pid ) posix_kill($pid, SIGTERM); exit; } global $DEAMON_LOCK_HANDLER; function daemonize($signalHandler = false ) { global $DEAMON_LOCK_HANDLER; if( ! deamon_file_lock() ) { printf("Deamon is already running...n"); exit(); } umask(0); $pid = pcntl_fork(); if( $pid < 0 ) { printf("Can't forkn"); exit; } else if( $pid ) { exit; } $sid = posix_setsid(); if( $sid < 0 ) { printf("Can't set session leadern"); exit; } deamon_bind_signals($signalHandler); $pid = pcntl_fork(); if( $pid < 0 || $pid ) { exit; } ftruncate($DEAMON_LOCK_HANDLER, 0); fwrite($DEAMON_LOCK_HANDLER, posix_getpid()); chdir('/'); fclose( STDIN ); fclose( STDOUT ); fclose( STDERR ); } function deamon_bind_signals($signalHandler = false) { $signalHandler = !$signalHandler ? "deamon_signal_handler" : $signalHandler; pcntl_signal(SIGTERM, $signalHandler); pcntl_signal(SIGHUP, $signalHandler); pcntl_signal(SIGUSR1, $signalHandler); } function deamon_file_lock() { global $DEAMON_LOCK_HANDLER; $DEAMON_LOCK_HANDLER = fopen(realpath(__DIR__) . '/' . DEAMON_LOCK_FILE, 'c'); if( ! $DEAMON_LOCK_HANDLER ) { printf("Can't open lock filen"); die(); } if( !flock( $DEAMON_LOCK_HANDLER, LOCK_EX | LOCK_NB ) ) { return false; } return true; } function deamon_signal_handler($signo) { switch( $signo ) { case SIGTERM: case SIGHUP: case SIGUSR1: break; } }
And a small example of how to use the library.
/** * demon.php */ function sighandler($sig) { global $robot; if( $sig == SIGTERM ) { global $DEAMON_LOCK_HANDLER; fclose( $DEAMON_LOCK_HANDLER ); $robot->message("SIGTEM exit(0)"); exit; } } define('DEAMON_LOCK_FILE', 'run/mydeamon.pid'); require_once '_deamonlib.php'; daemonize("sighandler"); while( true ) { pcntl_signal_dispatch(); // do something here sleep( 1 ); }