PHP を使用して PDF ファイルを動的に作成する

PHP を使用して PDF ファイルの書式と内容を容易に制御する

この記事では PHP を使用して PDF ファイルを動的に作成するプロセス全体を見て行きます。Free PDF ライブラリー (FPDF) や PDFLib-Lite などのオープンソース・ツールと PHP コードを使用し、内容に合わせて PDF フォーマットを制御する方法を試してみましょう。

Jack D. Herrington, Senior Software Engineer, Fortify Software, Inc.

Photo of Jack HerringtonJack Herrington はサンフランシスコ湾岸地域に住む技術者、著作者、講演者です。彼の最新の活動や記事を http://jackherrington.com で知ることができます。



2011年 7月 29日

時として、印刷用にページの表示方法を正確に制御しなければならない場合があります。そうした場合、HTML は選択肢として最適ではありません。PDF ファイルであれば、ページの表示方法や、テキスト、グラフィックス、画像をページ上に表示する方法を完全に制御することができます。しかし残念なことに、PHP ツールキットには PDF ファイルを作成するための API が標準的に含まれているわけではないため、PHP を使用して PDF ファイルを作成するには少し作業が必要になります。

よく使われる頭文字語

  • API: Application Programming Interface
  • DOM: Document Object Mode
  • HTML: HyperText Markup Language
  • PDF: Portable Document Format
  • W3C: World Wide Web Consortium
  • XML: Extensible Markup Language

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 で表示されたダービーの結果
HTML で表示されたダービーの結果のスクリーン・キャプチャー

この結果では、勝ったチームを太字フォントで表示するという工夫もされており、どのチームがどの大会で勝ったのか見やすくなっています。

PDF を作成する

データが用意できたので、今度は 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 で表示した 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 の最初のバージョンのスクリーン・キャプチャーとして、画面に「Beast of the East 2011」という見出しが表示されています。

このページを下にスクロールすると、各大会がそれぞれ独自のページに表示されます。次のステップでは、そのページに結果を追加します。


ローラー・ダービーの結果の表を作成する

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
チームとスコアを含むローラー・ダービーの結果の表を 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
ロゴの画像を含む、完成した 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 などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=742579
ArticleTitle=PHP を使用して PDF ファイルを動的に作成する
publish-date=07292011