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

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

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

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

@ -3,7 +3,7 @@
* @Author: witersen * @Author: witersen
* @Date: 2022-04-24 23:37:05 * @Date: 2022-04-24 23:37:05
* @LastEditors: witersen * @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:27:42 * @LastEditTime: 2022-04-30 19:57:12
* @Description: QQ:1801168257 * @Description: QQ:1801168257
*/ */
@ -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
*/ */
$this->SyncRepAndAuthz(); $this->SyncRepAndAuthz();
/**
* 及时更新
*/
parent::UPdateAuthz();
/**
* 对用户有权限的仓库路径列表进行一一验证
*
* 确保该仓库的路径存在于仓库的最新版本库中
*/
$this->SyncRepPathCheck();
/**
* 及时更新
*/
parent::UPdateAuthz();
/** /**
* 用户有权限的仓库路径列表 => svn_user_pri_paths数据表 * 用户有权限的仓库路径列表 => svn_user_pri_paths数据表
* *
@ -353,7 +432,7 @@ class svnrep extends controller
'rep_name' => $this->requestPayload['rep_name'] 'rep_name' => $this->requestPayload['rep_name']
]); ]);
FunMessageExit(); FunMessageExit(200, 1, '已保存');
} }
/** /**
@ -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); $cmdSvnlookTree = sprintf("svnlook tree '%s' --full-paths --non-recursive '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'], $path);
$result = FunShellExec($cmdSvnlookTree); $result = FunShellExec($cmdSvnlookTree);
$result = $result['result'];
$resultArray = explode("\n", trim($result)); $resultArray = explode("\n", trim($result));
unset($resultArray[0]); unset($resultArray[0]);
$resultArray = array_values($resultArray); $resultArray = array_values($resultArray);
@ -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); $cmdSvnlookTree = sprintf("svnlook tree '%s' --full-paths --non-recursive '%s'", SVN_REPOSITORY_PATH . $this->requestPayload['rep_name'], $path);
$result = FunShellExec($cmdSvnlookTree); $result = FunShellExec($cmdSvnlookTree);
$result = $result['result'];
$resultArray = explode("\n", trim($result)); $resultArray = explode("\n", trim($result));
unset($resultArray[0]); unset($resultArray[0]);
$resultArray = array_values($resultArray); $resultArray = array_values($resultArray);
@ -1209,10 +1290,10 @@ class svnrep extends controller
//使用svndump //使用svndump
$result = $this->SVNAdminRep->RepLoad($this->requestPayload['rep_name'], $this->requestPayload['fileName']); $result = $this->SVNAdminRep->RepLoad($this->requestPayload['rep_name'], $this->requestPayload['fileName']);
if ($result == '') { if ($result['error'] == '') {
FunMessageExit(); FunMessageExit();
} else { } else {
FunMessageExit(200, 0, '导入错误', $result); FunMessageExit(200, 0, '导入错误', $result['error']);
} }
} }
@ -1294,7 +1375,8 @@ class svnrep extends controller
foreach ($file_arr as $file_item) { foreach ($file_arr as $file_item) {
if ($file_item != '.' && $file_item != '..') { if ($file_item != '.' && $file_item != '..') {
if (in_array($file_item, $hooks_file_list)) { 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']); $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 @@
* @Author: witersen * @Author: witersen
* @Date: 2022-04-24 23:37:05 * @Date: 2022-04-24 23:37:05
* @LastEditors: witersen * @LastEditors: witersen
* @LastEditTime: 2022-04-28 02:03:15 * @LastEditTime: 2022-04-30 19:44:21
* @Description: QQ:1801168257 * @Description: QQ:1801168257
*/ */
@ -150,4 +150,14 @@ class controller
$arr = explode('.', $this->token); $arr = explode('.', $this->token);
return $arr[1]; 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 @@
* @Author: witersen * @Author: witersen
* @Date: 2022-04-24 23:37:05 * @Date: 2022-04-24 23:37:05
* @LastEditors: witersen * @LastEditors: witersen
* @LastEditTime: 2022-04-26 16:58:42 * @LastEditTime: 2022-04-30 19:26:32
* @Description: QQ:1801168257 * @Description: QQ:1801168257
*/ */
@ -63,6 +63,7 @@ function FunGetDirSizeDu($path)
{ {
$cmd = sprintf("du -s '%s' | awk '{print $1}'", $path); $cmd = sprintf("du -s '%s' | awk '{print $1}'", $path);
$result = FunShellExec($cmd); $result = FunShellExec($cmd);
$result = $result['result'];
$result = (int)trim($result) * 1024; $result = (int)trim($result) * 1024;
return $result; return $result;
} }

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

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

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

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

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

