将PHP转换为PDF的方式——使用DOMPDF

3
我正在使用PHP生成一个列表(一种学生预约卡),我希望能够将其保存为PDF格式。通过使用PHP和DOMPDF,我已经成功地实现了基本的布局。
但是,当我尝试将以下内容保存为PDF时,无法正常工作。
<?php
session_start();

// User session check
    if(!$_SESSION['email'])
        {
        header("Location: login.php");//redirect to login page to secure the welcome page without login access.
        }

    include("php/getCustomerEvents.php");

// get row id = student id
    $id = $_GET[id];


// check user language
    $lang = $_SESSION['lang'];

    switch ($lang) 
    {
      case 'en':
      $lang_file = 'lang.en.php';
      break;

      //case 'fr':
      //$lang_file = 'lang.fr.php';
      //break;

      case 'nl':
      $lang_file = 'lang.nl.php';
      break;

      default:
      $lang_file = 'lang.nl.php';
    }

    include_once 'lang/'.$lang_file;

// Debug code
//print_r($_SESSION);
//echo "----------------------------------------------------------------------->".$_SESSION['lang']." = taal <br>";
//echo "----------------------------------------------------------------------->".$_SESSION['name']." = naam <br>";
//echo "----------------------------------------------------------------------->".$_SESSION['resource']." = id <br>";
//Echo "----------------------------------------------------------------------->".$_SESSION['admin']." = admin <br>";
?> 

<!DOCTYPE html>

<html>
  <head>
    <meta charset="UTF-8">
    <title></title>

    <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>

    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
      <link rel="stylesheet" href="css/bootstrap-select.css">



    <style type="text/css">
    .bs-example{
        margin: 20px;
    }
    /* Fix alignment issue of label on extra small devices in Bootstrap 3.2 */
    .form-horizontal .control-label{
        padding-top: 7px;
    }
    </style>
  </head>

  <body >

                    <!-- Main content -->
                    <section class="content" >

                    <!-- Your Page Content Here -->

                        <div class="row">

                            <div class="col-md-12">

                                <div class="box">
                                    <div class="box-header">
                                      <h3 class="box-title"><?php echo $lang['LBL_LIST_EVENTS']; ?></h3>
                                    </div><!-- /.box-header -->

                                    <div class="box-body">
                                        <table id="instructors" class="table table-bordered table-striped table-hover">
                                            <thead>
                                              <tr>
                                                <th><?php echo $lang['LBL_LESSON']; ?></th>
                                                <th><?php echo $lang['LBL_LOCATION']; ?></th>
                                                <th><?php echo $lang['LBL_TITLE']; ?></th>
                                                <th><?php echo $lang['LBL_EVENT_START']; ?></th>
                                                <th><?php echo $lang['LBL_EVENT_END']; ?></th>
                                              </tr>
                                            </thead>
                                            <tbody>
                                                <?php customerevents($id); ?><!-- function from getCustomerEvents.php -->
                                            </tbody>
                                        </table>
                                    </div><!-- /.box-body -->

                                    <div class="box-footer">
                                        <button type="submit" class="btn btn-success" ><span class="glyphicon glyphicon-print" aria-hidden="true"></span> PDF </button>
                                        <button type="submit" class="btn btn-success" ><span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> MAIL </button>
                                    </div><!-- /.box-footer -->
                              </div><!-- /.box -->
                            </div><!-- /.col -->
                        </div><!-- /.row -->
                    </section><!-- /.content -->


                <!-- Main Footer -->
                <footer class="main-footer">
                    <!-- To the right -->
                    <div class="pull-right hidden-xs">

                    </div>
                    <!-- Default to the left --> 
                    <strong>Copyright &copy; 2015 <a href="http:\\www.biqsit.be">biqs it</a>.</strong> All rights reserved.
                </footer>

  </body>
</html>

我使用的代码生成PDF:

<?php
require_once("../dompdf/dompdf_config.inc.php");

