在DigitalOcean通过crontab运行PHPSpreadsheet无法保存文件的问题
Crontab运行PHP脚本异常:邮件中断+Excel无法保存的排查方案
问题重现
通过浏览器URL运行PHP脚本时,所有邮件发送成功,XLSX文件能正常保存到指定路径,执行流畅;但通过crontab定时运行时,仅能发送前两封邮件,最后一封发送失败,同时XLSX文件无法保存,且无报错日志输出。
服务器环境
- 服务器:DigitalOcean
- PHP版本:8.2.13
依赖配置(composer.json)
{ "require": { "phpoffice/phpspreadsheet": "^1.29", "phpmailer/phpmailer": "^6.9.1" } }
涉事脚本代码
<?php require dirname(dirname(__FILE__)).'/vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; include dirname(dirname(__FILE__)) . '/includes/mail.php'; // 发送邮件通知:"STARTED CRON" $spreadsheet = new Spreadsheet(); $newsheet = new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet($spreadsheet, "My first sheet"); $spreadsheet->addSheet($newsheet); $activesheet = $spreadsheet->setActiveSheetIndexByName("My first sheet"); $activesheet->getTabColor()->setRGB("FF0000"); $activesheet->setCellValue("A1", "Test"); $activesheet->setCellValue("A2", "Some numbers..."); $activesheet->setCellValue("A3", 1); $activesheet->setCellValue("A4", 2); $activesheet->setCellValue("A5", "=SUM(A3:A4)"); $activesheet->getStyle("A1")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID); $activesheet->getStyle("A1")->getFill()->getStartColor()->setARGB("FFC6EFCE"); // 浅绿色 // 发送邮件通知:"SET THE DATA" $destinationfile = "/folder/to/file/TEST_FILE.xlsx"; $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, "Xlsx"); $writer->setPreCalculateFormulas(false); $writer->save($destinationfile); // 发送邮件通知:"FINISHED CRON"
排查与修复方案
1. 修正路径与权限问题
Crontab默认工作目录是用户主目录,不是脚本所在目录,容易导致路径解析错误:
- 将脚本中所有相对路径替换为绝对路径,比如确认
/folder/to/file/TEST_FILE.xlsx是服务器真实存在的完整路径,避免依赖dirname(__FILE__)组合解析。 - 检查目标目录权限:执行
chmod 755 /folder/to/file/确保目录可读写,若crontab以特定用户运行,执行chown username:username /folder/to/file/调整目录所有者。
2. 强制捕获错误日志
脚本无错误捕获机制,crontab的错误不会默认输出,需手动添加日志记录:
修改脚本关键位置,添加错误捕获:
// 在$writer->save()前添加 error_reporting(E_ALL); ini_set('display_errors', 1); ini_set('log_errors', 1); ini_set('error_log', '/绝对路径/to/error.log'); // 写死日志文件绝对路径 try { $writer->save($destinationfile); // 发送"FINISHED CRON"邮件 } catch (\Exception $e) { error_log('Excel保存失败: ' . $e->getMessage()); // 新增错误通知邮件 sendMail('脚本执行失败', $e->getMessage()); // 调用mail.php中的发送函数 }
同时修改crontab命令,强制输出所有日志:
* * * * * php /绝对路径/to/your/script.php >> /绝对路径/to/cron.log 2>&1
3. 对齐PHP CLI与FPM环境配置
浏览器用PHP-FPM,crontab用PHP CLI,两者配置可能不一致:
- 执行
php -v确认CLI版本为8.2.13,和FPM环境一致。 - 执行
php -m检查是否缺少PhpSpreadsheet依赖的扩展(如zip、xml),缺失则安装对应扩展。 - 对比CLI和FPM的
php.ini配置,确保allow_url_fopen等必要参数开启状态一致。
4. 排查PHPMailer CLI环境问题
最后一封邮件失败大概率是脚本崩溃导致后续代码未执行,也可能是邮件配置问题:
- 确认
mail.php中的SMTP证书文件使用绝对路径,CLI环境无法识别相对路径的证书。 - 在
mail.php中添加日志,记录每一封邮件的发送状态,排查是否存在资源未释放导致的发送阻塞。
内容的提问来源于stack exchange,提问作者Jo H
相关产品推荐
相关产品推荐

