PHP脚本被cron调用需指定PHP绝对路径、使用绝对路径引用文件、添加日志重定向,并在脚本中用glob/scandir安全遍历日志文件,逐个校验可写性后再unlink,避免因环境变量缺失、路径错误或权限问题导致失败。

PHP 脚本怎么被 cron 正确调用执行
直接写 php /path/to/clean_logs.php 在 cron 里大概率失败,不是权限问题,而是环境变量缺失——特别是 PATH 和当前工作目录。cron 默认的 PATH 很窄(通常只有 /usr/bin:/bin),找不到你系统里装的 PHP(比如 /usr/local/bin/php 或 /opt/homebrew/bin/php)。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 先用
which php查出完整路径,比如是/usr/local/bin/php,就硬编码进 cron 行,别依赖PATH - 脚本开头加
#!/usr/local/bin/php并给脚本+x权限,然后 cron 写成/path/to/clean_logs.php(更干净,但需确认系统允许执行 shebang 脚本) - 务必用绝对路径:日志路径、配置文件路径、
include的路径全得写死,避免因 cron 工作目录是/root或/导致file_get_contents('config.php')找不到文件 - 加日志重定向,例如
0 2 * * * /usr/local/bin/php /var/www/clean_logs.php >> /var/log/clean_logs.log 2>&1,否则失败了你根本不知道
为什么 clean_logs.php 里不能只用 unlink() 删文件
unlink() 单删一个文件没问题,但清日志常要按时间、大小、后缀批量处理,裸写循环容易漏逻辑或崩内存。比如遍历 /var/log/php/ 下几百个文件,每个都 filemtime() + unlink(),没做异常捕获,遇到权限拒绝或正在写入的文件就会中断整个脚本。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
glob('/var/log/php/*.log', GLOB_NOSORT)或scandir()+is_file()安全过滤,避开...和子目录 - 对每个文件先
is_writable()再unlink(),失败时error_log("failed to delete {$file}: " . error_get_last()['message']); - 加时间判断别只看文件名:用
filemtime($file) 删 7 天前的,而不是靠strpos($file, '20240101')这种脆弱匹配 - 大日志目录建议加
set_time_limit(0)和ini_set('memory_limit', '64M'),防止超时或内存溢出
logs_php_cron 是什么?它和普通 cron 有啥区别
没有叫 logs_php_cron 的标准工具或扩展——这名字大概率是你看到某项目里自定义的脚本名、配置项或 crontab 注释行(比如 # logs_php_cron: daily cleanup)。它不是 PHP 内置功能,也不是 Linux cron 的子命令。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 检查你的项目目录里是否存在
logs_php_cron这个可执行文件或 shell 脚本,它可能只是封装了php clean.php+ 参数解析的 wrapper - 如果在 crontab 里看到类似
*/5 * * * * /usr/local/bin/logs_php_cron,用cat /usr/local/bin/logs_php_cron看内容,大概率就是一行带路径的 php 调用 - 别把它当黑盒:只要最终落到
php xxx.php,调试方式和普通 PHP cron 脚本完全一致——改脚本、加日志、手动运行验证
怎样避免多个 cron 实例同时跑导致日志删错或报错
如果清理脚本执行慢(比如扫描上万文件),而 cron 配置成每 5 分钟一次,就可能出现两个 php clean_logs.php 进程同时读写同一目录,轻则重复删、重则 unlink() 报 Warning: unlink(): No such file or directory。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 加简单文件锁:脚本开头
$lock = '/tmp/clean_logs.lock'; if (file_exists($lock)) exit; file_put_contents($lock, getmypid()); register_shutdown_function(function() use ($lock) { @unlink($lock); }); - 更可靠用
flock():打开一个锁文件句柄并尝试非阻塞加锁,失败直接 exit,不依赖临时文件存在性 - 在 crontab 中加
if [ ! -f /tmp/clean_logs.running ]; then touch /tmp/clean_logs.running; php /path/to/clean.php; rm /tmp/clean_logs.running; fi(shell 层面控制) - 终极方案:把清理逻辑改成「标记+异步」,比如先 mv 日志到
/tmp/to_delete/,再另起轻量脚本快速删,主流程不卡
真正难的不是写那几行 unlink(),而是让 cron 在各种边界下稳定触发、失败可追溯、并发不打架——这些细节藏在日志路径、PHP 路径、锁机制和错误捕获里,少一个,半夜告警你就得爬起来查。











