0,0
рейтинг
18 августа 2013 в 10:52

Разработка → Конвертируем HTML в PDF при помощи Dompdf перевод tutorial

PDF, PHP*

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-Rangesboolean, отсылает заголовок “Accept-Ranges” (по умолчанию false).
  • Attachmentboolean, отсылает заголовок “Content-Disposition: attachment” заставляя браузер отображать запрос на сохранение (по умолчанию true).
  • compressboolean, включает сжатие содержимого (по умолчанию 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.

На самом деле довольно трудно объяснить все функции библиотеки в статье вроде этой, поэтому не забудьте просмотреть документацию и исходный код, а также изучите такие полезные функции, как добавление колбэков, использование своих шрифтов и др.

Оригинал — phpmaster.com/convert-html-to-pdf-with-dompdf
Перевод: Shameer C
Александр Михайленко @NtMag1steR
карма
9,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (18)

  • +2
    Все PHP решения не годятся для генерации больших PDF, так как очень медленные и требуют невероятное количество оперативной памяти. Если у вас свой сервер — ставьте что-то типа PrinceXML. В моем проекте позволило ускорить генерацию раз в 10 и снизить потребление памяти в 2-3 раза.
  • 0
    А есть ли возможность контролировать (знать), сколько страниц PDF-файла сгенерировала эта бибилиотека?
  • +2
    Если есть возможность ставить на сервер свой софт, то одним из лучших решений будет wkhtmltopdf.
    • 0
      Перебрав в своев время несколько альтернатив, именно на wkhtmltopdf и остановился. Дергать тяжелый бинарник, конечно, иногда накладно, но конечный продукт стоит того.
      • 0
        Зато оно блин работает так, как надо. Плюс куча правильных опций (например, можно выставить нужный вам медиа, скажем print.
  • +1
    если внутри html есть изображения?
  • –1
    Не увидел заветной аббревиатуры XSL-FO. Стало быть, это какой-то унылый велосипед.
    • 0
      HTML не является подмножеством XML, так что ниодно из монструозных чудовищ сумрачного мира XML для задачи перевода HTML в PDF заведомо неприменимо.
      • 0
        Сделать из HTML валидный XML ничего не стоит.
        • 0
          Достаточно использовать XHTML.
    • 0
      В Ваших руках есть возможность исправить ситуацию, написав соответствующее дополнение и закоммитив его на Github.
  • 0
    Есть ещё mPDF для php. Может быть вы дополните статью сравнением и качеством генерации html в pdf?
    • 0
      Это перевод оригинальной статьи. Ее ценность в быстром рецепте как сделать kickstart генерации PDF средствами стандартного LAMP (даже на виртуальном хостинге). А так конечно было бы неплохо сделать и полный обзор.
  • 0
    одно время намучился с ним, пришлось очень много дописывать/переписывать(изображение, и четкое соответствие html и получаемого документа ). Размер получаемых документов меньше 650кб так и не получилось добиться.
    Как сейчас с этим дела?
    • +1
      Такая же беда была. Просто в каждый документ шрифт вкладывается, а в стандартной поставке они довольно жирные.
      Перешел с гельветики на freesans — размер одностраничного акта стал 50 кБ вместо 600.
      • +1
        Спасибо, ваш бы совет да 2 года назад. Но теперь буду знать.
        • 0
          Шрифт можно значительно уменьшить, выкинув ненужные диапазоны символов, для этого можно воспользоваться сервисом fontsquirrel для этого. Оставить только Lowercase, Uppercase, Numbers, Punctuation и указать Unicode ranges 0410-044F,0401,0451 (Cyrillic лишних символов вставляет, поэтому не советую).

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.