见过不少老站的处理方式:写个 task.php,靠别人挂个监控或者用 JS 定时刷来触发,更狠的是每次有人访问首页顺带跑一遍统计。这些歪招的共同问题是不可控——没人访问就不跑,被搜索引擎高频抓取就狂跑。定时任务就该交给系统的 cron。
PHP 从命令行跑有个专属的 SAPI 叫 CLI,和网页那套 php-fpm 是两条通道,超时限制、执行模式都不一样,天生适合干定时任务。
# 先确认CLI可用
php -v
which php # 记下这个路径,写cron要用绝对路径
写个简单的任务脚本,比如每天凌晨统计昨天的访问量写进数据库:
// /var/www/tasks/daily_stats.php
if (PHP_SAPI !== 'cli') exit; // 禁止浏览器访问,防被执行
$pdo = new PDO('mysql:host=localhost;dbname=site', 'user', 'pass');
$yesterday = date('Y-m-d', strtotime('-1 day'));
$sql = "INSERT INTO daily_stats SELECT ?, COUNT(*) FROM logs WHERE created_at >= ? AND created_at < ? + INTERVAL 1 DAY";
$pdo->prepare($sql)->execute([$yesterday, $yesterday, $yesterday]);
echo "done: {$yesterday}\n"; // 输出会被cron日志记录
开头那句 PHP_SAPI 判断是安全底线:脚本放在 web 目录外最稳,实在没法挪也得挡住浏览器直接访问。然后加进 crontab:
# crontab -e
# 每天凌晨 2:30 执行
30 2 * * * /usr/bin/php /var/www/tasks/daily_stats.php >> /var/log/tasks.log 2>&1
结尾的 >> 日志 2>&1 别省,标准输出和报错都落进日志文件,任务没跑或者跑挂了一查便知。排错三连:grep CRON /var/log/syslog 看有没有触发、tail 任务日志看报错、手动用同样命令跑一遍复现问题。
任务多了以后注意错峰:统计任务放 2 点、备份放 3 点、日志切割放 4 点,全堆在凌晨 0 点那一份钟,磁盘 IO 抢起来个个都慢。crontab 的时间字段精确到分钟,够用了。
数据来源:PHP官方手册 命令行用法
A5创业网 版权所有