PHP邮件附件异常排查:0KB、文件名错误及多附件显示问题
PHP邮件附件常见问题排查与解决
问题1:发送的附件始终为0KB
现象:已保留附件头与内容间的空行,但附件大小始终为0KB。
错误原因:循环中错误将文件原名存入数组,后续读取时用文件名而非临时文件路径,无法获取上传文件的实际内容。
错误代码片段:
for($i = 0; $i < count($_FILES['filename']['name']); $i++){ $tmp_name = $_FILES['filename']['tmp_name'][$i]; if (file_exists($tmp_name)){ $fname[] = $_FILES['filename']['name'][$i]; } }
解决思路:需同时存储上传文件的临时路径和原文件名,临时路径用于读取文件内容,原文件名用于在邮件中显示正确的附件名称。
问题2:附件大小恢复正常,但文件名丢失后缀
现象:修改为存储临时路径后,附件大小正常,但接收端显示的文件名没有后缀。
原因:邮件头中未指定附件的原始文件名,默认使用无后缀的临时文件名。
解决方法:构建邮件附件部分时,通过Content-Disposition头指定filename参数,值为上传文件的原文件名。示例:
// 单个附件的头信息示例 $attachmentHeader = "Content-Disposition: attachment; filename=\"{$fname[$i]}\"\r\n";
问题3:仅第一个附件正常,其余附件显示为乱码文本
现象:分别存储临时路径和原文件名后,第一个附件显示正常,后续附件变成无意义的字母数字乱码。
常见原因及解决:
- 边界(Boundary)处理错误:多附件邮件需用唯一边界字符串分隔每个部分,若循环中重复使用错误边界或未正确闭合附件块,会导致解析异常。
解决:生成唯一边界字符串,每个附件块前后用--{$boundary}包裹,最后用--{$boundary}--结束所有附件。 - 文件名编码问题:非ASCII文件名未按邮件标准编码,导致显示乱码。
解决:将原文件名转换为RFC 2047格式编码,示例:$encodedFilename = '=?UTF-8?B?' . base64_encode($fname[$i]) . '?='; $attachmentHeader = "Content-Disposition: attachment; filename=\"{$encodedFilename}\"\r\n"; - 文件内容读取与编码错误:循环读取文件时未重置文件指针,或未对文件内容进行base64编码。
解决:读取每个附件时重新打开临时文件,读取后进行base64编码,示例:$fileContent = file_get_contents($fpath[$i]); $encodedContent = chunk_split(base64_encode($fileContent));
完整多附件邮件构建核心示例:
// 生成唯一边界 $boundary = md5(uniqid(time())); $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\r\n"; // 构建邮件正文 $message = "--{$boundary}\r\n"; $message .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n"; $message .= "邮件正文内容\r\n\r\n"; // 循环处理每个附件 for($i = 0; $i < count($fpath); $i++){ $fileContent = file_get_contents($fpath[$i]); $encodedContent = chunk_split(base64_encode($fileContent)); $encodedFilename = '=?UTF-8?B?' . base64_encode($fname[$i]) . '?='; $message .= "--{$boundary}\r\n"; $message .= "Content-Type: application/octet-stream\r\n"; $message .= "Content-Transfer-Encoding: base64\r\n"; $message .= "Content-Disposition: attachment; filename=\"{$encodedFilename}\"\r\n\r\n"; $message .= $encodedContent . "\r\n"; } // 结束边界 $message .= "--{$boundary}--"; // 发送邮件 mail($to, $subject, $message, $headers);
内容的提问来源于stack exchange,提问作者fafa
相关产品推荐
相关产品推荐

