php使用wkhtmltopdf导出pdf

参考:史上最强php生成pdf文件,html转pdf文件方法

       http://biostall.com/wkhtmltopdf-add-header-footer-to-only-first-last-page/ 指定页面显示或者因此header和footer

        http://blog.csdn.net/sibang/article/details/38733305

wkhtmltopdf "www.baidu.com" --header-html "D:htmlToPDFApppdfheader.html" baidu.pdf
wkhtmltopdf --javascript-delay 3000 -T 0 -R 0 -L 0 -B 0 --enable-javascript --enable-plugins http://didc.iwom-trends.com/bhqkgk.aspx 88-10TEST.PDF

下载地址http://code.google.com/p/wkhtmltopdf/downloads/detail?name=wkhtmltox-0.11.0_rc1-installer.exe&can=2& --JavaScript-delay 3000 可以延迟加载(主要作用是解决页面加载不完整的现象)

延时加载js,--JavaScript-delay 3000  解决js加载不完全如下类:

<?php namespace CanGelisPDF;

use LeagueFlysystemAdapterInterface;
use LeagueFlysystemFilesystem;
class PDF {

    /**
     * Random name that will be the name of the temporary files
     *
     * @var string
     */
    protected $fileName;

    /**
     * Folder in which temporary files will be saved
     *
     * @var string
     */
    protected $folder;

    /**
     * HTML content that will be converted to PDF
     *
     * @var string
     */
    protected $htmlContent = null;

    /**
     * Params to be executed by wkhtmltopdf
     *
     * @var array
     */
    protected $params = array();

    /**
     * Input Path that will be generated to PDF Doc.
     *
     * @var string
     */
    protected $path = null;

    /**
     * PDF File's Binary content
     *
     * @var mixed
     */

    protected $contents = null;

    /**
     * Available command parameters for wkhtmltopdf
     *
     * @var array
     */
    protected $availableParams = array(
        'grayscale', 'orientation', 'page-size',
        'lowquality', 'dpi', 'image-dpi', 'image-quality',
        'margin-bottom', 'margin-left', 'margin-right', 'margin-top',
        'page-height', 'page-width', 'no-background', 'encoding', 'enable-forms',
        'no-images', 'disable-internal-links', 'disable-javascript',
        'password', 'username', 'footer-center', 'footer-font-name',
        'footer-font-size', 'footer-html', 'footer-left', 'footer-line',
        'footer-right', 'footer-spacing', 'header-center', 'header-font-name',
        'header-font-size', 'header-html', 'header-left', 'header-line', 'header-right',
        'header-spacing', 'print-media-type', 'zoom','javascript-delay'
    );

    /**
     * wkhtmltopdf executable path
     *
     * @var string
     */
    protected $cmd;

    /**
     * Initialize temporary file names and folders
     */
    public function __construct($cmd, $tmpFolder = null)
    {
        $this->cmd = $cmd;
        $this->addParam('javascript-delay',5000);//增加延时执行js,add by zhaoliang 20170215
        $this->fileName = uniqid(rand(0, 99999));

        if (is_null($tmpFolder))
        {
            $this->folder = sys_get_temp_dir();
        } else
        {
            $this->folder = $tmpFolder;
        }


    }

    /**
     * Loads the HTML Content from plain text
     *
     * @param string $html
     *
     * @return $this
     */
    public function loadHTML($html)
    {
        $this->htmlContent = $html;

        return $this;
    }

    /**
     * Loads the input source as a URL
     *
     * @param string $url
     *
     * @return $this
     */
    public function loadUrl($url)
    {
        return $this->setPath($url);
    }

    /**
     * Loads the input source as an HTML File
     *
     * @param $file
     *
     * @return $this
     */
    public function loadHTMLFile($file)
    {
        return $this->setPath($file);
    }

    /**
     * Generates the PDF and save the PDF content for the further use
     *
     * @return string
     * @throws PDFException
     */
    public function generate()
    {
        $returnVar = $this->executeCommand($output);

        if ($returnVar == 0)
        {
            $this->contents = $this->getPDFContents();
        } else
        {
            throw new PDFException($output);
        }

        $this->removeTmpFiles();

        return $this;
    }


    /**
     * Saves the pdf content to the specified location
     *
     * @param $fileName
     * @param AdapterInterface $adapter
     * @param bool $overwrite
     *
     * @return $this
     */
    public function save($fileName, AdapterInterface $adapter, $overwrite = false)
    {
        $fs = new Filesystem($adapter);

        if ($overwrite == true) {
            $fs->put($fileName, $this->get());
        } else {
            $fs->write($fileName, $this->get());
        }

        return $this;
    }

    public function get()
    {
        if (is_null($this->contents)) {
            $this->generate();
        }
        return $this->contents;
    }

