Создать pdf файл из элемента инфоблока, дать скачать пользователю, поддерживать в актуальном состоянии или отправить на e-mail.

Просмотров: 7277

Задача: при каждом посещении статьи, на сайте, нужно создавать pdf файл с ее содержимым и записывать в свойство инфоблока.

Сконвертировать HTML в PDF файл и сохранить:

Для начала, нам нужно просто сгенерировать pdf файл и сохранить. Сделать это можно несколькими способами, но при всех нужно использовать дополнительные библиотеки. Я буду использовать DOMPDF так как, с помощью него можно как угодно сверстать pdf файл, используя обычный html.

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

Pdf файл будем создавать из текста статьи. В детальном шаблоне статьи создаем файл result_modifier.php (если его еще нет) и создаем переменную с html кодом будущего pdf файла. Сверстать можете как угодно:

$articleTitle = $arResult['NAME']; // название статьи
$articleImg = base64_encode(
	file_get_contents($arResult['DETAIL_PICTURE']['SRC'])
); // картинка
$articleText = $arResult['DETAIL_TEXT']; // текст статьи
$articleID = $arResult['ID']; // ID статьи-элемента

$articleToPdf = 
'<html lang=ru><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><body>
<style type="text/css">
    * {box-sizing: border-box; margin: 0; padding: 0;}
    body {font-family: DejaVu Sans;}
    h1 {font-size: 25px; text-align: center;}
    img {margin:0px 20px; max-width: 100%;}
    p {font-size: 15px; line-height: 23px;}
</style>
<body>'.
   '<h1>' . $articleTitle  . '</h1>'.
   '<img src="data:image/jpg;base64,' . $articleImg . '" width="100%">'.
   '<p>'. $articleText . '</p>'.
'</body></html>';

Обратите внимание: картинку статьи мы преобразовали в base64 иначе она не отобразится в pdf файле.

Теперь качаем библиотеку DOMPDF и загружаем на сайт и подключаем в этом же файле (result_modifier.php). Если планируете использовать библиотеку повсеместно на сайте, можете подключить ее глобально ко всему проекту. Мне нужно только в статьях.

require_once 'ПУТЬ_КУДА_ЗАГРУЗИЛИ_DOMPDF/dompdf/autoload.inc.php';
use Dompdf\Dompdf;
$dompdf = new Dompdf();
$dompdf->loadHtml($articleToPdf);
$dompdf->setPaper('a4', 'portrait');
$dompdf->render();
$output = $dompdf->output(0);

Пояснения:

  • use Dompdf\Dompdf: подключили класс Dompdf
  • dompdf->loadHtml: загрузили наш HTML код со статьей
  • $dompdf->setPaper: установли формат бумаги в A4 с портретной ориентацией. В Dompdf много настроек, по поводу вывода. Смотрите в документации.
  • dompdf->render: запустили генерацию pdf файла.
  • $output = $dompdf->output: в переменной $output получили pdf файл возвращенный как строка.

Теперь, сохраним pdf файл в свойство инфоблока. Сделаем это методом CIBlockElement::Update.

$el = new CIBlockElement;
$PROP = array();
$PROP['ATT_PDF_FILE'] = CFile::MakeFileArray($pdfLink); // В переменной путь к созданному PDF файлу
$arUpdateArticle = Array(
  "PROPERTY_VALUES"=> $PROP,
);
$res = $el->Update($articleID, $arUpdateArticle);
Если, хотите сразу сохранить файл в произвольное место, используйте:
file_put_contents('/ПУТЬ_КУДА_СОХРАНЯЕТЕ/'.$articleTitle.".pdf", $output);

Если хотите отдать файл на скачивание сразу, используйте
$dompdf->stream($articleTitle . ".pdf");
вместо $output = $dompdf->output(0);

Если не хотите, что бы файл создавался каждый раз и пересохранялся: обверните его в проверку на наличие файла.

if (empty($arResult['PROPERTY']['ATT_PDF_FILE']['VALUE'])) {
		....
		Весь наш код
		....
	}

Соотвественно, не используйте условие- если файл нужно создавать каждый раз. Например: статья постоянно меняется и нужно держать pdf файл в актуальном состоянии.

Pdf файл будет создаваться каждый раз при открытии статьи и для каждого пользователя будет максимально актуальным.

Отправить файл на электронную почту, через почтовое событие.

Если хотите реализовать отправку файла на электронную почту, можете использовать метод CEvent::Send

Создаем почтовое событие, например: SEND_ARTICLE_PDF_FILE примерно, с таким содержанием:

Ваш файл #PDF_NAME#.pdf  во вложении к этому письму

И обработчик, в который получаем email пользователя

Event::send(array(
	"EVENT_NAME" => "SEND_ARTICLE_PDF_FILE",
	"LID" => "s1",
	"C_FIELDS" => array(
		"PDF_NAME" => $articleTitle,
		"USER_MAIL" => $userEmail // Это используем в поле "Кому"
    ),
   "FILE" => array($arResult['PROPERTY']['ATT_PDF_FILE']['VALUE']),
));

Данный метод поставит почтовое событие в очередь. Если хотите отправить вне очереди используйте Event::sendImmediate вместо Event::send

В параметр "FILE" можете передать массив ID зарегистрированных в системе файлов или полные пути до файлов - если не используете запись pdf файла в свойство элемента (или хотите приложить, еще несколько файлов).

Михаил Базаров 09.11.2023
Да, правльно нужно сделать массив из файла в а не из результата - поправил в заметке
Гость 09.11.2023
Цитата
написал:
Да, правльно нужно сделать массив из файла в а не из результата - поправил в заметке
Михаил, подскажите, а можно сохранять pdf в свойство, до этого не сохраняв его на сервере ?
Сейчас получается его надо сохранить сначала в папку, а уже потом в свойство.
Михаил Базаров 09.11.2023
Думаю так не получится, можно удалять файл после сохранения в свойство
Код
unlink('путь к файлу')
Гость 09.11.2023
Цитата
написал:
Думаю так не получится, можно удалять файл после сохранения в свойство
Код
 unlink('путь к файлу') 
Спасибо, тоже думал так сделать (рабочий вариант) 👍
Подскажите, есть ли дельные статьи по поводу верстки в pdf ?
Задача - сделать бланк заявления по гарантии товара, исходя из заполненной формы на сайте 👨‍💻
Гость 09.11.2023
Михаил, а как сделать, чтобы в свойство сохранялось оригинальное название ?
Сейчас битрикс называет файл аброкадаброй.
Михаил Базаров 09.11.2023
В настройках главного модуля попробуйте поставить галку "Сохранять исходные имена файлов"
Михаил Базаров 09.11.2023
Цитата
Гость написал:
Подскажите, есть ли дельные статьи по поводу верстки в pdf ?
Задача - сделать бланк заявления по гарантии товара, исходя из заполненной формы на сайте 👨‍💻

Там же обычный html перед сохранением. То есть наверстываете что угодно, как обычную html страницу и сохраняете с помощью domToPdf в PDF собственно.
Гость 09.11.2023
Цитата
написал:
В настройках главного модуля попробуйте поставить галку "Сохранять исходные имена файлов"
Можно это сделать только для одного конкретного инфоблока ?
Гость 11.11.2023
Цитата
Гость написал:
Цитата
написал:
В настройках главного модуля попробуйте поставить галку "Сохранять исходные имена файлов"
Можно это сделать только для одного конкретного инфоблока ?
Михаил, можете подсказать ?
Михаил Базаров 11.11.2023
Для одного конкретного не получится, попробуйте в ТП битрикс написать - может подскажут что то дельное.