e-mail parser

dkDimon

Guest
e-mail parser

Добрый день. Не подскажет ли кто хороший модуль для парсинга тела письма. А нужно вот что - в теле письма найти часть типа text/plain. Работаю с ящиком через imap_ функции. Казалось бы, можно использовать imap_fetchbody(), указывая part-no = 1, но не всегда это дает текстовую часть.
 

ForJest

- свежая кровь
dkDimon
А просмотреть количество частей - не судьба? И проверить их типы?
 

dkDimon

Guest
Можно. imap_fetchstructure() и рекурсивно ищем часть с типом 1/PLAIN. А как получить эту часть? imap_fetchbody() с номером? Не работает...
 

440hz

php.ru
Re: e-mail parser

Автор оригинала: dkDimon
Добрый день. Не подскажет ли кто хороший модуль для парсинга тела письма. А нужно вот что - в теле письма найти часть типа text/plain. Работаю с ящиком через imap_ функции. Казалось бы, можно использовать imap_fetchbody(), указывая part-no = 1, но не всегда это дает текстовую часть.
я вот так разбираю письмо для поста фоток с телефона на сайт. может пригодиться?
 

Bermuda

Новичок
Re: e-mail parser

Автор оригинала: dkDimon
Добрый день. Не подскажет ли кто хороший модуль для парсинга тела письма. А нужно вот что - в теле письма найти часть типа text/plain.
Ниже скрипт написанный год назад, для того чтобы читать почту на Siemens S45 который кириллицу в своем почтовом клиенте не понимает наглухо. Скрипт получает письмо на stdin и парсит его.

1. Сохраняет _только_важные_ заголовки.
2. Ищет _только_текстовые_ блоки.
3. Определяет кодировку заголовков, текста и делает транслитерацию.
4. Убирает мусор, прикрепленные файлы, двойные пробелы, переводы строк.
5. То что осталось вполне можно читать на телефоне :)

Может кому пригодится :)
PHP:
<?php
require_once 'Mail/mimeDecode.php';

$max_input_size = 1024*1024;
$max_output_size = 8*1024;
define('LOWERCASE',3); 
define('UPPERCASE',1); 

//Таблица транслитерации
$trans = array(
"А" => "A",
"Б" => "B",
"В" => "V",
"Г" => "G",
"Д" => "D",
"Е" => "E",
"Ё" => "JO",
"Ж" => "ZH",
"З" => "Z",
"И" => "I",
"Й" => "J",
"К" => "K",
"Л" => "L",
"М" => "M",
"Н" => "N",
"О" => "O",
"П" => "P",
"Р" => "R",
"С" => "S",
"Т" => "T",
"У" => "U",
"Ф" => "F",
"Х" => "H",
"Ц" => "C",
"Ч" => "CH",
"Ш" => "SH",
"Щ" => "SHH",
"Ъ" => chr(35),
"Ы" => "Y",
"Ь" => chr(39),
"Э" => "JE",
"Ю" => "JU",
"Я" => "JA",
"а" => "a",
"б" => "b",
"в" => "v",
"г" => "g",
"д" => "d",
"е" => "e",
"ё" => "jo",
"ж" => "zh",
"з" => "z",
"и" => "i",
"й" => "j",
"к" => "k",
"л" => "l",
"м" => "m",
"н" => "n",
"о" => "o",
"п" => "p",
"р" => "r",
"с" => "s",
"т" => "t",
"у" => "u",
"ф" => "f",
"х" => "h",
"ц" => "c",
"ч" => "ch",
"ш" => "sh",
"щ" => "shh",
"ъ" => chr(35),
"ы" => "y",
"ь" => chr(39),
"э" => "je",
"ю" => "ju",
"я" => "ja",
);

//Функция для автоматического определения кодировки
//Может давать неверные результаты на слишком маленьких текстах.
function detect_cyr_charset($str)
	{
	$charsets = Array(
		'k' => 0,
		'w' => 0,
		'd' => 0,
		'i' => 0,
		'm' => 0
		);

	for ($i = 0, $length = strlen($str); $i < $length; $i++)
		{
		$char = ord($str[$i]); 

		//non-russian characters 
		if ($char < 128 || $char > 256) continue; 

		//CP866 
		if (($char > 159 && $char < 176) || ($char > 223 && $char < 242)) $charsets['d']+=LOWERCASE;
		if (($char > 127 && $char < 160)) $charsets['d']+=UPPERCASE;

		//KOI8-R 
		if (($char > 191 && $char < 223)) $charsets['k']+=LOWERCASE;
		if (($char > 222 && $char < 256)) $charsets['k']+=UPPERCASE;

		//WIN-1251 
		if ($char > 223 && $char < 256) $charsets['w']+=LOWERCASE;
		if ($char > 191 && $char < 224) $charsets['w']+=UPPERCASE;

		//MAC 
		if ($char > 221 && $char < 255) $charsets['m']+=LOWERCASE;
		if ($char > 127 && $char < 160) $charsets['m']+=UPPERCASE;

		//ISO-8859-5 
		if ($char > 207 && $char < 240) $charsets['i']+=LOWERCASE;
		if ($char > 175 && $char < 208) $charsets['i']+=UPPERCASE;
		}
	arsort($charsets);
	return key($charsets);
	}

