You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Drupal:Cron调用main()时邮件附件未发送,手动访问URL调用正常

解决Drupal中hook_cron调用main()发送邮件缺失附件的问题

我之前也碰到过一模一样的情况,核心原因是cron运行的环境和Web请求触发的环境完全不一样,下面给你拆解可能的问题点和对应的解决办法:

1. 文件路径问题(最常见)

当你通过Web访问/admin/config/send时,PHP的当前工作目录是Drupal的根目录,所以如果你的附件路径是相对路径(比如sites/default/files/attachments/report.pdf),Web环境下能正常找到。但cron运行时,它的当前工作目录可能是服务器的根目录(/)或者你的用户主目录,这时候相对路径就失效了,找不到附件自然发不出去。

解决办法:

把所有附件路径改成绝对路径,用Drupal内置的函数来生成可靠的绝对路径:

// 代替相对路径,用这个方式获取文件绝对路径
$attachment_path = drupal_realpath('public://attachments/report.pdf');
// 然后在邮件函数里使用这个绝对路径
$params['attachments'] = array(
  array(
    'filepath' => $attachment_path,
    'filename' => 'report.pdf',
    'filemime' => 'application/pdf',
  ),
);

2. Cron运行的权限问题

Web请求是用Web服务器的用户(比如www-dataapache)运行的,而cron通常是用系统用户(比如你的SSH用户或者root)运行的。如果附件文件的权限只允许Web用户读取,cron的运行用户没权限访问,就无法加载附件。

解决办法:

  • 检查附件文件的权限:确保文件的读权限对cron运行用户开放,比如设置权限为644,目录权限为755
  • 或者让cron用Web服务器用户运行,比如在crontab里指定:
# 用www-data用户运行Drupal cron
0 * * * * sudo -u www-data /usr/bin/php /path/to/drupal/cron.php

3. main()函数依赖Web请求上下文

如果你的main()函数里用到了Web请求相关的变量(比如$_SERVER里的内容,或者依赖当前的用户会话、请求参数),而cron运行时没有这些上下文,可能导致附件生成逻辑失败(比如动态生成的附件没创建成功)。

解决办法:

  • 检查main()里的附件生成/获取逻辑,把依赖Web上下文的部分抽出来,改成独立的逻辑,不依赖请求参数。
  • 如果需要动态生成附件,确保在cron环境下能正确生成文件到指定的绝对路径,并且权限正确。

4. 邮件发送函数的差异

有些Drupal邮件模块(或者自定义的邮件发送逻辑)在Web环境下会自动处理附件,但cron环境下可能需要显式传递附件参数,或者某些配置没生效。

解决办法:

  • 确认main()里的邮件发送代码,在cron环境下是否正确传递了attachments参数给drupal_mail()或者你用的邮件函数。比如:
function main() {
  // 确保attachment参数正确传递,且路径是绝对路径
  $attachments = array(
    array(
      'filepath' => drupal_realpath('public://attachments/report.pdf'),
      'filename' => 'Monthly Report.pdf',
      'filemime' => 'application/pdf',
    ),
  );
  
  $message = drupal_mail('mymodule', 'notification', $to, language_default(), array('attachments' => $attachments), $from, TRUE);
}

快速调试技巧

可以在hook_cron里加日志,输出当前工作目录和附件路径的存在情况,方便定位问题:

function hook_cron() {
  // 输出当前工作目录到Drupal日志
  watchdog('cron_mail', 'Current working directory: @cwd', array('@cwd' => getcwd()));
  
  $attachment_path = drupal_realpath('public://attachments/report.pdf');
  // 检查文件是否存在且可读
  if (file_exists($attachment_path) && is_readable($attachment_path)) {
    watchdog('cron_mail', 'Attachment found and readable: @path', array('@path' => $attachment_path));
  } else {
    watchdog('cron_mail', 'Attachment missing or unreadable: @path', array('@path' => $attachment_path), WATCHDOG_ERROR);
  }
  
  main();
}

然后去Drupal的日志页面(/admin/reports/dblog)查看日志,就能快速知道是路径问题还是权限问题了。

内容的提问来源于stack exchange,提问作者Marwen Amri

火山引擎 最新活动