个性化阅读
专注于IT技术分析

如何在Symfony 3中使用SnappyBundle(wkhtmltopdf)从HTML创建PDF

本文概述

你是否曾经尝试使用诸如DomPdf或TCPDF之类的PHP库创建带有复杂图表的PDF文件, 但这样的****任务不是吗?没有太多可用的服务器端免费库来生成图表, 而那些可用的库没有为将其作为图像嵌入到我们的PDF中创建很好的图表。

服务器端生成图表的一种替代方法是使用Javascript(客户端)生成图表。有许多Javascript库可以创建精美的图表, 你可以检索其SVG(或base64图像)并将其返回到服务器, 以将它们作为图像包含在PDF中。听起来不错且功能强大, 但是此解决方案有一个缺点。 SVG会更改, 并会根据用户显示器的分辨率或浏览器窗口的尺寸, 在稍后的PDF中引起尺寸问题。

作为解决方案, 某些Web应用程序将生成一个html视图作为对浏览器的响应(它将呈现你的花式图表), 并且用户将需要使用(并知道如何)浏览器将内容保存(或打印)为PDF 。但是, 作为用户, 你可能只想单击一个按钮即可下载PDF, 选择保存位置, 仅此而已。你不认为对像TCPDF之类的库做一件容易的事吗?

到处都是问题, 但这正是wkhtmltopdf派上用场的地方, 因为你将能够以与在网站中一样的方式编写css, html和javascript(显然有一些最小的限制), 并且PDF看起来很棒。

在本文中, 你将学习如何在symfony 3项目中实现SnappyBundle, 以及如何生成不同方式的PDF。

要求

你需要wkhtmltopdf在系统中可用并且在命令提示符下可访问。 wkhtmltopdf是一个命令行工具, 可使用Qt WebKit渲染引擎将HTML渲染为PDF和各种图像格式。它们完全”无头运行”, 不需要显示或显示服务。

  • Windows:你可以在安装区域中下载每种体系结构(x86和x64)的安装程序。尽管稍后你可以在config.yml文件中更改wkhtmltopdf可执行文件的路径, 但是建议将wkhtmltopdf用作系统上的环境变量(如果你不想为wkhtmltopdf创建环境变量, 则可以提供可执行文件的完整路径)。你可以在本文中阅读如何在Windows中创建环境变量。
  • Debian / Ubuntu:你可以使用以下命令直接在控制台中从wkhtmltopdf安装发行版:
$ sudo apt-get install wkhtmltopdf

在此处访问wkhtmltopdf的主页以获取更多信息。

1)安装和配置SnappyBundle

Snappy本身就是wkhtmltopdf转换实用程序的PHP(5.3+)包装器。它允许你使用Webkit引擎从html文档生成pdf或图像文件。 KnpSnappyBundle为你的Symfony项目提供了简单的集成。

要在你的项目中安装SnappyBundle, 请执行以下composer命令:

composer require knplabs/knp-snappy-bundle

或手动添加将软件包名称添加到你的composer.json文件中, 然后执行composer install:

{
    "require": {
        "knplabs/knp-snappy-bundle": "~1.4"
    }
}

下载完成后, 启用捆绑软件, 将以下行添加到你的内核中:

$bundles = [
    //..//
    new Knp\Bundle\SnappyBundle\KnpSnappyBundle(), ];      

最后, 你只需要在config.yml文件中添加基本配置, 即可提供并启用wkhtmltopdf的二进制路径。

请注意, 如前所述, SnappyBundle需要wkhtmltopdf才能运行, 因此在使用config.yml的二进制选项之前, 我们需要提供wkhtmltopdf可执行文件的完整路径, 否则你将面临最常见的错误之一:

退出状态代码” 1″表示出了点问题:stderr:”” stdout:””

Windows中的二进制路径

使用wkhtmltopdf的默认安装程序(和默认安装设置), 主分区的程序文件中应该有一个文件夹wkhtmltopdf / bin, 其中包含wkhtmltopdf的可执行文件, 因此你只需要提供以下示例的路径即可。

但是, 如果你使用的是自定义安装, 则只需使用二进制属性中包含wkhtmltopdf可执行文件的新安装更改路径。

# Windows configuration
knp_snappy:
    pdf:
        enabled:    true
        # If you have wkhtmltopdf as an environment variable you don't need to provide the
        # full path to the executable, use it in the same way as you use in the console
        #binary:  "wkhtmltopdf"
        binary:     "\"C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltopdf.exe\""
        options:    []
    image:
        enabled:    true
        binary:     "\"C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltoimage.exe\""
        options:    []

Linux / Unix中的二进制路径, 例如

如果使用apt-get方法安装了wkhtmltopdf, 则路径可能是:

# app/config/config.yml
knp_snappy:
    pdf:
        enabled:    true
        binary:     /usr/local/bin/wkhtmltopdf
        options:    []
    image:
        enabled:    true
        binary:     /usr/local/bin/wkhtmltoimage
        options:    []

如何更改PDF生成设置

你可以在config.yml文件中默认更改设置:

# config.yml
knp_snappy:
    pdf:
        enabled:    true
        binary:     "wkhtmltopdf"
        options:    
            no-outline: true
            page-size: LETTER
            # Recommended to set UTF-8 as default encoding :)
            encoding: UTF-8

或者使用PHP和snappy的setOption方法在控制器(或服务等)中进行动态分析:

$snappy = $this->get('knp_snappy.pdf');
$snappy->setOption('no-outline', true);
$snappy->setOption('page-size', 'LETTER');
$snappy->setOption('encoding', 'UTF-8');

你可以在本文档中看到可用于wkhtmltopdf的所有选项的完整列表。

更改生成PDF的缓存路径

