Прикрепление файлов к письму на 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.
«Исправляем» это:
- Открываем файл /bitrix/modules/main/lib/mail/mail.php
- И вносим правки в ядро :), добавляя в метод setAttachment блок исключения:
Было:
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 = ''; }Т.е. если при попытке получить содержимое файла вывалилось исключение «Файл не найден», пробуем получить содержимое по сконвертированному в обратную сторону имени файла. Теперь все файлы отправляются.
← Назад в раздел