PHP中exec()调用外部PHP脚本触发无限循环的问题排查
解决PHP exec()调用脚本出现无限循环的问题
问题场景
需要在PHP脚本test.php中通过exec()调用另一个PHP脚本simple.php(预期长时间运行),但终端直接执行php tasks/simple.php正常,通过exec()调用时却出现无限循环或脚本被重复调用数千次的情况。
测试代码
simple.php
<?php error_log('simple.php called.'); echo 'OK'; ?>
test.php
<?php error_log('test.php called'); // 检测无限循环的测试代码 $cmd = 'dir'; // 该命令可正常运行 //$cmd = 'php tasks/simple.php'; // 无限循环 //$cmd = 'php tasks/simple.php >/dev/null &'; // 浏览器无卡顿,但simple.php被调用数千次 //$cmd = 'php tasks/this-script-does-not-exist.php';// 无限循环 //$cmd = "php /home/public_html/my_test/tasks/simple.php"; // 无限循环 //$cmd = 'php /home/public_html/my_test/tasks/simple.php'; // 无限循环 //$cmd = 'php-cli tasks/simple.php'; // 返回值:127,输出为空数组 //$cmd = "php-cli /home/public_html/my_test/tasks/simple.php"; // 返回值:0,输出含乱码的HTTP响应头及内容 //$cmd = "php /home/public_html/my_test/tasks/simple.php"; // 无限循环 $output = null; $return_val = -1; exec($cmd, $output, $return_val); echo "<pre>Return val: " . print_r($return_val, true) . "</pre>"; echo "<pre>Output: " . print_r($output, true) . "</pre>"; ?>
可行解决思路
- 检查Web服务器重写规则:大概率是
.htaccess或服务器配置中的重写规则,将CLI调用的PHP请求错误转发回test.php,触发循环。比如规则将所有请求导向入口脚本,而CGI模式的PHP会把CLI调用识别为HTTP请求,触发重写。 - 使用PHP CLI绝对路径:不要用
php或php-cli这类相对命令,直接指定CLI版本的绝对路径(比如/usr/bin/php或/usr/local/bin/php),避免调用到CGI/FastCGI版本的PHP,后者会触发Web请求流程。 - 强制CLI模式运行:在
simple.php开头添加判断,确保只有CLI模式才能执行,阻断HTTP请求触发的执行:
if (php_sapi_name() !== 'cli') { error_log('simple.php called via non-CLI SAPI, exiting.'); exit; }
- 彻底隔离输出与后台运行:调用时将标准输出和错误输出都重定向,同时后台运行,避免输出回流触发Web服务器的错误处理:
$cmd = '/usr/bin/php /home/public_html/my_test/tasks/simple.php > /dev/null 2>&1 &';
- 验证权限与环境:确保Web服务器用户(如
www-data)拥有执行PHP CLI的权限,且能读取simple.php文件;同时检查PATH环境变量,避免命令找不到的情况。 - 添加调试日志:在两个脚本中增加更详细的日志,比如记录进程ID、SAPI类型:
// test.php中 error_log('test.php called, PID: '.getmypid().' SAPI: '.php_sapi_name()); // simple.php中 error_log('simple.php called, PID: '.getmypid().' SAPI: '.php_sapi_name());
通过日志可以确认是否是同一进程循环,还是新进程被重复创建。
内容的提问来源于stack exchange,提问作者Boycott A.I.
相关产品推荐
相关产品推荐

