PHP在网页中动态生成PDF文件详细教程


Posted in PHP onJuly 05, 2014

本文详细介绍使用 PHP 动态构建 PDF 文件的整个过程。使用免费 PDF 库 (FPDF) 或 PDFLib-Lite 等开源工具进行实验,并使用 PHP 代码控制 PDF 内容格式。

有时您需要准确控制要打印的页面的呈现方式。在这种情况下,HTML 就不再是最佳选择了。PDF 文件使您能够完全控制页面的呈现方式,以及文本、图形和图像在页面上的呈现方式。遗憾的是,用来构建 PDF 文件的 API 不属于 PHP 工具包的标准部件。现在您需要提供一点帮助。

当您在网络上搜索,寻找对 PHP 的 PDF 支持时,您首先发现的可能是商业 PDFLib 库及其开源版本 PDFLib-Lite。 这些都是很好的库,但是商业版本相当昂贵。PDFLib 库的精简版本库仅作为原始版本分发,当您尝试在托管环境下安装精简版本时,就会出现这个限制问题。

另一种选择是免费 PDF 库 (FPDF),它是本机 PHP,无需要进行任何编译,是完全免费的,因此,您不会像在未许可版本的 PDFLib 中那样看到水印。这个免费的 PDF 库正是我在本文中会用到的库。

我们将使用女子旱滑比赛的得分来演示动态构建 PDF 文件的过程。这些得分是从 Web 中获得并被转换成 XML。清单 1 显示了一个示例 XML 数据文件。

清单 1. XML 数据

<events> 
 <event name="Beast of the East 2011">
  <game score1="88" team1="Toronto Gore-Gore Rollergirls" team2="Montreal La Racaille" score2="11">
  <game score1="58" team1="Toronto Death Track Dolls" team2="Montreal Les Contrabanditas" score2="49">
   ...
 </game></game></event>
 <event name="Dustbowl Invitational 2011">
   ...
 </event>
 <event name="The Great Yorkshire Showdown 2011">
   ...
 </event>
</events>

XML 的根元素是一个 events 标记。按事件对数据进行分组,每个事件都包含多个比赛。在 events 标记内,是一系列的 event 标记,在这些标记中有多个 game 标记。 这些 game 标记中包含参加比赛的两个队的名称以及他们在比赛中的得分。

清单 2 展示了用来读取 XML 的 PHP 代码。

<?php
function getResults() {
 $xml = new DOMDocument(); 
 $xml->load('events.xml'); 
 $events = array();
 foreach($xml->getElementsByTagName('event') as $event) { 
  $games = array();
  foreach($event->getElementsByTagName('game') as $game) {
   $games []= array( 'team1' => $game->getAttribute('team1'),
    'score1' => $game->getAttribute('score1'),
    'team2' => $game->getAttribute('team2'),
    'score2' => $game->getAttribute('score2') );
  }
  $events []= array( 'name' => $event->getAttribute('name'),
   'games' => $games );
 }
 return $events;
}
?>

这段脚本实现了一个 getResults 函数,以便将 XML 文件读入 DOM 文档。然后使用 DOM 调用遍历所有 event 和 game 标记,以构建一个事件阵列。该数列内的每个元素都是一个散列表,包含事件名称和比赛项目的阵列。结构基本上是 XML 结构的内存版。

为了测试这个脚本的作用,将构建一个 HTML 导出页面,使用 getResults 函数读取文件,然后以一系列 HTML 表的形式输出数据。清单 3 显示了该测试所用的 PHP 代码。

清单 3. 结果 HTML 页面

<?php
include_once('getresults.php');
$results = getResults();
foreach( $results as $event ) {
?>
<h1><?php echo( $event['name'] ) ?></h1>

<?php
foreach( $event['games'] as $game ) {
 $s1 = (int)$game['score1'];
 $s2 = (int)$game['score2'];
?>

<?php
}
?>
<table><tbody><tr>
 <td style="font-weight:<?php echo( ( $s1 > $s2 ) ? 'bold' : 'normal') ?>">
  <?php echo( $game['team1'] ) ?></td>
 <td><?php echo( $s1 ) ?></td>
 <td style="font-weight:<?php echo( ( $s2 > $s1 ) ? 'bold' : 'normal') ?>">
  <?php echo( $game['team2'] ) ?></td>
 <td><?php echo( $s2 ) ?></td>
</tr></tbody></table>
<?php
}
?>

通过代码 getresults.php,XML 数据文件被上传到 Web 服务器,您可以查看 HTML 结果,这与 图 1 类似。
图 1. HTML 格式的竞赛结果

PHP在网页中动态生成PDF文件详细教程

