PHP带附件邮件仅发附件,表单其他信息未送达问题求助
问题分析与修复方案
我瞅了下你的代码,发现几个关键问题导致姓名、邮箱这些表单信息没跟着邮件发出去,顺便还帮你修正了几个MIME结构和变量使用的小bug,一起来看看:
存在的核心问题
- 你只处理了附件部分,完全没把姓名、邮箱这些表单数据加入到邮件内容里,multipart/mixed类型的邮件需要包含文本内容块和附件块两部分
- 变量
$nom先通过htmlentities转义,又直接用$_POST['firstname']覆盖,失去了XSS防护的作用 - 附件读取时错误使用了原文件名
$nom_fichier,应该用上传后的临时文件路径$source - MIME分隔符的使用不规范,每个内容块必须以
--$boundary开头,结尾用--$boundary-- - 请求头里重复声明了
MIME-Version,容易导致解析异常 - 邮件内容的拼接逻辑混乱,没有按照MIME结构正确组织
修复后的完整代码
<?php error_reporting(E_ALL); ini_set("display_errors", 1); // 显示错误 // 处理表单数据并做XSS防护 $nom = htmlentities($_POST['firstname'], ENT_QUOTES, 'UTF-8'); $email = htmlentities($_POST['email'], ENT_QUOTES, 'UTF-8'); // 检查邮件服务商支持的换行符 if(preg_match("#@(hotmail|live|msn)\.[a-z]{2,4}$#i", $email)){ $passage_ligne = "\n"; }else{ $passage_ligne = "\r\n"; } $email_to = "mon adresse email"; // 收件人邮箱 $email_subject = "Recrutement "; // 邮件主题 $boundary = md5(rand()); // 随机分隔符密钥 // 构建邮件头,避免重复声明MIME-Version $headers = "MIME-Version: 1.0{$passage_ligne}"; $headers .= "From: EA <{$email}>{$passage_ligne}"; // 用用户邮箱作为发件人回复地址更合理 $headers .= "Reply-To: {$nom} <{$email}>{$passage_ligne}"; $headers .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"{$passage_ligne}{$passage_ligne}"; // 初始化邮件内容,先添加表单信息的文本部分 $email_message = "--{$boundary}{$passage_ligne}"; $email_message .= "Content-Type: text/plain; charset=UTF-8{$passage_ligne}"; $email_message .= "Content-Transfer-Encoding: 8bit{$passage_ligne}{$passage_ligne}"; $email_message .= "新的招聘咨询信息{$passage_ligne}{$passage_ligne}"; $email_message .= "姓名: {$nom}{$passage_ligne}"; $email_message .= "邮箱: {$email}{$passage_ligne}{$passage_ligne}"; // 处理附件 if(isset($_FILES["fichier"]) && $_FILES['fichier']['error'] === UPLOAD_ERR_OK && $_FILES['fichier']['name'] != ""){ $nom_fichier = $_FILES['fichier']['name']; $source = $_FILES['fichier']['tmp_name']; $type_fichier = $_FILES['fichier']['type']; $taille_fichier = $_FILES['fichier']['size']; if($nom_fichier != ".htaccess"){ if(in_array($type_fichier, ["image/jpeg", "image/pjpeg", "application/pdf"])){ if ($taille_fichier <= 2097152) { // 2MB限制 // 替换文件名特殊字符 $nom_fichier = strtr($nom_fichier, ["é"=>"e", "è"=>"e", "à"=>"a"]); // 读取并编码附件内容 $content = file_get_contents($source); $encoded_content = chunk_split(base64_encode($content)); // 添加附件部分到邮件 $email_message .= "--{$boundary}{$passage_ligne}"; $email_message .= "Content-Type: {$type_fichier}; name=\"{$nom_fichier}\"{$passage_ligne}"; $email_message .= "Content-Transfer-Encoding: BASE64{$passage_ligne}"; $email_message .= "Content-Disposition: attachment; filename=\"{$nom_fichier}\"{$passage_ligne}{$passage_ligne}"; $email_message .= $encoded_content . $passage_ligne; }else{ $email_message .= "用户尝试发送附件,但文件大小超过2MB。{$passage_ligne}"; } }else{ $email_message .= "用户尝试发送附件,但文件格式不正确(仅支持JPEG/PDF)。{$passage_ligne}"; } }else{ $email_message .= "用户尝试发送.htaccess附件,已拒绝。{$passage_ligne}"; } } // 结束MIME分隔符 $email_message .= "--{$boundary}--{$passage_ligne}"; // 发送邮件 if(mail($email_to, $email_subject, $email_message, $headers)){ header('Location: index.php'); exit; // 跳转后终止脚本执行 }else{ echo "邮件发送失败,请检查服务器邮件配置"; } ?>
关键修改说明
- 新增文本内容块:在邮件最开头添加了包含姓名、邮箱的纯文本部分,确保收件人能看到表单提交的基础信息
- 规范变量处理:保留
htmlentities的转义(并指定编码和引号规则),避免XSS风险 - 修复附件读取路径:用上传临时文件路径
$source读取内容,而不是原文件名(原文件名在服务器上不存在) - 规范MIME结构:每个内容块都以
--$boundary开头,结尾用--$boundary--闭合,确保邮件客户端能正确解析 - 优化邮件头:将用户的邮箱和姓名设置为回复地址,更符合实际使用场景,同时去掉重复的
MIME-Version声明 - 增加错误判断:用
UPLOAD_ERR_OK判断文件上传是否成功,避免无效的文件处理 - 脚本终止:跳转页面后添加
exit,防止后续代码执行
内容的提问来源于stack exchange,提问作者Safa Jwd
相关产品推荐
相关产品推荐