Snappy默认情况下使用sys_get_temp_dir()方法来获取系统的临时文件文件夹以保存PDF, 但是你可以使用secondary_folder属性更改要更改的路径:

# app/config/config.yml
knp_snappy:
    temporary_folder: %kernel.cache_dir%/snappy

上一个示例将目标放在SF3项目的缓存文件夹中的文件夹(var / cache / snappy)。

2)例子

从Web网址渲染PDF

以下示例将以PDF格式显示我们的代码世界首页:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        $filename = 'myFirstSnappyPDF';
        $url = 'http://ourcodeworld.com';
        

        return new Response(
            $snappy->getOutput($url), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'inline; filename="'.$filename.'.pdf"'
            )
        );
    }
}

从项目URL渲染PDF(symfony路由)

在此示例中有2条路线:

sandbox_homepage:
    path:     /
    defaults: { _controller: sandboxBundle:Default:index }
    
sandbox_pdfexample:
    path:     /pdf-example
    defaults: { _controller: sandboxBundle:Default:pdf }

和控制器:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class DefaultController extends Controller
{
    public function indexAction()
    {
        return $this->render('sandboxBundle:Default:index.html.twig', [
            
        ]);
    }
    
    /**
     *  Render in a PDF the sandbox_homepage URL
     * @return Response
     */
    public function pdfAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        $filename = 'myFirstSnappyPDF';
        
        // use absolute path !
        $pageUrl = $this->generateUrl('sandbox_homepage', array(), UrlGeneratorInterface::ABSOLUTE_URL);
        
        return new Response(
            $snappy->getOutput($pageUrl), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'inline; filename="'.$filename.'.pdf"'
            )
        );
    }
}

注意:使用当前的Request对象自动检测生成绝对URL时使用的主机。从Web上下文外部(例如在控制台命令中)生成绝对URL时, 此操作无效。请参阅如何从控制台生成URL, 以了解如何解决此问题。

从twig视图的HTML渲染PDF

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        
        $html = $this->renderView('sandboxBundle:Default:template.html.twig', array(
            //..Send some data to your view if you need to //
        ));
        
        $filename = 'myFirstSnappyPDF';

        return new Response(
            $snappy->getOutputFromHtml($html), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'inline; filename="'.$filename.'.pdf"'
            )
        );
    }
}

返回PDF响应以便在浏览器中查看

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        
        $html = '<h1>Hello</h1>';
        
        $filename = 'myFirstSnappyPDF';

        return new Response(
            $snappy->getOutputFromHtml($html), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'inline; filename="'.$filename.'.pdf"'
            )
        );
    }
}

以附件形式返回PDF响应(下载响应)

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        
        $html = '<h1>Hello</h1>';
        
        $filename = 'myFirstSnappyPDF';

        return new Response(
            $snappy->getOutputFromHtml($html), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'attachment; filename="'.$filename.'.pdf"'
            )
        );
    }
}

wkhtmltopdf主要功能(和优点)的基本示例

只需按照你在浏览器中的方式工作, wkhtmltopdf将负责将其转换为pdf。在此示例中, 我们将生成具有一些基本功能的PDF, 例如javascript, svg等的用法。

<h1>{{title}}</h1>
<p>This is my awesome first PDF generated using Snappy in my Symfony 3 project.</p>
<p>UTF-8 Test : κ?σμε</p>
<p>Image : </p><br>
<img height="200" src="http://ourcodeworld.com/resources/img/ocw-empty.png"/>
<p>SVG Example : </p><br>
<div>
    <!-- Do not forget to give width and height to your svg 
        use PLAIN SVG directly (<svg>content</svg>)
        Tiger SVG EXAMPLE : https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg
    -->
</div>
<p>Canvas Example with Javascript: </p><br>
<div>
    <canvas id="myCanvas" width="300" height="200"/>
</div>
<hr>
<span id="dinamic-content"></span>
<script>
    document.getElementById("dinamic-content").innerHTML = 'This string has been appended using javascript';
    
    // Draw circle on canvas
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    ctx.beginPath();
    ctx.arc(100, 75, 50, 0, 2*Math.PI);
    ctx.stroke();
</script>

我们将使用一个简单的控制器将生成的PDF返回到浏览器:

<?php

namespace sandboxBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $snappy = $this->get('knp_snappy.pdf');
        
        $html = $this->renderView('sandboxBundle:Default:template.html.twig', array(
            'title' => 'Hello World !'
        ));
        
        $filename = 'myFirstSnappyPDF';

        return new Response(
            $snappy->getOutputFromHtml($html), 200, array(
                'Content-Type'          => 'application/pdf', 'Content-Disposition'   => 'inline; filename="'.$filename.'.pdf"'
            )
        );
    }
}

PDF输出应如下所示:

twig视图中的SnappyBundle PDF-javascript

结论

  • 你需要在计算机上安装wkhtmltopdf。 Snappy只是一个包装器, 使用几行PH​​P即可使你轻松轻松地生成PDF。如果你不是安装设置的朋友, 则可以在项目中使用wkhtmltopdf作为作曲者依赖项的”便携式”版本。
  • wkhtmltopdf允许你从Web url(或纯html)创建图像(屏幕快照), 并且SnappyBundle附带了包装器, 请在文档中详细了解此功能。
  • 多亏了wkhtmltopdf, 你可以使用Javascript修改HTML内容以生成PDF, 这非常方便, 可以使用客户端代码(如Highcharts, D3.js等库)在PDF中显示图表或图形。

玩得开心 !

赞(0)
未经允许不得转载:srcmini » 如何在Symfony 3中使用SnappyBundle(wkhtmltopdf)从HTML创建PDF

评论 抢沙发

评论前必须登录!