在该结果中,对获胜队使用了粗体,以便查看哪支队赢得了哪场比赛。

构建 PDF

获得数据之后,应将重点放在构建 PDF 文件上。第一步是下载 FPDF 库,然后将其安装在与现有应用文件集相同的目录中。实际上,只要是在 PHP 库路径中,您可以将它安装在任何您喜欢的地方。追踪您放置字体目录的地方,因为您需要设置 ‘FPDF_FONTPATH',如 清单 4 所示。

清单 4. PDF Hello World

<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');

require( 'fpdf.php' );

$pdf = new FPDF();
$pdf->SetFont('Arial','',72);
$pdf->AddPage();
$pdf->Cell(40,10,"Hello World!",15);
$pdf->Output();
?>

这段脚本实际上是一个 “Hello World”,但采用的是 PDF 格式而不是 HTML。这段脚本执行的第一个操作是使用 define 语句设置 FPDF 字体目录的位置。然后使用 require 语句引入 FPDF 库。这段脚本从该库创建了一个 FPDF 对象,设置字体,添加一个页面,然后使用 Cell 方法将一些文本放在该页面上,并输出 PDF。

图 2 展示了一切都正常情况下的结果。

图 2. PDF 格式的 Hello World

PHP在网页中动态生成PDF文件详细教程

如果没有看到 PDF,那么您可能想在命令行运行这段脚本,查看是否丢失了 fpdf.php 文件或者存在其他问题。

既然 PDF 呈现正常,那么现在应该将其与旱滑结果文件合并,并查看可以动态生成哪些内容。清单 5 展示了该合并操作的第一个版本。

清单 5. 显示结果的首版 PDF

<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');

require( 'fpdf.php' );
require( 'getresults.php' );

class PDF extends FPDF
{
function EventTable($event)
{
  $this->Cell(40,10,$event['name'],15);
  $this->Ln();
}
}

$pdf = new PDF();
$pdf->SetFont('Arial','',48);
foreach( getResults() as $event ) {
 $pdf->AddPage();
 $pdf->EventTable($event); 
}
$pdf->Output();
?>

我们没有从外部扩展 FPDF 类别,而是使用我们自己的 PDF 子类来扩展 FPDF 类别。在这些子类内,我们创建了一个名为 EventTable 的新方法,为给定事件构建了一个结果表。在这种情况下,我们从小处着手,只输出了事件名称。该名称位于脚本底部,包装在 foreach 循环中,该脚本为每个事件添加一个页面,然后调用 EventTable 方法。

可在 图 3 中看到这段脚本的输出。

图 3. 动态 PDF 的第一个版本

PHP在网页中动态生成PDF文件详细教程

向下滚动页面,以展示每个事件都在自己的页面上。此处的下一步操作是开始将结果添加到页面。

构建结果表

在构建 PDF 文件时,构建无表结构就像构建 HTML 一样简单。构建表的方法是构建许多宽度、字体、填充颜色、行颜色等各不相同的单元。

清单 6 展示了设置表的标题栏的添加代码。

清单 6. 添加结果表标题

<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');

require( 'fpdf.php' );
require( 'getresults.php' );

class PDF extends FPDF
{
function EventTable($event)
{
  $this->SetFont('','B','24');
  $this->Cell(40,10,$event['name'],15);
  $this->Ln();

  $this->SetXY( 10, 45 );

  $this->SetFont('','B','10');
  $this->SetFillColor(128,128,128);
  $this->SetTextColor(255);
  $this->SetDrawColor(92,92,92);
  $this->SetLineWidth(.3);

  $this->Cell(70,7,"Team 1",1,0,'C',true);
  $this->Cell(20,7,"Score 1",1,0,'C',true);
  $this->Cell(70,7,"Team 2",1,0,'C',true);
  $this->Cell(20,7,"Score 2",1,0,'C',true);
  $this->Ln();
}
}

$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
 $pdf->AddPage();
 $pdf->EventTable($event); 
}
$pdf->Output();
?>

此处的添加代码用于设置字体、颜色和行宽。然后它将呈现包含四个标题列的几个单元格。然后调用 Ln 方法(该方法与回车键等效)启用一个新行。

在浏览器中查看这段脚本时,可以看到类似 图 4 的内容。

图 4. 包含表的标题行的页面

PHP在网页中动态生成PDF文件详细教程

在 图 4 中,标题以白色文本呈现在灰色背景上。这种格式有助于将其与呈现在标题下面的数据进行区分。要呈现比赛结果,请在 清单 7 中添加以下代码。

清单 7. 添加完整的结果表

<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');

require( 'fpdf.php' );
require( 'getresults.php' );

