САМОУЧИТЕЛЬ PHP 4

Отправка и перекодирование писем


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

r    вставку заголовка From

в письмо, если он еще не присутствует в сообщении;

r    преобразование  письма в нужную кодировку кириллицы;

r    вставку соответствующего значения в заголовок Content-type, чтобы письмо было "понятно" любой почтовой программе;

r    поддержку функций мини-шаблонизатора, который мы уже написали.

В листинге 32.2 приведен исходный код функции. Как обычно, мы помещаем функцию в отдельный модуль библиотекаря (библиотекарь описан в главе 29). Этот модуль будет использовать возможности, предоставляемые библиотекой Minitemplate.phl.

Листинг 32.2. Функция PostMail(): Mail.phl

<?

Uses("Minitemplate");

// Кодировка по умолчанию для исходного текста.

define("DefaultCode","w");

// Функция возвращает строку $st, переведенную из кодировки



// $from в кодировку $to. Возможные значения этих параметров:

// w[indows]  — windows-1251

// k[oi8-r]   — koi8-r

// m[ac]      — x-mac-cyrillic

// i[so]      — iso-8859-5

// t[ranslit] — translit ("английскими"

буквами — "русские" слова)

// Замечание: квадратными скобками помечены необязательные символы.

// параметр $from не может равняться "t", потому что трудно

// восстанавливать текст из транслита (хотя эта задача и разрешима).

// Функция полезна и сама по себе, но все-таки чаще всего ее

// применяют для работы с почтой. Именно поэтому я включаю

// ее в этот модуль.

function EncodeString($st,$to,$from=DefaultCode)

{ // Оставляем только первые буквы названий кодировок

  $from=strtolower(substr($from,0,1));

  $to  =strtolower(substr($to,0,1));

  // Пытаемся воспользоваться встроенной в PHP функцией


  if($to!="t") return convert_cyr_string($st,$from,$to);

  // Иначе нужно преобразовать строку в Translit, что придется

  // делать "вручную" — при помощи strtr().

  // Сначала заменяем "односимвольные" фонемы.

  $st=strtr($st,"абвгдеёзийклмнопрстуфхъыэ",

                "abvgdeeziyklmnoprstufh'ie");

  $st=strtr($st,"АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЭ",

                "ABVGDEEZIYKLMNOPRSTUFH'IE");

  // Затем — "многосимвольные".

  $st=strtr($st,array(

    "ж"=>"zh",  "ц"=>"ts", "ч"=>"ch", "ш"=>"sh",

    "щ"=>"shch","ь"=>"",   "ю"=>"yu", "я"=>"ya",

    "Ж"=>"ZH",  "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH",

    "Щ"=>"SHCH","Ь"=>"",   "Ю"=>"YU", "Я"=>"YA"

  ));

  // Возвращаем результат.

  return $st;

}

// Значения параметра Content-tyep charset в зависимости от

// односимвольного названия кодировки.

global $CoderCharset;

$CoderCharset["w"]="windows-1251";

$CoderCharset["i"]="iso-8859-5";

$CoderCharset["k"]="koi8-r";

$CoderCharset["m"]="x-mac-cyrillic";

$CoderCharset["t"]="koi8-r";

// Разделитель тела и заголовков (таких как From: и т. д.) в письме.

define("MailDivider","~StartOfMail");

// Посылает письмо $msg по заданному адресу $to, перед этим

// преобразовав его в кодировку $encTo. Проставляет поле

// charset и правильно обрабатывает имя получателя (если

// в теле письма уже указано "To: Вася", то в результате

// получается "To: Вася <vasya@pupkin.ru>"). Если работа происходит



// в Win32, то письмо не посылается, а создается отладочный файл,

// в котором будет содержаться текст письма.

// Письмо должно состоять из заголовков и тела, разделенных

// маркером ~StartOfMail.

function SendMail($to,$msg,$encTo=DefaultCode,$encFrom=DefaultCode)

