diff --git a/.gitignore b/.gitignore index 89e6cac..c8bbe8b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,12 @@ *.pem *.log *.glb +*.zip +*.rar +*.pdf +*.docx +*.xls +*.doc *.gltf *.mp3 *.mp4 @@ -20,5 +26,6 @@ web/ud/2026/* web/ud/2027/* web/ud/2028/* **/unpackage/ +**/tmp/ web.ini diff --git a/fork/fork_apinotify.php b/fork/fork_apinotify.php new file mode 100644 index 0000000..475b20c --- /dev/null +++ b/fork/fork_apinotify.php @@ -0,0 +1,185 @@ + 0) { + //echo "pcntl_wexitstatus: $status\n"; + //$exitCode = pcntl_wexitstatus($status); + //echo "子进程退出,状态码: $exitCode\n"; + $currentProcesses--; + if ($currentProcesses < 0) + $currentProcesses = 0; + } +}); +function outlog($msg) { + savelogfile('fork_apinotify', $msg); +} +function mainProcess() { + global $shouldStop, $currentProcesses, $logpath; + $db = new \ciy\db(); + $maxProcesses = 30; //1GB=15-20个进程 + $batchSize = 20; // 每次批量获取的记录数 + $spawnInterval = 100; // 子进程启动间隔(毫秒) + // 安装SIGCHLD信号处理器,避免僵尸进程 + + outlog('主进程启动,PID: ' . getmypid()); + $isbusy = false; + while (true) { + pcntl_signal_dispatch(); + if ($shouldStop) { + $time = time(); + while ($currentProcesses > 0 && $time > time() - 60) { + pcntl_signal_dispatch(); + sleep(1); + } + outlog('已关闭:' . $currentProcesses); + exit(0); + } + + if ($currentProcesses >= $maxProcesses) { + //echo "达到最大子进程数限制 ($maxProcesses),等待子进程退出...\n"; + sleep(1); + continue; + } + file_put_contents($logpath . 'fork_apinotify.tak', 'curr=' . $currentProcesses . ',max=' . $maxProcesses . ',batch=' . $batchSize . ',spawn=' . $spawnInterval . ',time=' . time()); + + $csql = new \ciy\sql('ap_transfer'); + //默认nexttimes=9999999999999,有90/100通知后,nexttimes=0,等待推送。 + //推成功,nexttimes=9999999999998 + //没成功,首次retimes=now,nexttimes=now+retimesspan+10s,直至24小时后=9999999999997 + //retimes>0判断是否有二次推送,判断商户api质量 + //nexttimes=9999999999997,判断是否始终推送失败,判断商户api接入能力 + //nexttimes=9999999999996,fork执行脚本非法跳出bug,或强制关闭导致 + $csql->where('nexttimes<', time()); + $csql->limit(1, $batchSize); + $orderrows = $db->get($csql); + if ($orderrows === false || count($orderrows) == 0) { + //echo "没有待处理任务,等待3秒...\n"; + sleep(3); + continue; + } + //outlog('发现待处理任务: ' . count($notifyrows) . '个'); + foreach ($orderrows as $orderrow) { + if (empty($orderrow['notifyurl'])) + continue; + if ($currentProcesses >= $maxProcesses) { + if (!$isbusy) + outlog('任务拥堵:' . $currentProcesses . '/' . $maxProcesses); + $isbusy = true; + sleep(3); + break; + } + if ($currentProcesses < $maxProcesses / 2) { + if ($isbusy) + outlog('拥堵暂缓:' . $currentProcesses . '/' . $maxProcesses); + $isbusy = false; + } + $pid = pcntl_fork(); + if ($pid == -1) { + outlog('创建子进程失败:' . pcntl_strerror(posix_get_last_error())); + } elseif ($pid) { + //echo "创建子进程成功,PID: $pid, 处理任务 ID: $id\n"; + $currentProcesses++; + usleep($spawnInterval * 1000); + } else { + //echo "子进程开始执行任务,PID: " . getmypid() . ", 任务 ID: $id\n"; + fork_apinotify($orderrow); + exit; + } + } + usleep(500 * 1000); + } +} +if (!extension_loaded('pcntl')) { + die("PCNTL扩展未加载,无法使用多进程功能\n"); +} +mainProcess(); + +function fork_apinotify($orderrow, $debug = false) { + $db = new \ciy\db(); + $id = $orderrow['id']; + $updata = array(); + $updata['nexttimes'] = 9999999999996; + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + $db->update($csql, $updata); + //orderrow就是数据集,再加上时间戳、sign、pairsign + $retapi = $orderrow; + unset($retapi['signature']); + $signstr = ''; + ksort($retapi); + foreach ($retapi as $key => $value) { + $signstr .= $key . '=' . $value . '&'; + } + $signstr = substr($signstr, 0, -1); + $sign = sha256($signstr); + $retapi['hash'] = $sign; + + $http = new \ciy\http(); + $http->set_timeout(10); + $http->request($orderrow['notifyurl'], json_encode($retapi)); + $result = $http->get_data(); + if (strpos($result, 'success') !== false) { + $updata = array(); + $updata['nexttimes'] = 9999999999998; + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) { + if ($debug) clog('操作notify失败succ:' . $db->error); + savelogfile('err_db', '操作notify失败succ:' . $db->error); + } + } else { + $updata = array(); + $retimes = $orderrow['retimes']; + $time = time(); + if ($retimes == 0) { + $updata['retimes'] = $time; + $updata['nexttimes'] = $time + 10; + } else { + $time = $time + ($time - $retimes) + 10; + if ($time - $retimes < 136400) + $updata['nexttimes'] = $time + ($time - $retimes) + 10; + else + $updata['nexttimes'] = 9999999999997; + } + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) { + if ($debug) clog('操作notify失败fail:' . $db->error); + savelogfile('err_db', '操作notify失败fail:' . $db->error); + } + } + exit(1); +} \ No newline at end of file diff --git a/fork/fork_order.php b/fork/fork_order.php new file mode 100644 index 0000000..cc037d1 --- /dev/null +++ b/fork/fork_order.php @@ -0,0 +1,206 @@ + 0) { + //echo "pcntl_wexitstatus: $status\n"; + //$exitCode = pcntl_wexitstatus($status); + //echo "子进程退出,状态码: $exitCode\n"; + $currentProcesses--; + if ($currentProcesses < 0) + $currentProcesses = 0; + } +}); +function outlog($msg) { + savelogfile('fork_order', $msg); +} +function mainProcess() { + global $shouldStop, $currentProcesses, $logpath; + $db = new \ciy\db(); + $maxProcesses = 30; //1GB=15-20个进程 + $batchSize = 20; // 每次批量获取的记录数 + $spawnInterval = 100; // 子进程启动间隔(毫秒) + // 安装SIGCHLD信号处理器,避免僵尸进程 + + outlog('主进程启动,PID: ' . getmypid()); + $isbusy = false; + while (true) { + pcntl_signal_dispatch(); + if ($shouldStop) { + $time = time(); + while ($currentProcesses > 0 && $time > time() - 60) { + pcntl_signal_dispatch(); + sleep(1); + } + outlog('已关闭:' . $currentProcesses); + exit(0); + } + + if ($currentProcesses >= $maxProcesses) { + //echo "达到最大子进程数限制 ($maxProcesses),等待子进程退出...\n"; + sleep(1); + continue; + } + file_put_contents($logpath . 'fork_order.tak', 'curr=' . $currentProcesses . ',max=' . $maxProcesses . ',batch=' . $batchSize . ',spawn=' . $spawnInterval . ',time=' . time()); + + $csql = new \ciy\sql('ap_transfer'); + $csql->where('orderstatus=20'); + $csql->limit(1, $batchSize); + $orderrows = $db->get($csql); + if ($orderrows === false || count($orderrows) == 0) { + //echo "没有待处理任务,等待3秒...\n"; + sleep(3); + continue; + } + //outlog('发现待处理任务: ' . count($orderrows) . '个'); + foreach ($orderrows as $orderrow) { + if ($currentProcesses >= $maxProcesses) { + if (!$isbusy) + outlog('任务拥堵:' . $currentProcesses . '/' . $maxProcesses); + $isbusy = true; + sleep(3); + break; + } + if ($currentProcesses < $maxProcesses / 2) { + if ($isbusy) + outlog('拥堵暂缓:' . $currentProcesses . '/' . $maxProcesses); + $isbusy = false; + } + $pid = pcntl_fork(); + if ($pid == -1) { + outlog('创建子进程失败:' . pcntl_strerror(posix_get_last_error())); + } elseif ($pid) { + //echo "创建子进程成功,PID: $pid, 处理任务 ID: $id\n"; + $currentProcesses++; + usleep($spawnInterval * 1000); + } else { + //echo "子进程开始执行任务,PID: " . getmypid() . ", 任务 ID: $id\n"; + fork_order($orderrow); + exit; + } + } + usleep(500 * 1000); + } +} +if (!extension_loaded('pcntl')) { + die("PCNTL扩展未加载,无法使用多进程功能\n"); +} +mainProcess(); + +function fork_order($orderrow, $debug = false) { + $db = new \ciy\db(); + $id = $orderrow['id']; + $updata = array(); + $updata['orderstatus'] = 30; + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) { + if ($debug) clog('操作status=30:' . $db->error); + savelogfile('err_db', '操作status=30:' . $db->error); + exit(1); + } + //验签一次,验签失败,则90错误 + $fail = null; + if (!empty($orderrow['signature'])) { + $csql = new \ciy\sql('ap_api'); + $csql->where('id', $orderrow['apiid']); + $apirow = $db->getone($csql); + if (!is_array($apirow)) + $fail = array('errmsg' => 'API未找到', 'status' => 90); + else { + if (empty($apirow['pubkey'])) { + $fail = array('errmsg' => '数字证书无公钥', 'status' => 90); + } else { + $waitsignstr = 'amount=' . $orderrow['amount'] . ',addtimes=' . $orderrow['addtimes']; + $retsign = verifysign_api($apirow['pubkey'], $orderrow['signature'], $waitsignstr); + if (is_string($retsign)) + $fail = array('errmsg' => $retsign, 'status' => 90); + } + } + } + //$fail = array('errmsg' => $ret, 'status' => 90); //处理具体业务,失败赋值 + + if ($fail) { + try { + $db->begin(); + $updata = array(); + $updata['uptimes'] = tostamp(); + $updata['orderstatus'] = $fail['status']; + if ($fail['status'] == 90) + $updata['nexttimes'] = 0; + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) + throw new \Exception('操作order fail失败:' . $db->error); + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + savelogfile('err_db', $ex->getMessage()); + } + exit(4); + }else{ + try { + $db->begin(); + $updata = array(); + $updata['uptimes'] = tostamp(); + $updata['orderstatus'] = 100; + $updata['nexttimes'] = 0; + $csql = new \ciy\sql('ap_transfer'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) + throw new \Exception('操作order succ失败:' . $db->error); + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + savelogfile('err_db', $ex->getMessage()); + } + exit(0); + } +} + +function verifysign_api($signKey, $signature, $waitsignstr) { + if (strpos($signKey, '-----BEGIN RSA PUBLIC KEY-----') === false && strpos($signKey, '-----BEGIN PUBLIC KEY-----') === false) + $signKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($signKey, 64, "\n") . "\n-----END PUBLIC KEY-----"; + $signbin = hex2bin($signature); + if ($signbin === false) + return errjson('签名格式错误'); + $hashbin = hex2bin(hash('sha256', $waitsignstr)); + $result = openssl_verify($hashbin, $signbin, $signKey, OPENSSL_ALGO_SHA256); + if ($result === 0) + return '数字证书验签失败'; + else if ($result !== 1) + return '数字证书验签错误:' . openssl_error_string(); + return true; +} diff --git a/web/admin/ap/art_post.php b/web/admin/ap/art_post.php index 0b07eb8..78523d5 100644 --- a/web/admin/ap/art_post.php +++ b/web/admin/ap/art_post.php @@ -106,7 +106,7 @@ class art_post { return errjson('请填写排序位'); if (empty($name)) return errjson('请填写文章标题'); - if (empty($content)) + if ($content == '[MD]') return errjson('请填写内容'); $datarow = null; if ($id > 0) { @@ -161,6 +161,7 @@ class art_post { $db->commit(); } catch (\Exception $ex) { $db->rollback(); + savelogfile('err_db', $ex->getMessage()); return errjson($ex->getMessage()); } $ret['data'] = $updata; @@ -214,6 +215,7 @@ class art_post { $db->commit(); } catch (\Exception $ex) { $db->rollback(); + savelogfile('err_db', $ex->getMessage()); return errjson($ex->getMessage()); } $ret['ids'] = $vids; @@ -375,7 +377,7 @@ class art_post { else { $csqlchk = new \ciy\sql('ap_art_post'); $csqlchk->where('id', $id)->column('id'); - $chkid = (int)$db->get1($csqlchk); + $chkid = toint($db->get1($csqlchk)); if ($chkid != $id) $errmsg = $name . '在数据库中不存在'; $value = $id; @@ -389,7 +391,7 @@ class art_post { if (!is_numeric($showdat)) $errmsg = $name . '不是数字'; else - $value = (int)$showdat; + $value = toint($showdat); } } else if ($name == '文章状态') { if (empty($showdat)) { @@ -430,7 +432,7 @@ class art_post { if (!is_numeric($showdat)) $errmsg = $name . '不是数字'; else - $value = (int)$showdat; + $value = toint($showdat); } } else if ($name == '阅读数') { if (empty($showdat)) { @@ -440,7 +442,7 @@ class art_post { if (!is_numeric($showdat)) $errmsg = $name . '不是数字'; else - $value = (int)$showdat; + $value = toint($showdat); } } else if ($name == '摘要') { if (empty($showdat)) { @@ -483,7 +485,7 @@ class art_post { else { $uniques[] = $unq; $csql->column('id'); - $chkid = (int)$db->get1($csql); + $chkid = toint($db->get1($csql)); if ($chkid > 0 && (($id > 0 && $chkid != $id) || $id == 0)) $firsthtml = '
按钮样式+
自定尺寸按钮+
图标按钮+
span标签+
下拉按钮+
识别号+
登录用户+
ECC签名+
ECC验签+
PIN码+
重置PIN码+
读写标记+
初始化+
生成RSA密钥对+
RSA签名+
RSA验签+
钱包登录+
钱包签名+
钱包验签+
' + table.data[id].TABLE_COMMENT + ''
- });
- }
- if (btn == 'edit') {
- ciyfn.alert({
- title: '更名'
- , content: document.getElementById("alert_edit").innerHTML
- //, noparent:true
- , fn_showed: function (doc, dom) {
- var dat = table.data[id];
- $5('[name=name]', dom).val(dat.TABLE_COMMENT);
- }
- , cb: function (opn) {
- if (opn.btn == "关闭")
- return opn.close();
- opn.inputs.id = id;
- opn.inputs.tabname = table.data[id].TABLE_NAME;
- if (ciyfn.throttle(opn.dombtn)) return;
- ciyfn.callfunc('update', opn.inputs, function (json) {
- table.updateline(json);
- opn.close();
- ciyfn.toast('更新成功');
- });
- },
- btns: ["提交", "*关闭"]
- });
+ window.open('code_create.html?dbcid=' + table.once.dbsaas.id + '&table=' + table.data[id].TABLE_NAME);
}
}
diff --git a/web/admin/develop/code_list.php b/web/admin/develop/code_list.php
index 0361c4a..47d5457 100644
--- a/web/admin/develop/code_list.php
+++ b/web/admin/develop/code_list.php
@@ -6,14 +6,17 @@ class code_list {
static function setwhere($db, $post) {
$query = $post->get('query');
$csql = new \ciy\sql('INFORMATION_SCHEMA.TABLES');
- $csql->where('TABLE_SCHEMA', objstr($query, 'schema'));
return [$query, $csql];
}
public static function json_init() {
global $db;
$rsuser = verifyfast();
$post = new \ciy\post();
+ $csql = new \ciy\sql('zc_dev_dbsaas');
+ $csql->where('id', getint('dbcid'));
+ $dbsaasrow = $db->getone($csql);
list($where, $csql) = self::setwhere($db, $post);
+ $csql->where('TABLE_SCHEMA', $dbsaasrow['schem']);
$rows = $db->get($csql);
for ($i = 0; $i < count($rows); $i++)
$rows[$i]['id'] = $i + 1;
@@ -31,6 +34,11 @@ class code_list {
if ($post->getbool('once')) {
$ret['once'] = array();
+ $ret['once']['dbsaas'] = $dbsaasrow;
+ $csql = new \ciy\sql('zc_dev_dbcode');
+ $csql->where('dbcid', getint('dbcid'));
+ $csql->column('tabl');
+ $ret['once']['dbcode'] = $db->get($csql);
$input = array();
$input[] = array(
'type' => 'input',
diff --git a/web/admin/develop/code_mb_vue3.php b/web/admin/develop/code_mb_vue3.php
index 4580e20..32ef4a3 100644
--- a/web/admin/develop/code_mb_vue3.php
+++ b/web/admin/develop/code_mb_vue3.php
@@ -8,7 +8,7 @@ function code_mbvue3($post) {
$titname = $post->get('_bcod_titname', '', 'all');
$logtype = $post->get('_bcod_logtype', '', 'all');
$uploadpat = $post->get('_bcod_uploadpat', '', 'all');
- $liiddict = $post->get('_bcod_liiddict', '', 'all');
+ $liiddict = str_replace(',',',', $post->get('_bcod_liiddict', '', 'all'));
$tabdict = $post->get('_bcod_tabdict', '', 'all');
$uniquedata = $post->get('_bcod_uniquedata', '', 'all');
$chk_in = $post->get('_bcod_chk_in') == 'yes';
diff --git a/web/admin/develop/code_pc_html.php b/web/admin/develop/code_pc_html.php
index 0fafef0..78dac58 100644
--- a/web/admin/develop/code_pc_html.php
+++ b/web/admin/develop/code_pc_html.php
@@ -1,19 +1,25 @@
get('schema', '', 'all');
+ $tabname = $post->get('table', '', 'all');
+ $subpath = $post->get('subpath', '', 'all');
$maindb = $post->get('_bcod_maindb', '', 'all');
$verifyfunc = $post->get('_bcod_verifyfunc', '', 'all');
$titname = $post->get('_bcod_titname', '', 'all');
$saascode = $post->get('_bcod_saascode', '', 'all');
+ if ($saascode) {
+ $saascode = explode('=', $saascode);
+ if (count($saascode) == 1)
+ $saascode[1] = $saascode[0];
+ }
$uploadpat = $post->get('_bcod_uploadpat', '', 'all');
- $liiddict = $post->get('_bcod_liiddict', '', 'all');
- $uptabcard = $post->get('_bcod_uptabcard', '', 'all');
+ $liiddict = str_replace(',',',', $post->get('_bcod_liiddict', '', 'all'));
+ $uptabcard = str_replace(',',',', $post->get('_bcod_uptabcard', '', 'all'));
$uptabcards = array();
if (!empty($uptabcard))
$uptabcards = explode(',', $uptabcard);
- $viewtabcard = $post->get('_bcod_viewtabcard', '', 'all');
+ $viewtabcard = str_replace(',',',', $post->get('_bcod_viewtabcard', '', 'all'));
$viewtabcards = array();
if (!empty($viewtabcard))
$viewtabcards = explode(',', $viewtabcard);
@@ -107,7 +113,9 @@ function code_pc_html($post) {
$topbtns[] = '' . $str . '';
} else {
$subs = explode('|', $str); //操作|成果|方法|-修改|删除
- $btnhtml = "{$subs[0]}\n";
+ $btnhtml .= " ";
$topbtns[] = $btnhtml;
}
}
@@ -144,7 +153,7 @@ function code_pc_html($post) {
data;
- if (($querycount < 5 && count($topbtns) < 4) || count($topbtns) < 2) {
+ if (($querycount < 5 && count($topbtns) < 4) || count($topbtns) < 3) {
foreach ($topbtns as $topbtn) {
$codex .= ' ' . $topbtn . "\n";
}
@@ -156,7 +165,7 @@ data;
data;
- if (!(($querycount < 5 && count($topbtns) < 4) || count($topbtns) < 2)) {
+ if (!(($querycount < 5 && count($topbtns) < 4) || count($topbtns) < 3)) {
$codex .= " ' + table.data[id].name + ''";
- $codex .= "\n });";
- $codex .= "\n }";
+ $subpathn = '';
+ $ind = strpos($subpath, '\\');
+ if($ind > 0)
+ $subpathn = str_replace('\\','/', substr($subpath, $ind+1)) . '/';
+ foreach ($subgomenus as $subgomenu) {
+ $xid = 'xxxid';
+ if(isset($subgomenu[2]))
+ $xid = $subgomenu[2];
+ $codex .= "\n if (btn == '{$subgomenu[1]}') {";
+ $codex .= "\n ciyfn.sendsignal(window.top, 'manage_ifropen', {";
+ $codex .= "\n url: '{$subpathn}{$subgomenu[1]}.html?_{$xid}=' + id";
+ $codex .= "\n , name: '{$subgomenu[0]}' + table.data[id].name + ''";
+ $codex .= "\n });";
+ $codex .= "\n }";
+ }
+ if (count($subgomenus) == 0) {
+ $codex .= "\n if (btn == 'sub') {";
+ $codex .= "\n ciyfn.sendsignal(window.top, 'manage_ifropen', {";
+ $codex .= "\n url: 'xxx.html?_xxxid=' + id";
+ $codex .= "\n , name: '{$titname}' + table.data[id].name + ''";
+ $codex .= "\n });";
+ $codex .= "\n }";
+ }
$codex .= "\n }";
$codex .= "\n";
$codex .= "\n function getdata(id, act, cb) {";
@@ -753,6 +797,8 @@ if($hasedit){
continue;
if ($col == 'auditstatus' || $col == 'audittimes' || $col == 'audituser' || $col == 'auditmsg')
continue;
+ if ($saascode && $saascode[0] == $fld['col'])
+ continue;
$sgcol = (isset($fld['set']['colview']) ? $fld['set']['colview'] : '24');
$codex .= "\n html += '