Add analytics
[bus.git] / busui / owa / includes / Daemon.class.php
blob:a/busui/owa/includes/Daemon.class.php -> blob:b/busui/owa/includes/Daemon.class.php
  <?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 __construct()
  {
  error_reporting(0);
  set_time_limit(0);
  ob_implicit_flush();
   
  }
   
  /**
  * 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...');
   
  if (!function_exists('pcntl_fork')) {
  $this->_logMessage('Forking 2...');
  }
  $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, $status, WNOHANG) > 0);
  break;
  }
  }
   
  /**
  * Releases daemon pid file
  * This method is called on exit (destructor like)
  *
  * @access public
  * @since 1.0
  * @return void
  */
  function __destruct()
  {
  if ($this->_isChildren && file_exists($this->pidFileLocation))
  {
  $this->_logMessage('Releasing daemon');
   
  unlink($this->pidFileLocation);
  }
  }
  }
  ?>