Login   Register  
PHP Classes
elePHPant
Icontem

File: Daemon.class.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Michal Golebiowski  >  Daemon  >  Daemon.class.php  >  Download  
File: Daemon.class.php
Role: Class source
Content type: text/plain
Description: Daemon base class
Class: Daemon
Create and control Unix daemon processes
Author: By
Last change: There was an error in method releaseDaemon() - wrong condition caused untimely deleting PID file.
Again thanks goes to Josef Svoboda for pointing it out :-)

Now we can set Daemon::requireSetIdentity to true/false for terminating daemon if seting identity has failed.

Other minor changes.
Date: 9 years ago
Size: 6,993 bytes
 

Contents

Class file image Download
<?php
/**
 * @package binarychoice.system.unix
 * @since 1.0.3
 */

// Log message levels
define('DLOG_TO_CONSOLE'1);
define('DLOG_NOTICE'2);
define('DLOG_WARNING'4);
define('DLOG_ERROR'8);
define('DLOG_CRITICAL'16);

/**
 * Daemon base class
 *
 * Requirements:
 * Unix like operating system
 * PHP 4 >= 4.3.0 or PHP 5
 * PHP compiled with:
 * --enable-sigchild
 * --enable-pcntl
 *
 * @package binarychoice.system.unix
 * @author Michal 'Seth' Golebiowski <seth at binarychoice dot pl>
 * @copyright Copyright 2005 Seth
 * @since 1.0.3
 */
class Daemon
{
   
/**#@+
    * @access public
    */
   /**
    * User ID
    * 
    * @var int
    * @since 1.0
    */
   
var $userID 99;

   
/**
    * Group ID
    * 
    * @var integer
    * @since 1.0
    */
   
var $groupID 99;
   
   
/**
    * Terminate daemon when set identity failure ?
    * 
    * @var bool
    * @since 1.0.3
    */
   
var $requireSetIdentity false;

   
/**
    * Path to PID file
    * 
    * @var string
    * @since 1.0.1
    */
   
var $pidFileLocation '/tmp/daemon.pid';

   
/**
    * Home path
    * 
    * @var string
    * @since 1.0
    */
   
var $homePath '/';
   
/**#@-*/


   /**#@+
    * @access protected
    */
   /**
    * Current process ID
    * 
    * @var int
    * @since 1.0
    */
   
var $_pid 0;

   
/**
    * Is this process a children
    * 
    * @var boolean
    * @since 1.0
    */
   
var $_isChildren false;

   
/**
    * Is daemon running
    * 
    * @var boolean
    * @since 1.0
    */
   
var $_isRunning false;
   
/**#@-*/


