Newsgroup: it.comp.www.php
Titolo: script per il parsing di un messaggio mime

dove si puo trovare uno script (o le istruzioni)
per ottenere il parsing di un e-mail:
arriva un messaggio di posta
lo salvo sul server (nello stato in cui si trova .eml che e' standard)
poi lo devo visualizzare, IMAP non va bene
le immagini nel testo(html) devono essere visibili
il messaggio diventa una pagina web con le immagini al suo posto,
gli attachment devono essere scaricabili
______
|  []   ... |  immagine
|   ......   |
|......      |
|______|
- - - - - lista allagati

 lo salvo sul server (nello stato in cui si trova .eml che e' standard)
standard? in che senso?
--
~omar

 ~omar

 hai un esempio se no non so cosa farmene,
Ti faccio un esempio *agricolo* per farti capire il meccanismo, la 
documentazione presente nella home del progetto e' molto piu' 
dettagliata e parla anche degli allegati.
#-----------------------------------
require_once 'Mail/mimeDecode.php';
$params = array(
                         include_bodies  => 'true',
                         decode_bodies   => 'true',
                         decode_headers  => 'true',
);
$stdin = implode("", file("php://stdin"));
$decoder = new Mail_mimeDecode($stdin);
$struttura = $decoder->decode($params);
$mittente = $struttura->headers[from];
$destinatario = $struttura->headers[to];
$oggetto = $struttura->headers[subject];
$corpo = $struttura->body;
#-----------------------------------
Ho utilizzato
$stdin = implode("", file("php://stdin"));
perche' in questo caso analizzo la mail appena il server pop3 la riceve;
qmail ad esempio, alla ricezione della mail, la puo' inviare al volo in 
STDOUT ad uno script che vuoi... in questo caso uno in PHP che analizza 
il messaggio e si comporta di conseguenza.
--
~omar

 >>
http://pear.php.net/package/Mail_Mime
ho trovato questa classe, e un po modificata perche dava errori ma non so se
ho corretto bene
<?
#################################################
# Class DecodeMessage: Mime message decoder
# by AKAN NKWEINI
# 
ak...@p3mail.com
# 
http://www.p3mail.com
#################################################
class DecodeMessage{
 var $header;
 var $fullmessage;
 var $auto_decode = true;
 var $attachment_path = "attachments";
 var $choose_best = true;
 var $best_format = "text/html";
 function InitHeaderAndBody($header, $body) {
  $this->header = $header;
  $this->body = $body;
  $this->fullmessage = chop($header)."\t\n\t\n".ltrim($body);
 }
 function Body() {
  return trim($this->body);
 }
 function InitMessage($msg) {
  $i = 0;
  $m = "";
  $messagebody = "";
  $line = explode("\n",trim($msg));
  for ($j=0;$j<count($line);$j++)
   if (chop($line[$j]) == ""  AND $i < 1) :
    $this->header = $m;
    $i++;
   endif;
   if ($i > 0)
    $messagebody .= $line[$j]."\n";
   $m .= $line[$j]."\n";
  }
  $this->body = $messagebody;
  $this->fullmessage = $msg;
 }
 function Headers($field="") {
  if ($field == "") :
   return $this->header;
  else :
   $hd = "";
   $field = $field.":";
   $start = 0;
   $j=0;
   $header = eregi_replace("\r", "\n", $this->header);
   $p = explode("\n", $header);
   do {
    for ($i=$start;$i<count($p)-1;$i++) {
     if (ereg("^($field)", $p[$i]))  :
        $position = $i;
        $hd .= ereg_replace("$field", "",$p[$i]);
        break;
       endif;
    }
    if (ereg("^($field)", $p[$i]))  :
     for ($i=$position+1;$i<count($p)-2;$i++) {
      $tok = strtok($p[$i], " ");
      if (ereg(":$", $tok) AND (!(eregi("^($field)", $tok))))
       break;
      $hd .= ereg_replace("$field", "",$p[$i]);
     }
     $start=$i+1;
    endif;
   } while ($j++ < count($p));
  return $hd;
  endif;
 }
 function ContentType() {
  $c = $this->Headers("Content-Type");
  $ct = ereg_replace("[[:space:]]", "", $c);
  if (!(ereg(";", $ct))) :
   $content["type"] = trim($ct);
  else :
   $p = explode (";", $ct);
   for ($i=0;$i<count($p);$i++) {
    if (eregi("^(text)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(multipart)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(application)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(message)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(image)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(audio)", $p[$i])) :
     $content["type"] = $p[$i];
    elseif (eregi("^(charset)", $p[$i])) :
     $content["charset"] = eregi_replace("(charset=)|(\")", "", $p[$i]);
    elseif (eregi("^(report-type)", $p[$i])) :
     $content["report-type"] = eregi_replace("(report-type=)|(\")", "",
$p[$i]);
    elseif (eregi("^(type)", $p[$i])) :
     $content["subtype"] = eregi_replace("(type=)|(\")", "", $p[$i]);
    elseif (eregi("^(boundary)", $p[$i])) :
     $content["boundary"] = eregi_replace("(boundary=)|(\")", "", $p[$i]);
    elseif (eregi("^(name)", $p[$i])) :
     $content["name"] = eregi_replace("(name=)|(\")", "", $p[$i]);
    elseif (eregi("^(access-type)", $p[$i])) :
     $content["access-type"] = eregi_replace("(access-type=)|(\")", "",
$p[$i]);
    elseif (eregi("^(site)", $p[$i])) :
     $content["site"] = eregi_replace("(site=)|(\")", "", $p[$i]);
    elseif (eregi("^(directory)", $p[$i])) :
     $content["directory"] = eregi_replace("(directory=)|(\")", "", $p[$i]);
    elseif (eregi("^(mode)", $p[$i])) :
     $content["mode"] = eregi_replace("(mode=)|(\")", "", $p[$i]);
    endif;
   }
  endif;
  return $content;
 }
 function ContentDisposition() {
  $c = $this->Headers("Content-Disposition");
  $c = ereg_replace("[[:space:]]", "", $c);
  if (!(ereg(";", $c))) :
   $cd["type"] = $c;
  else :
   $p = explode(";", $c);
   for ($i=0;$i<count($p);$i++) {
    if (eregi("^(inline)", $p[$i])) :
     $cd["type"] = $p[$i];
    elseif (eregi("^(attachment)", $p[$i])) :
     $cd["type"] = $p[$i];
    elseif(eregi("^(filename)", $p[$i])) :
     $cd["filename"] = eregi_replace("(filename=)|(\")", "", $p[$i]);
    endif;
   }
  endif;
  return $cd;
 }
 function my_array_shift(&$array) {
  reset($array);
  $key = key($array);
  $val = current($array);
  unset($array[$key]);
  return $val;
 }
 function my_array_compact(&$array) {
  while (list($key, $val) = each($array)) :
      if (chop($val) == '')
       unset($array[$key]);
  endwhile;
 }
  function my_in_array($value, $array) {
  while (list($key, $val) = each($array)) :
      if (strcmp($value, $val) == 0)
       return true;
  endwhile;
  return false;
 }
  function Result() {
  $is_multipart_alternative = false;
  $is_multipart_related = false;
  $found_best = false;
  do {
   $next_message = "";
   do {
    $next_multipart = "";
    $content = $this->ContentType();
    $cd = $this->ContentDisposition();
    if ( eregi("^(multipart)", $content["type"]) ) :
     if ( eregi("multipart/alternative", $content["type"]) ) :
      $is_multipart_alternative = true;
     endif;
     if ( eregi("multipart/related", $content["type"]) ) :
      $is_multipart_related = true;
     endif;
     $boundary = "--".$content["boundary"];
     $p = explode($boundary, $this->body);
     for ($i=0;$i<count($p);$i++) {
      $this->InitMessage($p[$i]);
      $content = $this->ContentType();
      $this->ContentDisposition();
      if ($is_multipart_related AND (chop($this->Headers("Content-ID")) !=
'')) :
       $cont["id"] = ereg_replace("[<>]","", $this->Headers("Content-ID"));
       $cont["name"] = $content["name"];
       $contentid[] = $cont;
       unset($cont);
      endif;
      if (eregi("multipart", $content["type"])) :
       $multiparts[] = $p[$i];
      elseif (eregi("message", $content["type"])) :
       $messages[] = $p[$i];
      elseif ($this->choose_best AND eregi("text/plain", $content["type"])
AND $is_multipart_alternative  AND empty($found_best)) :
       $best = $p[$i];
      elseif ($this->choose_best AND eregi($this->best_format,
$content["type"]) AND $is_multipart_alternative ) :
       if (eregi("[[:alpha:]]", chop($p[$i]))) :
        $best = $p[$i];
        $found_best = true;
       endif;
      elseif (chop($content["type"]) != '' AND chop($this->body) !='') :
       $parts[] = $p[$i];
      endif;
file://echo
"<pre>($i)###".htmlspecialchars($this->header)."</pre>--###<hr>";
     }
          if (!empty($best) != '') :
        $parts[] = $best;
     endif;
    else :
     if (eregi("(message)", $content["type"])) :
      $messages[] = $this->fullmessage;
     elseif (chop($this->body) != '') :
      $parts[] = $this->fullmessage;
     endif;
    endif;
    unset($is_multipart_alternative);
    unset($best);
    unset($found_best);
    if (count($multiparts) > 0) :
     $next_multipart = $this->my_array_shift($multiparts);
     $this->InitMessage($next_multipart);
    endif;
   } while ($next_multipart != "");
        if (!empty($parts)) :
     for ($iy=0;$iy<count($parts);$iy++) {;
       $this->InitMessage($parts[$iy]);
      $ct = $this->ContentType();
      $cd = $this->ContentDisposition();
      if (eregi("text/html", $ct["type"]) AND count($contentid > 0)) :
       for ($k=0;$k<count($contentid);$k++) {
        $filelocation = $this->attachment_path."/".$contentid[$k]["name"];
        $cid = $contentid[$k]["id"];
        $cid = ereg_replace("[[:space:]]", "", $cid);
        $this->body = str_replace("cid:", "", $this->body);
        $this->body = str_replace($cid, $filelocation, $this->body);
       }
      endif;
      if ($this->auto_decode
       AND eregi("attachment", $cd["type"])
       OR eregi("base64", $this->Headers("Content-Transfer-Encoding"))
       ) :
        $filename = chop($ct["name"]) ? $ct["name"] : $cd["filename"];
        if (eregi("base64", $this->Headers("Content-Transfer-Encoding"))) :
         $file = base64_decode($this->body);
        elseif (eregi("quoted-printable",
$this->Headers("Content-Transfer-Encoding"))) :
         $file = quoted_printable_decode($this->body);
         $file = ereg_replace("(=\n)", "", $this->body);
         $file = $this->body;
        elseif (eregi("7bit", $this->Headers("Content-Transfer-Encoding")))
:
         $file = $this->body;
        endif;
        $filepath = $this->attachment_path."/".$filename;
        @unlink($filepath);
        if (chop($filename != '')) :
         $fp = @fopen($filepath, "a") OR die("Cannot open file
\"$filepath\"");
         fwrite($fp, $file);
         fclose($fp);
         if (eregi("attachment", $cd["type"]) OR eregi("inline",
$cd["type"])) :
echo "\n<p><a href=\"$filepath\">$filename</a><p>";
$np = "\n<p><a href=\"$filepath\">$filename</a><p>";
          $decoded_part["attachments"] = $filename;
         endif;
        endif;
      endif;
      if (eregi("^(text)", $ct["type"] )
          AND !(eregi("text/html", $ct["type"] ))
          AND !(eregi("attachment", $cd["type"] ))
          OR (chop($ct["type"]) == "")
         ) :
       $decoded_part["body"]["type"] = $ct["type"];
       $decoded_part["body"]["body"] = $this->body;
      elseif (eregi("text/html", $ct["type"] ) AND !(eregi("attachment",
$cd["type"] ))) :
       $decoded_part["body"]["type"] = $ct["type"];
       $decoded_part["body"]["body"] = $this->body;
file://echo "<pre>()###".htmlspecialchars($ct["type"])."</pre>--###<hr>";
      endif;
        if(!empty($decoded_part)){
       $dp[] = $decoded_part;
        unset($decoded_part);   }
     }
    endif;
     $message[] = $dp;
    unset($dp);
    unset($is_multpart_related);
    unset($contentid);
    unset($parts);
      /* if (count($messages) > 0) :
     $this->my_array_compact($messages);
     $next_message = $this->my_array_shift($messages);
     $this->InitMessage($next_message);
     $this->InitMessage($this->body);
    endif; */
    } while ($next_message != "");
    return $message;
 }
};
?>
<?
// script di prova
include("mimedecode.php");
$buffer = file_get_contents("read.eml"); // Mail Content from pipe or
whatever
$msg = new DecodeMessage();
$msg->InitMessage($buffer);
$msg->Headers();
/* echo $fu = $msg->latte();
         var_dump($fu);   */
$file = $msg->Result();
$body = $msg->body();
                /*
          $cercato = array("3D","3D2","=20");
          $sostituito = array("","","");
           $file[0][2]["body"]["body"] = str_replace($cercato, $sostituito,
$body); */
      $input = preg_replace("/=\r?\n/", '', $body);
        // Replace encoded characters
  $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
         // var_dump($file);
          ?><textarea rows="5" cols="60" ><?= $body; ?></textarea>
<?= $input; ?>

Io mi ero scritto qualcosina, molto semplice, che mi serve per
un'applicazione del genere (client newsgroup)
Tratta anche i files uuencodati nel testo (uuencode e uudecode sono
funzioni di php5 ma puoi usare il phpcompat per usarle con il 4)
questo e' un esempio di messaggio con allegato (uuencodato):
http://www.3bsoft.com/newsgroup_article-200-7.html
http://www.3bsoft.com/modules.php?name=NewsGroups&file=article&grp_id=7&id_article=200&fmt=raw
e questo un messaggio con immagine:
http://www.3bsoft.com/newsgroup_article-162-7.html
http://www.3bsoft.com/modules.php?name=NewsGroups&file=article&grp_id=7&id_article=162&fmt=raw
function parseMimePart(&$part) {
    if (ereg("Content-Type\: ([^\n]*)\n(.*)", $part, $arr)) {
        // ci puo' essere anche il charset ed altre info, devo
splittare sul ";"
        $ctypes = explode(";", $arr[1]);
        $ctype = $ctypes[0];
        // togliere l'eventuale ";" in fondo
        $part = $arr[2];
    }
	if ($ctype=="multipart/alternative" || $ctype=="multipart/related") {
	    // devo ulteriormente suddividere
	    if (ereg("boundary=\"([^\n]*)\"\n", $part, $marker)) {
			 $subpart = explode(trim($marker[1]), $part);
             // quando faccio explode mi separa anche la parte
boundary="...
             // per cui la prima parte del messaggio e' in subpart[2]
			 $part = $subpart[2];
             // di questa sottoparte va reanalizzato il content type
			 if (ereg("Content-Type\: ([^\n]*)\n(.*)", $part, $arr)) {
				// ci puo' essere anche il charset ed altre info, devo splittare
sul ";"
				$ctypes = explode(";", $arr[1]);
				$ctype = $ctypes[0];
				// togliere l'eventuale ";" in fondo
				$part = $arr[2];
			 }
	    }
	};
    if (ereg("charset\=\"([^\n]*)\"\n(.*)", $part, $arr)) {
        $charset = $arr[1];
        $part = $arr[2];
    }
	if (ereg("Content-Transfer-Encoding\: ([^\n]*)\n(.*)", $part, $arr)) {
 	    $cTransferEncoding = $arr[1];
	    $part = $arr[2];
    }
	if (ereg("Content-Disposition: attachment;
filename=\"([^\"]*)\"\n(.*)", $part, $arr)) {
		$filename = $arr[1];
		$part = $arr[2];
	}
	switch (strtolower($cTransferEncoding)) {
            case '7bit':
                break;
            case 'quoted-printable':
                // Remove soft line breaks
				$part = preg_replace("/=\r?\n/", '', $part);
				// Replace encoded characters
				$part = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))",
$part);
				// wrap delle linee
				//$part=textwrap($part,80,"\n");
                break;
            case 'base64':
                $part = base64_decode($part);
                break;
            default:
                // nessuna modifica
	}
	if ($ctype=="text/plain") {
        $part = htmlentities($part);
	} else if ($ctype=="text/html") {
        $part = strip_tags($part);
	}
}
function getBody($compressedBody) {
    global $grp_id, $id_article, $fmt;
    $a_body = gzuncompress($compressedBody);
    $links = "";
	// trattamento messaggi formati da piu' parti
	// non sempre esiste la stringa iniziale, "This is a ..."
	// puo' anche cominciare direttamente con il marker, es:
	// 
http://www.3bsoft.com/newsgroup_article-4656-3.html
	if (ereg("^This is a multi-part message in MIME
format\.\n[\n]{0,1}([^\n]*)\r?\nContent-Type\:", $a_body, $marker)
	    || ereg("^\n?([^\n]*)\r?\nContent-Type\:",$a_body, $marker)) {
	   $parti = explode(trim($marker[1]), $a_body);
	   $a_body = $parti[1];
	   parseMimePart($a_body);
       $a_body = html_entity_decode($a_body);
	   for ($p=2; $p<count($parti); $p++) {
		   if (ereg("Content-Disposition: attachment; filename=\"([^\"]*)\"",
$parti[$p], $arr)
		      || ereg("Content-Disposition: attachment; filename=([^ \n]*)",
$parti[$p], $arr)) {
                   if (eregi(".jpg", $arr[1]) || eregi(".gif",
$arr[1])) {
                        // immagine
			            $links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Zoom $arr[1]\"> <img
src=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]&maxwidth=640\"
border=\"0\" alt=\"attach\"></a>";
                   } else  {
                        // file da scaricare
			            $links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Download $arr[1]\"><img
src=\"modules/NewsGroups/images/attach.gif\" border=\"0\">$arr[1]</a>";
                   }
	       }
	   }
       $a_body = htmlentities(wordwrap($a_body,78,"\n"))."\n".$links;
	} else {
       // riduco subito la dimensione di a_body tagliando il reale
contenuto del file,
       // altrimenti ereg e' troppo lenta
	   $a_body = ereg_replace("(begin [0-7]{3}
[^\r\n]+\r?\n).+(`\r?\nend\r?\n)","\\1<uuencoded file>\n\\2", $a_body);
       // estraggo tuti i files...
       if (ereg("begin [0-7]{3}
([^\r\n]+)\n.+\r?\n`\r?\nend\n(.+)",$a_body, $arr)) {
			   if (eregi(".jpg", $arr[1]) || eregi(".gif", $arr[1])) {
                    // immagine
		            $links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Zoom $arr[1]\"> <img
src=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]&maxwidth=640\"
border=\"0\" alt=\"attach\"></a>";
               } else  {
                    // file da scaricare
		            $links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Download $arr[1]\"><img
src=\"modules/NewsGroups/images/attach.gif\" border=\"0\">$arr[1]</a>";
               }
 			   while (ereg("begin [0-7]{3}
([^\r\n]+)\n.+\r?\n`\r?\nend\n(.+)",$arr[2],$arr)) {
					   if (eregi(".jpg", $arr[1]) || eregi(".gif", $arr[1])) {
							// immagine
							$links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Zoom $arr[1]\"> <img
src=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]&maxwidth=640\"
border=\"0\" alt=\"attach\"></a>";
					   } else  {
							// file da scaricare
							$links .= "<hr><a
href=\"modules.php?name=NewsGroups&file=article&grp_id=$grp_id&id_article=$id_article&getfile=$arr[1]\"
target=\"$arr[1]\" title=\"Download $arr[1]\"><img
src=\"modules/NewsGroups/images/attach.gif\" border=\"0\">$arr[1]</a>";
					   }
               }
	   }
	   $a_body = ereg_replace("begin [0-7]{3}
[^\r\n]+\r?\n.+`\r?\nend\r?\n","", $a_body);
       $a_body = htmlentities(wordwrap($a_body,78,"\n"))."\n".$links;
	}
    return $a_body;
}
function getFileInBody($compressedBody, $filename) {
    global $grp_id, $id_article;
    $a_body = gzuncompress($compressedBody);
	// trattamento messaggi formati da piu' parti
	if (ereg("^This is a multi-part message in MIME
format\.\n[\n]{0,1}([^\n]*)\r?\nContent-Type\:", $a_body, $marker)
		|| ereg("^\n?([^\n]*)\r?\nContent-Type\:",$a_body, $marker)) {
	   $parti = explode($marker[1], $a_body);
	   // dovrei aggiungere a part i vari files allegati con un (Removed
file ...)
	   for ($p=2; $p<count($parti); $p++) {
		   if (ereg("Content-Disposition: attachment; filename=\"([^\"]*)\"",
$parti[$p], $arr)
		      || ereg("Content-Disposition: attachment; filename=([^ \n]*)",
$parti[$p], $arr)) {
               if ($arr[1]==$filename) {
                    $a_body = $parti[$p];
 			        parseMimePart($a_body);
			   }
	       }
	   }
	} else {
	   // file allegato, da rimuovere
	   //begin [0-7]{3} ([^\r\n]+)\r?\n.+`\r?\nend\r?\n
	   if (ereg("begin [0-7]{3} $filename\n(.+)\r?\n`\r?\nend\n",$a_body,
$arr)) {
	       $a_body = uudecode($arr[1]);
	   }
	}
    return $a_body;
}

    file://begin [0-7]{3} ([^\r\n]+)\r?\n.+`\r?\nend\r?\n


Devi prima identificare il marker e quindi creare l'array con un
explode() (vedi il codice che ho postato); il primo elemento dell'array
lo passi a parseMimePart() per ottenere il testo, i successivi
identifichi che tipo sono e se sono allegati richiami ancora
parseMimePart() per farti restituire il file binario ... e' tutto nel
codice che ho postato e come puoi vedere dai link funziona piuttosto
bene
... Comunque prima o poi finiro' per rilasciare tutto il pacchetto per
gestione newsgroups in phpnuke ...