Задать вопрос
imater
@imater

Как разобрать это вложенное письмо на PHP и сохранить вложенные туда файлы?

В моём скрипте при помощи Zend mail, парсится письмо в котором вложено письмо в формате «message/rfc822».



Как разобрать это вложенное письмо на PHP и сохранить вложенные файлы в указанное место?



Мой скрипт (проблемное место отмечено фразой «УМА НЕ ПРИЛОЖУ, КАК ПАРСИТЬ ЭТО СООБЩЕНИЕ И РАЗОБРАТЬ ЕГО ВЛОЖЕНИЯ»):

ini_set('memory_limit', '-1');<br>
require_once('Zend/Mail/Storage/Pop3.php');<br><br>
$mail = new Zend_Mail_Storage_Pop3(array('host' => 'mail.42tree.ru',<br>
										 'user'=> '4tree@42tree.ru',<br>
										 'password' => '***'));<br><br>
echo $mail->countMessages() . " messages found<br>";<br><br>
$i=1;<br>
$s=1;<br><br>
$message = $mail[$_GET['id']]; // id = указан в адресной строке, это номер письма<br><br>
$title = decode_mime_string( $message->subject ); // заголовок<br><br>
echo "title = ".$title."<br>";<br><br>
$part = $message;<br><br>
function transformHTML($str) { //украшаем HTML формат.<br>
   if ((strpos($str,"<HTML") < 0) || (strpos($str,"<html")    < 0)) {<br>
  		$makeHeader = "<html><head><meta http-equiv=\"Content-Type\"    content=\"text/html; charset=iso-8859-1\"></head>\n";<br>
   	if ((strpos($str,"<BODY") < 0) || (strpos($str,"<body")    < 0)) {<br>
   		$makeBody = "\n<body>\n";<br>
   		$str = $makeHeader . $makeBody . $str ."\n</body></html>";<br>
   	} else {<br>
   		$str = $makeHeader . $str ."\n</html>";<br>
   	}<br>
   } else {<br>
   	$str = "<meta http-equiv=\"Content-Type\" content=\"text/html;    charset=iso-8859-1\">\n". $str;<br>
   }<br>
   	return $str;<br>
 }<br><br><br>
