前两天收到狗友说网站里的PHP开发的测算系统源码,反馈"支付点不了、后台弹窗烦人、短信发不出去"。本以为是常规小修,结果一打开代码就发现问题比想象中多。
这篇文章记录下当天的完整修复过程。

一套自研PHP框架的在线测算平台,结构大概是这样:
├── control/ → 48个控制器├── model/ → 34个数据模型 ├── core/ → 24个核心类库├── acs/ → 完整管理后台├── ffsm/ → 前端H5├── templates/ → 495个模板文件└── 数据库 → 88万行SQL功能涵盖八字、紫微、塔罗、生肖星座、姓名分析、号码吉凶、14套抽签——外加独立的商城模块和分销代理系统。
支付方面,同时支持微信官方、支付宝官方、易支付(3方)、PayPal、Stripe五条通道。
功能确实全,但代码层面需要打磨的地方也不少。
第一个问题是客户反馈最紧急的——点击微信支付直接白屏。
打开浏览器开发者工具,请求返回500,但PHP日志里啥也没有。这就只能逐行看代码了。
在 ctl_pay.php 里排查了十分钟,发现 go() 方法结束后多了个 }:
php
复制
public function go() { // ...支付逻辑... exit;} // ← 正常的 go() 结束#header("Location:..."); // 注释代码} // ← 多出来的!这一行把整个类提前关闭了public function pay_go() { // ← 此时已经在类外面了,语法错误多了一个 } 导致从 pay_go() 开始的十几个方法全都在类外部。PHP解析到这些方法时直接报Fatal Error,返回500。
修复方式: 删掉多余的 }。
就这么一行改动,解决了十几个方法不能调用的问题。
继续看支付流程,发现一个经典的逻辑顺序问题:
php
复制
header('Location: https://pay.com');die;mod_order::up_order(array('paytype'=>1), ...);up_order() 写在 die 后面——换句话说,微信支付的支付方式永远记录不上去。
修复方式: 把 up_order() 移到 header() 和 die 之前。
同样的模式还有好几处。有一处 mod_order::up_order() 写在 exit 后面,同样永远不会执行。
这种问题在快速迭代中很容易出现,修改逻辑时加了 exit 或 die 就忘了把后面的代码移走。
再看核心文件 core/init.php,自动加载函数里有这样一行:
php
else if( file_exists ( require PATH_ROOT.'/model/'.$classfile ) )require 被包裹在 file_exists 的参数里。如果文件不存在,require 直接抛Fatal Error,file_exists 根本没机会执行——等于一个没有防护的炸弹。
修复方式:
php
else if( file_exists ( PATH_ROOT.'/model/'.$classfile ) )去掉 require,只检查文件是否存在。
检查代码时发现系统中用了 ??(Null合并运算符):
php
$business = $config['business'] ?? '';这是PHP 7.0才引入的语法。如果部署在PHP 5.6上,直接报语法错误。
修复方式: 改为兼容的写法:
php
$business = $config['business'] ? $config['business'] : '';测试支付完整流程时发现,用户在易支付平台付完钱后,回调请求返回404,订单状态更新不了。
排查后发现是回调URL路径的问题。系统生成的回调地址是:
http://domain.com/SDK/notify_url.php但实际文件位置在 ffsm/SDK/notify_url.php。如果网站文档根目录指向项目根目录而非 ffsm/ 子目录,这个路径就匹配不上。
修复方式:
不是传统意义上的webshell后门,但比那更隐蔽。
后台不定时弹出"授权验证失败"的弹窗。查了一下,后台模板文件中有 {$page_meta} 变量,这个变量在 init.php 中从数据库的 system_config_cache 表加载数据。而数据库预置数据里包含了一个远程JS脚本地址。
大概流程是这样:
页面渲染 → 读取数据库缓存表 → 获取远程JS地址 → 加载执行 ↓ 验证域名是否授权 ↓ 未授权则弹窗data/file_cache/index.php 中有一段逻辑:检测到手机访问且域名不是 www.****key.com 的,自动跳转到该域名。
config/inc_user_api.php 配置了一套完整的远程用户中心,指向 ****key.com,包含用户登录、在线状态上报、Cookie共享等功能。
虽然已被注释掉,但如果有人部署时没留意这个文件,用户数据会发送到远程服务器。
系统中使用的实时测算功能调用了 api.7rhd.com 的接口。这个是业务功能的一部分,不算恶意后门,但数据经过第三方服务器。
修完Bug后,顺便把支付流程理顺了。
原来的设计有点混乱——后台勾选了"易支付"就显示"易支付微信"和"易支付支付宝"两个按钮,勾选了"官方支付"就显示"官方微信"和"官方支付宝"。一共四套按钮,用户看着都晕。
改造后统一为两套按钮(微信+支付宝),后台配置决定路由:
后台勾选"易支付" ↓微信按钮 → go() → 自动走易支付接口支付宝按钮 → go() → 自动走易支付接口后台不勾选"易支付" ↓微信按钮 → go() → 走官方微信API支付宝按钮 → go() → 走官方支付宝API改了2个文件,45个模板一个没动。 这就是改底层的威力。
原系统只支持"短信宝"一家服务商。增加了一个Spug推送助手的选项:
https://push.spug.cc/send/{模板ID}?code=验证码&targets=手机号做了接口抽象,后续再加其他服务商只需要扩展一个方法。
这一整天下来:
如果你有类似的源码系统正在使用或准备部署,建议做一次类似的审计。基础问题修一修,线上能省很多事。
关注星标公众号,去源码网里下载
后台回复「验证码」获取本次修复涉及的完整代码通道 有问题欢迎评论区交流,每条都会看