1
0
www.mikescher.com/app/lib/Yiinitializr/Cli/Daemon.php
2014-05-06 12:17:10 +02:00

164 lines
3.8 KiB
PHP

<?php
/**
* Daemon class file.
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @author Nofriandi Ramenta <nramenta@gmail.com>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @link https://github.com/nramenta/clio
* @copyright 2013 2amigOS! Consultation Group LLC
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace Yiinitializr\Cli;
/**
* Daemon provides helpers for starting and killing daemonized processes
*
* @author Antonio Ramirez <ramirez.cobos@gmail.com>
* @package Yiinitializr.Cli
* @since 1.0
*/
class Daemon
{
/**
* Daemonize a Closure object.
* @param array $options Set of options
* @param callable $callable Closure object to daemonize
* @return bool True on success
* @throws \Exception
*/
public static function work(array $options, \Closure $callable)
{
if (!extension_loaded('pcntl')) {
throw new \Exception('pcntl extension required');
}
if (!extension_loaded('posix')) {
throw new \Exception('posix extension required');
}
if (!isset($options['pid'])) {
throw new \Exception('pid not specified');
}
$options = $options + array(
'stdin' => '/dev/null',
'stdout' => '/dev/null',
'stderr' => 'php://stdout',
);
if (($lock = @fopen($options['pid'], 'c+')) === false) {
throw new \Exception('unable to open pid file ' . $options['pid']);
}
if (!flock($lock, LOCK_EX | LOCK_NB)) {
throw new \Exception('could not acquire lock for ' . $options['pid']);
}
switch ($pid = pcntl_fork()) {
case -1:
throw new \Exception('unable to fork');
case 0:
break;
default:
fseek($lock, 0);
ftruncate($lock, 0);
fwrite($lock ,$pid);
fflush($lock);
return true;
}
if (posix_setsid() === -1) {
throw new \Exception('failed to setsid');
}
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
if (!($stdin = fopen($options['stdin'], 'r'))) {
throw new \Exception('failed to open STDIN ' . $options['stdin']);
}
if (!($stdout = fopen($options['stdout'], 'w'))) {
throw new \Exception('failed to open STDOUT ' . $options['stdout']);
}
if (!($stderr = fopen($options['stderr'], 'w'))) {
throw new \Exception('failed to open STDERR ' . $options['stderr']);
}
pcntl_signal(SIGTSTP, SIG_IGN);
pcntl_signal(SIGTTOU, SIG_IGN);
pcntl_signal(SIGTTIN, SIG_IGN);
pcntl_signal(SIGHUP, SIG_IGN);
call_user_func($callable, $stdin, $stdout, $stderr);
}
/**
* Whether a process is running or not
* @param $file
* @return bool
* @throws \Exception
*/
public static function isRunning($file)
{
if (!extension_loaded('posix')) {
throw new \Exception('posix extension required');
}
if (!is_readable($file)) {
return false;
}
if (($lock = @fopen($file, 'c+')) === false) {
throw new \Exception('unable to open pid file ' . $file);
}
if (flock($lock, LOCK_EX | LOCK_NB)) {
return false;
} else {
flock($lock, LOCK_UN);
return true;
}
}
/**
* Kills a daemon process specified by its PID file.
*
* @param $file Daemon PID file
* @param bool $delete Flag to delete PID file after killing
* @return bool True on success, false otherwise
* @throws \Exception
*/
public static function kill($file, $delete = false)
{
if (!extension_loaded('posix')) {
throw new \Exception('posix extension required');
}
if (!is_readable($file)) {
throw new \Exception('unreadable pid file ' . $file);
}
if (($lock = @fopen($file, 'c+')) === false) {
throw new \Exception('unable to open pid file ' . $file);
}
if (flock($lock, LOCK_EX | LOCK_NB)) {
flock($lock, LOCK_UN);
throw new \Exception('process not running');
}
$pid = fgets($lock);
if (posix_kill($pid, SIGTERM)) {
if ($delete) unlink($file);
return true;
} else {
return false;
}
}
}