   /**
    * Constructor
    *
    * @access public
    * @since 1.0
    * @return void
    */
   
function Daemon()
   {
      
error_reporting(0);
      
set_time_limit(0);
      
ob_implicit_flush();

      
register_shutdown_function(array(&$this'releaseDaemon'));
   }

   
/**
    * Starts daemon
    *
    * @access public
    * @since 1.0
    * @return bool
    */
   
function start()
   {
      
$this->_logMessage('Starting daemon');

      if (!
$this->_daemonize())
      {
         
$this->_logMessage('Could not start daemon'DLOG_ERROR);

         return 
false;
      }


      
$this->_logMessage('Running...');

      
$this->_isRunning true;


      while (
$this->_isRunning)
      {
         
$this->_doTask();
      }

      return 
true;
   }

   
/**
    * Stops daemon
    *
    * @access public
    * @since 1.0
    * @return void
    */
   
function stop()
   {
      
$this->_logMessage('Stoping daemon');

      
$this->_isRunning false;
   }

   
/**
    * Do task
    *
    * @access protected
    * @since 1.0
    * @return void
    */
   
function _doTask()
   {
          
// override this method
   
}

   
/**
    * Logs message
    *
    * @access protected
    * @since 1.0
    * @return void
    */
   
function _logMessage($msg$level DLOG_NOTICE)
   {
         
// override this method
   
}

   
/**
    * Daemonize
    *
    * Several rules or characteristics that most daemons possess:
    * 1) Check is daemon already running
    * 2) Fork child process
    * 3) Sets identity
    * 4) Make current process a session laeder
    * 5) Write process ID to file
    * 6) Change home path
    * 7) umask(0)
    * 
    * @access private
    * @since 1.0
    * @return void
    */
   
function _daemonize()
   {
      
ob_end_flush();

      if (
$this->_isDaemonRunning())
      {
         
// Deamon is already running. Exiting
         
return false;
      }

      if (!
$this->_fork())
      {
         
// Coudn't fork. Exiting.
         
return false;
      }

      if (!
$this->_setIdentity() && $this->requireSetIdentity)
      {
         
// Required identity set failed. Exiting
         
return false;
      }

      if (!
posix_setsid())
      {
         
$this->_logMessage('Could not make the current process a session leader'DLOG_ERROR);

         return 
false;
      }

      if (!
$fp = @fopen($this->pidFileLocation'w'))
      {
         
$this->_logMessage('Could not write to PID file'DLOG_ERROR);

         return 
false;
      }
      else
      {
         
fputs($fp$this->_pid);
         
fclose($fp);
      }

      @
chdir($this->homePath);
      
umask(0);

      declare(
ticks 1);

      
pcntl_signal(SIGCHLD, array(&$this'sigHandler'));
      
pcntl_signal(SIGTERM, array(&$this'sigHandler'));

      return 
true;
   }

   
/**
    * Cheks is daemon already running
    *
    * @access private
    * @since 1.0.3
    * @return bool
    */
   
function _isDaemonRunning()
   {
      
$oldPid = @file_get_contents($this->pidFileLocation);

      if (
$oldPid !== false && posix_kill(trim($oldPid),0))
      {
         
$this->_logMessage('Daemon already running with PID: '.$oldPid, (DLOG_TO_CONSOLE DLOG_ERROR));

         return 
true;
      }
      else
      {
         return 
false;
      }
   }

   
/**
    * Forks process
    *
    * @access private
    * @since 1.0
    * @return bool
    */
   
function _fork()
   {
      
$this->_logMessage('Forking...');

      
$pid pcntl_fork();

      if (
$pid == -1// error
      
{
         
$this->_logMessage('Could not fork'DLOG_ERROR);

         return 
false;
      }
      else if (
$pid// parent
      
{
         
$this->_logMessage('Killing parent');

         exit();
      }
      else 
// children
      
{
         
$this->_isChildren true;
         
$this->_pid posix_getpid();

         return 
true;
      }
   }

   
/**
    * Sets identity of a daemon and returns result
    *
    * @access private
    * @since 1.0
    * @return bool
    */
   
function _setIdentity()
   {
      if (!
posix_setgid($this->groupID) || !posix_setuid($this->userID))
      {
         
$this->_logMessage('Could not set identity'DLOG_WARNING);

         return 
false;
      }
      else
      {
         return 
true;
      }
   }

   
/**
    * Signals handler
    *
    * @access public
    * @since 1.0
    * @return void
    */
   
function sigHandler($sigNo)
   {
      switch (
$sigNo)
      {
         case 
SIGTERM:   // Shutdown
            
$this->_logMessage('Shutdown signal');
            exit();
            break;

         case 
SIGCHLD:   // Halt
            
$this->_logMessage('Halt signal');
            while (
pcntl_waitpid(-1$statusWNOHANG) > 0);
            break;
      }
   }

   
/**
    * Releases daemon pid file
    * This method is called on exit (destructor like)
    *
    * @access public
    * @since 1.0
    * @return void
    */
   
function releaseDaemon()
   {
      if (
$this->_isChildren && file_exists($this->pidFileLocation))
      {
         
$this->_logMessage('Releasing daemon');

         
unlink($this->pidFileLocation);
      }
   }
}
?>