QP Encoding на Perl
Дата: 24 июня 2008 года
Стандарт MIME определяет 2 метода кодирования - Quoted Printable и Base64. Однако, часто программы поддерживают только один тип кодирования, обычно метод Quoted Printable, поэтому Вы можете быть вынуждены использовать именно его. Например, популярные почтовый сервис GMail неверно отображает темы закодированные Base64.
C точки же зрения эффективности (минимального размера закодированного сообщения) лучше применять:
- метод Quoted Printable, когда большая часть текста набрана латинским шрифтом с небольшим "вкраплением" 8-битных символов (буквы русского алфавита, в частности), т.к. в этом методе кодируются только 8-битные символы, но количество их увеличивается не меньше чем вдвое.
- метод Base64, когда большая часть текста состоит из 8-битных символов (например, полностью русскоязычный текст), т.к. в этом методе кодируется весь текст (включая латинский алфавит), но размер его увеличивается не более чем на треть.
Всегда применяйте прием кодирования текста с особой осторожностью: если программа Вашего абонента не поддерживает тип используемого в Вашем сообщении кодирования, то вместо текста он увидит бессвязный набор символов, который он должен будет суметь раскодировать с помощью дополнительных программных средств.
Если на PHP с функцией Quoted Printable нет никаких проблем, то на Perl такие проблемы иногда всплывают. Вот реализация:
#!/usr/bin/perl use POSIX qw(ceil floor); sub trim { my($string)=@_; for ($string) { s/^\s+//; s/\s+$//; } return $string; } sub qp_enc { $input=$_[0]; $line_max=int($_[1]); if ($line_max==0) {$line_max=76;} $space_conv=$_[2]; if ($space_conv!=true) {$space_conv=false;} @hex = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); @lines = split(/(\r\n|\r|\n)/, $input); $eol = "?=\r\n\t"; $escape = "="; $output = ""; $charset = "=?Windows-1251?Q?"; foreach (@lines) { $line=$_; $linlen = length($line); $newline = ""; for($i = 0; $i < $linlen; $i++) { $c = substr( $line, $i, 1 ); $dec = ord( $c ); if ( ( $i == 0 ) && ( $dec == 46 ) ) { $c = "=2E"; } if ( $dec == 32 ) { if ( $i == ( $linlen - 1 ) ) { $c = "_"; } else { if ( $space_conv ) {$c = "_";} } } else { if ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { $h2 = floor($dec/16); $h1 = floor($dec%16); $c = $escape.$hex["$h2"].$hex["$h1"]; } } if ( (length($newline) + length($c)) >= $line_max ) { $output .= $charset.$newline.$eol; $newline = ""; if ( $dec == 46 ) {$c = "=2E";} } $newline .= $c; } # end of for $output .= $charset.$newline.$eol; } # end of foreach $output =~ s/\r\n/\n/g; return trim($output); } print qp_enc("Привет codenet.ru, это тест !!!");