imap_fetchstructure()无法捕获name.bin格式附件问题咨询
解决imap_fetchstructure()无法捕获.bin附件的问题
看起来你遇到的问题是imap_fetchstructure()能正常抓取PDF、图片这类常规附件,却偏偏漏掉了需要的.bin文件——从你给出的结构信息来看,这个问题大概率是邮件结构嵌套导致你没遍历到深层子部分,或者没有正确解析附件的标识字段。咱们一步步来排查解决:
1. 先搞懂你拿到的结构含义
你给出的stdClass Object里,type => 3对应的是IMAP的TYPEMESSAGE类型(简单说就是这是一个内嵌的邮件片段),而你的.bin附件很大概率就藏在这个类型的parts子属性里(可惜你给出的结构没显示这部分,应该是没做递归遍历导致的)。
2. 核心解决方案:必须递归遍历所有邮件部分
imap_fetchstructure()返回的是一个层次化的结构,很多邮件都是多部分嵌套的(比如multipart/mixed里嵌套multipart/alternative,再嵌套具体的附件部分)。如果只遍历顶层的parts,肯定会漏掉藏在深层的附件。
给你一个现成的递归遍历代码示例
function getMailAttachments($imapConn, $msgNum) { $attachments = []; $msgStructure = imap_fetchstructure($imapConn, $msgNum); // 递归处理每个邮件部分的匿名函数 $parseSinglePart = function($part, $partPrefix = '') use (&$parseSinglePart, &$attachments, $imapConn, $msgNum) { $isAttachment = false; $fileName = ''; // 第一种判断附件的方式:从disposition参数里提取文件名 if (isset($part->disposition) && strtoupper($part->disposition) === 'ATTACHMENT') { if (isset($part->dparameters) && is_array($part->dparameters)) { foreach ($part->dparameters as $param) { if (strtoupper($param->attribute) === 'FILENAME') { $fileName = $param->value; $isAttachment = true; break; } } } } // 第二种判断方式:从parameters里提取文件名(部分邮件会用这个字段) if (!$isAttachment && isset($part->parameters) && is_array($part->parameters)) { foreach ($part->parameters as $param) { if (strtoupper($param->attribute) === 'NAME') { $fileName = $param->value; $isAttachment = true; break; } } } // 如果确认是附件,读取并解码内容 if ($isAttachment && !empty($fileName)) { // 构建imap_fetchbody需要的部分编号 $partId = $partPrefix . ($partPrefix ? '.' : '') . '1'; $rawContent = imap_fetchbody($imapConn, $msgNum, $partId); // 根据编码格式解码内容 switch ($part->encoding) { case 3: // BASE64编码 $decodedContent = base64_decode($rawContent); break; case 4: // QUOTED-PRINTABLE编码 $decodedContent = quoted_printable_decode($rawContent); break; // 其他编码类型可根据需求补充 } $attachments[] = [ 'filename' => $fileName, 'content' => $decodedContent, 'subtype' => $part->subtype ]; } // 如果当前部分有子部分,递归处理 if (isset($part->parts) && is_array($part->parts)) { $subPartIndex = 1; foreach ($part->parts as $subPart) { $newPrefix = $partPrefix . ($partPrefix ? '.' : '') . $subPartIndex; $parseSinglePart($subPart, $newPrefix); $subPartIndex++; } } }; $parseSinglePart($msgStructure); return $attachments; }
3. 针对.bin文件的额外检查点
- 你的
.bin文件subtype是OCTET-STREAM,上面的代码已经能覆盖到,只要文件名匹配.bin就会被捕获。 - 如果遇到文件名乱码的情况,可以用
imap_mime_header_decode()解码:$decodedName = imap_mime_header_decode($fileName); $fileName = $decodedName[0]->text;
4. 先验证邮件的完整结构
你可以先打印出完整的imap_fetchstructure()结果,确认.bin附件到底在哪个嵌套层级里:
$fullStructure = imap_fetchstructure($imapConn, $msgNum); echo '<pre>' . print_r($fullStructure, true) . '</pre>';
这样就能直观看到.bin附件所在的parts位置,确保递归遍历能覆盖到它。
内容的提问来源于stack exchange,提问作者megazoid
相关产品推荐
相关产品推荐

