2010-09-07 14 views
2
#!/usr/bin/php -q 
    <?php 
    $savefile = "savehere.txt"; 
    $sf = fopen($savefile, 'a') or die("can't open file"); 
    ob_start(); 

    // read from stdin 
    $fd = fopen("php://stdin", "r"); 
    $email = ""; 
    while (!feof($fd)) { 
     $email .= fread($fd, 1024); 
    } 
    fclose($fd); 
    // handle email 
    $lines = explode("\n", $email); 

    // empty vars 
    $from = ""; 
    $subject = ""; 
    $headers = ""; 
    $message = ""; 
    $splittingheaders = true; 

    for ($i=0; $i < count($lines); $i++) { 
     if ($splittingheaders) { 
      // this is a header 
      $headers .= $lines[$i]."\n"; 

      // look out for special headers 
      if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) { 
       $subject = $matches[1]; 
      } 
      if (preg_match("/^From: (.*)/", $lines[$i], $matches)) { 
       $from = $matches[1]; 
      } 
      if (preg_match("/^To: (.*)/", $lines[$i], $matches)) { 
       $to = $matches[1]; 
      } 
     } else { 
      // not a header, but message 
      $message .= $lines[$i]."\n"; 




     } 

     if (trim($lines[$i])=="") { 
      // empty line, header section has ended 
      $splittingheaders = false; 
     } 
    } 
/*$headers is ONLY included in the result at the last section of my question here*/ 
    fwrite($sf,"$message"); 
    ob_end_clean(); 
    fclose($sf); 
    ?> 

Ceci est un exemple de ma tentative. Le problème est que je reçois trop dans le fichier. Voici ce qui est écrit dans le fichier: (Je viens d'envoyer un tas d'ordures à ce que vous pouvez voir)Comment obtenir uniquement le contenu textuel d'un e-mail en plusieurs parties?

From xxxxxxxxxxxxx Tue Sep 07 16:26:51 2010 
Received: from xxxxxxxxxxxxxxx ([xxxxxxxxxxx]:3184 helo=xxxxxxxxxxx) 
    by xxxxxxxxxxxxx with esmtpa (Exim 4.69) 
    (envelope-from <xxxxxxxxxxxxxxxx>) 
    id 1Ot4kj-000115-SP 
    for xxxxxxxxxxxxxxxxxxx; Tue, 07 Sep 2010 16:26:50 -0400 
Message-ID: <[email protected]> 
From: "xxxxxxxxxxxxx" <xxxxxxxxxxxxxx> 
To: <xxxxxxxxxxxxxxxxxxxxx> 
Subject: stackoverflow is helping me 
Date: Tue, 7 Sep 2010 16:26:46 -0400 
MIME-Version: 1.0 
Content-Type: multipart/alternative; 
    boundary="----=_NextPart_000_0169_01CB4EA9.773DF5E0" 
X-Priority: 3 
X-MSMail-Priority: Normal 
Importance: Normal 
X-Mailer: Microsoft Windows Live Mail 14.0.8089.726 
X-MIMEOLE: Produced By Microsoft MimeOLE V14.0.8089.726 

This is a multi-part message in MIME format. 

------=_NextPart_000_0169_01CB4EA9.773DF5E0 
Content-Type: text/plain; 
    charset="iso-8859-1" 
Content-Transfer-Encoding: quoted-printable 

111 
222 
333 
444 
------=_NextPart_000_0169_01CB4EA9.773DF5E0 
Content-Type: text/html; 
    charset="iso-8859-1" 
Content-Transfer-Encoding: quoted-printable 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML><HEAD> 
<META content=3Dtext/html;charset=3Diso-8859-1 = 
http-equiv=3DContent-Type> 
<META name=3DGENERATOR content=3D"MSHTML 8.00.6001.18939"></HEAD> 
<BODY style=3D"PADDING-LEFT: 10px; PADDING-RIGHT: 10px; PADDING-TOP: = 
15px"=20 
id=3DMailContainerBody leftMargin=3D0 topMargin=3D0 = 
CanvasTabStop=3D"true"=20 
name=3D"Compose message area"> 
<DIV><FONT face=3DCalibri>111</FONT></DIV> 
<DIV><FONT face=3DCalibri>222</FONT></DIV> 
<DIV><FONT face=3DCalibri>333</FONT></DIV> 
<DIV><FONT face=3DCalibri>444</FONT></DIV></BODY></HTML> 

------=_NextPart_000_0169_01CB4EA9.773DF5E0-- 

Je trouve cela tout autour de la recherche, mais ont aucune idée de la façon de mettre en œuvre ou où insérer dans mon code ou si cela fonctionnerait. Alors, comment puis-je obtenir juste la zone de texte brut de l'e-mail dans mon fichier ou script pour la gestion furthr ??

Merci d'avance. stackoverflow est génial!

+0

Est-ce que le plein email? Il manque l'en-tête 'Content-Type: multipart/mixed', qui devrait spécifier quelle est la chaîne de frontière (dont le code a besoin). –

+0

C'est juste la partie de l'e-mail qui est enregistrée dans le fichier. C'est aussi dépouillé que je pourrais l'obtenir en utilisant le premier exemple de code. – Jimbo

+0