//Читаем stdin
$handle = fopen("php://stdin", "r");
$input = fread($handle, $max_input_size);
fclose($handle);

//Устанавливаем параметры для Mail_mimeDecode
$params['include_bodies'] = true;
$params['decode_bodies']  = true;
$params['decode_headers'] = true;

$decoder = new Mail_mimeDecode($input);
$structure = $decoder->decode($params);
$parts = $structure->parts;
$headers = $structure->headers;

//Генерируем уникальное имя для файла
$filename=tempnam("/home/vpopmail/domains/puchkov.com/movil/Maildir/new/", "");

//Сохраняем только жизненно важные заголовки, остальное мусор :-)
$mail_headers  = "Date: ".$headers["date"]."\n";
$mail_headers .= "From: ".$headers["from"]."\n";
$mail_headers .= "To: ".$headers["to"]."\n";
$mail_headers .= "Subject: ".$headers["subject"]."\n";

//Получаем текстовый блок и сохраняем в массив
if (($structure->ctype_primary=="text") and ($structure->ctype_secondary=="plain"))
	{
	$textos[] = $structure->body;
	}
	
//Письма часто состоят из нескольких блоков.
//Если данное письмо кроме текста содержит другие блоки
if (is_array($parts))
	{
	//то рассмотрим все блоки в цикле.
	foreach ($parts as $val)
		{
		//если это текстовый блок
		if (strtolower($val->ctype_primary)=="text")
			{
			//то сохраняем найденные тесктовые части в массив
			$textos[] = $val->body;
			}
		else
			{
			//а мусор кладем в другой массив. Мало ли, вдруг пригодится?
			$otros[] = $val->ctype_primary."/".$val->ctype_secondary.": ".$val->ctype_parameters["name"];
			}

		//Если это блок multipart, то поищем текст и внутри его.
		if ((strtolower($val->ctype_primary)=="multipart") and (strtolower($val->ctype_secondary)=="alternative"))
			{
			$sub_parts = $val->parts;
			//Если блок содержит вложенные блоки
			if (is_array($sub_parts))
				{
                //то рассмотрим все блоки в цикле.
				foreach ($sub_parts as $sub_val)
					{
                    //если это текстовый блок
					if (strtolower($sub_val->ctype_primary)=="text")
						{
			            //то сохраняем найденные тесктовые части в массив
						$textos[] = html_entity_decode (strip_tags($sub_val->body));
						}
					else
						{
			            //а мусор кладем в другой массив. Мало ли, вдруг пригодится?
						$otros[] = $sub_val->ctype_primary."/".$sub_val->ctype_secondary.": ".$sub_val->ctype_parameters["name"];
						}
					}
				}
			}
		}
	}
	
//определяем кодировку заголовков письма
$encoding = detect_cyr_charset($mail_headers);
//и конвертируем из исходной в CP1251
$mail_headers = convert_cyr_string($mail_headers, $encoding, "w");
//Делаем транслитерацию
$mail_headers = strtr($mail_headers, $trans);
//Заголовки теперь все в латинице

//Аналогичным образом поступаем с частями текстов.
//Так как кодировки заголовков и частей текста могут отличаться
//то обрабатываем каждый фрагмент текста по отдельности
foreach ($textos as $texto)
	{
	$i++;
	//определяем кодировку заголовков письма
	$encoding = detect_cyr_charset($texto);
    //конвертируем из исходной в CP1251
	$texto = convert_cyr_string($texto, $encoding, "w");
    //Делаем транслитерацию
	$texto = strtr($texto, $trans);
	//декодируем возможные символы HTML
	$texto = html_entity_decode(strip_tags($texto),ENT_QUOTES,"cp1251");
	//обрезаем "пустое"
	$texto = trim($texto);
	//убираем перевод строки
	$texto=ereg_replace("[\r\t\n]"," ",$texto);
	//убираем двойные пробелы
	$texto=ereg_replace (' +', ' ', $texto);
	//вставляем маркеры разделяющие части письма и сохраняем все в одну строку
	$message .= "\n=8<==chast' ".$i."==\n".$texto;
	}

