2010-09-07 6 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); 
    ?> 

Это пример моей попытки. Проблема в том, что я слишком много в файле. Вот что записывается в файл: (я просто послал кучу мусора в нем, как вы можете видеть)Как получить текстовый контент из многостраничного письма?

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-- 

Я нашел во время поиска вокруг, но не имеют ни малейшего представления о том, как реализовать или где вставить в моем коде или если он будет работать.

preg_match("/boundary=\".*?\"/i", $headers, $boundary); 
$boundaryfulltext = $boundary[0]; 

if ($boundaryfulltext!="") 
{ 
$find = array("/boundary=\"/i", "/\"/i"); 
$boundarytext = preg_replace($find, "", $boundaryfulltext); 
$splitmessage = explode("--" . $boundarytext, $message); 
$fullmessage = ltrim($splitmessage[1]); 
preg_match('/\n\n(.*)/is', $fullmessage, $splitmore); 

if (substr(ltrim($splitmore[0]), 0, 2)=="--") 
{ 
$actualmessage = $splitmore[0]; 
} 
else 
{ 
$actualmessage = ltrim($splitmore[0]); 
} 

} 
else 
{ 
$actualmessage = ltrim($message); 
} 

$clean = array("/\n--.*/is", "/=3D\n.*/s"); 
$cleanmessage = trim(preg_replace($clean, "", $actualmessage)); 

Итак, как я могу получить только текстовую область письма в мой файл или скрипт для обработки furthr ??

Заранее спасибо. stackoverflow отлично!

+0

Это полная Эл. адрес? В нем отсутствует заголовок 'Content-Type: multipart/mixed', который должен указать, какая строка границы (какой код вам нужен). –

+0

Это только часть электронной почты, которая сохраняется в файле. Это так же урезано, как я мог получить его, используя первый пример кода. – Jimbo

+0

Граничный заголовок важен для анализа вашей электронной почты, поскольку он указывает, где каждая * часть * электронной почты начинается и заканчивается. Без него все, что вы можете сделать, это догадываться, и вы знаете, что они говорят о том, чтобы принять ...;) Например, для вашего цитированного письма должен быть заголовок, например: 'Content-Type: multipart/mixed; border = "---- = _ NextPart_000_0163_01CB4EA5.46466520" ' –

ответ

12

Есть четыре шага, которые вам придется предпринять для того, чтобы выделить простую текстовую часть электронного тела:

1. Получить граничное MIME строку

Мы можем использовать регулярные выражения искать ваши заголовки (давайте предположим, что они находятся в отдельной переменной, $headers):

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

регулярное выражение будет искать для Content-Type заголовка, гр удерживает граничную строку, а затем фиксирует ее в первом capture group. Затем мы копируем эту группу захвата в переменную $boundary.

2. Разделить тело электронной почты на сегменты

После того, как у нас есть границы, мы можем разделить тело в различных его части (в вашем теле сообщения, тело будет предисловие -- каждый раз, когда он появляется). Согласно MIME spec, все до первой границы следует игнорировать.

$email_segments = explode('--' . $boundary, $message); 
array_shift($email_segments); // drop everything before the first boundary 

Это оставит нас с массивом, содержащим все сегменты, со всем, перед тем как первая граница будет игнорироваться.

3. Определите, какой сегмент является простым текстом.

Сегмент, который является открытым текстом, будет иметь заголовок Content-Type с MIME-типом text/plain. Теперь мы можем искать каждый сегмент для первого сегмента с этим заголовком:

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

Так что мы ищем является постоянным, мы можем использовать stristr (который находит первый экземпляр подстроки в строке, случай нечувствительно) вместо регулярного выражения. Если найден заголовок Content-Type, у нас есть наш сегмент.

4. Удалите любые заголовки из сегмента

Теперь нам нужно удалить все заголовки из сегмента мы нашли, как мы только хотим, фактическое содержание сообщения.Есть четыре MIME headers, которые могут отображаться здесь: Content-Type, как мы видели раньше, Content-ID, Content-Disposition и Content-Transfer-Encoding. Заголовки останавливали \r\n таким образом мы можем использовать, чтобы определить конец заголовков:

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

smodifier в конце регулярного выражения делает матч Dot символ перевода строки. .*? будет собирать как можно меньше символов (т.е. все до \r\n); ? является lazy modifier по адресу .*.

И после этого пункта $text будет содержать ваше содержание сообщения электронной почты.

Так все это вместе с кодом:

<?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

Я начинаю понимать, я думаю .. Итак, чтобы проверить, заменил бы все после // пустых vars ??? – Jimbo

+0

Не совсем. Это зависит от того, что вы хотите сделать (например, вы можете продолжить разделение заголовков или сбор «специальных» заголовков). Мой код ожидает, что у вас будет один блок текста для заголовков и один для сообщения, но вы можете просто заменить '$ headers' и' $ message' в моем коде '$ email', который, как ваш код должен содержать целая электронная почта. –

+0

AAAH, я не понимаю! Как я могу реализовать это в моем примере кода выше, чтобы проверить его? Я бы поставил ваш фрагмент перед файлом, который пишет файл? Затем напишите $ text вместо $ message? Я очень ценю вашу помощь И ПАЦИЕНТУ с этим новичком здесь. – Jimbo

0

Существует один ответ here:

Вам нужно только изменить эти 2 строки:

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

Ваша ссылка - 404. –