//$content = "../" . $_GET["content"];
//$file_name = $_GET["file_name"];

$dompdf = new DOMPDF();

//$html = file_get_contents($content);
$html = file_get_contents('../pdf_customer_events.php');
$dompdf->load_html($html);
$dompdf->render();
$dompdf->stream("sample.pdf");
?>

我做错了什么?还是DOMPDF不是正确的解决方案?

我非常推荐你去看看wkhtmltopdf。它是一个功能齐全的浏览器引擎,因此更容易实现,因为支持所有浏览器功能(而且速度很快!) - tillz
我非常确定使用 file_get_contents() 函数读取 PHP 文件将会检索到未解析的 PHP 代码。 - D4V1D
服务器上没有使用wkhtmltopdf吗?我需要它能在每个平台上运行。 - data2info
你也可以尝试使用TCPDF。 - PravinS
2个回答

5

打印原始文件

如果要转换不包含任何依赖项的文件,您可以获取其内容并将其提供给转换库。

$html = file_get_contents('pregenerated.html');

这种方法不允许传递可能需要的变量(会话/POST ...)。


打印高级原始文件

通过缓存内容,您避免将其发送到浏览器,然后可以将其提供给库。

ob_start();
include('content.php');
$html = ob_get_clean();

这样,您可以像通常一样传输会话/帖子/获取,甚至可以正确处理错误。您还可以使用模板引擎进行高级输出。

资源的主要问题

通过包含php脚本,所有子文件(脚本、css、iframes等)都不包含在内。因此,对于不包含图像的简单pdf,您需要在一个页面中获取所有内容。

相当不可维护...但是可行。


轻松处理资源

所以,幸运的是有一些php工具可以解释页面并获取任何子文件。最常见的是wkhtmltopdf,它是一个包括Chrome渲染引擎webkit的二进制文件,用于解释页面并打印pdf。

为此,您可以像上面的示例那样提供内容,或者提供url。您可以控制打印(边距、颜色等)

它有许多php包装器,使其易于在您的代码中使用。


更进一步

但是(总会有一个但是...)wkhtmltopdf没有使用最近的webkit引擎,如果像我们公司一样喜欢流畅的css3和javascript画布功能,则可能会很烦人。

我们所做的就是使用无头浏览器,将页面呈现为浏览器并将其打印为pdf(这已经是wkhtmltopdf使用优化和功能的内容了)。

最先进的无头浏览器可能是PhantomJS。基于Webkit,它可以轻松地打印出许多格式
而且它有一个PHP包装器:http://jonnnnyw.github.io/php-phantomjs/

var webPage = require('webpage');
var page = webPage.create();

page.viewportSize = { width: 1920, height: 1080 };
page.open("http://www.google.com", function start(status) {
  page.render('google_home.jpeg', {format: 'jpeg', quality: '100'});
  phantom.exit();
});

: 在我们公司中,我们使用 SlimerJS,因为它在我们构建服务时提供了更好的输出。这只是一个问题,因为我们的页面并不是为了跨浏览器保持一致性而制作的,转换混乱了一些部分...

在开发该服务时,SlimerJS 直到 0.10 版本才提供完整的 PDF 打印支持,而该版本还在开发中。因此,我们不得不自己编译最新的 xulrunner


我尝试使用完整的URL,但这似乎不是一个解决方案。此外,我删除了所有会话代码。在浏览器中可以访问URL http://www.data2info.be/_test/biqsdrive/pdf_customer_events.php,但PDF中仍然没有数据。 - data2info
你尝试过第二个选项吗? - Cyrbil
谢谢,你帮我回答了第二个问题。我会在新的回答中发布我的结果。 - data2info
@Cyrbil,关于无头浏览器的使用,你尝试过PhantomJS吗?它似乎使用了相对较新的Webkit版本。 - BrianS
是的,我们确实尝试过,但我不记得为什么当时(大约5个月前)它不完全适合我们。看起来PhantomJs可以完成这项工作,我会在上面加一行说明。 - Cyrbil

