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
2二進制ENCBINARY
3Base64ENCBASE64
4Quoted-PrintableENCQUOTEDPRINTABLE
5otherENCOTHER

變更日誌

版本 描述
8.1.0 imap 參數現在需要一個 IMAP\Connection 實例;先前,需要一個有效的 imap 資源

參見

新增註解

使用者貢獻的註解 12 則註解

50
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 等
}
}
?>
3
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 類別的方法...
2
php AT firstnetimpressions.com
22 年前
澄清要點

第七個主要內文類型不是文件中記載的「其他」,而實際上是「模型」。這包含 IGES、VRML、MESH、DWF 等。

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

「其他」是第八個主要內文類型。
2
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 本身的結構中提取資訊的基本知識,我希望它能幫助剛入門的人,因為它對我很有幫助 :/。
2
sirber at detritus dot qc dot ca
18 年前
「未知/未知」的「主要內文類型」將會是 int(9)。
1
masterbassist
19 年前
我認為以下行(在建立附件資訊時)

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

需要是

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

第一個版本在 PHP 5.0.3 下產生了 PHP 警告。第二個版本實際上會取得檔名。
2
phpnet,a,emailaddress,cjb,net
17 年前
另一個評論是為了告知人們一些應該在函數描述中的事情

imap_fetchstructure() 會下載整個電子郵件,包括附件和所有內容,而不僅僅是結構。
我猜這是一個未記錄的功能,而不是錯誤。

我原先以為腳本只會下載回傳的資料量,但我的腳本在被我注意到之前已經累積下載了 2.5 GB 的資料。希望其他人不會遇到這種情況。
1
hello at ivanbogomolov dot ru
5 年前
如果您的邏輯是基於比較結構字串,您必須進行不區分大小寫的比較。
<?php

$p
= imap_fetchstructure($this->_imap_resource, $mid);
//不要比較 $p->disposition == 'INLINE'
if(preg_match('/inline/i', $p->disposition))
{
//這個方法有效
}
?>
1
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
2
es96 at hotmail dot com
21 年前
如果您取得的 CHARSET 為 US-ASCII,即使標頭中有 Content-Type: 欄位,請確保標頭也有 MIME-Version: 欄位。

例如,以下標頭會正確回報 charset 為 KOI8-R

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

如果沒有 MIME-Version,則會回報為 US-ASII
2
jcastro at elnuevodia dot com
22 年前
我認為上面關於附件的注意事項是錯誤的。我測試了傳送有附件和沒有附件的檔案,我得到以下結果<br>
有附件:type=3 bytes=343648
無附件:type=0 bytes=2
因此檢查 $struct->bytes == " " 沒有意義。至少在我的測試中是這樣
使用 Windows 2000、PHP 4.2.1 和 Outlook 及 Exchange 執行。看起來檢查類型會更可靠
2
hholzgra at media-engineering dot de
24 年前
parts 物件在結構上是相同的
與 imap_fetchstructure 回傳的物件相同,每個物件描述一個子資料夾

parameters 和 dparameters 是 MIME 特有的,它們包含
Content-Type 和 Content-Disposion 標頭行中提供的額外參數,例如 Charset 或 Filename
To Top