Wrap в почтовых сообщениях некорректно работает с UTF-8

Главные вкладки

Аватар пользователя MarinaMim MarinaMim 20 февраля 2009 в 12:31

в почтовых сообщениях строки обрезаются очень коротко. Это происходит из-за того, что функция php wordwrap некорректно работает с UTF-8 - русские символы у нее имеют длину 2, а английские - 1. Из-за этого нельзя просто в 2 раза увеличить границу - строки с английскими словами (например, url) разъедутся.

Я добавила функцию _wordwrap, и изменила на нее вызов в _drupal_wrap_mail_line (файл includes/mail.inc)

Кстати, во втором вызов wordwrap, которые предполагает обрезать слова, пропущен 4й параметр, который, собственно и должен указывать на обрезание. Иначе вызов функции с шириной 996 после ширины 77 не имеет смысла.

function _drupal_wrap_mail_line(&$line, $key, $values) {
  // Use soft-breaks only for purely quoted or unindented text.
  $line = wordwrap($line, 77 - $values['length'], $values['soft'] ? "  \n" : "\n");
  // Break really long words at the maximum width allowed.
  $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
}

->

function _drupal_wrap_mail_line(&$line, $key, $values) {
  // Use soft-breaks only for purely quoted or unindented text.
  $line = _wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
  // Break really long words at the maximum width allowed.
  $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n", 1);
}

function _wordwrap( $str, $width, $break="\n") {
    $formatted = '';
    $position = -1;
    $prev_position = 0;
    $last_line = -1;
   
    /// looping the string stop at each space
    while( $position = mb_stripos( $str." ", " ", ++$position, 'utf-8' ) ) {
        if( $position > $last_line + $width + 1 ) {
            $formatted.= mb_substr( $str, $last_line + 1, $prev_position - $last_line - 1, 'utf-8' ).$break;
            $last_line = $prev_position;
        }
        $prev_position = $position;
    }
   
    /// adding last line without the break
    $formatted.= mb_substr( $str, $last_line + 1, mb_strlen( $str ), 'utf-8' );
    return $formatted;
}

Комментарии

Аватар пользователя Gairon Gairon 18 ноября 2009 в 11:59

Спасибо, пригодилось.

2neochief: посмотрел патч - он не прошел тест, да и версия у него стоит 7.x-dev. Он для Drupal 6 подходит?

PS: Странно что ширину текста письма в файле includes/mail.inc не вынесли в настройки, а просто забили её константой 77.

PPS: для хостинга где PHP < 5.2 строка

