PHP Conference Japan 2024

imap_fetchstructure

(PHP 4, PHP 5, PHP 7, PHP 8)

imap_fetchstructure读取特定邮件的结构

描述

imap_fetchstructure(IMAP\Connection $imap, int $message_num, int $flags = 0): stdClass|false

获取给定邮件的所有结构化信息。

参数

imap

一个 IMAP\Connection 实例。

message_num

邮件编号

flags

此可选参数只有一个选项,FT_UID,它告诉函数将 message_num 参数视为 UID

返回值

返回一个对象,其属性列在下面的表格中,或者在失败时返回 false

imap_fetchstructure() 的返回对象
type 主要主体类型
encoding 主体传输编码
ifsubtype 如果存在子类型字符串则为 true
subtype MIME 子类型
ifdescription 如果存在描述字符串则为 true
description 内容描述字符串
ifid 如果存在标识字符串则为 true
id 标识字符串
lines 行数
bytes 字节数
ifdisposition 如果存在处理字符串则为 true
disposition 处理字符串
ifdparameters 如果 dparameters 数组存在则为 true
dparameters 一个对象数组,每个对象都有一个 "attribute" 和一个 "value" 属性,分别对应于 Content-disposition MIME 头部的参数。
ifparameters 如果参数数组存在则为 true
parameters 一个对象数组,每个对象都有一个 "attribute" 和一个 "value" 属性。
parts 一个对象数组,结构与顶级对象相同,每个对象对应于一个 MIME 主体部分。

主要主体类型(值可能因使用的库而异,建议使用常量)
类型常量
0textTYPETEXT
1multipartTYPEMULTIPART
2messageTYPEMESSAGE
3applicationTYPEAPPLICATION
4audioTYPEAUDIO
5imageTYPEIMAGE
6videoTYPEVIDEO
7modelTYPEMODEL
8otherTYPEOTHER

传输编码(值可能因使用的库而异,建议使用常量)
类型常量
07bitENC7BIT
18bitENC8BIT
2BinaryENCBINARY
3Base64ENCBASE64
4Quoted-PrintableENCQUOTEDPRINTABLE
5otherENCOTHER

变更日志

版本 描述
8.1.0 imap 参数现在需要一个 IMAP\Connection 实例;以前需要一个有效的 imap 资源

参见

添加注释

用户贡献的注释 12 条注释

david at hundsness dot com
16 年前
这是一个解析和解码所有类型邮件(包括附件)的代码。我已经使用类似的代码一段时间了,所以它非常健壮。

<?php
function getmsg($mbox,$mid) {
// 输入 $mbox = IMAP 流,$mid = 消息 ID
// 输出以下所有内容:
global $charset,$htmlmsg,$plainmsg,$attachments;
$htmlmsg = $plainmsg = $charset = '';
$attachments = array();

// 报头
$h = imap_header($mbox,$mid);
// 在此处添加代码以获取日期、发件人、收件人、抄送、主题等…

// 正文
$s = imap_fetchstructure($mbox,$mid);
if (!
$s->parts) // 简单邮件
getpart($mbox,$mid,$s,0); // 传递 0 作为部分编号
else { // 多部分邮件:循环遍历每一部分
foreach ($s->parts as $partno0=>$p)
getpart($mbox,$mid,$p,$partno0+1);
}
}

function
getpart($mbox,$mid,$p,$partno) {
// $partno = '1', '2', '2.1', '2.1.3' 等,对于多部分邮件,如果是简单邮件则为 0
global $htmlmsg,$plainmsg,$charset,$attachments;

// 解码数据
$data = ($partno)?
imap_fetchbody($mbox,$mid,$partno): // 多部分邮件
imap_body($mbox,$mid); // 简单邮件
// 任何部分都可能被编码,甚至纯文本消息,所以检查所有内容。
if ($p->encoding==4)
$data = quoted_printable_decode($data);
elseif (
$p->encoding==3)
$data = base64_decode($data);

// 参数
// 获取所有参数,例如字符集、附件文件名等。
$params = array();
if (
$p->parameters)
foreach (
$p->parameters as $x)
$params[strtolower($x->attribute)] = $x->value;
if (
$p->dparameters)
foreach (
$p->dparameters as $x)
$params[strtolower($x->attribute)] = $x->value;

// 附件
// 任何带有文件名的部分都是附件,
// 所以附加的文本文件 (类型 0) 不会被误认为是消息。
if ($params['filename'] || $params['name']) {
// 文件名可以作为 'Filename' 或 'Name' 或两者同时给出
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// 文件名可能被编码,所以参见 imap_mime_header_decode()
$attachments[$filename] = $data; // 如果两个文件具有相同的名称,则这是一个问题
}

// 文本
if ($p->type==0 && $data) {
// 由于内联附件,消息可能会被分割成不同的部分,
// 所以用空行将各部分连接在一起。
if (strtolower($p->subtype)=='plain')
$plainmsg. = trim($data) ."\n\n";
else
$htmlmsg. = $data ."<br><br>";
$charset = $params['charset']; // 假设所有部分的字符集相同
}

// 嵌入式邮件
// 许多退回通知将原始邮件嵌入为类型 2,
// 但 AOL 使用类型 1 (多部分),此处未处理。
// 没有 PHP 函数可以解析嵌入式邮件,
// 所以这只是将原始源附加到主邮件中。
elseif ($p->type==2 && $data) {
$plainmsg. = $data."\n\n";
}

// 子部分递归
if ($p->parts) {
foreach (
$p->parts as $partno0=>$p2)
getpart($mbox,$mid,$p2,$partno.'.'.($partno0+1)); // 1.2, 1.2.1 等
}
}
?>
mkknapp at quadrapod dot com
23年前
假设 $struct = imap_fetchstructure($x,$y);

