PDF — формат, ставший уже стандартом. Он был изначально создан Adobe для представления текста и изображений в документе с фиксированной структурой. Давно не редкость для веб-приложений, поддерживающих скачку данных, таких как счета или отчеты, отдавать их в PDF формате. Так что в этой статье мы пройдем простую генерацию PDF документов используя PHP.
Dompdf — это отличная библиотека, способная генерировать PDF из HTML-разметки и CSS-стилей (в большинстве случаев это стили, совместимые с CSS 2.1 с поддержкой некоторых свойств CSS3). Мы можем определить, как наше содержимое должно выглядеть, используя эти знакомые технологии, и после легко конвертировать его в фиксированный документ. Также эта библиотека имеет и другие полезные и интересные функции.
Приступаем к работе
Dompdf доступен на GitHub и может быть установлен используя Composer. Установка через Composer без каких-либо ошибок часто вызывает трудности, поэтому я рекомендую просто использовать Git для установки Dompdf.
Библиотека требует PHP >= 5.0 с активированными расширениями mbstring и DOM. Также она требует несколько шрифтов, которые обычно доступны на большинстве компьютеров.
Перейдите в директорию, куда собираетесь установить библиотеку и выполните в командной строке:
git clone https://github.com/dompdf/dompdf.git
git submodule init
git submodule update
Как только мы скачали Dompdf, давайте напишем короткий пример, который сгенерирует простой PDF документ:
<?php
set_include_path(get_include_path() . PATH_SEPARATOR . "/path/to/dompdf");
require_once "dompdf_config.inc.php";
$dompdf = new DOMPDF();
$html = <<<'ENDHTML'
<html>
<body>
<h1>Hello Dompdf</h1>
</body>
</html>
ENDHTML;
$dompdf->load_html($html);
$dompdf->render();
$dompdf->stream("hello.pdf");
Для того, чтобы использовать библиотеку в проекте, мы сначала подтягиваем файл dompdf_config.inc.php, который содержит большую часть конфигурации Dompdf. Он также загружает autoloader и пользовательский файл конфигурации в котором мы можем переопределить параметры по умолчанию.
HTML-разметка передается как строка в метод load_html(). Альтернативно мы можем загрузить разметку из файла или URL, используя метод load_html_file(). Он принимает имя файла или URL веб-страницы в качестве аргумента.
Метод render() отображает HTML в PDF, и мы готовы к отдаче файла. Метод stream() отправляет результирующий PDF как вложение в браузер. Этот метод имеет необязательный второй параметр, массив опций:
- Accept-Ranges – boolean, отсылает заголовок “Accept-Ranges” (по умолчанию false).
- Attachment – boolean, отсылает заголовок “Content-Disposition: attachment” заставляя браузер отображать запрос на сохранение (по умолчанию true).
- compress – boolean, включает сжатие содержимого (по умолчанию true).
Только что мы сгенерировали очень простой PDF, но это не совсем практично. В реальности мы часто имеем требования к размеру листа, ориентации страницы, кодировке символов и т.д. Есть целый набор опций, которые мы можем установить, чтобы сделать Dompdf более подходящим для наших реальных потребностей. Все они перечислены и объяснены в файле dompdf_config.inc.php, который устанавливает им значения по умолчанию. Вы можете менять эти значения, обновляя файл пользовательской конфигурации dompdf_config.custom.inc.php. Вот некоторые из важных настроек:
- DOMPDF_DEFAULT_PAPER_SIZE – устанавливает размер листа по умолчанию для PDF-документа. Поддерживаемые размеры листов вы можете найти в файле include/cpdf_adapter.cls.php (значение по умолчанию — “letter”).
- DOMPDF_TEMP_DIR – указывает временную папку, используемую Dompdf. Убедитесь, что эта директория доступна на запись согласно настройкам вашего веб-сервера.
- DOMPDF_UNICODE_ENABLED – устанавливает, будет ли PDF использовать шрифты Unicode (по-умолчанию true).
- DOMPDF_ENABLE_REMOTE – активирует включение изображений или CSS-стилей из удалённых сайтов (по-умолчанию false).
- DEBUG_LAYOUT – устанавливает, будет ли отображена граница вокруг каждого HTML блока в PDF файле. Очень удобно для отладки макета (по умолчанию false).
Продвинутое использование
Теперь давайте немного поговорим о продвинутом использовании Dompdf. Возможно мы хотим сохранить сгенерированный PDF документ на диск, вместо того чтобы отсылать его в браузер. Вот как это делается:
<?php
$dompdf = new DOMPDF();
$dompdf->load_html($html);
$dompdf->render();
$output = $dompdf->output();
file_put_contents("/path/to/file.pdf", $output);
Вместо вызова stream(), как в прошлом примере, мы используем output(), который возвращает PDF как строку. Этот метод также принимает массив опций, но доступна лишь одна — compress (по умолчанию true).
Dompdf также позволяет нам добавлять хедер и футер к сгенерированному PDF, встраивая PHP-скрипт прямо в HTML, который он отображает. Но из-за того, что обработка произвольного кода может представлять из себя угрозу безопасности, значение конфигурации, которое отвечает за эту функциональность, по умолчанию выключено. Нам необходимо для начала установить опцию DOMPDF_ENABLE_PHP как true.
Как только мы включили выполнение встроенного PHP, объект PDF станет доступным внутри скрипта и мы сможем использовать его для манипуляций со страницей. Мы можем добавлять текст, линии, изображения, прямоугольники и т.д.
$html = <<<'ENDHTML'
<html>
<body>
<script type="text/php">
if (isset($pdf)) {
// open the PDF object - all drawing commands will
// now go to the object instead of the current page
$footer = $pdf->open_object();
// get height and width of page
$w = $pdf->get_width();
$h = $pdf->get_height();
// get font
$font = Font_Metrics::get_font("helvetica", "normal");
$txtHeight = Font_Metrics::get_font_height($font, 8);
// draw a line along the bottom
$y = $h - 2 * $txtHeight - 24;
$color = array(0, 0, 0);
$pdf->line(16, $y, $w - 16, $y, $color, 1);
// set page number on the left side
$pdf->page_text(16, $y, "Page: {PAGE_NUM} of {PAGE_COUNT}", $font, 8, $color);
// set additional text
$text = "Dompdf is awesome";
$width = Font_Metrics::get_text_width($text, $font, 8);
$pdf->text($w - $width - 16, $y, $text, $font, 8);
// close the object (stop capture)
$pdf->close_object();
// add the object to every page (can also specify
// "odd" or "even")
$pdf->add_object($footer, "all");
}
</script>
<h1>Hello Dompdf</h1>
</body>
</html>
ENDHTML;
Скрипт встроен прямо в HTML-разметку и сначала открывает объект, чтобы мы могли влиять на отображение. Вся отрисовка будет записана в этот объект и мы сможем добавить его на все выделенные страницы (хотя есть и ограничения).
Затем мы получаем реальную ширину и высоту страницы, чтобы посчитать координаты футера, который мы собираемся добавить. Также нам требуется предоставить обьект шрифта, поскольку мы добавляем текстовое содержимое. Font_Metrics::get_font() позволяет создать объект, который нам необходим. Мы также берем высоту данного шрифта из его размера используя get_font_height(), чтобы посчитать позиционирование содержимого футера. Метод get_font_width() возвращает ширину нашего текста для данного шрифта и размера, которую мы также используем в наших вычислениях.
Метод line() рисует линию из точки (X1,Y1) в точку (X2,Y2). Обратите внимание, значение цвета подставляется не совсем в RGB. Основной PDF-класс требует значения между 0 и 1, так что мы конвертируем значения RGB в эти новые значения. Чтобы получить лучшее приближение (approximation), вы можете поделить их на 255.
Мы добавляем номер для каждой страницы, используя метод page_text(), которой принимает координаты X и Y, а также текст, который будет добавлен, объект шрифта, размер шрифта и цвет. Dompdf автоматически заменяет значения для {PAGE_NUM} и {PAGE_COUNT} на каждой странице, и делает $pdf доступным для нас.
Также мы можем не использовать встроенный PHP и достигать аналогичного эффекта прямо из PHP, примерно так:
<?php
$dompdf = new DOMPDF();
$dompdf->set_paper("A4");
// load the html content
$dompdf->load_html($html);
$dompdf->render();
$canvas = $dompdf->get_canvas();
$font = Font_Metrics::get_font("helvetica", "bold");
$canvas->page_text(16, 800, "Page: {PAGE_NUM} of {PAGE_COUNT}", $font, 8, array(0,0,0));
$dompdf->stream("sample.pdf",array("Attachment"=>0));
Обратите внимание, мы размещаем код после вызова $dompdf->render() потому что мы, по существу, редактируем уже созданный PDF.
Подведем итоги
В этой статье мы обсудили простой способ конвертировать HTML в PDF используя Dompdf. Несмотря на то, что Dompdf отличная библиотека, она не является полностью универсальным решением для генерации PDF документов; она все же имеет определенные ограничения и проблемы. Dompdf не очень терпимо относится к плохо оформленному HTML и большие таблицы могут легко привести к переполнению памяти. Некоторые базовые функции CSS, такие как float не полностью поддерживаются. И вообще, поддержка CSS3 очень ограничена. Если вам необходимы функции, которые не поддерживаются в Dompdf, вам может помочь к примеру wkhtmltopdf. Тем не менее, Dompdf является очень простым и удобным инструментом для решения большинства задач по экспорту PDF.
На самом деле довольно трудно объяснить все функции библиотеки в статье вроде этой, поэтому не забудьте просмотреть документацию и исходный код, а также изучите такие полезные функции, как добавление колбэков, использование своих шрифтов и др.
Автор: NtMag1steR