@ -3,7 +3,7 @@
* @Author: witersen * @Author: witersen
* @Date: 2022-04-27 15:45:45 * @Date: 2022-04-27 15:45:45
* @LastEditors: witersen * @LastEditors: witersen
* @LastEditTime: 2022-04-30 02:26:16 * @LastEditTime: 2022-04-30 19:56:44
* @Description: QQ:1801168257 * @Description: QQ:1801168257
* @copyright: https://github.com/witersen/ * @copyright: https://github.com/witersen/
*/ */
@ -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
$svnadminInfoCmd = sprintf("svnadmin info '%s'", $repPath); $svnadminInfoCmd = sprintf("svnadmin info '%s'", $repPath);
$cmdResult = FunShellExec($svnadminInfoCmd); $cmdResult = FunShellExec($svnadminInfoCmd);
$cmdResult = $cmdResult['result'];
preg_match_all($this->REG_REP_INFO, $cmdResult, $svnadminInfoPreg); preg_match_all($this->REG_REP_INFO, $cmdResult, $svnadminInfoPreg);
@ -884,6 +908,7 @@ class Rep extends Core
$repPath = SVN_REPOSITORY_PATH . $repName; $repPath = SVN_REPOSITORY_PATH . $repName;
$svnadminInfoCmd = sprintf("svnlook tree '%s'", $repPath); $svnadminInfoCmd = sprintf("svnlook tree '%s'", $repPath);
$cmdResult = FunShellExec($svnadminInfoCmd); $cmdResult = FunShellExec($svnadminInfoCmd);
$cmdResult = $cmdResult['result'];
// $cmdResult = shell_exec($svnadminInfoCmd); // $cmdResult = shell_exec($svnadminInfoCmd);
$treeArray = explode("\n", $cmdResult); $treeArray = explode("\n", $cmdResult);
//去除数组中的空字符串键值 通常为最后一项 //去除数组中的空字符串键值 通常为最后一项
@ -1186,7 +1211,8 @@ class Rep extends Core
function GetRepRev($repName) function GetRepRev($repName)
{ {
$cmd = sprintf("svnadmin info '%s' | grep 'Revisions' | awk '{print $2}'", SVN_REPOSITORY_PATH . $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
function GetRepDetail($repName) function GetRepDetail($repName)
{ {
$cmd = sprintf("svnadmin info '%s'", SVN_REPOSITORY_PATH . $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
function GetRepRevFileSize($repName, $filePath) function GetRepRevFileSize($repName, $filePath)
{ {
$cmd = sprintf("svnlook filesize '%s' '%s'", SVN_REPOSITORY_PATH . $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); return FunFormatSize($size);
} }
@ -1219,6 +1247,7 @@ class Rep extends Core
{ {
$cmd = sprintf("svnlook history --limit 1 '%s' '%s'", SVN_REPOSITORY_PATH . $repName, $filePath); $cmd = sprintf("svnlook history --limit 1 '%s' '%s'", SVN_REPOSITORY_PATH . $repName, $filePath);
$result = FunShellExec($cmd); $result = FunShellExec($cmd);
$result = $result['result'];
$resultArray = explode("\n", $result); $resultArray = explode("\n", $result);
$content = preg_replace("/\s{2,}/", ' ', $resultArray[2]); $content = preg_replace("/\s{2,}/", ' ', $resultArray[2]);
$contentArray = explode(' ', $content); $contentArray = explode(' ', $content);
@ -1232,7 +1261,7 @@ class Rep extends Core
{ {
$cmd = sprintf("svnlook author -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName); $cmd = sprintf("svnlook author -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd); $result = FunShellExec($cmd);
return $result; return $result['result'];
} }
/** /**
@ -1242,7 +1271,7 @@ class Rep extends Core
{ {
$cmd = sprintf("svnlook date -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName); $cmd = sprintf("svnlook date -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd); $result = FunShellExec($cmd);
return $result; return $result['result'];
} }
/** /**
@ -1252,7 +1281,7 @@ class Rep extends Core
{ {
$cmd = sprintf("svnlook log -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName); $cmd = sprintf("svnlook log -r %s '%s'", $rev, SVN_REPOSITORY_PATH . $repName);
$result = FunShellExec($cmd); $result = FunShellExec($cmd);
return $result; return $result['result'];
} }
/** /**
@ -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); $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); $result = FunShellExec($cmd);
if (strstr($result, 'svn: E170001: Authentication error from server: Password incorrect')) {
FunMessageExit(200, 0, '密码错误'); if ($result['resultCode'] != 0) {
} //: Authentication error from server: Password incorrect
if (strstr($result, 'svn: E170001: Authorization failed')) { if (strstr($result['error'], 'svn: E170001')) {
FunMessageExit(200, 0, '无访问权限'); FunMessageExit(200, 0, '密码错误');
} }
if (strstr($result, 'svn: E220003: Invalid authz configuration')) { //: Authorization failed
FunMessageExit(200, 0, '配置文件配置错误 请使用svnauthz-validate工具检查'); if (strstr($result['error'], 'svn: E170001')) {
} FunMessageExit(200, 0, '无访问权限');
if (strstr($result, 'svn: E170013: Unable to connect to a repository at URL')) { }
FunMessageExit(200, 0, '其它错误' . $result); //: Invalid authz configuration
} if (strstr($result['error'], 'svn: E220003')) {
if (strstr($result, 'svn: warning: W160013:') || strstr($result, "svn: E200009: Could not list all targets because some targets don't exist")) { FunMessageExit(200, 0, '配置文件配置错误 请使用svnauthz-validate工具检查');
// FunMessageExit(200, 0, '该路径在仓库不存在 请刷新以同步'); }
FunMessageExit(200, 0, '该路径在仓库已不在版本库中'); //: 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 @@
* @Author: witersen * @Author: witersen
* @Date: 2022-04-24 23:37:06 * @Date: 2022-04-24 23:37:06
* @LastEditors: witersen * @LastEditors: witersen
* @LastEditTime: 2022-04-28 02:22:01 * @LastEditTime: 2022-04-30 19:59:26
* @Description: QQ:1801168257 * @Description: QQ:1801168257
*/ */
@ -34,7 +34,7 @@ class Daemon
/** /**
* 将程序变为守护进程 * 将程序变为守护进程
*/ */
private function initDaemon() private function InitDeamon()
{ {
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid < 0) { if ($pid < 0) {
@ -64,13 +64,13 @@ class Daemon
fclose(STDERR); fclose(STDERR);
} }
file_put_contents($this->pidFile, getmypid()); 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); $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or exit('启动失败:socket_create 错误' . PHP_EOL);
@ -97,53 +97,65 @@ class Daemon
if ($pid == -1) { if ($pid == -1) {
exit('启动失败:pcntl_fork 错误' . PHP_EOL); exit('启动失败:pcntl_fork 错误' . PHP_EOL);
} else if ($pid == 0) { } else if ($pid == 0) {
$this->handleRequest($client); $this->HandleRequest($client);
} else { } else {
} }
} }
} }
/** /**
* socket程序接收和处理请求 * 接收TCP连接并处理指令
*/ */
private function handleRequest($client) private function HandleRequest($client)
{ {
//接收客户端发送的数据 //接收客户端发送的数据
$data = socket_read($client, SOCKET_READ_LENGTH); $cmmand = socket_read($client, SOCKET_READ_LENGTH);
//console //console模式
$this->workMode == 'console' ? print_r(PHP_EOL . '---------receive---------' . PHP_EOL . $data . PHP_EOL) : ''; if ($this->workMode == 'console') {
echo PHP_EOL . '---------receive---------' . PHP_EOL;
if (trim($data) != '') { echo $cmmand . PHP_EOL;
/** }
* shell_exec方法拿不到执行指令的错误抛出信息
*/ if (trim($cmmand) != '') {
// $result = shell_exec($data); //定义错误输出文件路径
$stderrFile = TEMP_PATH . uniqid();
/**
* passthru会将所有的结果(包括正确的和错误的抛出信息输出) //将标准错误重定向到文件
* 可以使用 ob_start ob_get_contents ob_end_clean 拿到缓冲区的内容 //使用状态码来标识错误信息
*
* 此方法在console调试模式下会导致 $result 变量拿不到值;
* 但是在daemon模式下 $result 变量可以拿到值(猜测是输入到终端与输出到缓冲区的影响)
*/
ob_start(); ob_start();
passthru($data); passthru($cmmand . " 2>$stderrFile", $resultCode);
$result = ob_get_contents(); $buffer = ob_get_contents();
ob_end_clean(); ob_end_clean();
//将错误信息和正确信息分类收集
$result = [
'resultCode' => $resultCode,
'result' => trim($buffer),
'error' => file_get_contents($stderrFile)
];
//销毁文件
unlink($stderrFile);
} else { } else {
//探测程序会发送空信息 //探测程序会发送空信息
$result = ''; $result = [
'resultCode' => 0,
'result' => '',
'error' => ''
];
} }
//console //console模式
$this->workMode == 'console' ? print_r(PHP_EOL . '---------result---------' . PHP_EOL . $result . PHP_EOL) : ''; if ($this->workMode == 'console') {
echo PHP_EOL . '---------result---------' . PHP_EOL;
//处理没有返回内容的情况 否则 socket_write 遇到空内容会报错 echo 'resultCode: ' . $result['resultCode'] . PHP_EOL;
$result = trim($result) == '' ? ISNULL : trim($result); 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); socket_close($client);
@ -155,7 +167,7 @@ class Daemon
/** /**
* 检查操作系统是否符合要求 * 检查操作系统是否符合要求
*/ */
private function checkSysType() private function CheckSysType()
{ {
if (PHP_OS != 'Linux') { if (PHP_OS != 'Linux') {
exit('启动失败:当前操作系统不为Linux' . PHP_EOL); exit('启动失败:当前操作系统不为Linux' . PHP_EOL);
@ -173,7 +185,7 @@ class Daemon
/** /**
* 检查php版本是否符合要求 * 检查php版本是否符合要求
*/ */
private function checkPhpVersion() private function CheckPhpVersion()
{ {
if (PHP_VERSION < Required_PHP_VERSION) { if (PHP_VERSION < Required_PHP_VERSION) {
exit('启动失败:当前的PHP版本为:' . PHP_VERSION . ',要求的最低PHP版本为:' . Required_PHP_VERSION . PHP_EOL); exit('启动失败:当前的PHP版本为:' . PHP_VERSION . ',要求的最低PHP版本为:' . Required_PHP_VERSION . PHP_EOL);
@ -183,7 +195,7 @@ class Daemon
/** /**
* 检查需要的函数是否被禁用 * 检查需要的函数是否被禁用
*/ */
private function checkDisabledFunction() private function CheckDisabledFunction()
{ {
$disabled_function = explode(',', ini_get('disable_functions')); $disabled_function = explode(',', ini_get('disable_functions'));
$cli_needed_function = unserialize(CLI_NEEDED_FUNCTION); $cli_needed_function = unserialize(CLI_NEEDED_FUNCTION);
@ -200,7 +212,7 @@ class Daemon
/** /**
* 以守护进程模式工作 * 以守护进程模式工作
*/ */
private function startDaemon() private function StartDaemon()
{ {
if (file_exists($this->pidFile)) { if (file_exists($this->pidFile)) {
$pid = file_get_contents($this->pidFile); $pid = file_get_contents($this->pidFile);
@ -209,13 +221,13 @@ class Daemon
exit('程序正在运行中' . PHP_EOL); exit('程序正在运行中' . PHP_EOL);
} }
} }
$this->initDaemon(); $this->InitDeamon();
} }
/** /**
* 关闭守护进程 * 关闭守护进程
*/ */
private function stopDaemon() private function StopDaemon()
{ {
if (file_exists($this->pidFile)) { if (file_exists($this->pidFile)) {
$pid = file_get_contents($this->pidFile); $pid = file_get_contents($this->pidFile);
@ -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->CheckSysType();
$this->checkPhpVersion(); $this->CheckPhpVersion();
$this->checkDisabledFunction(); $this->CheckDisabledFunction();
if (isset($argv[1])) { if (isset($argv[1])) {
$this->workMode = $argv[1]; $this->workMode = $argv[1];
if (!in_array($this->workMode, $this->scripts)) { if (!in_array($this->workMode, $this->scripts)) {
exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL); exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL);
} }
if ($this->workMode == 'start') { if ($this->workMode == 'start') {
$this->startDaemon(); $this->StartDaemon();
} else if ($this->workMode == 'stop') { } else if ($this->workMode == 'stop') {
$this->stopDaemon(); $this->StopDaemon();
} else if ($this->workMode == 'console') { } else if ($this->workMode == 'console') {
$this->startConsole(); $this->StartConsole();
} }
} else { } else {
exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL); exit('用法:php svnadmin.php [start | stop | console]' . PHP_EOL);
@ -255,7 +267,10 @@ class Daemon
} }
} }
/**
* 将工作模式限制在cli模式
*/
if (preg_match('/cli/i', php_sapi_name())) { if (preg_match('/cli/i', php_sapi_name())) {
$deamon = new Daemon(); $deamon = new Daemon();
$deamon->run($argv); $deamon->Run($argv);
} }

Loading…
Cancel
Save