Печатная форма и PDF - шаблон печати, генерация файла, отдача
Делаем печать заказа и счёта: отдельная страница с пустым шаблоном, стили печати, сборка PDF библиотекой и проверка прав на документ.
Что нужно знать заранее
Печать из браузера и файл PDF - это две разные задачи с общим шаблоном. Первая дешевле и часто достаточна, вторая нужна там, где документ отправляют письмом или прикладывают к заказу.
Готовой печатной формы под произвольный документ в поставке нет. Собирают её сами: страница с данными, стили печати и, если нужен файл, библиотека сборки PDF из состава проекта.
Печатная форма показывает данные заказа, поэтому доступ к ней закрывают. Адрес вида «страница печати плюс номер заказа» перебирается за минуту, и чужой документ не должен открываться никому.
Шаги
- Завести отдельную страницу печати и подключить к ней пустой шаблон сайта.
- Проверить на этой странице права: документ видит владелец и сотрудник магазина.
- Собрать разметку документа и описать для неё стили печати.
- Добавить сборку файла PDF, если документ уходит письмом или в архив.
- Проверить кириллицу, разрывы страниц и картинки в готовом файле.
Решение
Делаем страницу печати с пустым шаблоном:
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/header.php';$APPLICATION->SetPageProperty('title', 'Заказ №' . $orderId);$APPLICATION->SetTemplate('print'); // пустой шаблон: без меню, шапки и подвалаОтдельный шаблон печати избавляет от борьбы со стилями сайта. В нём остаётся только разметка документа, а меню, баннеры и подвал не попадают на бумагу вообще.
Проверяем права на документ:
$order = \Bitrix\Sale\Order::load($orderId);if (!$order || ($order->getUserId() !== $USER->GetID() && !$USER->IsAdmin())) { \Bitrix\Main\Application::getInstance()->getContext() ->getResponse()->setStatus('403 Forbidden'); return; // чужой заказ по подобранному номеру открываться не должен}Проверка прав на печатной форме обязательна и делается до вывода разметки. Ссылку на печать посетитель получает из своего кабинета, но открыть адрес можно и напрямую, подставив чужой номер.
Описываем стили для печати:
@media print { .no-print { display: none; } /* кнопки и подсказки на бумагу не идут */ table { page-break-inside: avoid; } /* таблица не рвётся посередине строки */ body { font-size: 12pt; color: #000; }}Стили печати решают половину задач без всякого PDF. Посетитель нажимает печать в браузере и получает аккуратный документ, а разработчик экономит на библиотеке и её шрифтах.
Собираем файл PDF из той же разметки:
require $_SERVER['DOCUMENT_ROOT'] . '/local/vendor/autoload.php';$pdf = new \Dompdf\Dompdf(['defaultFont' => 'dejavu sans']); // шрифт с кириллицей$pdf->loadHtml($html);$pdf->render();file_put_contents($path, $pdf->output()); // файл сохраняем, а не отдаём сразуБиблиотека сборки PDF приходит в проект менеджером зависимостей и живёт в своём каталоге. Шрифт с поддержкой кириллицы указывают явно: со шрифтом по умолчанию русский текст превращается в квадраты.
Отдаём готовый файл посетителю:
header('Content-Type: application/pdf');header("Content-Disposition: attachment; filename*=UTF-8''" . rawurlencode('Заказ-' . $orderId . '.pdf'));readfile($path); // имя с кириллицей отдают кодированным заголовкомИмя файла с русскими буквами передают кодированным вариантом заголовка. Иначе браузер сохраняет документ под именем из случайных символов, и покупатель не находит его в загрузках.
Типичные проблемы
В готовом файле вместо русского текста квадраты.
Взят шрифт по умолчанию без поддержки кириллицы. Шрифт с русскими буквами подключают явно и кладут рядом с проектом.
На бумагу выводятся меню, баннеры и подвал сайта.
Печать идёт с обычной страницей сайта без стилей печати. Лишние блоки скрывают правилами для печати или выносят документ на отдельный шаблон.
Чужой заказ открывается подстановкой номера в адрес.
Печатная форма отдаётся без проверки владельца документа. Права проверяют до вывода разметки, а не в шаблоне.
Сборка файла заметно тормозит сайт.
Документ собирается заново на каждый запрос страницы печати. Готовый файл сохраняют и отдают повторно, а тяжёлые документы собирают фоновым заданием.
Картинки не попали в готовый файл.
В разметке указаны адреса, недоступные библиотеке сборки. Картинки подключают локальными путями к файлам на диске сервера.
Частые вопросы
Нужен ли PDF, если есть печать из браузера?
Не всегда: для печати на месте хватает стилей печати. Файл нужен там, где документ отправляют письмом, прикладывают к заказу или хранят.
Какую библиотеку выбрать для PDF?
Любую поддерживаемую с нормальной работой с кириллицей и таблицами. Ставят её менеджером зависимостей в каталог проекта, а не копируют файлами.
Где хранить готовые файлы документов?
В закрытом каталоге вне корня сайта, с отдачей через свой скрипт. Так документ не откроется по прямой ссылке случайному посетителю.
Как сделать печать нескольких документов сразу?
Собрать один файл из нескольких документов подряд с разрывами страниц. Пакетную сборку выносят в фоновое задание: она долгая и тяжёлая.
Можно ли печатать из административного раздела?
Да, ссылку на печать добавляют в карточку заказа своим кодом. Права там проверяет платформа, а разметка используется та же.
Смежное
- Файлы в коде - оглавление подтемы
- Выгрузка в Excel из кода: библиотека, объём, отдача файла - соседний формат документа
- Отдача файла с проверкой прав: скачивание мимо каталога - как закрывают готовые файлы
- Файлы из кода: сохранение, уменьшенные копии, удаление - хранение файлов проекта
- Личный кабинет покупателя: список заказов, повтор и отмена - откуда покупатель печатает заказ
- Composer в проекте на 1С-Битрикс - как ставят такие библиотеки
- Ядро D7 - устройство ядра целиком