Xiuno BBS 审计之问题15:PHP 8下SMTP 的功能不可用

管理

此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。

问题:each() 函数在 PHP 8.0 被移除,发送邮件时 Fatal error

现象

Xiuno BBS 4.0.4 内置的 PHPMailer 兼容类(位于 xiunophp/xn_send_mail.func.php)使用 each() 函数遍历数组。each() 在 PHP 7.2 被废弃,PHP 8.0 起整体移除。任何调用 each() 的代码在 PHP 8 下都会抛出 Fatal error: Uncaught Error: Call to undefined function each(),导致用户注册、找回密码、邮件通知等所有依赖 SMTP 的功能不可用。

源码证据

文件 xiunobbs_4.0.4/xiunophp/xn_send_mail.func.php 共 3 处 each() 调用:

// 第 1827 行:EncodeQPphp() 中遍历 $lines
public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
    $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
    $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
    $eol = "\r\n";
    $escape = '=';
    $output = '';
    while( list(, $line) = each($lines) ) {        // <-- PHP 8 Fatal error
      $linlen = strlen($line);
      ...

// 第 2933 行:邮件行折叠处理
while(list(,$line) = @each($lines)) {              // <-- PHP 8 Fatal error
  $lines_out = null;
  if($line == "" && $in_headers) {
    $in_headers = false;
  }

// 第 2962 行:发送邮件时拆分行
while(list(,$line_out) = @each($lines_out)) {      // <-- PHP 8 Fatal error
  if(strlen($line_out) > 0)
  {
    if(substr($line_out, 0, 1) == ".") {
      $line_out = "." . $line_out;
    }
  }
  fputs($this->smtp_conn,$line_out . $this->CRLF);

注:xiunophp/array.func.php 第 135-136 行原本也使用过 each(),作者已注释掉并改写为 foreach,注释明确写道 // php 7.2 deprecated each(),说明作者已知该问题但未同步修复 xn_send_mail.func.php

// xiunophp/array.func.php 第 134-137 行(已修复)
foreach($orderby as $k=>$v) {
    // php 7.2 deprecated each()
    //list($k, $v) = each($orderby);

风险等级与结论

兼容障碍(致命)each() 在 PHP 8.0 被移除,调用即 Fatal error: Call to undefined function each()

危害:

  1. route/user.php 第 5 行 include _include(XIUNOPHP_PATH.'xn_send_mail.func.php'); —— user 路由文件每次请求都会加载此 PHPMailer 类,但类定义本身不会立即触发错误;当用户开启 user_create_email_onuser_resetpw_on 并实际调用邮件发送(EncodeQPphp、SMTP fputs 流程)时直接 Fatal error。

  2. 第 1827 行 EncodeQPphp() 是 Quoted-Printable 编码路径,几乎所有 HTML 邮件都会触发。

  3. 第 2933、2962 行在 SMTP 协议层处理行折叠,任何通过 SMTP 发送的邮件都会触发。

修复建议:

  1. 将三处 while(list(,$v) = each($arr)) 改为 foreach($arr as $v)

    • 第 1827 行:foreach($lines as $line) {

    • 第 2933 行:foreach($lines as $line) {

    • 第 2962 行:foreach($lines_out as $line_out) {

  2. 由于 each() 内部会推进数组指针,而 foreach 不会,需确认循环体内没有依赖数组指针位置的其他调用(当前代码未依赖,可安全替换)。

  3. 同步升级 PHPMailer 到支持 PHP 8 的版本(≥ 6.5)。

最新回复

请先登录后再回复 登录

uid:1 管理
关注
随遇而安,随缘而行
发帖 81
评论 348
粉丝 11
关注 1
发新帖
目录
Xiuno BBS 审计之问题15:PHP 8下SMTP 的功能不可用