该系统为使用PHP开发的基于web的Subversion(SVN)服务器端管理工具。支持功能:SVN仓库管理、SVN用户管理、SVN分组管理、目录授权、目录浏览、Hooks管理、在线dump备份、在线备份恢复、SVN用户禁用、服务器状态管理、日志管理、消息通知、更新检测...
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

<?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);