PHP
Gerando PDF com Snappy

Nesse tutorial irei ensinar como gerar PDF no PHP utilizando a biblioteca Snappy da KnpLabs.
Sobre a Snappy
O Snappy é uma biblioteca PHP (5+) para geração de thumbnail, snapshot ou PDF de uma URL ou página HTML. Funciona como um wrapper sobre o wkhtmltopdf (que também tem a wkhtmltoimage).
O wkhtmltopdf é uma ferramenta de linha de comando Open-source (LGPLv3) que utiliza o motor QT WebKit (motor do Chrome, Safari, Opera e etc), para conversão/renderização de HTML em PDF ou imagens. E funciona em Linux, OSX e Windows.
Então para o Snappy funcionar, você precisa instalar ele no seu sistema operacional.
Instalação
Levando em consideração que possua conhecimento sobre como utilizar o Composer e que possua-o instalado, vamos instalar o Snappy:
composer require knplabs/knp-snappy
Se possuir alguma necessidade de ter o Snappy sem utilizar o Composer, pode baixar do repositório deles no Github: https://github.com/KnpLabs/snappy. Mas não ensinarei como fazer autoloader nesse caso.
Utilização do Snappy
Após a instalação do Snappy, você terá a biblioteca na sua pasta vendor e integrada ao autoloader do Composer. Então basta incluir o autoloader onde deseja utilizar e terá acesso as classes do Snappy.
Configuração
Para a efetiva utilização do Snappy, devemos configurar o caminho para o wkhtmltopdf que será utilizado para conversão para PDF e imagens.
Levando em consideração que você já possui o wkhtmltopdf instalado e sabe o caminho para ele, então vamos configurar!
Vamos supor que o caminho seja: /usr/local/bin/wkhtmltopdf
A passagem do caminho para o wkhtmltopdf pode ser feita via construtor
ou pelo método setBinary
da classe Knp\Snappy\Pdf
:
<?php
require_once 'vendor/autoload.php'; // Ou seu autoloader
use Knp\Snappy\Pdf;
$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');
Ou
<?php
require_once 'vendor/autoload.php'; // Ou seu autoloader
use Knp\Snappy\Pdf;
$snappy = new Pdf();
$snappy->setBinary('/usr/local/bin/wkhtmltopdf');
Com a configuração concluída, vamos testar várias situações.
Gerar PDF de uma URL e abrir no próprio navegador
Aqui será gerado um PDF com o conteúdo da página principal do blog da School of Net e irá abrir o mesmo na janela do navegador:
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Pdf;
$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');
// Cabeçalho para o navegador entender que o conteúdo é um PDF
header('Content-Type: application/pdf');
echo $snappy->getOutput('http://www.schoolofnet.com/blog/');
Gerar PDF com conteúdo de várias URLs e abrir no próprio navegador
Aqui será gerado um único PDF com o conteúdo de várias URLs, que são de 4 artigos do blog da School of Net:
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Pdf;
$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');
// Cabeçalho para o navegador entender que o conteúdo é um PDF
header('Content-Type: application/pdf');
echo $snappy->getOutput(
[
'http://www.schoolofnet.com/2015/07/trabalhando-com-repository-no-laravel/',
'http://www.schoolofnet.com/2015/04/como-usar-os-metodos-magicos-no-php/',
'http://www.schoolofnet.com/2015/04/enviando-emails-utilizando-swift-mailer/',
'http://www.schoolofnet.com/2015/04/instalando-e-integrando-apache-com-php-no-windows/',
]
);
Gerar PDF a partir de um HTML e abrir no próprio navegador
Aqui será gerado um PDF com o conteúdo de um HTML, vindo de uma variável, e será mostrado no navegador:
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Pdf;
$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');
// Cabeçalho para o navegador entender que o conteúdo é um PDF
header('Content-Type: application/pdf');
$html = <<<'EOD'
<h1>Relatório</h1>
<br/>
<table width="100%">
<thead>
<tr>
<th>Nome</th>
<th>E-mail</th>
<th>Telefone</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fulano da Silva</td>
<td>[email protected]</td>
<td>11 99999-8888</td>
</tr>
<tr>
<td>Sicrano Santos</td>
<td>[email protected]</td>
<td>11 99999-7777</td>
</tr>
<tr>
<td>João das Botas</td>
<td>[email protected]</td>
<td>11 99999-6666</td>
</tr>
</thead>
</table>
EOD;
$snappy->getOutputFromHtml($html, ['encoding' => 'UTF8']);
Gerando imagens PNG ao invés de PDF
Se deseja ao invés de gerar PDF, deseje que sejá uma imagem PNG, temos que:
- Mudar a classe de
use Knp\Snappy\Pdf
parause Knp\Snappy\Image
; - Utilizar o wkhtmltoimage ao invés do wkhtmltopdf;
Vamos considerar que o caminho para o wkhtmltoimage seja: /usr/local/bin/wkhtmltoimage.
Gera imagem PNG de uma URL e mostra no navegador
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Image;
$snappy = new Image('/usr/local/bin/wkhtmltoimage', ['format' => 'png']);
$snappy->setDefaultExtension('png');
// Cabeçalho para o navegador entender que o conteúdo é uma imagem PNG
header('Content-Type: image/png');
echo $snappy->getOutput('http://www.schoolofnet.com/blog/');
Gera imagem PNG de várias URLs e mostra no navegador
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Image;
$snappy = new Image('/usr/local/bin/wkhtmltoimage', ['format' => 'png']);
$snappy->setDefaultExtension('png');
// Cabeçalho para o navegador entender que o conteúdo é uma imagem PNG
header('Content-Type: image/png');
echo $snappy->getOutput(
array(
'http://www.schoolofnet.com/2015/07/trabalhando-com-repository-no-laravel/',
'http://www.schoolofnet.com/2015/04/como-usar-os-metodos-magicos-no-php/',
'http://www.schoolofnet.com/2015/04/enviando-emails-utilizando-swift-mailer/',
'http://www.schoolofnet.com/2015/04/instalando-e-integrando-apache-com-php-no-windows/',
)
);
Gera imagem PNG a partir de um HTML e mostra no navegador
<?php
require_once 'vendor/autoload.php';
use Knp\Snappy\Image;
$snappy = new Image('/usr/local/bin/wkhtmltoimage', ['format' => 'png']);
$snappy->setDefaultExtension('png');
// Cabeçalho para o navegador entender que o conteúdo é uma imagem PNG
header('Content-Type: image/png');
$html = <<<'EOD'
<h1 style="color: red;">Relatório</h1>
<br/>
<table width="100%">
<thead>
<tr>
<th>Nome</th>
<th>E-mail</th>
<th>Telefone</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fulano da Silva</td>
<td>[email protected]</td>
<td>11 99999-8888</td>
</tr>
<tr>
<td>Sicrano Santos</td>
<td>[email protected]</td>
<td>11 99999-7777</td>
</tr>
<tr>
<td>João das Botas</td>
<td>[email protected]</td>
<td>11 99999-6666</td>
</tr>
</thead>
</table>
EOD;
echo $snappy->getOutputFromHtml($html, ['encoding' => 'UTF8']);
Observação
Em todos os casos, se quisermos, ao invés de gerar o PDF e mostrar no navegador, que seja gerado e salvo em arquivo no próprio servidor, devemos:
- Remover os cabeçalhos que força o navegador a entender que é PDF o conteúdo retornado;
- Trocar os métodos
getOutput
egetOutputFromHtml
porgenerate
egenerateFromHtml
, respectivamente. Sendo que os métodos aceitam um segundo parâmetro obrigatório, que é o caminho completo pra o arquivo que será gerado com o conteúdo:
Gerar PDF de uma URL e salva no servidor
<?php
// Código anterior, sem o getOutput(...);
$snappy->generate('http://www.schoolofnet.com/blog/', '/app/arquivos/son/home-blog.pdf');
Gerar PDF com conteúdo de várias URLs e salva no servidor
<?php
// Código anterior, sem o getOutput(...);
$snappy->generate(
[
'http://www.schoolofnet.com/2015/07/trabalhando-com-repository-no-laravel/',
'http://www.schoolofnet.com/2015/04/como-usar-os-metodos-magicos-no-php/',
'http://www.schoolofnet.com/2015/04/enviando-emails-utilizando-swift-mailer/',
'http://www.schoolofnet.com/2015/04/instalando-e-integrando-apache-com-php-no-windows/',
],
'/app/arquivos/son/artigos.pdf'
);
Gerar PDF a partir de um HTML e salva no servidor
<?php
// Código anterior, sem o getOutputFromHtml(...);
$snappy->generateFromHtml($html, '/app/arquivos/relatorios/relatorio.pdf', ['encoding' => 'UTF8']);
Em todos os casos onde ser abre o arquivo no navegador, se quisermos ao invés de mostrar no navegador que seja forçado o download do arquivo, colocamos o cabeçalho de Content-Disposition: attachment;, assim:
- Se for PDF:
header('Content-Disposition: attachment; filename="schoolofnet-blog-home.pdf"');
- Se for Imagem:
header('Content-Disposition: attachment; filename="schoolofnet-blog-home.png"');
Bastando somente modificar o valor do parâmetro filename, para o nome que deseja com a extensão equivalente ao que está no cabeçalho Content-Type.
Considerações finais
Com o Snappy facilita a geração de PDF ou até imagens/snapshot de páginas, mas também serve tranquilamente para relatório. Basta considerar em gerar o html do relatório e passar para o Snappy ou até mesmo o relatório está em uma URL e você passar a URL para ele. Todo o CSS será considerado. Caso tenha versão de CSS para o media-type print, basta passar no $option a opção para forçar esse media-type. Veja na classes classes use Knp\Snappy\Pdf
ou use Knp\Snappy\Image
como fazer, mas as opções são do próprio wkhtmltopdf, bastando dá o comando dele com o -H e terá acesso a documentação.
Existe outra biblioteca que faz wrapper no wkhtmltopdf, caso deseje saber alternativas: phpwkhtmltopdf.
No packagist existem pacotes para diversos frameworks: