Не могу понять, почему Zend_Mail::addHeader() удаляет символы новой строки

(Так как это мой первый SO вопрос, позвольте мне сказать, что я надеюсь, что он не слишком специфичен для Zend. Насколько я могу судить, это не должно быть проблемой. Хотя я мог бы опубликовать его на форуме, посвященном Zend, я Я чувствую, что я, по крайней мере, с такой же вероятностью получу хороший ответ, тем более что ответ может касаться проблем, связанных с MIME, которые выходят за рамки Zend Framework. Я в основном пытаюсь понять, следует ли рассматривать проблему, с которой я сталкиваюсь, ZF ошибка, или если я что-то неправильно понимаю или неправильно использую.)

Я использовал Zend_Mail для создания MIME-сообщения, которое отправляется через SendGrid, службу рассылки электронной почты. Их платформа позволяет отправлять электронные письма через их SMTP-сервер, но предоставляет дополнительные возможности, когда вы используете специальный заголовок (X-SMTPAPI), значение которого представляет собой строку собственных параметров в кодировке JSON, которая может быть довольно длинной.

В конце концов, заголовок, который я передавал, стал слишком длинным (я думаю>1000 символов), и я получил ошибки. Я был сбит с толку, потому что знал, что его передают через встроенную функцию PHP wordwrap (), прежде чем я передал значение в Zend_Mail::addHeader(), поэтому я подумал, что длина строки никогда не должна быть проблемой.

Оказывается, что addHeader () удаляет новые строки очень преднамеренно и без особых пояснений в виде комментариев.

// In Zend_Mail::addHeader()
$value = $this->_filterOther($value);


// In Zend_Mail::_filterOther()
$rule = array("\r" => '',
              "\n" => '',
              "\t" => '',
);
return strtr($data, $rule);

Хорошо, сначала это казалось разумным - возможно, ZF хочет получить полный контроль над форматированием и переносом строк. Следующий метод, вызываемый в Zend_Mail::addHeader ():

$value = $this->_encodeHeader($value);

Этот метод кодирует значение (в кавычках-печатных или base64, в зависимости от ситуации) и разбивает его на строки соответствующей длины, но только если оно содержит "непечатаемые символы", как определено Zend_Mime:: isPrintable ($ value).

Если посмотреть на этот метод, символы новой строки (\ n) действительно считаются непечатными символами! Таким образом, если бы только они не были удалены из строки в предыдущем вызове метода, длинный заголовок закодировался бы как QP и был бы разбит на 72-символьные строки, и все работало бы хорошо. Фактически, я сделал тест, где закомментировал вызов _filterOther(), и длинный заголовок кодируется и проходит без проблем. Но сейчас я только что сделал небрежный взлом ZF, не понимая цели, стоящей за удаленной строкой, так что это не может быть долгосрочным решением.

Моим среднесрочным решением было расширить Zend_Mail и создать новый метод addHeaderForceEncode (), который всегда будет кодировать значение заголовка и, таким образом, всегда разбивать его на короткие строки. Но я все еще не удовлетворен, потому что я не понимаю, почему этот вызов _filterOther () был необходим в первую очередь - может быть, я вообще не должен был обойти это.

Может ли кто-нибудь объяснить мне, почему существует такое поведение зачеркивания строк? Кажется, что это неизбежно приводит к ситуациям, когда заголовок может стать слишком длинным, если он не содержит никаких "непечатных символов", кроме символов новой строки.

Я провел несколько различных поисков по этой теме и просмотрел некоторые сообщения об ошибках ZF, но не видел, чтобы кто-нибудь говорил об этом. Удивительно, но это, кажется, действительно неясная проблема. К вашему сведению, я работаю с ZF 1.11.11.


Обновление: В случае, если кто-то захочет следить за проблемой ZF, которую я открыл по этому поводу, вот она: Zend_Mail::addHeader () Раскрывает длинные заголовки, затем выдает исключение

1 ответ

Решение

Вы вероятно сталкиваетесь с несколькими вещами. Согласно RFC 2821, текстовые строки в SMTP не могут превышать 1000 символов:

текстовая строка

Максимальная общая длина текстовой строки, включая символ, составляет 1000 символов (не считая начальную точку, дублированную для прозрачности). Это число может быть увеличено за счет использования SMTP-сервисных расширений.

Заголовок не может содержать символы новой строки, поэтому, вероятно, Zend их удаляет. Для длинных заголовков обычно вставляют разрыв строки (CRLF в SMTP) и вкладку для их "переноса".

Выдержка из RFC 822:

Каждое поле заголовка можно рассматривать как одну логическую строку символов ASCII, содержащую имя поля и тело поля. Для удобства часть тела этого концептуального объекта может быть разбита на многострочное представление; это называется "складывание". Общее правило состоит в том, что там, где может быть линейно-пробел (НЕ просто LWSP-символы), вместо этого может быть вставлен CRLF, за которым сразу следует ПО СЛЕДУЮЩЕМУ одному LWSP-символу.

Я бы сказал, что _encodeHeader() Функция, возможно, должна смотреть на длину строки, и если заголовок длиннее некоторого магического значения, сделайте "wrap and tab", чтобы он занимал несколько строк.

Другие вопросы по тегам