{ global $CoderCharset;

  // Перекодируем

  $msg=EncodeString($msg,$encTo,$encFrom); // тело письма

  $head="";                                // заголовки

  // Если есть заголовки, выделяем их.

  if(strpos($msg,MailDivider)!==false) {

    $regs=split(MailDivider."\r?\n?",$msg,2); // тело и заголовки

    $head=trim($regs[0]);

    $msg=$regs[1];

  }

  // Работаем с заголовками. Разбиваем их на строки.

  if($head) $Lines=split("[\r\n]+",$head); else $Lines=array();

  $HasContType=0;   // число найденных заголовков Content-type

  $chs="charset=$CoderCharset[$encTo]";

  $subject="";

  for($i=0; $i<count($Lines); $i++) {

    $l=&$Lines[$i];

    // Проставляем текущую кодировку у письма. Для этого

    // проверяем, задан ли в нем заголовок Content-type и,

    // если задан, то модифицируем его, а если нет —

    // добавляем этот заголовок в начало и конец письма.

    if(eregi("^Content-type:",$l)) {

      if(eregi("charset *=",$l))

        $l=eregi_Replace("charset *= *[^;,\n]+",$chs,$l);

      else

        $l.="; $chs";

      $HasContType++;

    }

    // Проверяем значение поля "to" в письме — там может быть имя

    // получателя. В этом случае добавляем к нему еще и адрес.

    if(eregi("^to:([^\r\n]*)",$l,$regs)) {

      $to=trim($regs[1])." <$to>";

      $l="";

    }

    // Проверяем заголовок Subject. В некоторых верcиях PHP

    // передача пустого второго параметра в функцию mail()

    // приводит к нежелательным последствиям. Указывая в заголовке

    // значение Subject из письма, мы решаем проблему.

    if(eregi("^subject:([^\r\n]*)",$l,$regs)) {



      $subject=trim($regs[1]);

    }

  }

  // Нет заголовка Content-type — добавляем его в конец.

  if(!$HasContType) $Lines[]="Content-type: text/plain; $chs";

  // Соединяем строки опять вместе.

  $head=ereg_Replace("\n\n+","\n",join("\n",$Lines));

  // Посылаем письмо.

  $Result=@mail($to,$subject,$msg,$head)!=0;

  // В Windows параллельно ведем журнал писем (для отладки).

  if(getenv("COMSPEC")) {

    if(!@is_dir("debug")) mkdir("debug",0755);

    $f=fopen("debug/_debug_mail.txt","a+");

    fputs($f,"> to: $to\n");

    fputs($f,"$head\n--------\n");  

    fputs($f,"$msg\n-----------------------------------------\n\n");

    fclose($f);

  } 

  return $Result;

}

// Функция PostMail() "разворачивает" шаблон $msg, делая доступным для

// него переменные из массива $Vars (см. описание функций

// ExpandTemplate() и ExpandFile()). Затем она переводит результирующий

// текст в кодировку, заданную в $encTo (сам текст при этом

// рассматривается в кодировке $encFrom), и посылает его по электронной

// почте по адресу $to. Если строка $msg начинается с префикса

// file:, за которым следует имя файла, то шаблон письма загружается из

// этого файла при помощи ExpandFile(). В противном случае в качестве

// шаблона рассматривается сам параметр $msg.

function PostMail($to,$msg,$encTo=DefaultCode,

                  $Vars=false,$encFrom=DefaultCode)

{ if(eregi("^file:(.*)(\n|\$)",$msg,$P))

    $Text=ExpandFile(trim($P[1]),$Vars);   

  else

    $Text=ExpandTemplate($msg,$Vars);

  // Посылаем письмо.

  return SendMail($to,$Text,$encTo,$encFrom);

}

?>

Отличительной особенностью функции EncodeString() (а также всех остальных почтовых функций) является то, что она умеет перекодировать текст в транслит.



Термин "транслит" (сокращение от "транслитерация") означает такую кодировку кириллицы, при которой все "русские" буквы контекстно заменяются на записанные в соответствии с английской транскрипцией. Например, vot stroka, zapisannaya translitom. Эта кодировка особенно полезна для пользователей Unix, которые забыли установить у себя "русскую" таблицу символов.


Содержание раздела