You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.1 KiB
218 lines
6.1 KiB
<?php |
|
|
|
declare(strict_types=1); |
|
|
|
ini_set('display_errors', '1'); |
|
|
|
error_reporting(E_ALL); |
|
|
|
define('BASE_PATH', __DIR__); |
|
|
|
require_once BASE_PATH . '/../config/manual.config.php'; |
|
|
|
class Daemon |
|
{ |
|
|
|
private $pidfile; |
|
private $state; |
|
private $cmdlist = array( |
|
"start", |
|
"stop", |
|
"console" |
|
); |
|
|
|
function __construct() |
|
{ |
|
$this->pidfile = dirname(__FILE__) . '/svnadmind.pid'; |
|
} |
|
|
|
private function init_daemon() |
|
{ |
|
$pid = pcntl_fork(); |
|
if ($pid < 0) { |
|
exit('pcntl_fork 错误'); |
|
} elseif ($pid > 0) { |
|
exit(); |
|
} |
|
$sid = posix_setsid(); |
|
if (!$sid) { |
|
exit('posix_setsid 错误'); |
|
} |
|
$pid = pcntl_fork(); |
|
if ($pid < 0) { |
|
exit('pcntl_fork 错误'); |
|
} elseif ($pid > 0) { |
|
exit(); |
|
} |
|
chdir("/"); |
|
umask(0); |
|
if (defined('STDIN')) { |
|
fclose(STDIN); |
|
} |
|
if (defined('STDOUT')) { |
|
fclose(STDOUT); |
|
} |
|
if (defined('STDERR')) { |
|
fclose(STDERR); |
|
} |
|
file_put_contents($this->pidfile, getmypid()); |
|
return getmypid(); |
|
} |
|
|
|
private function init_socket() |
|
{ |
|
//创建套接字 |
|
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or exit("socket_create 错误\n"); |
|
|
|
//绑定地址和端口 |
|
socket_bind($socket, IPC_ADDRESS, (int)IPC_PORT) or exit("socket_bind 错误 可能是由于频繁启动 端口未释放 请稍后重试或检查端口冲突\n"); |
|
|
|
//设置可重复使用端口号 |
|
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); |
|
|
|
//监听 设置并发队列的最大长度 |
|
socket_listen($socket, (int)SOCKET_LISTEN_BACKLOG); |
|
|
|
while (true) { |
|
//非阻塞式回收僵尸进程 |
|
pcntl_wait($status, WNOHANG); |
|
|
|
$clien = socket_accept($socket) or exit("socket_accept 错误\n"); |
|
|
|
//非阻塞式回收僵尸进程 |
|
pcntl_wait($status, WNOHANG); |
|
|
|
$pid = pcntl_fork(); |
|
if ($pid == -1) { |
|
exit("pcntl_fork 错误\n"); |
|
} else if ($pid == 0) { |
|
$this->handle_request($clien); |
|
} else { |
|
} |
|
} |
|
} |
|
|
|
private function check_sys_type() |
|
{ |
|
if (PHP_OS != 'Linux') { |
|
exit("启动失败 \n当前操作系统不为Linux\n"); |
|
} |
|
if (file_exists('/etc/redhat-release')) { |
|
$info = file_get_contents('/etc/redhat-release'); |
|
if (!strstr($info, 'CentOS') && (strstr($info, '8.') || strstr($info, '7.'))) { |
|
exit("启动失败 \n仅支持CentOS 7 和 CentOS8 系统\n"); |
|
} |
|
return; |
|
} |
|
exit("启动失败 \n不支持当前操作系统\n"); |
|
} |
|
|
|
private function check_php_version() |
|
{ |
|
if (PHP_VERSION < Required_PHP_VERSION) { |
|
echo "启动失败 \n当前的PHP版本为 " . PHP_VERSION . " 最低的PHP版本要求为 " . Required_PHP_VERSION . "\n"; |
|
exit(); |
|
} |
|
} |
|
|
|
private function check_disabled_function() |
|
{ |
|
$disabled_function = explode(',', ini_get('disable_functions')); |
|
$needed_function = NEEDED_FUNCTION; |
|
foreach ($needed_function as $key => $value) { |
|
if (!in_array($value, $disabled_function)) { |
|
unset($needed_function[$key]); |
|
} |
|
} |
|
if (!empty($needed_function)) { |
|
echo "启动失败 \n需要的以下PHP函数被禁用:\n" . implode("\n", $needed_function) . "\n"; |
|
exit(); |
|
} |
|
} |
|
|
|
private function handle_request($clien) |
|
{ |
|
//接收客户端发送的数据 |
|
$data = socket_read($clien, (int)SOCKET_READ_LENGTH); |
|
|
|
//console |
|
$this->state == "console" ? print_r("\n---------接收内容---------\n" . $data . "\n") : ""; |
|
|
|
if (trim($data) != "") { |
|
//执行 |
|
$result = shell_exec($data); |
|
} else { |
|
//探测程序会发送空信息 |
|
$result = ""; |
|
} |
|
|
|
//console |
|
$this->state == "console" ? print_r("\n---------执行结果---------\n" . $result . "\n") : ""; |
|
|
|
//处理没有返回内容的情况 否则 socket_write 遇到空内容会报错 |
|
$result = $result == "" ? ISNULL : $result; |
|
|
|
//将结果返回给客户端 |
|
socket_write($clien, $result, strlen($result)) or die("socket_write 错误"); |
|
|
|
//关闭会话 |
|
socket_close($clien); |
|
|
|
//退出进程 |
|
exit(); |
|
} |
|
|
|
private function start_daemon() |
|
{ |
|
if (file_exists($this->pidfile)) { |
|
$pid = file_get_contents($this->pidfile); |
|
$result = trim(shell_exec("ps -ax | awk '{ print $1 }' | grep -e \"^$pid$\"")); |
|
if (strstr($result, $pid)) { |
|
echo "进程正在运行中 无需启动\n"; |
|
exit(); |
|
} |
|
} |
|
return $this->init_daemon(); |
|
} |
|
|
|
private function start() |
|
{ |
|
$this->start_daemon(); |
|
$this->init_socket(); |
|
} |
|
|
|
private function stop() |
|
{ |
|
if (file_exists($this->pidfile)) { |
|
$pid = file_get_contents($this->pidfile); |
|
posix_kill((int)$pid, 9); |
|
unlink($this->pidfile); |
|
} |
|
} |
|
|
|
public function run($argv) |
|
{ |
|
$this->check_sys_type(); |
|
$this->check_php_version(); |
|
$this->check_disabled_function(); |
|
if (isset($argv[1])) { |
|
$this->state = $argv[1]; |
|
if (!in_array($this->state, $this->cmdlist)) { |
|
echo "用法: php svnadmind.php [start] [stop] [console]\n"; |
|
exit(); |
|
} |
|
if ($this->state == 'start') { |
|
$this->start(); |
|
} else if ($this->state == 'stop') { |
|
$this->stop(); |
|
} else if ($this->state == 'console') { |
|
$this->init_socket(); |
|
} |
|
} else { |
|
echo "用法: php svnadmind.php [start] [stop] [console]\n"; |
|
} |
|
} |
|
} |
|
|
|
$deamon = new Daemon(); |
|
$deamon->run($argv);
|
|
|