L'en-tête de limite est important pour être en mesure d'analyser votre email car il spécifie où chaque * partie * de l'email commence et se termine. Sans cela, tout ce que vous pouvez faire est de deviner, et vous savez ce qu'ils disent de supposer ...;) Par exemple, pour votre email cité, il devrait y avoir un en-tête comme: 'Content-Type: multipart/mixed; boundary = "---- = _ NextPart_000_0163_01CB4EA5.46466520" ' –

Répondre

12

Il y a quatre étapes que vous devrez prendre afin d'isoler la partie de texte brut de votre corps e-mail:

1. Obtenir la chaîne de limite MIME

Nous pouvons utiliser une expression régulière pour rechercher vos en-têtes (supposons qu'ils sont dans une variable séparée, $headers):

$matches = array(); 
preg_match('#Content-Type: multipart\/[^;]+;\s*boundary="([^"]+)"#i', $headers, $matches); 
list(, $boundary) = $matches; 

l'expression régulière recherchera l'en-tête Content-Type que c contient la chaîne de délimitation, puis la capture dans le premier capture group. Nous copions ensuite ce groupe de capture dans la variable $boundary.

2. Séparez le corps de l'email en segments

Une fois que nous avons la frontière, nous pouvons diviser le corps dans ses différentes parties (dans votre corps de message, le corps sera préfacé par -- chaque fois qu'il apparaît). Selon le MIME spec, tout ce qui précède la première limite doit être ignoré. Cela nous laissera avec un tableau contenant tous les segments, avec tout ce qui précède la première limite ignorée.

3. Déterminez quel segment est en texte brut.

Le segment en texte brut aura un en-tête Content-Type avec le type MIME text/plain. Nous pouvons maintenant rechercher chaque segment pour le premier segment avec cet en-tête:

foreach ($email_segments as $segment) 
{ 
    if (stristr($segment, "Content-Type: text/plain") !== false) 
    { 
    // We found the segment we're looking for! 
    } 
} 

Depuis ce que nous cherchons est une constante, on peut utiliser stristr (qui trouve la première instance d'une sous-chaîne dans une chaîne, le cas insensiblement) au lieu d'une expression régulière. Si l'en-tête Content-Type est trouvé, nous avons notre segment.

4. Retirez tous les en-têtes du segment

Maintenant, nous devons supprimer tous les en-têtes du segment que nous avons trouvé, comme nous voulons que le contenu réel du message.Il y a quatre MIME headers qui peuvent apparaître ici: Content-Type comme nous l'avons vu précédemment, Content-ID, Content-Disposition et Content-Transfer-Encoding. En-têtes sont terminées par \r\n afin que nous puissions utiliser pour déterminer la fin des en-têtes:

$text = preg_replace('/Content-(Type|ID|Disposition|Transfer-Encoding):.*?\r\n/is', "", $segment); 

Le smodifier à la fin de l'expression régulière rend le match de point des nouvelles lignes. .*? collectera le moins de caractères possible (c'est-à-dire jusqu'à \r\n); le ? est un lazy modifier sur .*.

Et après ce point, $text contiendra le contenu de votre message.

Donc, pour mettre tout cela ensemble avec votre code:

<?php 
// read from stdin 
$fd = fopen("php://stdin", "r"); 
$email = ""; 
while (!feof($fd)) 
{ 
    $email .= fread($fd, 1024); 
} 
fclose($fd); 

$matches = array(); 
preg_match('#Content-Type: multipart\/[^;]+;\s*boundary="([^"]+)"#i', $email, $matches); 
list(, $boundary) = $matches; 

$text = ""; 
if (isset($boundary) && !empty($boundary)) // did we find a boundary? 
{ 
    $email_segments = explode('--' . $boundary, $email); 

    foreach ($email_segments as $segment) 
    { 
    if (stristr($segment, "Content-Type: text/plain") !== false) 
    { 
     $text = trim(preg_replace('/Content-(Type|ID|Disposition|Transfer-Encoding):.*?\r\n/is', "", $segment)); 
     break; 
    } 
    } 
} 

// At this point, $text will either contain your plain text body, 
// or be an empty string if a plain text body couldn't be found. 

$savefile = "savehere.txt"; 
$sf = fopen($savefile, 'a') or die("can't open file"); 
fwrite($sf, $text); 
fclose($sf); 
?> 
+0

Je commence à comprendre, je pense .. Donc, pour tester, est-ce que je remplacerais tout après // les vars vides ??? – Jimbo

+0

Pas exactement. Cela dépend de ce que vous voulez faire (par exemple, vous pouvez continuer à fractionner les en-têtes ou à collecter les en-têtes "spéciaux"). Mon code s'attend à ce que vous ayez un bloc de texte pour les en-têtes et un pour le message, mais vous pouvez simplement remplacer '$ headers' et' $ message' dans mon code par '$ email' qui, selon votre code, devrait contenir le email entier. –

+0

AAAH, je ne comprends pas! Comment puis-je implémenter ceci dans mon exemple de code ci-dessus, donc je peux le tester? Est-ce que je mettrais votre extrait avant de classer le fichier? Puis écrivez $ text au lieu de $ message? J'apprécie vraiment votre aide et PATIENCE avec ce débutant ici. – Jimbo

0

Il y a une réponse here:

Vous devez seulement changer ces 2 lignes:

require_once('/path/to/class/rfc822_addresses.php'); 
require_once('/path/to/class/mime_parser.php'); 
+0

Votre lien est 404. –