    /**
     * Remove temporary HTML and PDF files
     */
    public function removeTmpFiles()
    {
        if (file_exists($this->getHTMLPath()))
        {
            @unlink($this->getHTMLPath());
        }
        if (file_exists($this->getPDFPath()))
        {
            @unlink($this->getPDFPath());
        }
    }

    /**
     * Gets the contents of the generated PDF
     *
     * @return string
     */
    public function getPDFContents()
    {
        return file_get_contents($this->getPDFPath());
    }

    /**
     * Execute wkhtmltopdf command
     *
     * @param array &$output
     *
     * @return integer
     */
    public function executeCommand(&$output)
    {
        $descriptorspec = array(
            0 => array("pipe", "r"), // stdin is a pipe that the child will read from
            1 => array("pipe", "w"), // stdout is a pipe that the child will write to
            2 => array("pipe", "w") // stderr is a pipe that the child will write to
        );

        $process = proc_open($this->cmd . ' ' . $this->getParams() . ' ' . $this->getInputSource() . ' ' . $this->getPDFPath(), $descriptorspec, $pipes);

        $output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);

        fclose($pipes[0]);
        fclose($pipes[1]);
        fclose($pipes[2]);

        return proc_close($process);
    }


    /**
     * Gets the parameters defined by user
     *
     * @return string
     */
    protected function getParams()
    {
        $result = "";
        foreach ($this->params as $key => $value)
        {
            if (is_numeric($key))
            {
                $result .= '--' . $value;
            } else
            {
                $result .= '--' . $key . ' ' . '"' . $value . '"';
            }
            $result .= ' ';
        }
        return $result;
    }

    /**
     * Sets the input argument for wkhtmltopdf
     *
     * @param $path
     *
     * @return $this
     */
    protected function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * Adds a wkhtmltopdf parameter
     *
     * @param string $key
     * @param string $value
     */
    protected function addParam($key, $value = null)
    {
        if (is_null($value))
        {
            $this->params[] = $key;
        } else
        {
            $this->params[$key] = $value;
        }

    }

    /**
     * Converts a method name to a wkhtmltopdf parameter name
     *
     * @param string $method
     *
     * @return string
     */
    protected function methodToParam($method)
    {
        return snake_case($method, "-");
    }

    /**
     * Gets the Input source which can be an HTML file or a File path
     *
     * @return string
     */
    protected function getInputSource()
    {
        if (!is_null($this->path))
        {
            return $this->path;
        }

        file_put_contents($this->getHTMLPath(), $this->htmlContent);

        return $this->getHTMLPath();
    }

    /**
     * Gets the temporary saved PDF file path
     *
     * @return string
     */
    protected function getPDFPath()
    {
        return $this->folder . '/' . $this->fileName . '.pdf';
    }

    /**
     * Gets the temporary save HTML file path
     *
     * @return string
     */
    protected function getHTMLPath()
    {
        return $this->folder . '/' . $this->fileName . '.html';
    }

    /**
     * Gets the error file's path in which stderr will be written
     */
    protected function getTmpErrFilePath()
    {
        return $this->folder . '/' . $this->fileName . '.log';
    }

    /**
     * Handle method<->parameter conventions
     *
     * @param string $method
     * @param string $args
     *
     * @return $this
     * @throws PDFException
     */
    public function __call($method, $args)
    {
        $param = $this->methodToParam($method);
        if (in_array($param, $this->availableParams))
        {
            if (isset($args[0]))
            {
                $this->addParam($param, $args[0]);
            } else
            {
                $this->addParam($param);
            }
            return $this;
        } else
        {
            throw new PDFException('Undefined method: ' . $method);
        }
    }

}

__construct里面增加了代码$this->addParam('javascript-delay',5000);

下面是调用函数的部分:

    function generatePdfAction()
    {
        $html =$this->getView()->render('stat/analysis_h_test.php');//analysis_v.php横板
        header('Content-Type: application/pdf');
        header("Content-Disposition:attachment;filename=小文斌的数据分析.pdf");
        $path  = $this->getConfig()->wkhtmltopdf->path;
        $pdf = new CanGelisPDFPDF($path);
        echo $pdf->loadHTML($html)->get();

        return false;
    }

 函数名称不能带中划线,不然的话,根本不需要修改__construct,  直接在这里添加$pdf->javascript-delay(2000);语句即可。

完毕。

2017年2月16日,如果打印横板的话,参数为--orientation Landscape

2017年4月29日,解决分页问题:

