PHP发送邮件附件为空问题排查:附件大小0字节求解决
PHP发送带附件邮件附件为空(0字节)的问题排查与修复
核心问题分析
你的脚本附件为空(0字节),主要是文件读取环节的错误被掩盖,加上MIME格式不规范导致的,具体问题点如下:
- 错误抑制符掩盖了文件读取失败:你用
@前缀屏蔽了fopen、fread的错误信息,即便文件路径正确,若PHP没有读取该文件的权限,或者文件实际不存在,$data会被赋值为空,最终附件内容就是0字节。 - MIME换行符不统一:邮件标准要求所有头信息和内容的换行必须用
\r\n,你的脚本混合使用了\n和\r\n,可能导致邮件客户端解析附件时出错。 - 重复调用
filesize($file)且时机错误:第一次调用filesize时文件还没打开,若文件在两次调用期间被修改,会导致读取长度错误;更关键的是,若文件打开失败,filesize返回的数值会让fread读取无效内容。 - Content-Disposition格式错误:
size=".filesize($file)."不属于该字段的标准参数,多余的属性可能干扰邮件客户端解析附件。
修复后的脚本
$to = $destination; $from = 'test@test.test'; $fromName = 'Test'; $subject = $subject; $file = "./image-based-pdf-sample.pdf"; $htmlContent = $content; // 先检查文件是否存在且可读 if (!file_exists($file) || !is_readable($file)) { die("<h1>Error: 文件不存在或无法读取</h1>"); } $headers = "From: $fromName <$from>\r\n"; $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; $headers .= "MIME-Version: 1.0\r\n" . "Content-Type: multipart/mixed;\r\n" . " boundary=\"{$mime_boundary}\"\r\n"; $message = "--{$mime_boundary}\r\n" . "Content-Type: text/html; charset=\"UTF-8\"\r\n" . "Content-Transfer-Encoding: 7bit\r\n\r\n" . $htmlContent . "\r\n"; $message .= "--{$mime_boundary}\r\n"; $fp = fopen($file,"rb"); if (!$fp) { die("<h1>Error: 无法打开文件</h1>"); } // 通过fstat获取打开文件的大小,避免文件变化问题 $fileStat = fstat($fp); $data = fread($fp, $fileStat['size']); fclose($fp); $data = chunk_split(base64_encode($data)); $message .= "Content-Type: application/octet-stream; name=\"".basename($file)."\"\r\n" . "Content-Description: ".basename($file)."\r\n" . "Content-Disposition: attachment;\r\n" . " filename=\"".basename($file)."\"\r\n" . "Content-Transfer-Encoding: base64\r\n\r\n" . $data . "\r\n"; $message .= "--{$mime_boundary}--"; $returnpath = "-f" . $from; $mail = mail($to, $subject, $message, $headers, $returnpath); echo $mail?"<h1>Success</h1>":"<h1>Error</h1>";
关键修复点说明
- 添加文件存在性和可读性检查:提前判断文件状态,避免后续无意义的操作。
- 移除错误抑制符并添加打开失败检查:暴露文件读取的真实问题,方便排查。
- 统一使用
\r\n作为换行符:符合MIME邮件标准,避免解析错误。 - 用
fstat获取已打开文件的大小:确保读取长度准确,不受文件外部修改影响。 - 移除Content-Disposition中的多余size参数:遵循标准格式,避免解析干扰。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