<?php
while( $position mb_stripos$str." "" ", ++$position'utf-8' ) ) {
?>

выдает ошибку, т.к. функция mb_stripos() появилась только в PHP версии 5.2.

Аватар пользователя antton antton 8 мая 2010 в 18:13

Gairon, ну патч c drupal.org возможно не работает, из-за того что код в Drupal немного изменился. Возьмите блокнот, и посмотрите что на что заменяется. И вручную через блокнот - замените.

neochief, патч c drupal.org я применил, но всё равно какая-то кривость. В web-интерфейсе Mail.ru письмо нормально выглядит. Но вот когда я читаю то же письмо в обычной почтовой программе Mozilla Thunderbird, получаю полную кашу. Дело в том что патч добавляет пробелы в конце обрезаемых строк. А Mozilla Thunderbird автоматически объединяет строки на конце которых есть пробелы, чтобы письмо было удобнее читать.

Письмо после обработки функцией drupal_wordwrap:

Здравствуйте,_username!__

Вы_получили_это_письмо,_так_как_этот_адрес_эл.почты_был_
использован_при_регистрации_на_сайте_http://loginuri/.__
Имя_пользователя:_username__
Пароль:_password__

Вы_можете_войти_на_сайт,_воспользовавшись_одноразовой_ссылкой:__
http://loginurl/__

После_входа_на_сайт_вы_можете_сменить_пароль_на_странице_настроек:__
http://edituri/__

--__
С уважением,__
siteteam__

В результате Mozilla Thunderbird отображает такое письмо:

Здравствуйте, username!
Вы получили это письмо, так как этот адрес эл.почты былиспользован при регистрации на сайте http://loginuri/. Имя пользователя: username Пароль: password
Вы можете войти на сайт, воспользовавшись одноразовой ссылкой: http://loginurl/
После входа на сайт вы можете сменить пароль на странице настроек: http://edituri/
-- С уважением, siteteam

neochief, не подскажите как можно подкорректировать патч, чтобы на конце тех строк, где перенос должен быть обязательно - пробелов не было вообще? (сейчас там по два пробела)

Аватар пользователя antton antton 30 апреля 2010 в 1:41

Просветите меня, а зачем вообще делается перенос строк в почтовых сообщениях? Разве почтовая программа для чтения почты, ну или почтовый web-интерфейс сам не разорвёт строку в нужном месте. Какая цель делать такие разрывы? Я догадываюсь, что это предусматривает сам почтовый формат text/plain, но сходу не нашёл информацию по этой теме.

Аватар пользователя fairwind fairwind 30 апреля 2010 в 20:35

Я сейчас делаю проще: просто ставлю модуль htmlmail. Обрезание строк при отправке через CCK email field лечится хаком оного field Smile

Аватар пользователя antton antton 8 мая 2010 в 18:12

fairwind, спасибо. Формат text/html - это конечно выход. Но всё таки желательно посылать сообщения в стандартном формате text/plain, без использования html.

Немного переформулирую вопрос. Как можно переделать фикс http://drupal.org/node/540228, чтобы в конце строки где строка разбита функцией drupal_wordwrap - стоял двойной пробел, а там где изначально и так был перенос строки, вообще не было пробелов? Т.е. чтобы после обработки drupal_wordwrap получалось такое письмо:

Здравствуйте,_username!

Вы_получили_это_письмо,_так_как_этот_адрес_эл.почты_был__
использован_при_регистрации_на_сайте_http://loginuri/.
Имя_пользователя:_username
Пароль:_password

Вы_можете_войти_на_сайт,_воспользовавшись_одноразовой_ссылкой:
http://loginurl/

После_входа_на_сайт_вы_можете_сменить_пароль_на_странице_настроек:
http://edituri/

--
С уважением,
siteteam

Аватар пользователя antton antton 2 мая 2011 в 12:54

Нашёл способ борьбы с тем что мешало в фиксе neochief http://drupal.org/node/540228
Добавил строчку:

$return = trim($return);

Перед строкой:

return $return;

Это убирает пробелы в конце текстовых строк __
Ну и соответственно, после этого Mozilla Thunderbird отображает письмо нормально, а не превращает его в кашу.

Аватар пользователя Zonder Zonder 3 февраля 2012 в 1:19

У меня патч так и не заработал. Ругается, что не известна ему функция drupal_wordwrap.
Пока нашел выход только с решением топикастера.

Аватар пользователя Григорий_978 Григорий_978 4 февраля 2012 в 4:38

Так, проблема решена! я просто установил в настройках HTML Mail FULL HTML формат, однако системные сообщения немного надо настроить, токен ссылки надо заключить в  <a href=""></a>

Найти HTML Mail можно здесь:
http://drupalmodules.com/search/node/mail+category%3A41

Данная тема считай что закрыта, никакие PHP больше выполнять не надо, русский текст отныне не обрезается вообще (без переноса или вручную проставленного  <br/> ), как и любой другой конечно.

Аватар пользователя Григорий_978 Григорий_978 10 ноября 2015 в 11:48

Токен ссылки работают нормально даже без заключения их в
 <a href=""></a>
Но вот в фильтрованном HTML токен ссылки обрезаются и требуют заключения
в  <a href=""></a> (так как иначе в обрезанном виде они не работоспособны),
в фильтрованном HTML нельзя настроить отступ между строк,  <br/> не помогает

Аватар пользователя luciuz VII luciuz VII 11 апреля 2012 в 2:10

Григорий_978

можете скрин дать -- где это выставить?
поставил модули HTML Mail и Mail System
вроде выставил на странице /admin/config/system/htmlmail Post-filtering unfiltered -- один фиг обрезается