Сайт Романа ПарпалакаЗаметкиТехнологииВеб-разработкаОфлайн-версия сайта, или PDF и PHP

Офлайн-версия сайта, или PDF и PHP

22 февраля 2008 года

Недавно я сделал офлайновую версию статей с written.ru. Технически это pdf-файл размером немногим больше мегабайта, который автоматически генерируется на сервере. Включает тексты статей и картинки к ним. Обновляется по мере появления новых статей. Ниже — подробности о том, как это работает.


В некоторых случаях посетителям того или иного сайта было бы удобнее воспользоваться офлайн-версией, которую можно скачать на локальный компьютер. «Счастливые» обладатели модемов, а также вовремя не заплатившие за интернет пользователи сказали бы за офлайн-версии некоторых сайтов «спасибо».

CHM

Один из возможных вариантов создания офлайновых версий сайтов основан на использовании формата CHM (см., например, заметку Дмитрия Смирнова). CHM (или Microsoft HTML Help) — формат файлов справки Windows 98. Однако он оказался удачным не только для справочных систем приложений, но и для всевозможных учебников и документаций, которых расплодилось великое множество. Хотя ребята из Microsoft вскоре придумали для справки другой формат, CHM они поддерживают до сих пор. Также были созданы программы, читающие CHM под Linux.

В этом варианте сначала необходимо сохранить весь HTML, отдаваемый браузерам, в файлы, а потом, вместе с картинками и CSS, скомпилировать один-единственный CHM-файл. Такая процедура имеет ряд преимуществ:

Конечно, имеется и ряд недостатков, к которым можно добавить следующие:

Однако самый главный недостаток — отсутствие компиляторов CHM, работающих под Linux. Это значит, что полной автоматизации при создании офлайновой версии добиться нельзя. На локальном компьютере с Windows нужно хранить копию сайта, компилировать CHM и закачивать его на сервер (выбирать Windows-хостинг только из-за возможности генерировать CHM-файлы особого смысла нет).

PDF

В связи с указанными недостатками логично подобрать для офлайновой версии другой формат. Один из возможных — PDF. Как следует из его названия (Portable Document Format), у пользователей любых компьютеров и операционных систем не должно быть проблем с чтением файлов PDF. Этот формат поддерживает ряд возможностей, которые в принципе позволяют сделать офлайн-версию сайтов. Файлы PDF могут содержать текстовую и графическую информацию, внутренние и внешние гиперссылки, закладки, позволяющие организовать древовидную систему разделов. Давайте посмотрим, как это всё выглядит на практике.

Для работы с PDF-файлами в PHP есть интерфейс к библиотеке PDFlib. Однако этой библиотеки может не быть на сервере. Да и лицензия, по которой она распространяется, ограничивает ее применение. Из других вариантов можно отметить класс FPDF. Этот класс позволяет создавать PDF-файлы напрямую из PHP без дополнительных библиотек. Он содержит простейшие инструкции по выводу форматированного текста и графики. Например, вывести такую-то строку таким-то шрифтом, начиная с определенной позиции. К сожалению, никакого намека на поддержку HTML в FDPF нет. Однако примеры из документации работают правильно, и это не может не вдохновлять на дальнейшие поиски.

Чтобы использовать FPDF для наших целей, к нему нужно добавить парсер HTML. Самому писать такой парсер не хотелось, и я решил воспользоваться уже существующими разработками. Наиболее перспективной оказалась HTML2FPDF 3.0 beta. Это расширение класса FPDF, дополняющее его парсером HTML, поддержкой картинок GIF (сам FPDF поддерживает только PNG и JPEG) и рядом других небольших улучшений. Однако на практике выяснилось, что это действительно «beta». Мне пришлось покопаться в коде и исправить достаточное количество багов, прежде чем скрипты заработали более-менее приемлемо.

Поговорим теперь об особенностях расширения HTML2FPDF. Заявлено, что оно поддерживает HTML и частично CSS, однако на самом деле эта поддержка очень ограничена:

Это означает, что исходный HTML нужно подвергнуть определенным преобразованиям: заменить такие теги, как small и blockquote на i. Однако здесь тоже не всё так просто. Внутри строчного тега i не может находиться несколько параграфов — блочных тегов p (курсивом выделится только первый), поэтому содержимое каждого тега p из blockquote следует заключить в тег i.

Далее, поскольку мы собрались объединить в одном документе несколько статей, следует определенным образом разграничить внутренние ссылки на статьи в том же документе от внешних ссылок. Во-первых, все относительные пути в ссылках нужно превратить в пути, начинающиеся от корня веб-сервера. Значения атрибутов HREF во внутренних ссылках нужно поменять на #N, а заголовки статей разметить якорями: <a name="N"><h1>Заголовок</h1></a>. Для картинок, в отличие от ссылок, в атрибуты SRC нужно записать абсолютные пути, так как значения этих атрибутов будут передаваться функции fopen(). Вообще-то, HTML2FPDF вроде как должен сам разбираться с относительными путями, но я решил перестраховаться и предварительно преобразовать все пути.

Еще нужно осветить вопрос о поддержке кириллицы. По умолчанию в FPDF поддерживается кодировка cp1252 для шрифтов Times, Arial, Courier. Однако использовать можно любой шрифт TrueType или Type1, причем поддержка кириллической кодировки cp1251 тоже имеется. Шрифт можно либо встроить в документ, либо нет, рассчитывая на то, что он будет установлен у пользователя в системе.

