時として、印刷用にページの表示方法を正確に制御しなければならない場合があります。そうした場合、HTML は選択肢として最適ではありません。PDF ファイルであれば、ページの表示方法や、テキスト、グラフィックス、画像をページ上に表示する方法を完全に制御することができます。しかし残念なことに、PHP ツールキットには PDF ファイルを作成するための API が標準的に含まれているわけではないため、PHP を使用して PDF ファイルを作成するには少し作業が必要になります。
PHP で PDF をサポートしているものがないか Web を検索すると、おそらく最初に見つかるものは商用の PDFLib ライブラリーとそのオープンソース版の PDFLib-Lite でしょう。これらは優れたライブラリーですが、商用版はかなり高額です。このライブラリーの軽量版はソースでのみ配布されており、ホスト環境にインストールしようとする場合には、その制約が問題になるかもしれません。
もう 1 つの選択肢は、ネイティブ PHP の Free PDF ライブラリー (FPDF) です。FPDF はコンパイルする必要がなく、完全に無料なので、ライセンス許可されていないバージョンの PDFLib を使用した場合のように透かしが見えてしまうことはありません。この記事では Free 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'/>
...
</event>
<event name='Dustbowl Invitational 2011'>
...
</event>
<event name='The Great Yorkshire Showdown 2011'>
...
</event>
</events>
|
この XML のルート要素は events タグです。データは複数の大会 (event)
にグループ分けされ、各大会にはいくつもの試合 (game) が含まれています。events タグの中には一連の
event タグがあり、event タグの中には複数の
game タグがあります。game タグには、対戦する 2 チームそれぞれの名前と、その試合での各チームのスコアが含まれています。
リスト 2 は、この XML を読み取るための PHP コードを示しています。
リスト 2. getresults.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;
}
?>
|
このスクリプトは XML ファイルを DOMDocument に読み込む getResults
関数を実装しています。次に DOM を呼び出してすべての event タグと game タグをトラバースし、大会の配列を作成します。配列の各要素の中にはハッシュ・テーブルがあり、そのテーブルには大会の名前と、行われた試合の配列が含まれています。この構造は基本的に、XML の構造をメモリー内に複製したものです。
このスクリプトの動作をテストするために、HTML によるエクスポート・ページを作成します。このページは getResults 関数を使用してファイルを読み取り、データを一連の HTML の表として出力します。リスト
3 は、このテストをするための PHP コードを示しています。
リスト 3. 試合の結果の HTML ページ
<html><head><title>Event Results</title></head>
<body>
<?php
include_once('getresults.php');
$results = getResults();
foreach( $results as $event ) {
?>
<h1><?php echo( $event['name'] ) ?></h1>
<table>
<?php
foreach( $event['games'] as $game ) {
$s1 = (int)$game['score1'];
$s2 = (int)$game['score2'];
?>
<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>
<?php
}
?>
</table>
<?php
}
?>
</body></html>
|
このコードと getresults.php、そして XML データ・ファイルを Web サーバーにアップロードすると、試合の結果が図 1 のように HTML で表示されます。
図 1. HTML で表示されたダービーの結果
この結果では、勝ったチームを太字フォントで表示するという工夫もされており、どのチームがどの大会で勝ったのか見やすくなっています。
データが用意できたので、今度は PDF ファイルの作成に焦点を当てます。最初のステップは、FPDF
ライブラリーをダウンロードし、既存のアプリケーションのファイル・セットと同じディレクトリーにインストールすることです。実際には、PHP
ライブラリーのパスに指定されている限り、好きな場所に FPDF ライブラリーをインストールすることができます。リスト 4 のように 'FPDF_FONTPATH' を設定する必要があるため、fonts ディレクトリーをどこに配置したかを覚えておく必要があります。
リスト 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!」を出力しますが、HTML ではなく PDF で表示します。このスクリプトではまず、define 文を使って FPDF の fonts ディレクトリーの場所を設定します。次に require 文を使って FPDF ライブラリーを読み込みます。ここから、このスクリプトは FPDF オブジェクトを作成し、フォントを設定し、ページを追加し、Cell メソッドを使ってページ上にテキストを配置し、PDF を出力しています。
図 2 はすべてが適切に動作した場合の結果を示しています。
図 2. PDF で表示した Hello World
PDF が表示されない場合には、このスクリプトをコマンドラインで実行し、fpdf.php ファイルが実際にあるかどうか、あるいは他に問題がないかどうかを確認する必要があるかもしれません。
これで PDF による表示ができるようになったので、この 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 の最初のバージョン
このページを下にスクロールすると、各大会がそれぞれ独自のページに表示されます。次のステップでは、そのページに結果を追加します。
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();
?>
|
この追加のコードでは、フォント、色、線幅を設定しています。そして 4 つの列で構成される見出しのセルを描画します。次に Ln メソッドを呼び出します。Ln メソッドは新しい行を開始するための改行と同じです。
このスクリプトをブラウザーで表示すると、図 4 のようになります。
図 4. 表の見出し行が表示されたページ
図 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
$fill 変数により、表の各行の色を 1 行おきに切り換えています。勝ったチームの名前とスコアは太字で斜体のフォントで表示されているため、非常に目立ちます。また、見出しでは 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
FPDF ライブラリーのその他すべてのメソッド (グラフィックスの描画や、フロー・テキストの追加、ハイパーリンクの追加、余白や縦向き横向きといったページ設定など) を使用すると、PDF ファイルを完全に制御することができます。
適切なツールを使用すれば、驚くほど簡単に PHP で PDFファイルを作成することができます。この方法は、請求書やチケットの印刷、フォームへの記入など、コンテンツのレイアウトを正確に制御する必要のある用途に理想的です。
学ぶために
- さまざまな標準のための素晴らしいサイト、W3C にアクセスしてください。特にこの記事に関連しているのは XML 標準です。
- PHP のサイトは PHP の資料のサイトとして最高です。
- 著者の Jack Herrington が developerWorks に寄稿した他の記事も読んでください
(2005年3月から現在まで)。Ajax、JSON、PHP、XML、その他の技術が解説されています。
- New to XML では、XML を学ぶために必要なリソースを入手することができます。
- developerWorks の XML ゾーンには、XML
の領域でのスキルを磨くためのリソースが豊富に用意されています。XML 技術文書一覧に用意された、さまざまな技術記事やヒント、チュートリアル、技術標準、IBM Redbooks を見てください。
- XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
- developerWorks の
Technical events and webcasts で最新情報を入手してください。
- 今すぐ Twitter に参加して developerWorks のツイートをフォローしてください。
- developerWorks podcasts でソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
- developerWorks On demand
demos をご覧ください。初心者のための製品インストール方法やセットアップのデモから、上級開発者のための高度な機能に至るまで、多様な話題が解説されています。
製品や技術を入手するために
- PDF ファイルを作成するための商用ライブラリー、PDFLib を試してみてください。
- PDFLib 7 のオープンソース版 PDFLib-Lite をダウンロードし、PDFLib 7 の機能のサブセットを試してみてください。
- PECL パッケージをダウンロードしてください。PECL パッケージは PDFLib プログラミング・ライブラリーをラップし、PDF ファイルをオンザフライで処理する拡張機能です。
- この記事で PDF
ファイルを生成するために使用したライブラリー、FPDF を入手してください。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox
のオンライン試用版で、DB2、Lotus、Rational、Tivoli、WebSphere などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- XML zone discussion
forums では XML に関する議論が行われています。
- developerWorks コミュニティーに参加し、開発者向けのブログ、フォーラム、グループ、ウィキなどを利用しながら、他の developerWorks ユーザーとやり取りしてください。