1
感谢 @Cyrbil,我得到了下面的可工作代码。但是CSS仍然存在问题,导致PDF无法生成。根据我的发现,这与bootstrap.css有关。已经尝试删除*之前和之后的内容,但仍然无法呈现PDF。但我可能应该将此作为一个新问题发布。
<?php
session_start();
require_once("dompdf/dompdf_config.inc.php");

// User session check
    // if(!$_SESSION['email'])
        // {
        // header("Location: login.php");//redirect to login page to secure the welcome page without login access.
        // }

    include("php/getCustomerEvents.php");

// get row id = student id
    $id = $_GET["id"];


//check user language
    $lang = $_SESSION['lang'];

    switch ($lang) 
    {
      case 'en':
      $lang_file = 'lang.en.php';
      break;

      case 'fr':
      $lang_file = 'lang.fr.php';
      break;

      case 'nl':
      $lang_file = 'lang.nl.php';
      break;

      default:
      $lang_file = 'lang.nl.php';
    }

    include_once 'lang/'.$lang_file;

ob_start(); // start output buffer
?> 


<!DOCTYPE html>

<html>
  <head> 
    <meta charset="UTF-8">
    <title></title>

    <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>

    <!--link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" /-->
    <link href="css/biqs_print_bootstrap.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="css/bootstrap-select.css">  


    <style type="text/css">
    .bs-example{
        margin: 20px;
    }
    /* Fix alignment issue of label on extra small devices in Bootstrap 3.2 */
    .form-horizontal .control-label{
        padding-top: 7px;
    }
        tbody:before, tbody:after { display: none; }

    </style>
  </head>

  <body >

                    <!-- Main content -->
                    <section class="content" >

                    <!-- Your Page Content Here -->

                        <div class="row">

                            <div class="col-md-12">

                                <div class="box">
                                    <div class="box-header">
                                      <h3 class="box-title"><?php echo $lang['LBL_LIST_EVENTS']; ?></h3>
                                    </div><!-- /.box-header -->

                                    <div class="box-body">
                                        <table id="instructors" class="table table-bordered table-striped table-hover">
                                            <thead>
                                              <tr>
                                                <th><?php echo $lang['LBL_LESSON']; ?></th>
                                                <th><?php echo $lang['LBL_LOCATION']; ?></th>
                                                <th><?php echo $lang['LBL_TITLE']; ?></th>
                                                <th><?php echo $lang['LBL_EVENT_START']; ?></th>
                                                <th><?php echo $lang['LBL_EVENT_END']; ?></th>
                                              </tr>
                                            </thead>
                                            <tbody>
                                                <?php customerevents($id); ?><!-- function from getCustomerEvents.php -->
                                            </tbody>
                                        </table>
                                    </div><!-- /.box-body -->

                                    <div class="box-footer">

                                    </div><!-- /.box-footer -->
                              </div><!-- /.box -->
                            </div><!-- /.col -->
                        </div><!-- /.row -->
                    </section><!-- /.content -->


                <!-- Main Footer -->
                <footer class="main-footer">
                    <!-- To the right -->
                    <div class="pull-right hidden-xs">

                    </div>
                    <!-- Default to the left --> 
                    <strong>Copyright &copy; 2015 <a href="http:\\www.biqsit.be">biqs it</a>.</strong> All rights reserved.
                </footer>

  </body>
</html>


<?php
$html = ob_get_contents();
ob_end_clean();

$dompdf = new DOMPDF();
$dompdf->load_html($html);
$dompdf->render();
$dompdf->stream("sample.pdf");

echo $html;
?>

你的CSS需要硬编码,因为PHP代码无法解释它(浏览器读取HTML并加载任何脚本/CSS/图像)。我编辑了我的答案,提供另一种选择...生成PDF总是很麻烦 :) - Cyrbil
我将使用http://purecss.io/的CSS。这在PDF中给了我很好的结果。 - data2info

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接