Генерация PDF в PHP: от простых HTML до сложных отчётов
Генерация PDF в PHP: обзор подходов
Создание PDF-документов на серверной стороне - часто встречающаяся задача в веб-разработке. PHP предоставляет несколько библиотек и методов, каждая из которых подходит для определённых сценариев. Ниже рассмотрены основные варианты, начиная с наиболее универсального и простого в освоении.
Как сгенерировать PDF из HTML с минимальными усилиями?
Наиболее эффективное решение - использование библиотеки Dompdf. Она преобразует HTML+CSS в PDF, поддерживает большинство стандартных стилей, шрифты (включая кириллицу) и легко интегрируется с любым PHP-проектом.
// Установка через Composer
composer require dompdf/dompdf
<?php
require 'vendor/autoload.php';
use Dompdf\Dompdf;
$html = '<h1 style="color: #2c3e50;">Привет, мир!</h1>
<p>Это PDF, созданный из HTML.</p>
<table border="1" width="100%">
<tr><td>Ячейка 1</td><td>Ячейка 2</td></tr>
</table>';
$dompdf = new Dompdf();
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$dompdf->stream('document.pdf', ['Attachment' => 1]); // 1 - скачать, 0 - открыть в браузере
?>
После выполнения кода пользователю будет предложено скачать PDF-файл. Объект Dompdf загружает HTML, устанавливает размер страницы, рендерит содержимое и отправляет результат в поток.
Типичные проблемы и их решение:
- Не отображаются кириллические символы. Добавьте вызов
$dompdf->set_option('isFontSubsettingEnabled', true);и укажите шрифт, поддерживающий кириллицу (например, DejaVu Sans). - Большие объёмы HTML приводят к ошибке памяти. Увеличьте лимит памяти в PHP:
ini_set('memory_limit', '256M'); - CSS-свойства (Flexbox, Grid) игнорируются. Dompdf не поддерживает современные CSS-макеты; используйте табличную вёрстку или позиционирование через float/absolute.
Как создать PDF с нуля без HTML?
Если требуется полный контроль над содержимым (позиции, шрифты, графика), лучше подходит библиотека FPDF. Она работает без внешних зависимостей, но не умеет парсить HTML.
<?php
require_once 'fpdf/fpdf.php';
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40,10,'Текст в ячейке');
$pdf->Output('F','file.pdf'); // Сохранить в файл
?>
Проблема: FPDF не поддерживает кириллицу по умолчанию - требуется подключение внешнего шрифта или использование UTF-8 через AddFont. Рекомендуется скачать шрифт DejaVu и добавить его.
Как создать PDF с поддержкой Unicode и сложной верстки?
Библиотека TCPDF - расширенная альтернатива FPDF. Она поддерживает HTML-теги, Unicode, работу с изображениями, водяные знаки, нумерацию страниц и многое другое.
<?php
require_once 'tcpdf/tcpdf.php';
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8');
$pdf->SetCreator('My App');
$pdf->AddPage();
$pdf->writeHTML('<h2>Заголовок</h2><p>Простой HTML.</p>');
$pdf->Output('example.pdf', 'I'); // I - вывод в браузер
?>
Ошибки: Если HTML не отображается корректно, проверьте закрытие тегов и используйте только теги, поддерживаемые TCPDF (<h1>–<h6>, <p>, <table>, <br>, <b> и т.д.).
Как легко конвертировать HTML в PDF с помощью готовой обертки?
Библиотека HTML2PDF построена на основе TCPDF и предоставляет более удобный интерфейс для конвертации HTML.
<?php
require_once 'html2pdf/vendor/autoload.php';
use Spipu\Html2Pdf\Html2Pdf;
$html2pdf = new Html2Pdf('P', 'A4', 'fr');
$html2pdf->writeHTML('<h1>Документ</h1>');
$html2pdf->output('test.pdf');
?>
Как не нагружать сервер и генерировать PDF через облачный сервис?
Если требуется снизить нагрузку на хостинг или нужны продвинутые функции (конвертация сложных макетов, большие объёмы данных), можно воспользоваться внешними API (например, PDF Generator API или DocRaptor).
<?php
// Пример запроса к PDF Generator API
$html = '<h1>Отчёт</h1>';
$postData = ['html' => $html];
$ch = curl_init('https://api.pdfgeneratorapi.com/v1/templates/...');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$result = curl_exec($ch);
curl_close($ch);
// $result содержит PDF
?>
Проблема: Зависимость от внешнего сервиса (доступность, скорость, стоимость). Подходит для проектов, где стабильность не критична или есть бюджет.
Расширенные примеры генерации PDF
1. Сложный отчёт с изображением, таблицей и водяным знаком (Dompdf)
В этом примере используется Dompdf для создания многостраничного документа с логотипом, таблицей данных и водяным знаком.
<?php
require_once 'vendor/autoload.php';
use Dompdf\Dompdf;
use Dompdf\Options;
// Настройка опций
$options = new Options();
$options->set('isRemoteEnabled', true); // для загрузки изображений по URL
$dompdf = new Dompdf($options);
$html = '<html>
<body>
<div style="text-align: center;">
<img src="logo.png" width="150">
<h2>Ежемесячный отчёт</h2>
</div>
<table border="1" cellpadding="5" width="100%">
<thead>
<tr style="background-color: #4CAF50; color: white;">
<th>Показатель</th><th>Значение</th>
</tr>
</thead>
<tbody>
<tr><td>Выручка</td><td>1 200 000 руб.</td></tr>
<tr><td>Расходы</td><td>800 000 руб.</td></tr>
<tr><td>Прибыль</td><td>400 000 руб.</td></tr>
</tbody>
</table>
<p style="page-break-before: always;">Вторая страница с водяным знаком.</p>
<div style="position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); opacity: 0.1; font-size: 80px;">КОНФИДЕНЦИАЛЬНО</div>
</body>
</html>';
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$dompdf->stream('report.pdf', ['Attachment' => 0]);
?>
Результат: сгенерированный PDF содержит две страницы: первая - с таблицей и логотипом, вторая - с водяным знаком. Файл открывается в браузере (Attachment = 0).
2. Создание PDF с нуля, используя FPDF и пользовательский шрифт
Пример демонстрирует добавление кириллического шрифта, рисование линий и использование изображения.
<?php
require_once 'fpdf/fpdf.php';
class PDF extends FPDF
{
function Header()
{
$this->Image('logo.png',10,6,30);
$this->SetFont('DejaVu','B',12);
$this->Cell(0,10,'Заголовок документа',0,1,'C');
$this->Ln(15);
}
function Footer()
{
$this->SetY(-15);
$this->SetFont('DejaVu','',8);
$this->Cell(0,10,'Страница '.$this->PageNo().'/{nb}',0,0,'C');
}
}
$pdf = new PDF();
$pdf->AliasNbPages();
$pdf->AddFont('DejaVu','','DejaVuSans.ttf',true);
$pdf->AddPage();
$pdf->SetFont('DejaVu','',14);
$pdf->Cell(0,10,'Привет, кириллица!',0,1);
$pdf->Output('F','output.pdf');
?>
Результат: PDF-файл с кириллицей, нумерацией страниц и логотипом в шапке. Файл сохраняется на сервере.
3. Генерация многостраничного PDF с помощью TCPDF и нумерация страниц
TCPDF позволяет легко добавлять колонтитулы, встроенные шрифты и управлять разрывами страниц.
<?php
require_once 'tcpdf/tcpdf.php';
class MYPDF extends TCPDF {
public function Header() {
$this->SetFont('dejavusans', 'B', 10);
$this->Cell(0, 10, 'Отчёт номер ' . $this->getAliasNumPage(), 0, 1, 'R');
}
public function Footer() {
$this->SetY(-15);
$this->SetFont('dejavusans', '', 8);
$this->Cell(0, 10, 'Страница '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, 0, 'C');
}
}
$pdf = new MYPDF('P', 'mm', 'A4', true, 'UTF-8');
$pdf->SetCreator('My App');
$pdf->SetAutoPageBreak(true, 20);
$pdf->AddPage();
$html = '<h2>Первый раздел</h2><p>Текст...</p>';
$pdf->writeHTML($html);
$pdf->AddPage();
$html2 = '<h2>Второй раздел</h2><p>Продолжение...</p>';
$pdf->writeHTML($html2);
$pdf->Output('example.pdf', 'I');
?>
Результат: двухстраничный PDF с колонтитулами на каждой странице, отображающими номер страницы и общее количество.
4. Отправка PDF в ответ на HTTP-запрос с установкой заголовков
Этот пример показывает, как правильно установить HTTP-заголовки, чтобы браузер загрузил файл.
<?php
require_once 'vendor/autoload.php';
use Dompdf\Dompdf;
$dompdf = new Dompdf();
$dompdf->loadHtml('<h1>Документ PDF</h1>');
$dompdf->render();
// Устанавливаем заголовки
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="download.pdf"');
// Можно заменить inline на attachment для принудительного скачивания
header('Content-Length: ' . strlen($dompdf->output()));
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
echo $dompdf->output();
?>
Результат: в браузере открывается PDF (inline) или предлагается скачать (attachment). Заголовки помогают корректно обработать файл на клиенте.