-1

在我们的 PHP 应用程序中,有一个函数可以PHPMailer在收集发送过程的日志时发送邮件:

function sendWithLog(PHPMailer $mail, &$debug_log, $log_level = PHPMailer_SMTP::DEBUG_CONNECTION) {
    $debug_log = [];
    $mail->SMTPDebug = $log_level ?: PHPMailer_SMTP::DEBUG_CONNECTION;
    $mail->Debugoutput = function($message) use(&$debug_log) {
        $debug_log[] = $message;
    };

    $sent = $mail->send();

    $debug_log = !$sent
                ? $mail->ErrorInfo
                . ($debug_log ? "\n" . implode("\n", $debug_log) : "")
                : "";

    return $sent;
}

所以,$debug_log通过引用传递的变量,首先应该初始化为一个空数组,最后变成一个字符串。

如果再次调用该函数,作为上一次调用的传递$debug_log$debug_log我会看到此错误:

PHP 致命错误:未捕获的错误:字符串不支持 [] 运算符

但是,在使用语句绑定到闭包之前,该变量仍应初始化为空数组use(),所以我真的不明白这个错误是如何发生的。

我尝试使用此处代码的简化版本重现该行为,但它似乎不会触发错误。

编辑:

我通过改变这样的功能解决了这个问题:

function sendWithLog(PHPMailer $mail, &$debug_log, $log_level = PHPMailer_SMTP::DEBUG_CONNECTION) {
    $messages = []; // <-- different variable for collecting the log messages!
    $mail->SMTPDebug = $log_level ?: PHPMailer_SMTP::DEBUG_CONNECTION;
    $mail->Debugoutput = function($message) use(&$messages) {
        $messages[] = $message;
    };

    $sent = $mail->send();

    $debug_log = !$sent
                ? $mail->ErrorInfo
                . ($messages ? "\n" . implode("\n", $messages) : "")
                : "";

    return $sent;
}

但是,我仍然想知道它如何首先触发错误。

使用示例如下:

// $users -> query result from database
while($user = $users->fetch()) {
  // build mail and then
  $sent = sendWithLog($mail, $mail_log);
  // here $mail_log should be initialized to NULL the first time by the PHP engine
  // and in subsequent calls it is the log string of the previous call which should be
  // reset to [] first thing inside the function call

  if(!$sent) {
    error_log("ERROR SENDING MAIL: $mail_log");
  }
}

编辑 2

这是一个示例堆栈跟踪:

PHP Fatal error:  Uncaught Error: [] operator not supported for strings in /opt/agews64/www/includes/class/AGEws/Mail.php:134
Stack trace:
0 /opt/agews64/www/includes/class/PHPMailer/SMTP.php(220): AGEws_Mail::{closure}('CLIENT -> SERVE...', 1)
1 /opt/agews64/www/includes/class/PHPMailer/SMTP.php(991): PHPMailer_SMTP->edebug('CLIENT -> SERVE...', 1)
2 /opt/agews64/www/includes/class/PHPMailer/SMTP.php(885): PHPMailer_SMTP->client_send('QUIT\r\n')
3 /opt/agews64/www/includes/class/PHPMailer/SMTP.php(827): PHPMailer_SMTP->sendCommand('QUIT', 'QUIT', 221)
4 /opt/agews64/www/includes/class/PHPMailer.php(1721): PHPMailer_SMTP->quit()
5 /opt/agews64/www/includes/class/PHPMailer.php(670): PHPMailer->smtpClose()
6 /opt/agews64/www/includes/class/AGEws/Mail.php(147): PHPMailer->__destruct()
7 /opt/agews64/www/includes/class/AGEws/Mail.php(118): AGEws_Mail::sendWithLog(NULL, 'SMTP Error: Dat...', 3)
8 /opt/agews64/www/includes/class/AGEws/Cron/Import.php(154): AGEws_Mail::prepareAndSendWithLog('SMTP Error: Dat...', Array, 'Risu in /opt/agews64/www/includes/class/AGEws/Mail.php on line 134
4

1 回答 1

1

这对评论来说太长了,所以让我在这里输入

考虑到您的示例,我唯一能想到的-我不确定这里的内部工作原理,但无论如何让我尝试解释一下-是:

您设置$mail->Debugoutput为将项目附加到的可调用对象$debug_log。现在,当您在函数结束时设置$debug_log为字符串($debug_log = !$sent等)时,设置字符串期间,可能会发生这种implode()情况,当字符串连接由于某种原因$mail->Debugoutput再次被调用时(可能在a __toString()?),它试图将一个数组项附加到$debug_log,这是不可能的,因为它被设置为一个字符串。因此错误。

于 2018-07-26T12:07:19.857 回答