phpmailer 6.9+ 在 php 8.5 上添加附件须用绝对路径或 addstringattachment,禁用 create_function;中文名需转 iso-8859-1 或改英文名;注意临时文件清理、smtp 超时及 $_files 错误校验。

PHPMailer 6.9+ 在 PHP 8.5 上添加附件的正确写法
PHP 8.5 已移除 create_function() 和部分反射兼容层,老版本 PHPMailer(如 5.x 或未更新的 6.x)会直接报 Fatal error: Uncaught Error: Call to undefined function create_function()。必须用 PHPMailer 6.9.0+,且附件逻辑不能依赖已废弃的回调写法。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
composer require phpmailer/phpmailer:^6.9确保装的是最新稳定版,别用dev-master—— 它可能含未合入的 PHP 8.5 补丁但不稳定 - 附件路径必须是绝对路径,
$mail->addAttachment('/var/www/html/report.pdf')可行,$mail->addAttachment('report.pdf')在 CLI 模式下大概率失败(工作目录不一致) - 如果附件来自内存(比如生成的 PDF 字节流),用
$mail->addStringAttachment($pdfContent, 'report.pdf', 'base64', 'application/pdf'),别试图用addAttachment传资源句柄或临时文件名
中文附件名乱码或无法下载的问题
PHPMailer 默认用 ISO-8859-1 编码文件名,遇到中文就变成 =?UTF-8?B?... 编码后仍可能被某些邮箱客户端截断或解析失败。这不是 PHP 8.5 特有,但在新环境下更显眼。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 手动设置编码:在
addAttachment()后立刻调用$mail->setLanguage('zh');(需提前加载语言包),或更稳妥地——改用addStringAttachment()并显式传入$encoding = 'base64'和$type,避开文件名自动编码逻辑 - 如果坚持用磁盘文件,先用
mb_convert_encoding($filename, 'ISO-8859-1', 'UTF-8')做兼容性降级(仅限纯中文无 emoji 场景),否则宁可改名为英文(如invoice_202405.pdf) - Outlook 和 Apple Mail 对 RFC 2231 格式的长文件名支持不一,超过 30 字符的中文名建议截断 + 加哈希后缀,例如
订单详情_'.substr(md5($id), 0, 4).'.pdf
send() 返回 true 却没收到邮件?查附件大小和超时
PHP 8.5 默认启用更严格的超时控制,加上附件上传本身耗时,send() 可能因 SMTP 超时静默返回 true(实际未发出去),尤其用 QQ 邮箱、163 等国内 SMTP 服务时。
采用三层架构开发,前台集成了产品在线展示,用户注册、在线调查、在线投稿后台有类别管理\图书管理\订单管理\会员管理\配送范围管理\邮件列表\广告管理\友情链接管理等后台添加图书时自动生成缩略图和文字水印主要参考了petshop的设计架构、使用了Asp.net2.0中很多MemberShip、master等新功能后台管理地址/web/admin/ 超级管理员账号密码均为aspx1特别提示:该系统需要
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 加日志:在
send()前后打点,用$mail->SMTPDebug = 2;查看完整 SMTP 流程,重点盯DATA阶段是否卡住或被重置 - 附件总大小建议压到 8MB 以内;PHP 8.5 的
post_max_size和upload_max_filesize若设为 2M,而你附了 5M 文件,PHP 会静默丢弃 POST 数据,$_FILES为空但脚本继续执行——得靠error_get_last()检查是否触发了UPLOAD_ERR_INI_SIZE - 用
$mail->Timeout = 30;显式设超时,别依赖默认值;若用 Gmail SMTP,记得开「应用专用密码」并关两步验证,否则认证直接被拒,错误信息是SMTP Error: Could not authenticate.
从 $_FILES 直接 addAttachment 的坑
很多人图省事,把 $_FILES['file']['tmp_name'] 直接喂给 addAttachment(),结果在 PHP 8.5 下偶发失败——不是权限问题,而是 move_uploaded_file() 未完成前,PHP 可能在请求结束时自动清理 tmp_name 对应的临时文件,导致 PHPMailer 读空内容。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 务必先
move_uploaded_file($_FILES['file']['tmp_name'], $destPath)到 Web 可读目录(如/var/www/uploads/),再传$destPath给addAttachment() - 检查
$_FILES['file']['error'] === UPLOAD_ERR_OK,否则后续全白忙;UPLOAD_ERR_NO_FILE常被忽略,但用户没选文件时它就是 4 - 临时文件路径不要拼接用户输入:
$_FILES['file']['name']可能含../../etc/passwd,必须过滤或忽略原名,用服务端生成的随机名(uniqid().'.pdf')
最易被忽略的一点:PHPMailer 的 addAttachment() 不校验文件是否存在或可读,只在真正发送时才 fopen 失败——所以测试必须走完整流程,不能只看 send() 返回值。










