Browse Source

修复bug 1、GetUserRepCon有时候会直接通过而不提示无权限2、通过重定向stderr实现错误信息信息的收集3、增加用户扫描个人仓库路径权限信息列表时进行存在性检查 如果不存在则同步修改atuthz文件

docker-svn
witersen 3 years ago
parent
commit
1fb0d31856
  1. 13
      02.php/app/controller/statistics.class.php
  2. 5
      02.php/app/controller/subversion.class.php
  3. 94
      02.php/app/controller/svnrep.class.php
  4. 12
      02.php/app/core/controller.class.php
  5. 3
      02.php/app/function/file.function.php
  6. 6
      02.php/app/function/socket.function.php
  7. 5
      02.php/extension/SVNAdmin/src/class/SVNInfo.class.php
  8. 84
      02.php/extension/SVNAdmin/src/class/SVNRep.class.php
  9. 119
      02.php/server/svnadmind.php

13
02.php/app/controller/statistics.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-28 01:53:50
* @LastEditTime: 2022-04-30 19:22:53
* @Description: QQ:1801168257
*/
@ -40,6 +40,7 @@ class statistics extends controller @@ -40,6 +40,7 @@ class statistics extends controller
* ----------负载计算开始----------
*/
$laodavg = FunShellExec("cat /proc/loadavg | awk '{print $1,$2,$3}'");
$laodavg = $laodavg['result'];
$laodavgArray = explode(' ', $laodavg);
//获取CPU15分钟前到现在的负载平均值
@ -53,6 +54,7 @@ class statistics extends controller @@ -53,6 +54,7 @@ class statistics extends controller
//获取cpu总核数
$cpuCount = FunShellExec('grep -c "model name" /proc/cpuinfo');
$cpuCount = $cpuCount['result'];
$cpuCount = (int)trim($cpuCount);
//一分钟的平均负载 / (cpu总核数 * 2),超过100则为100 不超100为真实值取整
@ -91,12 +93,14 @@ class statistics extends controller @@ -91,12 +93,14 @@ class statistics extends controller
* st steal 实时
*/
$topResult = FunShellExec('top -b -n 1 | grep Cpu');
$topResult = $topResult['result'];
preg_match('/ni,(.*?)id/', $topResult, $matches);
$id = 100 - (float)trim($matches[1]);
//cpu型号
$cpuModelArray = [];
$cpuModelName = FunShellExec("cat /proc/cpuinfo | grep 'model name' | uniq");
$cpuModelName = $cpuModelName['result'];
$explodeArray = explode("\n", trim($cpuModelName));
foreach ($explodeArray as $value) {
if (trim($value) != '') {
@ -107,10 +111,12 @@ class statistics extends controller @@ -107,10 +111,12 @@ class statistics extends controller
//物理cpu个数
$cpuPhysical = FunShellExec("cat /proc/cpuinfo | grep 'physical id' | sort -u | wc -l");
$cpuPhysical = $cpuPhysical['result'];
$cpuPhysical = (int)trim($cpuPhysical);
//每个物理cpu的物理核心数
$cpuPhysicalCore = FunShellExec("cat /proc/cpuinfo | grep 'cpu cores' | wc -l");
$cpuPhysicalCore = $cpuPhysicalCore['result'];
$cpuPhysicalCore = (int)trim($cpuPhysicalCore);
//总物理核心数 = 物理cpu个数 * 每个物理cpu的物理核心数(每个物理cpu的物理核心数都一样吗?)
@ -118,6 +124,7 @@ class statistics extends controller @@ -118,6 +124,7 @@ class statistics extends controller
//逻辑核心总数(线程总数)
$cpuProcessor = FunShellExec("cat /proc/cpuinfo | grep 'processor' | wc -l");
$cpuProcessor = $cpuProcessor['result'];
$cpuProcessor = (int)trim($cpuProcessor);
/**
@ -143,10 +150,12 @@ class statistics extends controller @@ -143,10 +150,12 @@ class statistics extends controller
*/
//物理内存总量
$memTotal = FunShellExec("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'");
$memTotal = $memTotal['result'];
$memTotal = (int)trim($memTotal);
//操作系统可用内存总量(没有使用空闲内存)
$memFree = FunShellExec("cat /proc/meminfo | grep 'MemAvailable' | awk '{print $2}'");
$memFree = $memFree['result'];
$memFree = (int)trim($memFree);
//操作系统已使用内存总量
@ -177,6 +186,7 @@ class statistics extends controller @@ -177,6 +186,7 @@ class statistics extends controller
function GetDisk()
{
$rs = FunShellExec('df -lh | grep -E "^(/)"');
$rs = $rs['result'];
//将多个连续的空格换为一个
$result = preg_replace("/\s{2,}/", ' ', $rs);
@ -220,6 +230,7 @@ class statistics extends controller @@ -220,6 +230,7 @@ class statistics extends controller
{
//操作系统类型和版本
$os = FunShellExec("cat /etc/redhat-release");
$os = $os['result'];
//仓库占用体积
$repSize = FunFormatSize(FunGetDirSizeDu(SVN_REPOSITORY_PATH));

5
02.php/app/controller/subversion.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:32:15
* @LastEditTime: 2022-04-30 19:24:09
* @Description: QQ:1801168257
*/
@ -27,6 +27,7 @@ class subversion extends controller @@ -27,6 +27,7 @@ class subversion extends controller
function GetStatus()
{
$result = FunShellExec("ps auxf | grep -v 'grep' | grep svnserve");
$result = $result['result'];
if ($result == '') {
FunMessageExit(200, 0, 'svnserve服务未在运行,SVN用户将无法使用仓库浏览功能');
@ -64,6 +65,7 @@ class subversion extends controller @@ -64,6 +65,7 @@ class subversion extends controller
//检测运行信息
$runInfo = FunShellExec('ps auxf|grep -v "grep"|grep svnserve');
$runInfo = $runInfo['result'];
//检测安装信息
$installInfo = file_exists('/usr/bin/svnserve');
@ -86,6 +88,7 @@ class subversion extends controller @@ -86,6 +88,7 @@ class subversion extends controller
$version = '-';
if ($installed != 0) {
$versionInfo = FunShellExec('svnserve --version');
$versionInfo = $versionInfo['result'];
preg_match_all(REG_SUBVERSION_VERSION, $versionInfo, $versionInfoPreg);
if (array_key_exists(0, $versionInfoPreg[0])) {
$version = trim($versionInfoPreg[1][0]);

94
02.php/app/controller/svnrep.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:27:42
* @LastEditTime: 2022-04-30 19:57:12
* @Description: QQ:1801168257
*/
@ -149,7 +149,69 @@ class svnrep extends controller @@ -149,7 +149,69 @@ class svnrep extends controller
}
}
FunShellExec('echo \'' . $authzContet . '\' > ' . SVN_AUTHZ_FILE);
if ($authzContet != $this->globalAuthzContent) {
FunShellExec('echo \'' . $authzContet . '\' > ' . SVN_AUTHZ_FILE);
}
}
/**
* 对用户有权限的仓库路径列表进行一一验证
*
* 确保该仓库的路径存在于仓库的最新版本库中
*
* 此方式可以清理掉因为目录/文件名进行修改/删除后造成的authz文件冗余
* 但是此方式只能清理对此用户进行的有权限的授权 而不能清理无权限的情况
* 以后有时间会考虑对所有的路径进行扫描和清理[todo]
*/
function SyncRepPathCheck()
{
//获取在authz文件配置的用户有权限的仓库路径列表
$userRepList = [];
//获取用户有权限的仓库列表
$userRepList = array_merge($userRepList, $this->SVNAdminUser->GetUserPriRepListWithPriAndPath($this->globalAuthzContent, $this->globalUserName));
//获取用户所在的所有分组
$userGroupList = $this->Svngorup->GetSvnUserAllGroupList($this->globalUserName);
//获取分组有权限的仓库路径列表
foreach ($userGroupList as $value) {
$userRepList = array_merge($userRepList, $this->SVNAdminGroup->GetGroupPriRepListWithPriAndPath($this->globalAuthzContent, $value));
}
//按照全路径去重
$tempArray = [];
foreach ($userRepList as $key => $value) {
if (in_array($value['unique'], $tempArray)) {
unset($userRepList[$key]);
} else {
array_push($tempArray, $value['unique']);
}
}
//处理不连续的下标
$userRepList = array_values($userRepList);
$authzContent = $this->globalAuthzContent;
foreach ($userRepList as $key => $value) {
$cmd = sprintf("svnlook tree '%s' --full-paths --non-recursive '%s'", SVN_REPOSITORY_PATH . $value['repName'], $value['priPath']);
$result = FunShellExec($cmd);
if (strstr($result['error'], 'svnlook: E160013:')) {
//路径在仓库不存在
//从配置文件删除指定仓库的指定路径
$tempResult = $this->SVNAdminRep->DelRepPath($authzContent, $value['repName'], $value['priPath']);
if ($tempResult != '1') {
$authzContent = $tempResult;
}
}
}
//写入配置文件
if ($authzContent != $this->globalAuthzContent) {
FunShellExec('echo \'' . $authzContent . '\' > ' . SVN_AUTHZ_FILE);
}
}
/**
@ -292,6 +354,23 @@ class svnrep extends controller @@ -292,6 +354,23 @@ class svnrep extends controller
*/
$this->SyncRepAndAuthz();
/**
* 及时更新
*/
parent::UPdateAuthz();
/**
* 对用户有权限的仓库路径列表进行一一验证
*
* 确保该仓库的路径存在于仓库的最新版本库中
*/
$this->SyncRepPathCheck();
/**
* 及时更新
*/
parent::UPdateAuthz();
/**
* 用户有权限的仓库路径列表 => svn_user_pri_paths数据表
*
@ -353,7 +432,7 @@ class svnrep extends controller @@ -353,7 +432,7 @@ class svnrep extends controller
'rep_name' => $this->requestPayload['rep_name']
]);
FunMessageExit();
FunMessageExit(200, 1, '已保存');
}
/**
@ -560,6 +639,7 @@ class svnrep extends controller @@ -560,6 +639,7 @@ class svnrep extends controller
//获取全路径的一层目录树
$cmdSvnlookTree = sprintf("svnlook tree '%s' --full-paths --non-recursive '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'], $path);
$result = FunShellExec($cmdSvnlookTree);
$result = $result['result'];
$resultArray = explode("\n", trim($result));
unset($resultArray[0]);
$resultArray = array_values($resultArray);
@ -653,6 +733,7 @@ class svnrep extends controller @@ -653,6 +733,7 @@ class svnrep extends controller
//获取全路径的一层目录树
$cmdSvnlookTree = sprintf("svnlook tree '%s' --full-paths --non-recursive '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'], $path);
$result = FunShellExec($cmdSvnlookTree);
$result = $result['result'];
$resultArray = explode("\n", trim($result));
unset($resultArray[0]);
$resultArray = array_values($resultArray);
@ -1209,10 +1290,10 @@ class svnrep extends controller @@ -1209,10 +1290,10 @@ class svnrep extends controller
//使用svndump
$result = $this->SVNAdminRep->RepLoad($this->requestPayload['rep_name'], $this->requestPayload['fileName']);
if ($result == '') {
if ($result['error'] == '') {
FunMessageExit();
} else {
FunMessageExit(200, 0, '导入错误', $result);
FunMessageExit(200, 0, '导入错误', $result['error']);
}
}
@ -1294,7 +1375,8 @@ class svnrep extends controller @@ -1294,7 +1375,8 @@ class svnrep extends controller
foreach ($file_arr as $file_item) {
if ($file_item != '.' && $file_item != '..') {
if (in_array($file_item, $hooks_file_list)) {
$hooks_type_list[$file_item]['shell'] = FunShellExec(sprintf("cat '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'] . '/' . 'hooks' . '/' . $file_item));
$temp = FunShellExec(sprintf("cat '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'] . '/' . 'hooks' . '/' . $file_item));
$hooks_type_list[$file_item]['shell'] = $temp['result'];
$hooks_type_list[$file_item]['shell'] = trim($hooks_type_list[$file_item]['shell']);
}
}

12
02.php/app/core/controller.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-28 02:03:15
* @LastEditTime: 2022-04-30 19:44:21
* @Description: QQ:1801168257
*/
@ -150,4 +150,14 @@ class controller @@ -150,4 +150,14 @@ class controller
$arr = explode('.', $this->token);
return $arr[1];
}
/**
* 重新从authz文件中读取内容
*
* 由于有些操作会更改authz文件内容且其它操作依赖这一实时结果 因此需要及时更新
*/
final function UPdateAuthz()
{
$this->globalAuthzContent = file_exists(SVN_AUTHZ_FILE) ? file_get_contents(SVN_AUTHZ_FILE) : '';
}
}

3
02.php/app/function/file.function.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-26 16:58:42
* @LastEditTime: 2022-04-30 19:26:32
* @Description: QQ:1801168257
*/
@ -63,6 +63,7 @@ function FunGetDirSizeDu($path) @@ -63,6 +63,7 @@ function FunGetDirSizeDu($path)
{
$cmd = sprintf("du -s '%s' | awk '{print $1}'", $path);
$result = FunShellExec($cmd);
$result = $result['result'];
$result = (int)trim($result) * 1024;
return $result;
}

6
02.php/app/function/socket.function.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:05
* @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:14:02
* @LastEditTime: 2022-04-30 19:17:16
* @Description: QQ:1801168257
*/
@ -21,7 +21,7 @@ function FunShellExec($shell) @@ -21,7 +21,7 @@ function FunShellExec($shell)
socket_write($socket, $shell);
$reply = socket_read($socket, (int)SOCKET_READ_LENGTH);
socket_close($socket);
return $reply = $reply == ISNULL ? '' : $reply;
return unserialize($reply);
}
/**
@ -34,12 +34,10 @@ function FunDetectState() @@ -34,12 +34,10 @@ function FunDetectState()
{
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
@socket_connect($sock, IPC_ADDRESS, (int)IPC_PORT);
socket_set_nonblock($sock);
socket_set_block($sock);
$v = array($sock);

5
02.php/extension/SVNAdmin/src/class/SVNInfo.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-27 17:58:13
* @LastEditors: witersen
* @LastEditTime: 2022-04-28 02:09:18
* @LastEditTime: 2022-04-30 19:28:20
* @Description: QQ:1801168257
* @copyright: https://github.com/witersen/
*/
@ -34,6 +34,7 @@ class Info extends Core @@ -34,6 +34,7 @@ class Info extends Core
$bindHost = '';
$svnserveContent = FunShellExec('cat ' . $SVNSERVE_ENV_FILE);
$svnserveContent = $svnserveContent['result'];
//匹配端口
if (preg_match('/--listen-port[\s]+([0-9]+)/', $svnserveContent, $portMatchs) != 0) {
@ -46,6 +47,7 @@ class Info extends Core @@ -46,6 +47,7 @@ class Info extends Core
}
$listenContent = FunShellExec('cat ' . $LISTEN_FILE);
$listenContent = $listenContent['result'];
if (!FunCheckJson($listenContent)) {
//文件格式错误则初始化
@ -73,6 +75,7 @@ class Info extends Core @@ -73,6 +75,7 @@ class Info extends Core
}
$listenContent = FunShellExec('cat ' . $LISTEN_FILE);
$listenContent = $listenContent['result'];
$listenArray = json_decode($listenContent, true);
return [

84
02.php/extension/SVNAdmin/src/class/SVNRep.class.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-27 15:45:45
* @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:26:16
* @LastEditTime: 2022-04-30 19:56:44
* @Description: QQ:1801168257
* @copyright: https://github.com/witersen/
*/
@ -618,6 +618,29 @@ class Rep extends Core @@ -618,6 +618,29 @@ class Rep extends Core
}
}
/**
* 从配置文件删除指定仓库的指定路径
*
* 1 已删除
* string 正常
*/
function DelRepPath($authzContent, $repName, $repPath)
{
//处理路径结尾
if ($repPath != '/') {
if (substr($repPath, strlen($repPath) - 1, 1) == '/') {
$repPath = substr($repPath, 0, strlen($repPath) - 1);
}
}
preg_match_all(sprintf($this->REG_AUTHZ_REP_SPECIAL_PATH_WITH_CON, $repName, str_replace('/', '\/', $repPath)), $authzContent, $authzContentPreg);
if (array_key_exists(0, $authzContentPreg[0])) {
return str_replace($authzContentPreg[0][0], "", $authzContent);
} else {
return '1';
}
}
/**
* 从配置文件删除指定仓库的所有路径
*
@ -866,6 +889,7 @@ class Rep extends Core @@ -866,6 +889,7 @@ class Rep extends Core
$svnadminInfoCmd = sprintf("svnadmin info '%s'", $repPath);
$cmdResult = FunShellExec($svnadminInfoCmd);
$cmdResult = $cmdResult['result'];
preg_match_all($this->REG_REP_INFO, $cmdResult, $svnadminInfoPreg);
@ -884,6 +908,7 @@ class Rep extends Core @@ -884,6 +908,7 @@ class Rep extends Core
$repPath = SVN_REPOSITORY_PATH . $repName;
$svnadminInfoCmd = sprintf("svnlook tree '%s'", $repPath);
$cmdResult = FunShellExec($svnadminInfoCmd);
$cmdResult = $cmdResult['result'];
// $cmdResult = shell_exec($svnadminInfoCmd);
$treeArray = explode("\n", $cmdResult);
//去除数组中的空字符串键值 通常为最后一项
@ -1186,7 +1211,8 @@ class Rep extends Core @@ -1186,7 +1211,8 @@ class Rep extends Core
function GetRepRev($repName)
{
$cmd = sprintf("svnadmin info '%s' | grep 'Revisions' | awk '{print $2}'", SVN_REPOSITORY_PATH . $repName);
return (int)trim(FunShellExec($cmd));
$result = FunShellExec($cmd);
return (int)$result['result'];
}
/**
@ -1195,7 +1221,8 @@ class Rep extends Core @@ -1195,7 +1221,8 @@ class Rep extends Core
function GetRepDetail($repName)
{
$cmd = sprintf("svnadmin info '%s'", SVN_REPOSITORY_PATH . $repName);
return trim(FunShellExec($cmd));
$result = FunShellExec($cmd);
return $result['result'];
}
/**
@ -1208,7 +1235,8 @@ class Rep extends Core @@ -1208,7 +1235,8 @@ class Rep extends Core
function GetRepRevFileSize($repName, $filePath)
{
$cmd = sprintf("svnlook filesize '%s' '%s'", SVN_REPOSITORY_PATH . $repName, $filePath);
$size = (int)trim(FunShellExec($cmd));
$result = FunShellExec($cmd);
$size = (int)$result['result'];
return FunFormatSize($size);
}
@ -1219,6 +1247,7 @@ class Rep extends Core @@ -1219,6 +1247,7 @@ class Rep extends Core
{
$cmd = sprintf("svnlook history --limit 1 '%s' '%s'", SVN_REPOSITORY_PATH . $repName, $filePath);
$result = FunShellExec($cmd);
$result = $result['result'];
$resultArray = explode("\n", $result);
$content = preg_replace("/\s{2,}/", ' ', $resultArray[2]);
$contentArray = explode(' ', $content);
@ -1232,7 +1261,7 @@ class Rep extends Core @@ -1232,7 +1261,7 @@ class Rep extends Core
{
$cmd = sprintf("svnlook author -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd);
return $result;
return $result['result'];
}
/**
@ -1242,7 +1271,7 @@ class Rep extends Core @@ -1242,7 +1271,7 @@ class Rep extends Core
{
$cmd = sprintf("svnlook date -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd);
return $result;
return $result['result'];
}
/**
@ -1252,7 +1281,7 @@ class Rep extends Core @@ -1252,7 +1281,7 @@ class Rep extends Core
{
$cmd = sprintf("svnlook log -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd);
return $result;
return $result['result'];
}
/**
@ -1292,22 +1321,31 @@ class Rep extends Core @@ -1292,22 +1321,31 @@ class Rep extends Core
{
$cmd = sprintf("svn list '%s' --username '%s' --password '%s' --no-auth-cache --non-interactive --trust-server-cert", $checkoutHost . '/' . $repName . $repPath, $svnUserName, $svnUserPass);
$result = FunShellExec($cmd);
if (strstr($result, 'svn: E170001: Authentication error from server: Password incorrect')) {
FunMessageExit(200, 0, '密码错误');
}
if (strstr($result, 'svn: E170001: Authorization failed')) {
FunMessageExit(200, 0, '无访问权限');
}
if (strstr($result, 'svn: E220003: Invalid authz configuration')) {
FunMessageExit(200, 0, '配置文件配置错误 请使用svnauthz-validate工具检查');
}
if (strstr($result, 'svn: E170013: Unable to connect to a repository at URL')) {
FunMessageExit(200, 0, '其它错误' . $result);
}
if (strstr($result, 'svn: warning: W160013:') || strstr($result, "svn: E200009: Could not list all targets because some targets don't exist")) {
// FunMessageExit(200, 0, '该路径在仓库不存在 请刷新以同步');
FunMessageExit(200, 0, '该路径在仓库已不在版本库中');
if ($result['resultCode'] != 0) {
//: Authentication error from server: Password incorrect
if (strstr($result['error'], 'svn: E170001')) {
FunMessageExit(200, 0, '密码错误');
}
//: Authorization failed
if (strstr($result['error'], 'svn: E170001')) {
FunMessageExit(200, 0, '无访问权限');
}
//: Invalid authz configuration
if (strstr($result['error'], 'svn: E220003')) {
FunMessageExit(200, 0, '配置文件配置错误 请使用svnauthz-validate工具检查');
}
//: Unable to connect to a repository at URL
if (strstr($result['error'], 'svn: E170013')) {
FunMessageExit(200, 0, '无法连接到仓库');
}
//: Could not list all targets because some targets don't exist
if (strstr($result['error'], 'svn: warning: W160013') || strstr($result['error'], "svn: E200009")) {
FunMessageExit(200, 0, '该授权路径在仓库不存在 请刷新以同步');
}
FunMessageExit(200, 0, '其它错误' . $result['error']);
}
return $result;
return $result['result'];
}
}

119
02.php/server/svnadmind.php

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
* @Author: witersen
* @Date: 2022-04-24 23:37:06
* @LastEditors: witersen
* @LastEditTime: 2022-04-28 02:22:01
* @LastEditTime: 2022-04-30 19:59:26
* @Description: QQ:1801168257
*/
@ -34,7 +34,7 @@ class Daemon @@ -34,7 +34,7 @@ class Daemon
/**
* 将程序变为守护进程
*/
private function initDaemon()
private function InitDeamon()
{
$pid = pcntl_fork();
if ($pid < 0) {
@ -64,13 +64,13 @@ class Daemon @@ -64,13 +64,13 @@ class Daemon
fclose(STDERR);
}
file_put_contents($this->pidFile, getmypid());
$this->initSocket();
$this->InitSocket();
}
/**
* 监听指定端口
* 创建TCP套接字并监听指定端口
*/
private function initSocket()
private function InitSocket()
{
//创建套接字
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or exit('启动失败:socket_create 错误' . PHP_EOL);
@ -97,53 +97,65 @@ class Daemon @@ -97,53 +97,65 @@ class Daemon
if ($pid == -1) {
exit('启动失败:pcntl_fork 错误' . PHP_EOL);
} else if ($pid == 0) {
$this->handleRequest($client);
$this->HandleRequest($client);
} else {
}
}
}
/**
* socket程序接收和处理请求
* 接收TCP连接并处理指令
*/
private function handleRequest($client)
private function HandleRequest($client)
{
//接收客户端发送的数据
$data = socket_read($client, SOCKET_READ_LENGTH);
//console
$this->workMode == 'console' ? print_r(PHP_EOL . '---------receive---------' . PHP_EOL . $data . PHP_EOL) : '';
if (trim($data) != '') {
/**
* shell_exec方法拿不到执行指令的错误抛出信息
*/
// $result = shell_exec($data);
/**
* passthru会将所有的结果(包括正确的和错误的抛出信息输出)
* 可以使用 ob_start ob_get_contents ob_end_clean 拿到缓冲区的内容
*
* 此方法在console调试模式下会导致 $result 变量拿不到值;
* 但是在daemon模式下 $result 变量可以拿到值(猜测是输入到终端与输出到缓冲区的影响)
*/
$cmmand = socket_read($client, SOCKET_READ_LENGTH);
//console模式
if ($this->workMode == 'console') {
echo PHP_EOL . '---------receive---------' . PHP_EOL;
echo $cmmand . PHP_EOL;
}
if (trim($cmmand) != '') {
//定义错误输出文件路径
$stderrFile = TEMP_PATH . uniqid();
//将标准错误重定向到文件
//使用状态码来标识错误信息
ob_start();
passthru($data);
$result = ob_get_contents();
passthru($cmmand . " 2>$stderrFile", $resultCode);
$buffer = ob_get_contents();
ob_end_clean();
//将错误信息和正确信息分类收集
$result = [
'resultCode' => $resultCode,
'result' => trim($buffer),
'error' => file_get_contents($stderrFile)
];
//销毁文件
unlink($stderrFile);
} else {
//探测程序会发送空信息
$result = '';
$result = [
'resultCode' => 0,
'result' => '',
'error' => ''
];
}
//console
$this->workMode == 'console' ? print_r(PHP_EOL . '---------result---------' . PHP_EOL . $result . PHP_EOL) : '';
//处理没有返回内容的情况 否则 socket_write 遇到空内容会报错
$result = trim($result) == '' ? ISNULL : trim($result);
//console模式
if ($this->workMode == 'console') {
echo PHP_EOL . '---------result---------' . PHP_EOL;
echo 'resultCode: ' . $result['resultCode'] . PHP_EOL;
echo 'result: ' . $result['result'] . PHP_EOL;
echo 'error: ' . $result['error'] . PHP_EOL;
}
//将结果返回给客户端
socket_write($client, $result, strlen($result)) or die('启动失败:socket_write 错误' . PHP_EOL);
//将结果序列化并返回
socket_write($client, serialize($result), strlen(serialize($result))) or die('失败:socket_write 错误' . PHP_EOL);
//关闭会话
socket_close($client);
@ -155,7 +167,7 @@ class Daemon @@ -155,7 +167,7 @@ class Daemon
/**
* 检查操作系统是否符合要求
*/
private function checkSysType()
private function CheckSysType()
{
if (PHP_OS != 'Linux') {
exit('启动失败:当前操作系统不为Linux' . PHP_EOL);
@ -173,7 +185,7 @@ class Daemon @@ -173,7 +185,7 @@ class Daemon
/**
* 检查php版本是否符合要求
*/
private function checkPhpVersion()
private function CheckPhpVersion()
{
if (PHP_VERSION < Required_PHP_VERSION) {
exit('启动失败:当前的PHP版本为:' . PHP_VERSION . ',要求的最低PHP版本为:' . Required_PHP_VERSION . PHP_EOL);
@ -183,7 +195,7 @@ class Daemon @@ -183,7 +195,7 @@ class Daemon
/**
* 检查需要的函数是否被禁用
*/
private function checkDisabledFunction()
private function CheckDisabledFunction()
{
$disabled_function = explode(',', ini_get('disable_functions'));
$cli_needed_function = unserialize(CLI_NEEDED_FUNCTION);
@ -200,7 +212,7 @@ class Daemon @@ -200,7 +212,7 @@ class Daemon
/**
* 以守护进程模式工作
*/
private function startDaemon()
private function StartDaemon()
{
if (file_exists($this->pidFile)) {
$pid = file_get_contents($this->pidFile);
@ -209,13 +221,13 @@ class Daemon @@ -209,13 +221,13 @@ class Daemon
exit('程序正在运行中' . PHP_EOL);
}
}
$this->initDaemon();
$this->InitDeamon();
}
/**
* 关闭守护进程
*/
private function stopDaemon()
private function StopDaemon()
{
if (file_exists($this->pidFile)) {
$pid = file_get_contents($this->pidFile);
@ -227,27 +239,27 @@ class Daemon @@ -227,27 +239,27 @@ class Daemon
/**
* 以控制台模式工作 用于调试
*/
private function startConsole()
private function StartConsole()
{
$this->initSocket();
$this->InitSocket();
}
public function run($argv)
public function Run($argv)
{
$this->checkSysType();
$this->checkPhpVersion();
$this->checkDisabledFunction();
$this->CheckSysType();
$this->CheckPhpVersion();
$this->CheckDisabledFunction();
if (isset($argv[1])) {
$this->workMode = $argv[1];
if (!in_array($this->workMode, $this->scripts)) {
exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL);
}
if ($this->workMode == 'start') {
$this->startDaemon();
$this->StartDaemon();
} else if ($this->workMode == 'stop') {
$this->stopDaemon();
$this->StopDaemon();
} else if ($this->workMode == 'console') {
$this->startConsole();
$this->StartConsole();
}
} else {
exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL);
@ -255,7 +267,10 @@ class Daemon @@ -255,7 +267,10 @@ class Daemon
}
}
/**
* 将工作模式限制在cli模式
*/
if (preg_match('/cli/i', php_sapi_name())) {
$deamon = new Daemon();
$deamon->run($argv);
$deamon->Run($argv);
}

Loading…
Cancel
Save