The function imap_fetchbody() seems uncapable of getting subordinate parts of a message/rfc822-part. I had problems with getting an attachment that was forwarded in such a part, because the object given by imap_fetchstructure() would assume that the part was represented by the string "2.1.2.1.2".
So I wrote this set of functions which parses the raw message-body and creates an array with the struture corresponding to the structure given by imap_fetchstructure(). The function mail_fetchpart() (see below) will work on the array and return even those parts that I could not get with imap_fetchbody().
Example usage of this function: mail_fetchpart($mbox, 2, "2.1.2.1.2");
Note: If the message does not contain multiple pars, the body of the message can be accessed by the part-string "1".
I have more functions for parsing and decoding messages, just email me.
// get the body of a part of a message according to the
// string in $part
function mail_fetchpart($mbox, $msgNo, $part) {
$parts = mail_fetchparts($mbox, $msgNo);
$partNos = explode(".", $part);
$currentPart = $parts;
while(list ($key, $val) = each($partNos)) {
$currentPart = $currentPart[$val];
}
if ($currentPart != "") return $currentPart;
else return false;
}
// splits a message given in the body if it is
// a mulitpart mime message and returns the parts,
// if no parts are found, returns false
function mail_mimesplit($header, $body) {
$parts = array();
$PN_EREG_BOUNDARY = "Content-Type:(.*)boundary=\"([^\"]+)\"";
if (eregi ($PN_EREG_BOUNDARY, $header, $regs)) {
$boundary = $regs[2];
$delimiterReg = "([^\r\n]*)$boundary([^\r\n]*)";
if (eregi ($delimiterReg, $body, $results)) {
$delimiter = $results[0];
$parts = explode($delimiter, $body);
$parts = array_slice ($parts, 1, -1);
}
return $parts;
} else {
return false;
}
}
// returns an array with all parts that are
// subparts of the given part
// if no subparts are found, return the body of
// the current part
function mail_mimesub($part) {
$i = 1;
$headDelimiter = "\r\n\r\n";
$delLength = strlen($headDelimiter);
// get head & body of the current part
$endOfHead = strpos( $part, $headDelimiter);
$head = substr($part, 0, $endOfHead);
$body = substr($part, $endOfHead + $delLength, strlen($part));
// check whether it is a message according to rfc822
if (stristr($head, "Content-Type: message/rfc822")) {
$part = substr($part, $endOfHead + $delLength, strlen($part));
$returnParts[1] = mail_mimesub($part);
return $returnParts;
// if no message, get subparts and call function recursively
} elseif ($subParts = mail_mimesplit($head, $body)) {
// got more subparts
while (list ($key, $val) = each($subParts)) {
$returnParts[$i] = mail_mimesub($val);
$i++;
}
return $returnParts;
} else {
return $body;
}
}
// get an array with the bodies all parts of an email
// the structure of the array corresponds to the
// structure that is available with imap_fetchstructure
function mail_fetchparts($mbox, $msgNo) {
$parts = array();
$header = imap_fetchheader($mbox,$msgNo);
$body = imap_body($mbox,$msgNo, FT_INTERNAL);
$i = 1;
if ($newParts = mail_mimesplit($header, $body)) {
while (list ($key, $val) = each($newParts)) {
$parts[$i] = mail_mimesub($val);
$i++;
}
} else {
$parts[$i] = $body;
}
return $parts;
}