class PDF extends FPDF
{
function EventTable($event)
{
  $this->SetFont('','B','24');
  $this->Cell(40,10,$event['name'],15);
  $this->Ln();

  $this->SetFont('','B','10');
  $this->SetFillColor(128,128,128);
  $this->SetTextColor(255);
  $this->SetDrawColor(92,92,92);
  $this->SetLineWidth(.3);

  $this->Cell(70,7,"Team 1",1,0,'C',true);
  $this->Cell(20,7,"Score 1",1,0,'C',true);
  $this->Cell(70,7,"Team 2",1,0,'C',true);
  $this->Cell(20,7,"Score 2",1,0,'C',true);
  $this->Ln();

  $this->SetFillColor(224,235,255);
  $this->SetTextColor(0);
  $this->SetFont('');

  $fill = false;

  foreach($event['games'] as $game)
  {
    $this->SetFont('Times',((int)$game['score1']>(int)$game['score2'])?'BI':'');
    $this->Cell(70,6,$game['team1'],'LR',0,'L',$fill);
    $this->Cell(20,6,$game['score1'],'LR',0,'R',$fill);
    $this->SetFont('Times',((int)$game['score1']<(int)$game['score2'])?'BI':'');
    $this->Cell(70,6,$game['team2'],'LR',0,'L',$fill);
    $this->Cell(20,6,$game['score2'],'LR',0,'R',$fill);
    $this->Ln();
    $fill =! $fill;
  }
  $this->Cell(180,0,'','T');
}
}

$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
 $pdf->AddPage();
 $pdf->EventTable($event); 
}
$pdf->Output();
?>

除了标题行之外,在 EventTable 方法中还有一个 foreach 循环,它将在每个比赛上进行迭代。图 5 显示了用于此用途的代码。

图 5. 包含结果表的 PDF

PHP在网页中动态生成PDF文件详细教程

$fill 变量可通过切换来改变表中每行的颜色。优胜队的名称和得分用加粗、斜体字体表示,这样可以清晰显示它们。还需注意的是,字体从标题的 Arial 字体更改成了显示比赛内容所用的 Times 字体。

要完成示例代码,则需要添加一些图形。

使用图形进行修饰

向 PDF 添加图像非常容易。首先需要从 Web 抓取一个图像。我抓取了一个旱滑参赛队的徽标,并将其存储为 PNG 格式的图像。 此后,我一直使用 清单 8 中的新代码。

清单 8. 添加徽标图像

<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');

require( 'fpdf.php' );
require( 'getresults.php' );

class PDF extends FPDF
{
function EventTable($event)
{
  $this->Image('logo.png',5,5,33);

  $this->SetXY( 40, 15 );

  $this->SetFont('','B','24');
  $this->Cell(40,10,$event['name'],15);
  $this->Ln();

  $this->SetXY( 10, 45 );

  $this->SetFont('','B','10');
  $this->SetFillColor(128,128,128);
  $this->SetTextColor(255);
  $this->SetDrawColor(92,92,92);
  $this->SetLineWidth(.3);

  $this->Cell(70,7,"Team 1",1,0,'C',true);
  $this->Cell(20,7,"Score 1",1,0,'C',true);
  $this->Cell(70,7,"Team 2",1,0,'C',true);
  $this->Cell(20,7,"Score 2",1,0,'C',true);
  $this->Ln();

  $this->SetFillColor(224,235,255);
  $this->SetTextColor(0);
  $this->SetFont('');

  $fill = false;

  foreach($event['games'] as $game)
  {
   $this->SetFont('Times',((int)$game['score1']>(int)$game['score2'])?'BI':'');
   $this->Cell(70,6,$game['team1'],'LR',0,'L',$fill);
   $this->Cell(20,6,$game['score1'],'LR',0,'R',$fill);
   $this->SetFont('Times',((int)$game['score1']<(int)$game['score2'])?'BI':'');
   $this->Cell(70,6,$game['team2'],'LR',0,'L',$fill);
   $this->Cell(20,6,$game['score2'],'LR',0,'R',$fill);
   $this->Ln();
   $fill =! $fill;
  }
  $this->Cell(180,0,'','T');
}
}

$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
 $pdf->AddPage();
 $pdf->EventTable($event); 
}
$pdf->Output();
?>

清单 8中的关键方法是 Image 方法,它为图像、位置和宽度选取一个文件名称。所有其它参数都是可选的,因此您只指定您想要的信息便可。

到 SetXY 的一些新调用会将文本和表左右移动到适当的位置,防止其覆盖图像。

图 6 显示了这段脚本的输出结果。

图 6. 带有徽标图像的已完成的 PDF

PHP在网页中动态生成PDF文件详细教程

