164 lines
3.8 KiB
PHP
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;
|
|
}
|
|
}
|
|
}
|