|
Написать данную статью меня заставила недавняя ситуация, когда на своём рабочем сайте потребовалось динамически генерировать страницы каталога в PDF.
Поскольку из меня web-программист мягко скажем «не очень» и зарабатываю отнюдь не сайтами, в прошлом году задача была отдана стороннему исполнителю,
в результате чего был получен относительно рабочий результат в виде связки MODX и упомянутого Dompdf. Но, к сожалению (или счастью?), ничто не вечно
в этом мире и в один не самый прекрасный день Dompdf стал выбрасывать ошибку вида «Fatal error: Uncaught exception 'Dompdf\Exception' with message 'No block-level parent found. Not good.' in /home...».
Попытка решить вопрос с изначальным исполнителем вылилось только в ответ: XXX денег. Встречный закономерный вопрос: а собственно по чьей вине всё
упало так быстро повис в воздухе. Забегая вперёд скажу, что причина была в смене версии PHP с 5 на 7 на хостинге, т.е. вопросов к исполнителю скажем
так не возникло бы, ХХХ+ денег заслужено могли быть его. Но… подождав месяц пояснений пришлось разбираться самому. Благо «в программирование» в
принципе умею и изначальный шаблон генерации не сильно устраивал: по ТЗ мы просили разместить на 1 страницу информацию, а нам сделали 2 и говорили
что уложить на 1 невозможно. Хм… странно, мы же как то вручную укладывали до этого :)
Причина самой ошибки была найдена в интернете очень быстро: на сайте стояла версия 5c98652b, которая не сильно дружит с PHP 7+.
Глубоко рыть не стал, а просто аккуратно обновил на текущую 8f49b3b0 с официального репозитария.
Закономерно всё «волшебным» образом восстановилось. Зачем было использовать в начале 2019 года столь древнюю версию оставим на совести исполнителя.
Далее началась самая интересная часть, а именно замена шаблона генерации. Первоначальный шаблон в Word’е на одну страницу был такой. Немного поковыряв
начинку Dompdf и поисковики на предмет тонкостей родился вот такой шаблон в HTML:
|
{$pagetitle}
{$longtitle}
|
|
Область применения
{$content}
Конструкция светильников
{$construction}
|
|
Технические характеристики
{$nTableHTML}
|
Габаритные размеры
|
|
|
©2011-{$curyear} Мастер ЛЕД. Документ создан {$curdata} в {$curtime}
|
Откатав шаблон в браузере, получил список «установленных» шрифтов, радостно накатил его на свой Dompdf и… крепко обломался: получил кучу знаков
вопроса вместо русских букв. Мда, методом перебора выяснил, что кириллицу отображает только один доступный шрифт DejaVuSans. В принципе с ним всё
работало неплохо, но из за своеобразности этого шрифта были нюансы в заголовке. Плюс душа просила максимального соответствия шаблону (как бы «фирменный
стиль»). Кстати на этом месте мне стало понятно, почему исполнитель так и не смог уложить всё на одну страницу :)
На вопрос «Dompdf и кириллица/русские буквы/Unicode» интернет давал просто огромную кучу советов по формированию шрифтов из TTF в AFM. Но… убив один
вечер результат был один и тот же: шрифты в целом прописывались (было видно по английским буквам), только на сайте упорно вместо русских букв
отображались знаки вопроса. Не вариант.
От отчаяния начал крепко думать «а может заменить Dompdf на что то другое?». Но вдумчивый поиск показал что «из коробки» с кириллицей мало кто дружит
из подобных библиотек. Т.е. менять «шило на мыло» глобально смысла не было. Надо «отшлифовывать» то, что имею, благо оно работает плюс-минус. Первоначально
решил разобраться как вообще Dompdf понимает кодировки и как надо сформировать файл нужного шрифта. На этом моменте удивило что рабочий шрифт DejaVuSans
имел расширение UFM, описание формата которого сходу не нашёл. Зато очень быстро нашёл интересный конвертер… ttf2ufm.exe. Первый попавшийся в интернете
экземпляр радостно сказал, что в x64 он работать не будет. Ну ок, я не гордый :) Эмулятор x86 запускать не сильно хотелось и пока искал рабочий вариант
exe’шника неожиданно наткнулся на интересную страничку. Дословно процитирую что зацепило:
Если долго биться головой об стену, то есть вероятность ее пробить. (ц) Я
Все таки переборол эту ботву. Кароче, рецепт такой:
1. Вытаскиваем из директории C:\windows\fonts файло arialuni.ttf и кладем его рядом с ttf2ufm.exe
2. Запускаем следующую ботву:
ExpandedWrap disabled
ttf2ufm.exe -A -F -l russian arialuni.ttf arialuni
3. Дальше действуем так, как указано в README.
Вопрос решен. 8-) 8-) 8-)
Ну и следующее дополнение:
Хы. Кстати, подойдут и обычные шрифты. Не обязательно Unicode. Главное в командной строке указать -l russian
Попробовал и… УРА! Получил свой желаемый результат. А именно файлы шрифтов с расширением UFM, которые великолепно понимаются Dompdf и не менее
великолепно отображают русские буквы.
Я не знаю как тебя зовут johen с сайта sources.ru, но тебе от меня самый низкий поклон за такую чёткую и рабочую инструкцию!
Кстати при таком «ручном» вводе шрифтов не забываем прописать их правильно в dompdf_font_family_cache.dist.php по шаблону:
'verdana' =>
array(
'bold' => $distFontDir . 'verdanab',
'bold_italic' => $distFontDir . 'verdanaz',
'italic' => $distFontDir . 'verdanai',
'normal' => $distFontDir . 'verdana'
)
Ещё если шрифт не содержит нужного написания в курсиве и жирном шрифте, то прописывать надо примерно так:
'impact' =>
array(
'bold' => $distFontDir . 'impact',
'bold_italic' => $distFontDir . 'impact',
'italic' => $distFontDir . 'impact',
'normal' => $distFontDir . 'impact'
),
Ссылки по статье:
- Шаблон документа в Word;
- Шрифт Arial;
- Шрифт Impact;
- Шрифт Verdana;
- Рабочий комплект ttf2ufm (проверено на Windows 10).
Остальные шрифты я думаю Вы легко получите самостоятельно :)
Кстати ещё немного пришлось повозиться с неразрывным пробелом (& nbsp;) в разных кодировках, ибо Dompdf его категорически не понимает и выводит «квадратики» в файл. Решилось всё такой функцией на PHP:
function removeHTML($string)
{
$string = html_entity_decode($string);
$string = strip_tags($string);
$string = str_replace(html_entity_decode(' '),' ',$string);
return $string;
}
$content=removeHTML($content);
Функция попутно убирает все лишние теги HTML, чтобы исправить возможные косяки в базе и получить красивый pdf-документ. Ключевое в функции str_replace это как подаём код неразрывного пробела: html_entity_decode(' ')Остальное по учебнику :)
Для особо ленивых общий файл работы с Dompdf получился такой:
getObject('modResource', array('id' => $id));
$parent = $modx->getObject('modResource', array('id' => $object->get('parent')));
$curyear = date('Y');
$curdata = date('m.d.y');
$curtime = date('H:i');
$pagetitle = $object->get('pagetitle');
$pagetitle = removeHTML($pagetitle);
$longtitle = $object->get('longtitle');
$longtitle = removeHTML($longtitle);
$longtitle = mb_strtoupper($longtitle);
$content = $object->get('content');
$content_pos = strpos($content,'Для определения модели');
if ($content_pos !== false){
$content = substr($content,0,$content_pos);
}
$content=removeHTML($content);
$image = $object->getTVValue('image');
$construction = $object->getTVValue('construction');
$construction=removeHTML($construction);
$dimensions = $object->getTVValue('dimensions');
$hideGabarit = empty($dimensions) ? 'display: none;' : '';
$hideConstruction = empty($construction) ? 'display: none;' : '';
if(strpos($dimensions,"rgb-ctr-2k")!==false)$hideGabarit = "display: none;"; /* add fix pic */
$table = trim($object->getTVValue('table'));
$nTableHTML = empty($table) ? '' : <<
|
{$pagetitle}
{$longtitle}
|
|
Область применения
{$content}
Конструкция светильников
{$construction}
|
|
Технические характеристики
{$nTableHTML}
|
Габаритные размеры
|
|
|
©2011-{$curyear} Мастер ЛЕД. Документ создан {$curdata} в {$curtime}
|
HTML;
$dompdf = new Dompdf();
$dompdf->set_base_path(realpath(dirname(__FILE__).'/../'));
$dompdf->load_html($nPageHTML);
$dompdf->setPaper('a4', 'portrait');
$dompdf->render();
$dompdf->stream($pagetitle.".pdf", ["Attachment" => 0]);
?>
Для скачивания доступны следующие файлы:
- Шаблон документа в Word;
- Шрифт Arial;
- Шрифт Impact;
- Шрифт Verdana;
- Рабочий комплект ttf2ufm (проверено на Windows 10).
Последнее изменение страницы 04.02.2020 18:00 MSK
|