需要注意的是,如果邮件没有附件,$struct->parts 是一个空数组,而 $struct->bytes 有值。如果邮件有任何附件,$struct->bytes 总是等于 0。要获取主正文的大小,必须调用 structure->part[0]->bytes。要获取整个邮件的大小,可以使用 strlen(imap_body) 或将所有部分的 ->bytes 加起来。

另一个有趣的点
当有正文而没有附件时
count($struct->parts) = 0
当有正文和 1 个附件时
count($struct->parts) = 2

这些 imap 函数真的需要更好的文档。例如,提供 dparameter 和 parameter 类的使用方法……
php AT firstnetimpressions.com
22年前
澄清说明

第七种主要正文类型并非文档中所述的“其他”,而是“模型”。这包括 IGES、VRML、MESH、DWF 等。

http://www.isi.edu/in-notes/iana/assignments/media-types/media-types

“其他”是第八种主要正文类型。
chrislhill at "O_o" hotmail dot com
21年前
对于刚开始使用的人来说,这可能会有很大帮助,因为我花了好几个小时才弄清楚数组是如何精确存储的。(当时我不知道 print_r 函数 :P)

$struct = imap_fetchstructure($mbox, $msgnumber);
print_r($struct);

将为您提供邮件的更好示例,但它们使用上面的变量方法称为 $struct。

$struct->type; // 将返回类型
$struct->encoding // 将返回编码

等等..

这可以通过多种不同的方式完成,但这只是从 fetchstructure 本身的结构中提取信息的入门知识,我希望它能帮助刚开始学习的人,因为它可以帮助我:/。
sirber at detritus dot qc dot ca
18年前
“主要正文类型”为“unknown/unknown”将是 int(9)。
masterbassist
19年前
我认为以下行(在构建附件信息时)

>>> "filename" => $parts[$i]->parameters[0]->value

需要改为

>>> "filename" => $parts[$i]->dparameters[0]->value

第一个版本在 PHP 5.0.3 下生成了 PHP 警告。第二个版本实际上获取了文件名。
phpnet,a,emailaddress,cjb,net
17年前
另一个评论是为了告知人们关于函数描述中真正应该包含的内容

imap_fetchstructure() 下载整个电子邮件,包括所有附件,而不仅仅是结构。
我认为这是一个未记录的功能,而不是错误。

我之前假设脚本只会下载返回的数据量,但是我的脚本下载了累积的 2.5 GB 才注意到。希望不会再有人遇到这种情况。
hello at ivanbogomolov dot ru
5年前
如果你的逻辑基于比较结构字符串,则必须不区分大小写地进行比较。
<?php

$p
= imap_fetchstructure($this->_imap_resource, $mid);
//不要比较 $p->disposition == 'INLINE'
if(preg_match('/inline/i', $p->disposition))
{
//这样可行
}
?>
alchrystal88 at web dot de
5年前
如果附件名称错误,例如:

正确的名称
字符串 -> Prüfbericht Hersteller.pdf

fetchstructure 对象名称
=?ISO-8859-1?Q?Pr=FCfbericht_Hersteller=2Epdf?=

解决方法:重新转换

imap_mime_header_decode($fetchstructure->dparameters->value)[0]->text

imap_mime_header_decode($filename)[0]->text
es96 at hotmail dot com
21年前
即使报头包含 Content-Type: 字段,如果仍然获取到 US-ASCII 的字符集,请确保报头也包含 MIME-Version: 字段。

例如,以下报头将正确报告字符集为 KOI8-R

MIME-Version: 1.0
Content-Type: text/plain; charset="koi8-r"

没有 MIME-Version 字段,则会报告为 US-ASCII。
jcastro at elnuevodia dot com
22年前
我认为上面关于附件的说明是错误的。我测试了发送带有和不带有附件的文件,得到以下结果:有附件:type=3 bytes=343648
无附件:type=0 bytes=2
所以检查 $struct->bytes == " " 没有任何意义。至少在我的测试中是这样。
运行环境:Windows 2000,PHP 4.2.1,使用 Outlook 和 Exchange。检查 type 看起来更可靠。
hholzgra at media-engineering dot de
24年前
各个部分对象在
结构上与 imap_fetchstructure 返回的对象相同,每个对象描述一个子文件夹

parameters 和 dparameters 是 MIME 特定的,它们包含
Content-Type 和 Content-Disposition 报头行中提供的额外参数,例如字符集或文件名。
To Top