解决分页问题
wkhtmltopdf 很好用,但也有些不尽人意。就是当一个html页面很长我需要在指定的地方分页那怎么办呢? wkhtmltopdf 开发者在开发的时候并不是没有考虑到这一点,
例如下面这个html页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>pdf</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<style type="text/css">
*{ margin:0px; padding:0px;}
div{ 800px; height:1362px;margin:auto;}
</style>
<body>
<div style=" background:#030"></div>
<div style=" background:#033"></div>
<div style=" background:#369"></div>
<div style=" background:#F60"></div>
<div style=" background:#F3C"></div>
<div style=" background:#F0F"></div>
<div style=" background:#0FF"></div>
<div style=" background:#FF0"></div>
<div style=" background:#00F"></div>
<div style=" background:#0F0"></div>
<div style=" background:#033"></div>
<div style=" background:#369"></div>
<div style=" background:#F60"></div>
<div style=" background:#030"></div>
<div style=" background:#033"></div>
<div style=" background:#369"></div>
<div style=" background:#F60"></div>
<div style=" background:#F3C"></div>
<div style=" background:#F0F"></div>
<div style=" background:#0FF"></div>
<div style=" background:#FF0"></div>
<div style=" background:#00F"></div>
<div style=" background:#0F0"></div>
</body>
</html>

当我把它生成pdf的时候我想让每个块都是一页,经过无数次调试pdf的一页大约是1362px,但是越往后值就不对了,目前还不知道pdf一页是多少像素。

但是wkhtmltopdf 有个很好的方法,就是在那个div的样式后添加一个:page-break-inside:avoid;就ok了。真正管用的是page-break-before:always;

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
    <html xmlns="http://www.w3.org/1999/xhtml">  
    <head>  
    <title>pdf</title>  
    <link href="css/style.css" rel="stylesheet" type="text/css" />  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    </head>  
    <style type="text/css">  
    *{ margin:0px; padding:0px;}  
    div{ 800px; min-height:1362px;margin:auto;page-break-inside:avoid;}  
    </style>  
    <body>  
    <div style=" background:#030"></div>  
    <div style=" background:#033"></div>  
    <div style=" background:#369"></div>  
    <div style=" background:#F60"></div>  
    <div style=" background:#F3C"></div>  
    <div style=" background:#F0F"></div>  
    <div style=" background:#0FF"></div>  
    <div style=" background:#FF0"></div>  
    <div style=" background:#00F"></div>  
    <div style=" background:#0F0"></div>  
    <div style=" background:#033"></div>  
    <div style=" background:#369"></div>  
    <div style=" background:#F60"></div>  
    <div style=" background:#030"></div>  
    <div style=" background:#033"></div>  
    <div style=" background:#369"></div>  
    <div style=" background:#F60"></div>  
    <div style=" background:#F3C"></div>  
    <div style=" background:#F0F"></div>  
    <div style=" background:#0FF"></div>  
    <div style=" background:#FF0"></div>  
    <div style=" background:#00F"></div>  
    <div style=" background:#0F0"></div>  
    </body>  
    </html>  

添加页码:

wkhtmltopdf专成pdf文件之后的页码显示问题
在页面header或者footer上面添加page(当前页数)topage(总页数)来显示页码

wkhtmltopdf 0.12.2.1 (with patched qt) on ubuntu 14 works with <P style="page-break-before: always">
wkhtmltopdf 0.9.9 used to work with <hr/> to produce a new page.

https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1551

wkhtmltopdf --footer-right '[page]/[topage]' http://www.google.com google.pdf



header和footer参数说明

Headers And Footer Options

--footer-center*	<text>	Centered footer text
--footer-font-name*	<name>	Set footer font name (default Arial)
--footer-font-size*	<size>	Set footer font size (default 11)
--footer-html*	<url>	Adds a html footer
--footer-left*	<text>	Left aligned footer text
--footer-line*		Display line above the footer
--footer-right*	<text>	Right aligned footer text
--footer-spacing*	<real>	Spacing between footer and content in mm (default 0)
--header-center*	<text>	Centered header text
--header-font-name*	<name>	Set header font name (default Arial)
--header-font-size*	<size>	Set header font size (default 11)
--header-html*	<url>	Adds a html header
--header-left*	<text>	Left aligned header text
--header-line*		Display line below the header
--header-right*	<text>	Right aligned header text
--header-spacing*	<real>	Spacing between header and content in mm (default 0)


页码以及时间等参数的说明

 * [page]       Replaced by the number of the pages currently being printed
 * [frompage]   Replaced by the number of the first page to be printed
 * [topage]     Replaced by the number of the last page to be printed
 * [webpage]    Replaced by the URL of the page being printed
 * [section]    Replaced by the name of the current section
 * [subsection] Replaced by the name of the current subsection
 * [date]       Replaced by the current date in system local format
 * [time]       Replaced by the current time in system local format

如下是一条测试语句:

E:Program Fileswkhtmltopdfin>wkhtmltopdf.exe --footer-right [page]/[topage]  --javascript-delay 3000 -T 0 -R 20 -L 0 -B 10 
--enable-javascript --enable-plugins "http://blog.sunansheng.com/python/odoo/odoo.html" oddo.pdf

完毕。