Вкратце процедура добавления шрифтов заключается в следующем. При помощи утилиты ttf2pt1 из файлов шрифтов .ttf генерируются файлы с расширением .amf. Затем скриптом font/makefont/makefont.php (из папки с FPDF) из AMF-файлов создаются файлы с описанием шрифтов для FPDF с расширением .php, а также из .ttf — сжатые шрифты с расширением .z. Файл с расширением .php необходимо поместить в папку font в папке FPDF. Если туда же поместить и файл с расширением .z, то при создании PDF-файла шрифт будет встроен в него.

Следует отметить, что все необходимые файлы можно сгенерировать онлайн, используя сервис fPDF Font File Converter. Подробнее с тонкостями добавления новых шрифтов можно ознакомиться на сайте FPDF.

В конструкторе класса HTML2FPDF (функция HTML2FPDF() в файле html2fpdf.php) необходимо зарегистрировать каждый добавленный шрифт вызовом функции AddFont('FontName','','font.php'). Потом на этот шрифт можно переключаться функцией SetFont('FontName'). Если вы хотите изменить основной шрифт, поменяйте его название внутри всех вызовов функции SetFont() в файле html2fpdf.php. Не забывайте, что курсивный, полужирный и полужирный курсивный шрифты хранятся в отдельных файлах. Все эти файлы нужно добавлять в FPDF.

FPDF поддерживает закладки (bookmarks). Многоуровневые закладки позволяют с легкостью делать древовидное меню. Однако нужно учитывать одну деталь — русские символы должны быть в кодировке UTF-16. Вот как выглядит дерево закладок для нашего примера (о нем еще пойдет речь):

Закладки в PDF

В программах просмотра PDF-файлов обычно есть возможность поиска. К сожалению, Adobe Reader не может искать русский текст, но это проблемы исключительно данного продукта. В Foxit Reader, например, с поиском всё в порядке.

Что касается быстродействия, то у рассматриваемого метода с ним не всё в порядке. При большом объеме HTML (особенно, с картинками) время работы скрипта может превысить лимит в 30 секунд. Однако это не является непреодолимой трудностью, в случае необходимости можно прибегнуть к методу разделенных вычислений. Этот метод описан в книге Дмитрия Котерова «Самоучитель PHP 4», вкратце его суть заключается в выполнении небольшой части долгих вычислений и сохранении в файл промежуточных результатов после каждого обращения к страницам сайта.

В заключение приведем пошаговую инструкцию для тех, кто решит воспользоваться описанным здесь методом создания PDF-файлов на сервере из HTML.

  1. Скачайте и установите класс FPDF, ознакомьтесь с ним, посмотрите, достаточно ли вам его возможностей. Он хорошо документирован, и к нему прилагаются примеры использования.
  2. Для использования русского языка добавьте необходимые шрифты, как было описано выше. Чаще всего одного шрифта вроде Times будет вполне достаточно.
  3. Изменения и исправления. В HTML2FPDF используется не оригинальный, а измененный класс FPDF. Но последняя версия HTML2FPDF — «бета», выпущенная в 2005 году. Мне пришлось исправить некоторые ошибки как в самом расширении HTML2FPDF, так и в дополнениях к FPDF, сделанных автором этого расширения. Скачайте архив с исправленными файлами HTML2FPDF и поместите их в директорию FPDF (файлы с совпадающими именами нужно заменить). В этом архиве есть файл pdfsite.php. Это работающий пример, создающий офлайновую версию сайта из нескольких документов согласно описанным здесь требованиям. Вы можете взять за основу этот пример и доработать его.

Предложенный метод автоматического создания документов PDF на сервере может быть использован не только для офлайновых версий сайтов, но и для подготовки прайс-листов, текстов договоров и других документов, которые будет распечатывать пользователь.

Поделиться
Посмотрите в блоге

Читайте также


Миниатюры на PHP
В ходе разработки и обслуживания сайтов часто возникает необходимость в создании миниатюр — уменьшенных копий изображений. В тексте страницы вместо большой картинки можно поместить такую копию, являющуюся ссылкой на исходный файл.
2007
Adobe Reader
У меня давно сложилось впечатление, что Adobe Reader — тормознутая вещь. Несколько лет я использовал другую программу просмотра pdf-файлов, Foxit Reader.
2010
Латех и веб-технологии
В прошлый раз я рассказал о своем сервисе, который генерирует для веба картинки с математическими формулами на латехе.
2014
Офлайновая версия сайта
Когда-то давно я прочитал у Димы Смирнова о том, как можно использовать офлайновую версию сайта.
2009

Комментарии

#1. 27 марта 2009 года, 06:49. Жандос пишет:
Спасиб запарился с русскими буквами
нехватает тока утф
#2. 23 июля 2009 года, 19:18. Всеволод пишет:
Спасибо за статью и за исправленную либу!!!

Оставьте свой комментарий


Формулы на латехе: $$f(x) = x^2-\sqrt{x}$$ превратится в $$f(x) = x^2-\sqrt{x}$$.
Выделение текста: [i]курсивом[/i] или [b]жирным[/b].
Цитату оформляйте так: [q = имя автора]цитата[/q] или [q]еще цитата[/q].
Других команд или HTML-тегов здесь нет.