Формирование PDF из веб-адреса средствами PHP
Генерация PDF из URL в PHP: обзор методов
Для создания PDF-документов на основе HTML-страниц, доступных по URL, существует несколько подходов. Выбор зависит от требований к точности рендеринга, производительности и простоте интеграции. Рассмотрим основной способ и альтернативные решения.
Как создать PDF из HTML, загруженного по внешнему URL, используя встроенную PHP библиотеку?
Наиболее распространенное решение в экосистеме PHP - библиотека Dompdf или mpdf. Они принимают HTML-строку и преобразуют её в PDF. Для получения HTML по URL используется file_get_contents или cURL.
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Dompdf\Dompdf;
use Dompdf\Options;
// URL целевой страницы
$url = 'https://example.com/report';
// Получение HTML с возможностью обработки ошибок
$html = @file_get_contents($url);
if ($html === false) {
die('Не удалось загрузить URL.');
}
// Настройка Dompdf
$options = new Options();
$options->set('isRemoteEnabled', true); // Для загрузки изображений по URL
$dompdf = new Dompdf($options);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
// Вывод PDF в браузер
$dompdf->stream('document.pdf', ['Attachment' => 0]);
?>
Пояснение шагов:
- Подключение autoload для Composer.
- Загрузка HTML через file_get_contents. Для HTTPS может потребоваться настройка php.ini (allow_url_fopen=On).
- Включение опции isRemoteEnabled для обработки внешних CSS и изображений.
- Рендеринг и отправка файла пользователю.
Типичные ошибки и их решение:
- Кириллица отображается кракозябрами - используйте $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); перед loadHtml.
- Сложные CSS-стили не применяются - Dompdf ограничен в поддержке CSS3. Для точного отображения лучше использовать wkhtmltopdf или сервисы API.
- Изображения не загружаются - проверьте, что allow_url_fopen включён, или используйте cURL с настройкой User-Agent.
Как быстро получить PDF из URL без локальных библиотек?
Для задач, где не требуется собственная инфраструктура, подходят сторонние API, например Pdflayer или PDFCrowd. Они принимают URL и возвращают готовый PDF.
<?php
$apiUrl = 'https://api.pdflayer.com/api/convert?access_key=ВАШ_КЛЮЧ&document_url=' . urlencode('https://example.com');
$pdfContent = file_get_contents($apiUrl);
file_put_contents('result.pdf', $pdfContent);
echo 'PDF сохранён.';
?>
Преимущества: простота, поддержка CSS, отсутствие нагрузки на сервер. Недостатки: платные тарифы, задержки сети, ограничения по объёму.
Частая проблема: Лимит бесплатных запросов. Решение - подписка или кэширование PDF на диске.
Как конвертировать веб-страницу в PDF с максимальной точностью рендеринга?
Утилита wkhtmltopdf использует движок WebKit для рендеринга. Её можно вызвать из PHP через shell_exec или symfony/process.
<?php
$url = 'https://example.com';
$outputFile = 'page.pdf';
$command = "wkhtmltopdf --enable-local-file-access --margin-top 10 --margin-bottom 10 $url $outputFile";
$output = shell_exec(escapeshellcmd($command));
echo "PDF создан: $outputFile";
?>
Пояснение: --enable-local-file-access требуется для доступа к внешним файлам. Для Windows путь к исполняемому файлу нужно указывать полностью.
Ошибка wkhtmltopdf not found - установите утилиту на сервер. На Ubuntu: sudo apt-get install wkhtmltopdf. Для работы с HTTPS может потребоваться обновление до версии с поддержкой SSL.
Как создать PDF из HTML-кода с полным контролем над структурой документа?
Библиотека TCPDF позволяет вручную добавлять ячейки, линии, изображения, но не поддерживает прямой парсинг сложного HTML. Можно скомбинировать её с простым парсингом для извлечения данных из URL.
<?php
require_once 'tcpdf/tcpdf.php';
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetFont('dejavusans', '', 12);
$pdf->AddPage();
// Получаем содержимое URL (например, через file_get_contents)
$html = file_get_contents('https://example.com/invoice');
// TCPDF понимает базовый HTML, но не CSS
$pdf->writeHTML($html, true, false, true, false, '');
$pdf->Output('invoice.pdf', 'I');
?>
Ограничение: большинство CSS-свойств игнорируются. Подходит для простых текстовых документов.
Проблема: Неверное отображение таблиц. Решение - использовать методы TCPDF для ручного построения таблиц.
Расширенные примеры и нестандартные случаи
Пример 1: Dompdf с кэшированием HTML и обработкой кириллицы
<?php
require 'vendor/autoload.php';
use Dompdf\Dompdf;
use Dompdf\Options;
function fetchHtml($url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
$html = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
// Перекодировка в UTF-8
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
return $html;
}
try {
$html = fetchHtml('https://example.com/document');
$options = new Options();
$options->set('isHtml5ParserEnabled', true);
$options->set('isRemoteEnabled', true);
$options->set('defaultFont', 'DejaVu Sans');
$dompdf = new Dompdf($options);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'landscape');
$dompdf->render();
// Сохранить в файл
file_put_contents('output.pdf', $dompdf->output());
echo 'PDF сгенерирован.';
} catch (Exception $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>
Результат:
PDF сгенерирован в файл output.pdf. Для страниц с кириллицей используется шрифт DejaVu Sans, что исключает проблему квадратов.
Пример 2: Использование wkhtmltopdf с опциями настройки
<?php
$url = 'https://example.com/long-report';
$output = '/tmp/report.pdf';
// Команда с детальными параметрами
$cmd = sprintf(
'wkhtmltopdf --page-size A4 --orientation Landscape --margin-top 15mm --margin-bottom 15mm --footer-left "[page]" --footer-right "[date]" %s %s 2>&1',
escapeshellarg($url),
escapeshellarg($output)
);
$result = shell_exec($cmd);
echo $result; // Вывод возможных ошибок
if (file_exists($output)) {
echo "Файл создан: $output";
}
?>
Результат:
Файл создан: /tmp/report.pdf. Документ содержит нумерацию страниц и дату в подвале.
Пример 3: Работа с внешними изображениями в Dompdf через base64
<?php
// Если изображение не загружается, можно встроить его в HTML как base64
$imageData = base64_encode(file_get_contents('https://example.com/logo.png'));
$html = '<img src="data:image/png;base64,' . $imageData . '" width="200">';
// Далее стандартный рендеринг Dompdf
?>
Результат:
Изображение отображается в PDF без внешних запросов, что полезно при отключённом isRemoteEnabled.
Пример 4: Использование mpdf с защитой паролем
<?php
require_once __DIR__ . '/vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf(['mode' => 'utf-8', 'format' => 'A4']);
$html = file_get_contents('https://example.com/confidential');
$mpdf->WriteHTML($html);
// Установить пароль на открытие
$mpdf->SetProtection(['copy', 'print'], 'user123', 'owner123');
$mpdf->Output('secure.pdf', 'D');
?>
Результат:
Скачиваемый PDF защищён паролем. При открытии запрашивается пароль 'user123'.