//Если в письме был мусор вроде прикрепленных файлов по
//5 мегабайт, то так и быть приклеим его к концу письма.
if (is_array($otros))
	{
	$message .= "\n=8<=Dop-no==";
	foreach ($otros as $otro)
		{
		$message .= "\n".$otro;
		}
	}
$message = $mail_headers.$message;
//сохраняем письмо на диск
$handle = fopen($filename, "w");
//Размер письма ограничен переменной $max_output_size
//Если мусора было много, то весь он все равно не влезет,
//но чтобы знать, что в письме было что-то еще,
//нилишним будет его прикрепить
fwrite($handle, $message, $max_output_size);
fclose($handle);

?>
-~{}~ 23.09.05 19:36:

[OFFTOPIC]Соврал. Скрипту два года. Год назад у меня уже появился SL55, а два года назад у меня был S45i. Именно он не понимал русского языка :)[/OFFTOPIC]
 

DiTHER

bang bang
Bermuda, красиво такие посты делать? То-то же.. И detect_cyr_charset без копирайтов... фу

dkDimon, части достаются несколько диким образом:

если есть:
Код:
ALTERNATIVE
        PLAIN
        HTML

note: обычно такие письма создает Outlook
письмо, то:
PHP:
$part_index = '1.1'; // для того чтобы достать alternative->plain часть
$part_index = '1.2'; // для того чтобы достать alternative->html часть

$fetched_part = imap_fetchbody($mbox,$msgno,$part_index);
Иными словами система очень дикая :) Ибо заставляет сохранять индексы всех частей в случае вложенности.

Если тебе нужно построить какой-то полуавтомат для почты (почтового робота может) - пиши в личку, совсем недавно я занимался таким же извращением :) помогу :).
 

Bermuda

Новичок
Автор оригинала: DiTHER
Bermuda, красиво такие посты делать? То-то же..
Ни чуствую ни капли вины. К посту нельзя прикрепить файл, а выкладывать у себя на сайте файл из 100 строк кода, только для того чтобы показать его на форуме в одном посте не стоит тех усилий. В данном конкретном случае проще и удобнее включить код в пост, более того он нормально оформлен и читаем.

И detect_cyr_charset без копирайтов... фу
Да, все верно. Функцию определения кодировки я взял вот отсюда:
http://tony2001.phpclub.net/misc/detect_charset/detect.phps
Взял ее как есть и использовал в своем скрипте. Я не выдаю это функцию за свой гениальный труд. Я из функции не выкинул ни единого комментария, ни копирайтов, ни одной строчки. К скрипту ни прилагалсь лицензия. И я не приписываю себе его авторство, хотя идея простая и вместе с тем очень ценная. Предлагаешь мне написать небольшой благодарственный тескт и включить его в свой скрипт? Насколько я понимаю на форум как раз и служит для общения, обмена кодом, опытом, идеями. Зато некоторые шарятся по приватам, боятся, что их сверхценный код украдут и при первых же признаках знакомого кода кричат "Фу, плагиат! А где копирайты?!". А я да, часто читаю этот форум, заимствую некоторые идеи, опыт, иногда код. Как думаешь, это лучше чем шарится по приватам?
 

SiMM

Новичок
> а выкладывать у себя на сайте файл из 100 строк кода, только для того чтобы показать его на форуме в одном посте
http://phpclub.ru/paste
PS: дали бы чтоли ссылочку в правилах...
 

DiTHER

bang bang
Bermuda
Да, все верно. Функцию определения кодировки я взял вот отсюда:
http://tony2001.phpclub.net/misc/de...set/detect.phps
Взял ее как есть и использовал в своем скрипте. Я не выдаю это функцию за свой гениальный труд. Я из функции не выкинул ни единого комментария, ни копирайтов, ни одной строчки. К скрипту ни прилагалсь лицензия. И я не приписываю себе его авторство, хотя идея простая и вместе с тем очень ценная.
речь не о "краже кода" и не о "фу плагиат", а о элементарном уважении.

Ни чуствую ни капли вины. К посту нельзя прикрепить файл, а выкладывать у себя на сайте файл из 100 строк кода, только для того чтобы показать его на форуме в одном посте не стоит тех усили
лучше не парится и заставить сотню-другую человек попарится самостоятельно. угу.
 

Bermuda

Новичок
Автор оригинала: DiTHER
Bermuda
речь не о "краже кода" и не о "фу плагиат", а о элементарном уважении.
Лично я tony2001 уважаю, часто читаю, перенимаю опыт. Но вот кто ты такой, чтобы судить о моем уважении к tony2001 я так и не понял, не телепат я. Лучше нужно обяснять о чем "речь".

SiMM спасибо за ссылочкую буду прользоваться. Не знал.
 
Сверху