Cron执行PHP脚本无法完整生成CSV,是否为超时问题?
我来帮你分析下这个问题——浏览器里能正常生成完整的628KB文件,但Cron调用就只出133KB的不完整文件,大概率是执行环境差异或者超时/资源限制导致的,下面是具体的排查和解决步骤:
一、先优化PHP脚本的潜在问题
你的代码里有几个可以调整的点,可能是导致数据截断的关键:
补全文件资源关闭操作
你打开了$handle用来读取源CSV,但循环结束后没有调用fclose($handle)。虽然脚本结束时PHP会自动回收资源,但如果Cron环境下脚本提前终止,很可能导致数据写入不完整。建议在循环结束后补上:fclose($handle);优化fgetcsv的长度参数
你把长度设为90000000其实没必要,反而可能因为预估长度的问题导致行截断。如果把这个参数设为0或者NULL,PHP会自动检测每行的实际长度(直到换行符),反而更可靠。修改这一行:while (($data = fgetcsv($handle, 0, ";")) !== FALSE) {放宽执行时间和内存限制
浏览器环境和Cron触发的执行环境(不管是Web还是CLI)的超时逻辑不一样,脚本里的set_time_limit(60)可能不够用。建议改成无时间限制,同时增加内存预留:ini_set('display_errors',1); error_reporting(E_ALL); set_time_limit(0); // CLI模式下默认无限制,Web环境下强制关闭时间限制 ini_set('memory_limit', '256M'); // 可根据实际需求调整到512M或更高增加日志记录定位中断点
为了搞清楚脚本到底在哪里中断,可以在循环里加入日志记录,方便排查:$row = 0; $fp = fopen('changed-stock.csv', 'w'); if (($handle = fopen("https://www.xxx.de/xxx/bestand.csv", "r")) !== FALSE) { while (($data = fgetcsv($handle, 0, ";")) !== FALSE) { $row++; // 每处理100行记录一次日志,方便追踪进度 if ($row % 100 == 0) { error_log("Processed $row rows at " . date('Y-m-d H:i:s')); } $data[9] = str_replace(['0.00', '1.00', '2.00', ..., '20.00'], ['0','1','2',...,'20'], $data[9]); fputcsv($fp, $data); } error_log("Completed processing total $row rows"); fclose($handle); // 关闭源文件指针 } fclose($fp);之后查看PHP的错误日志,就能知道脚本是执行完成了,还是在某一行突然中断。
二、调整Cron的执行方式
用wget调用Web脚本很容易遇到Web服务器的超时限制(比如Apache的Timeout、Nginx的fastcgi_read_timeout),建议直接用PHP CLI执行脚本,稳定性会高很多:
替换Cron命令为PHP CLI执行
把原来的wget命令改成:
01 * * * * /usr/bin/php /absolute/path/to/your/csvread/xx/change-stock.php >> /var/log/csv_process.log 2>&1
- 注意把
/absolute/path/to/your/替换成脚本的实际绝对路径 >> /var/log/csv_process.log 2>&1会把脚本的输出和错误都记录到日志文件,方便后续排查
如果一定要用wget,需要增加超时参数避免提前断开:
01 * * * * /usr/bin/wget -q --timeout=300 --no-hangup http://xxx.de/csvread/xx/change-stock.php >> /var/log/wget_cron.log 2>&1
--timeout=300设置超时为300秒(5分钟)--no-hangup保证即使wget的父进程退出,脚本也能继续执行
三、验证步骤
- 手动用CLI执行脚本,测试是否能生成完整文件:
如果执行成功,说明脚本本身没问题,问题出在Cron的执行环境或者wget的设置上。/usr/bin/php /absolute/path/to/change-stock.php - 检查PHP CLI的配置:
执行/usr/bin/php -i | grep max_execution_time和/usr/bin/php -i | grep memory_limit,确认CLI模式下的时间和内存限制是否足够。
总结
最可能的几个原因:
- wget的超时限制导致HTTP请求提前断开
- PHP脚本的时间/内存限制不够,中途终止
- fgetcsv的长度参数设置不合理导致行截断
按照上面的步骤调整后,应该能解决这个问题。
内容的提问来源于stack exchange,提问作者Kallmas