function txt_to_html($dataTxt)  //превращаем текстовый формат в html для отображения<br>
{<br>
   $msgBody = ereg_replace("\n","<br>",$dataTxt);<br>
   $msgBody = preg_replace("/([^\w\/])(www\.[a-z0-9\-]+\.[a-z0-9\-]+)/i","$1http://$2",    $msgBody);<br>
   $msgBody = preg_replace("/([\w]+:\/\/[\w-?&;#~=\.\/\@]+[\w\/])/i","<A    TARGET=\"_blank\" HREF=\"$1\">$1</A>", $msgBody);<br>
   $msgBody = preg_replace("/([\w-?&;#~=\.\/]+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?))/i","<A    HREF=\"mailto:$1\">$1</A>",$msgBody);<br>
   return $msgBody;<br>
}<br><br>
function DisplayMessage($part) //главная функция которая отображает<br>
{<br>
$answer = "";<br>
	echo $part->contentType."<br>";<br>
	$type = explode(";",$part->contentType);<br><br>
	if($type[0]=="message/rfc822")<br>
		{<br>
		/*<br>
                <b>УМА НЕ ПРИЛОЖУ, КАК ПАРСИТЬ ЭТО СООБЩЕНИЕ И РАЗОБРАТЬ ЕГО ВЛОЖЕНИЯ</b><br>
                */<br>
		}<br><br>
	if($type[0]=="text/html") <br>
		{<br>
		$answer = ( decode_mime_string( base64_decode($part->getContent()) ) );<br>
//	    if(eregi("KOI8", $type[1]) OR true ) { $answer = iconv('KOI8-R', 'UTF-8', $answer); }<br>
//	    $answer = transformHTML($answer);<br>
		$answer = quoted_printable_decode ( decode_mime_string( ($part->getContent()) ) );<br>
	    if(eregi("KOI8", $type[1]) ) { $answer = iconv('KOI8-R', 'UTF-8', $answer); }<br>
		}<br><br>
	if($type[0]=="text/plain") <br>
		{<br>
		//base64_decode<br>
		$answer = txt_to_html( quoted_printable_decode( decode_mime_string( ($part->getContent()) ) ) );<br>
	    if(eregi("koi8", $type[1]) ) { $answer = iconv('KOI8-R', 'UTF-8', $answer); }<br>
	    if(eregi("windows-1251", $type[1])) { $answer = iconv('windows-1251', 'UTF-8', $answer); }<br>
		}<br><br>
	if( ($type[0]=="image/jpeg") || ($type[0]=="image/png") )<br>
		{<br>
		  $typename = $type[1];<br>
		  $typename = decode_mime_string( $typename );<br>
		  $filename = trim(ereg_replace('name=|"','',$typename));<br>
		  $file = "upload/".$filename;<br>
		  $content = base64_decode($part->getContent());<br>
		  file_put_contents($file,$content);<br>
		  $answer = "<br><img src='../mail/".$file."'><br>".$filename."<hr>";<br>
		}<br><br>
	if( in_array($type[0],array("application/msword","application/pdf","application/octet-stream")) )<br>
		{<br>
		  $typename = $type[1];<br>
		  $typename = decode_mime_string( $typename );<br>
		  $filename = trim(ereg_replace('name=|"','',$typename));<br>
		  $file = "upload/".$filename;<br>
		  $content = base64_decode($part->getContent());<br>
		  file_put_contents($file,$content);<br>
		  $answer = "<br><a href='../mail/".$file."'>".$filename."</a>";<br>
		}<br><br><br>
	return $answer."<br>";<br>
}<br><br>
$j=1;<br><br>
$counts = $message->countParts();<br>
echo $message->contentType."<hr>";<br><br>
for($ii=1; $ii<=$counts; $ii++) //перебираем все вложения одного письма<br>
	{<br>
	echo $ii."<br>";<br>
	$part = $message->getPart($ii);<br>
	if($part->isMultipart())  //если вложение тоже имеет вложения, парсим внутри<br>
		{<br>
		for($jj=1; $jj<=$part->countParts(); $jj++)<br>
			{<br>
			$part2 = $part->getPart($jj);<br>
				if($part2->isMultipart())  //обрабатываем третий уровень вложенности, возможно это бесполезно<br>
					{<br>
					for($jk=1; $jk<=$part2->countParts(); $jk++)<br>
						{<br>
						$part3 = $part2->getPart($jk);<br>
						echo DisplayMessage($part3);<br>
						}<br>
					}<br>
			echo DisplayMessage($part2);<br>
			}<br>
		}<br>
//	if($ii=3) print_r($part->countParts());<br>
	echo DisplayMessage($part);<br>
	}<br><br>
  • Вопрос задан
  • 3661 просмотр
Подписаться 2 Оценить Комментировать
Решения вопроса 1
imater
@imater Автор вопроса
Спасибо fort93t, решение:
Заставить ZF распарсить строку можно вот так:
$message = new Zend_Mail_Message(array(
    'raw' => $messageAsString,
));


Отлично работает! +1
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
merlin-vrn
@merlin-vrn
Это email-сообщение, вложенное как приложение в email-сообщение. Например, когда что-то пересылаешь «как вложение», это вложение получается вот такого типа.

Если я правильно понял документацию, в Zend есть некий RecursiveIterator, который должен, обходя дерево MIME, вызвать ваш код для каждой части, в том числе и зайти рекурсивно в это вложенное сообщение и обработать его. Данные могут содержаться в текстовой части или во вложениях этого вложенного сообщения.

Раз уж вы пытаетесь разбирать почтовые сообщения, то для вас обязательно прочитать и понять этот самый RFC 822 (неожиданно, правда?) а лучше — современную инкарнацию этого стандарта, RFC 5322, там детально описан формат. Даже несмотря на то, что за вас разбор по идее должен делать Zend, нужно понимать, что именно он делает.

Вкратце формат у email-сообщения такой: сначала заголовки (Content-Type, Subject, From, To, ...), разделённые \r\n, потом после \r\n\rn (пустая строка) идёт тело сообщения, которое может состоять из текстового блока, и если сообщение имеет MIME-тип multipart/*, то дальше идут уже вложения, разделённые указанной в Content-Type строкой; структура рекурсивная, то есть каждое вложение выглядит так же точно как сообщение — заголовки и тело, которое может так же состоять из частей.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы