
php脚本在浏览器中正常运行,但通过crontab执行时报“directory nonexistent”错误,根本原因是cron默认工作目录非脚本所在目录,导致相对路径(如./backups/)失效;解决方法是统一使用绝对路径操作文件。
php脚本在浏览器中正常运行,但通过crontab执行时报“directory nonexistent”错误,根本原因是cron默认工作目录非脚本所在目录,导致相对路径(如./backups/)失效;解决方法是统一使用绝对路径操作文件。
当PHP脚本通过Web服务器(如Apache或Nginx)执行时,其当前工作目录通常为Web根目录(例如/var/www/mysite.com/),因此./backups/db_20220522.sql能被正确解析。但crontab以独立shell环境运行,其默认工作目录通常是用户主目录(如/root)或空路径,而非PHP脚本所在位置——这导致所有相对路径(包括./backups/、../config.php等)全部失效,即使已调用set_include_path()也仅影响include/require类操作,对exec()中的文件路径无任何作用。
✅ 正确做法:在脚本中显式定义并切换到绝对路径:
<?php
// 定义脚本所在绝对路径(推荐用 __DIR__ 动态获取)
$baseDir = '/var/www/mysite.com';
$backupDir = $baseDir . '/backups';
// 确保备份目录存在(crontab运行时无GUI上下文,需主动创建)
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
// 构造绝对路径的dump文件名
$timestamp = date('Ymd');
$dumpFile = $backupDir . "/db_{$timestamp}.sql";
// 执行mysqldump(注意:务必使用绝对路径调用mysqldump二进制!)
$mysqldump = '/usr/bin/mysqldump'; // 用 `which mysqldump` 查准路径
$cmd = escapeshellcmd("{$mysqldump} -u username -p'password' database_name > " . escapeshellarg($dumpFile));
$result = exec($cmd, $output, $returnCode);
if ($returnCode !== 0) {
error_log("mysqldump failed: " . implode("\n", $output));
}⚠️ 关键注意事项:
- 不要依赖cd命令切换目录:cron中exec('cd /path && command')无效,因每个exec()调用启动新shell,cd不生效;
- 避免硬编码密码:生产环境应使用MySQL配置文件(~/.my.cnf)配合--defaults-extra-file参数,防止密码泄露至进程列表;
- 验证crontab用户权限:若脚本需写入/var/www/,确保cron运行用户(如root)对该目录有写权限(Ubuntu中www-data组可能受限);
- 日志调试建议:在crontab中重定向输出,例如:0 2 * /usr/bin/php /var/www/mysite.com/backup.php >> /var/log/backup.log 2>&1。
总结:crontab与Web执行环境本质不同——前者无预设工作目录、无继承Web服务器的路径上下文。一切路径(文件读写、命令调用、目录创建)必须使用绝对路径,并主动保障目录存在性与权限正确性,这是PHP定时任务健壮运行的基础前提。
立即学习“PHP免费学习笔记(深入)”;



















