Прикрепление файлов к письму на windows-1251

Уже достаточно давно в продукте появилось поддержка прикрепления файлов к почтовым событиям.

Прикрепить файл просто: вызываем метод Bitrix\Main\Mail\Event::send, в ключе FILE передаем либо массив ID из базы, либо массив путей. В старом методе CEvent::Send, который по факту уже является оберткой для нового, указываем параметр $files (описан в документации).

При передаче путей, Битрикс предварительно сохраняет файлы в таблицу b_file с помощью CFile::SaveFile. Общая логика такая:

  • Добавляется событие (b_event)
  • Сохраняются файлы в таблицу b_file (в случае указания путей)
  • Добавляется запись в таблицу b_event_attachment, которая содержит ID события (EVENT_ID) и ID файла (FILE_ID).
  • Агент рассылает письма, выбирая эти данные.

Все выглядит отлично, но «счастливые» обладатели сайтов на windows-1251 могут столкнуться с проблемами при прикреплении файлов с русскими именами.

Пусть у нас есть:

  • почтовое событие SOME_EVENT
  • почтовый шаблон для события SOME_EVENT с заранее заполненным полем «Кому»
  • два файла в корне file.jpg и file.jpg.

и мы хотим отправить письмо с этими файлами.

Следующий код успешно отправит письмо с 2 вложениями, но только на кодировке utf-8:

use Bitrix\Main\Mail\Event;

Event::send([ 
    "EVENT_NAME" => "SOME_EVENT",
    "LID" => "s1",
    "C_FIELDS" => [],
    "FILE" => [
        $_SERVER["DOCUMENT_ROOT"]."/файл.jpg",
        $_SERVER["DOCUMENT_ROOT"]."/file.jpg"
    ]
);

С windows-1251, в лучшем случае, в письме придет только один файл.

Необходимо правильно указать путь, так как кодировка сайта у нас windows-1251, а кодировка файловой системы – utf-8.

Полный код будет выглядеть следующим образом:

use \Bitrix\Main\Mail\Event;
use \Bitrix\Main\IO;

Event::send([
    "EVENT_NAME" => "SOME_EVENT",
    "LID" => "s1",
    "C_FIELDS" => [],
    "FILE" => [
        IO\Path::ConvertLogicalToPhysical($_SERVER["DOCUMENT_ROOT"]."/файл.jpg"),
        $_SERVER["DOCUMENT_ROOT"]."/file.jpg"
    ]
]);

Стоит отметить, что Битрикс не выдает вообще никакой ошибки в первом варианте (когда CFile::SaveFile отработал некорректно), а просто заносит в таблицу b_event_attachment в поле FILE_ID значение 0.

C IO\Path::ConvertLogicalToPhysical файл сохраняется корректно.

Вроде бы задача решена. Но если мы попробуем сейчас выполнить этот код, то придет 2 файла:

«file.jpg» - нормальный, а «файл.jpg» с нулевой длиной.

Происходит это из-за бага, который есть внутри ядра. Тикет создан в феврале 2017 с категорией «Ошибки», пока исправления нет. Суть в том, что агент, который отправляет письма производит двойную конвертацию имени файла. Сначала в CFile::MakeFileArray, а затем в классе Bitrix\Main\Mail\Mail:: setAttachment при вызове Bitrix\Main\IO\File::getFileContents.

«Исправляем» это:

  1. Открываем файл /bitrix/modules/main/lib/mail/mail.php
  2. И вносим правки в ядро :), добавляя в метод setAttachment блок исключения:
  3. Было:

    try {
        $fileContent = File::getFileContents($attachment["PATH"]);
    } catch (\Exception $exception) {
        $fileContent = '';
    }
    

    Стало:

    try {
        $fileContent = File::getFileContents($attachment["PATH"]);
    } catch (\Bitrix\Main\IO\FileNotFoundException $exception) {
        try {
            $fileContent = File::getFileContents(\Bitrix\Main\IO\Path::convertPhysicalToLogical($attachment["PATH"]));
        } catch (\Exception $exception) {
            $fileContent = '';
        }
    } catch (\Exception $exception) {
      $fileContent = '';
    }
    

    Т.е. если при попытке получить содержимое файла вывалилось исключение «Файл не найден», пробуем получить содержимое по сконвертированному в обратную сторону имени файла. Теперь все файлы отправляются.



    Назад в раздел


С чего начинается продвижение сайта, старт работ по поисковому продвижению и раскрутке сайта в компании Пиксель Плюс
Начало работ по поисковому продвижению сайта в компании «Пиксель Плюс». Базовые понятия.
Необходимость ежемесячной оплаты работ по поисковому продвижению сайта. Основные работы по сайту для его эффективной раскрутки и себестоимость работ
Я бы хотел заплатить за продвижение своего сайта 1 раз и быть высоко в выдаче по конкурентным запросам всегда, возможно ли такое?
Продвижение по трафику: вопросы клиентов и ответы на них
Ряд вопросов по продвижению сайта по трафику. Нюансы тарификации, расчёта стоимости работ, абонентской оплаты.
Часто задаваемые вопросы по веб-аналитике (FAQ)
Вопросы, которые часто задаются заказчиками услуги по веб-аналитике и оказанию самой услуги. Что такое веб-аналитика? Зачем проекту нужна веб-аналитика? Зачем нужно определять KPI и какие они бывают? И так далее.
Время продвижения и внесения изменений в результаты продвижения сайта, скорость реагирования Яндекса (Yandex) на внесение изменений на сайте
Я оплатил услуги продвижения сайта на месяц. Прошло уже 10 дней и позиции в Яндексе не улучшились, вы там работаете или нет?
Эффективное поисковое продвижение сайта в Яндексе и Google, комплексное продвижение сайта во всех поисковиках
В каких поисковых системах (Яндекс, Гугл, Рамблер, Mail.ru) я получаю хорошие позиции если сотрудничаю с вашей компанией?