该 PDF 库还提供了其他方法来呈现图形、添加流文本、添加超链接、管理页边距和方向等结构,您可以完全控制您的 PDF 文件。

结束语

使用合适的工具,通过 PHP 构建 PDF 文件是非常容易的。这种方法非常适用于打印发x票或票据,或填写表单,以及需要严格控制内容布局的任何项目。

PHP 相关文章推荐
php_xmlhttp 乱码问题解决方法
Aug 07 PHP
利用php绘制饼状图的实现代码
Jun 07 PHP
简单谈谈php中的unicode和utf8编码
Jun 10 PHP
php验证邮箱和ip地址最简单方法汇总
Oct 30 PHP
yii实现使用CUploadedFile上传文件的方法
Dec 28 PHP
详解PHP对象的串行化与反串行化
Jan 24 PHP
php自动载入类用法实例分析
Jun 24 PHP
PHP实现的链式队列结构示例
Sep 15 PHP
PHP实现新型冠状病毒疫情实时图的实例
Feb 04 PHP
tp5.1 框架数据库-数据集操作实例分析
May 26 PHP
PHP加MySQL消息队列深入理解
Feb 27 PHP
PHP7 list() 函数修改
Mar 09 PHP
PHP数组遍历知识汇总(包含遍历方法、数组指针操作函数、数组遍历测速)
Jul 05 #PHP
php遍历数组的4种方法总结
Jul 05 #PHP
CodeIgniter实现更改view文件夹路径的方法
Jul 04 #PHP
PHP关于htmlspecialchars、strip_tags、addslashes的解释
Jul 04 #PHP
php socket客户端及服务器端应用实例
Jul 04 #PHP
PHP使用range协议实现输出文件断点续传代码实例
Jul 04 #PHP
PHP实现对文本数据库的常用操作方法实例演示
Jul 04 #PHP
You might like
php表单提交问题的解决方法
2011/04/12 PHP
ThinkPHP模板中判断volist循环的最后一条记录的验证方法
2014/07/01 PHP
文字幻灯片
2006/06/26 Javascript
ExtJS 2.0实用简明教程之应用ExtJS
2009/04/29 Javascript
分享20款好玩的jQuery游戏
2011/04/17 Javascript
NodeJS学习笔记之MongoDB模块
2015/01/13 NodeJs
JavaScript实现广告的关闭与显示效果实例
2015/07/02 Javascript
快速使用Bootstrap搭建传送带
2016/05/06 Javascript
Bootstrap和Angularjs配合自制弹框的实例代码
2016/08/24 Javascript
iframe与主框架跨域相互访问实现方法
2017/09/14 Javascript
用vue封装插件并发布到npm的方法步骤
2017/10/18 Javascript
除Console.log()外更多的Javascript调试命令
2018/01/24 Javascript
vue自定义移动端touch事件之点击、滑动、长按事件
2018/07/10 Javascript
如何基于vue-cli3.0构建功能完善的移动端架子
2019/04/24 Javascript
Echarts动态加载多条折线图的实现代码
2019/05/24 Javascript
Vue 实现前端权限控制的示例代码
2019/07/09 Javascript
Vue实现简单的跑马灯
2020/05/25 Javascript
vue使用lodop打印控件实现浏览器兼容打印的方法
2021/02/07 Vue.js
[38:42]完美世界DOTA2联赛循环赛 Matador vs Forest BO2第二场 11.05
2020/11/05 DOTA
[49:30]DOTA2-DPC中国联赛正赛 Dragon vs Dynasty BO3 第二场 3月4日
2021/03/11 DOTA
python matplotlib坐标轴设置的方法
2017/12/05 Python
Python数据分析库pandas基本操作方法
2018/04/08 Python
Python解析json时提示“string indices must be integers”问题解决方法
2019/07/31 Python
python实现的按要求生成手机号功能示例
2019/10/08 Python
Django ORM实现按天获取数据去重求和例子
2020/05/18 Python
纯CSS3制作的鼠标悬停时边框旋转
2017/01/03 HTML / CSS
html5组织文档结构_动力节点Java学院整理
2017/07/11 HTML / CSS
Gibson London官网:以地道的英国男装而著称
2019/12/06 全球购物
2014升学宴答谢词
2014/01/26 职场文书
新年联欢会主持词
2014/03/27 职场文书
党员三严三实心得体会
2014/10/13 职场文书
2014年政风行风工作总结
2014/11/22 职场文书
电影雷锋观后感
2015/06/10 职场文书
python实现大文本文件分割成多个小文件
2021/04/20 Python
浅谈如何提高PHP代码质量之单元测试
2021/05/28 PHP
苹果可能正在打击不进行更新的 App
2022/04/24 数码科技