ColdFusion-開発効率を求められる今だから知りたい高性能Webアプリケーションサーバー

第6回 ColdFusionでPDFを扱う

この記事を読むのに必要な時間:およそ 4.5 分

PDFを暗号化する

cfpdfタグを使って,送信されてきたPDFファイルを暗号化してみることにしましょう。以下の例のpdfenc.cfmとして保存し,適当なPDFColdFusion 8パフォーマンス評価ガイドなど)をダウンロードした後,pdfenc.cfmにアクセスし,ダウンロードしたPDFとパスワードを入力し,⁠暗号化してダウンロード」ボタンを押してみましょう。ファイルダウンロードダイアログが表示されると思います。そして,ダウンロードしたPDFを開くには,先ほどフォームに入力したパスワードの入力が求められると思います。

<cfprocessingdirective pageEncoding="UTF-8" />
<cfif StructKeyExists(Form, 'submit')>
  <cffile action="upload" filefield="pdf" destination="#GetTempDirectory()#" nameconflict="MakeUnique">
  <cfpdf action="protect" newUserPassword="#Form.password#" source="#cffile.serverDirectory#/#cffile.serverFile#" name="aPdf">
  <cfset aDownloadName = ReplaceNoCase(cffile.serverFile, '.pdf', '_enc.pdf')>
  <cfheader name="Content-Disposition" value="attachment; filename=#aDownloadName#">
  <cfcontent type="application/octet-stream" variable="#ToBinary(aPdf)#" reset="false">
</cfif>
<cfcontent type="text/html; charset=UTF-8">
<form action="pdfenc.cfm" method="post" enctype="multipart/form-data">
  <p>PDFファイルを指定してください:<input type="file" name="pdf"><br>
     パスワードを入力してください:<input type="password" name="password" value=""><br>
     <input type="submit" name="submit" value="暗号化してダウンロード" ></p>
</form>

いくつか見慣れないタグやコードが出てきているので解説します。

cffileタグではHTMLフォームからアップロードされたファイルを実際にサーバー上にアップロードする作業をします。action属性に「upload」を指定し,フォームからのデータをアップロードする処理であることを明示します。次にfilefield属性にフォームのtype="file"に付けた名前(今回は「pdf⁠⁠)を指定し,どのフィールド名のファイルを扱うかを指定します。最後にdestination属性に,サーバーのどのディレクトリにファイルを置くかを指定します。今回はGetTempDirectory()関数でColdFusionの一時ファイルを置くディレクトリを指定しました。nameconflict="MakeUnique"となっているのは,destination属性で指定したディレクトリに同名のファイルがアップロードされた場合,サーバー上で上書きされないようにするための処置です。

cffileタグでファイルをアップロードすると,cffileスコープというスコープが生成されます。cffileスコープにはserverDirectory(アップロードしたファイルがあるディレクトリ。つまり先ほどdestination属性属性で設定したディレクトリ)やserverFile(アップロードしたファイルのファイル名)などが格納されています。それ以外の値についてはcffileスコープをcfdumpしてみてください(またはcffile action = "upload"のリファレンスページを参照してください⁠⁠。

次に,cfpdf action="protect"とし,source属性で指定したPDFファイルにnewUserPassword属性で指定したパスワードをかける処理をしています。パスワード処理したPDFファイルはname属性で指定した変数に格納されます。

ReplaceNoCase()関数は,その名前の通り大文字小文字を区別せず文字列を置換する関数で,ブラウザにダウンロードさせるファイル名の末尾が「_enc.pdf」になるように,元のアップロードファイル名からダウンロードファイル名を作り出しています。

cfheaderタグはHTTPレスポンスヘッダを指定するためのタグです。今回は先ほどReplaceNoCase()関数で作り出したファイル名でファイルを保存させたいため,HTTPレスポンスヘッダにContent-Dispositionを追加しています。

最後にcfcontentタグで,MIME media typeが「application/octet-stream」なデータをこれから送ることを宣言し,データの中身をvariable属性に渡しています。

オーダーメイドPDFを作る

cfpdfタグではPDF中の任意のページを抽出して,それらを結合し1枚のPDFにすることができます。この機能を利用してオーダーメイドPDFを作成することにしましょう。オーダーメイドPDFとは,あるPDFからユーザーが欲しいと思ったページのみを抽出し,1ファイルにまとめたPDFの事です。

まず,適当なPDFファイルColdFusion 8パフォーマンス評価ガイドなど)を{cf_root}/wwwroot/gihyo/6/source.pdfとして保存します。その後,以下のCFMLをordermade.cfmとして保存し,アクセスします。

<cfprocessingdirective pageEncoding="UTF-8" />
<!--- PDFのサムネイルを置くディレクトリなど --->
<cfset aCurrentDir = GetDirectoryFromPath(GetTemplatePath())>
<cfset aThumbsUrl = 'thumbs'>
<cfset aThumbsDir = aCurrentDir & aThumbsUrl>
<cfset aSourcePdf = aCurrentDir & 'source.pdf'>

<cfif NOT DirectoryExists(aThumbsDir)>
  <!--- PDFのサムネイルが作成されていないので作成する --->
  <cfdirectory
    action="create"
    directory="#aThumbsDir#">
  <cfpdf
    action="thumbnail"
    source="#aSourcePdf#"
    destination="#aThumbsDir#"
    format="png"
    scale="50"
    imagePrefix="thumbs"
    overwrite="yes">
</cfif>

<!--- オーダーメイドPDFを作る部分 --->
<cfif StructKeyExists(Form, 'submit')>
  <cfpdf action="merge" source="#aSourcePdf#" pages="#Form.page#" name="aPdf">
  <cfheader name="Content-Disposition" value="attachment; filename=catalog.pdf">
  <cfcontent type="application/octet-stream" variable="#ToBinary(aPdf)#" reset="false">
</cfif>

<!--- オーダーメイド用の情報を指定してもらう部分 --->
<cfcontent type="text/html; charset=UTF-8">
<cfpdf action="getInfo" source="#aSourcePdf#" name="aPDFInfo">
<form action="ordermade.cfm" method="post">
  <p>
    <cfoutput>
      <ul>
        <cfloop from="1" to="#aPDFInfo.TotalPages#" index="i">
          <li><input type="checkbox" name="page" value="#i#">ページ#i#
            <img src="#aThumbsUrl#/thumbs_page_#i#.png" height="100" style="vertical-align:middle;"></li>
        </cfloop>
      </ul>
    </cfoutput>
    <input type="submit" name="submit" value="オーダーメイドする" >
  </p>
</form>

すると,source.pdfとして保存したPDFの各ページのサムネイルが表示され,左横にチェックボックスが現れたと思います。欲しいページにチェックボックスを入れ,⁠オーダーメイドする」ボタンを押すと,チェックを入れたページのみが書き込まれたPDFが生成され,ダウンロードダイアログが表示されるかと思います。

図3 ordermade.cfmの実行結果

図3 ordermade.cfmの実行結果

このように顧客一人一人に合わせたPDFをサーバー上で作成することも可能なので,オーダーメイドのカタログを作成することも可能でしょう。

また,今回は紹介しませんでしたが,cfprintタグと組み合わせると,ColdFusionが動いているサーバーに接続されたプリンターからPDFを印刷することも可能です。顧客が選んだページのみをプリンタで出力し,顧客ごとにカスタマイズされたダイレクトメールを郵送するなどの使い方も考えられるでしょう。

まとめと次回予告

今回はAdobe製品の一員となったことで強化されたPDF機能をご紹介しました。

特にColdFusion 8で追加されたcfpdfタグでは,複雑なPDF操作がカプセル化されており,オーダーメイドPDFのような複雑な処理も40行程度で記述できてしまうことが分かりました。

今回はご紹介していませんが,DDXというLiveCycleで用いるPDF処理言語を用いると,PDFにヘッダを追加するなど,LiveCycleで行うような複雑なPDF操作をColdFusion上で実現することもできます。

帳票文化が色濃く残る日本において,PDFがタグ1つで簡便に扱えるColdFusionのメリットは計り知れないでしょう。

次回はラインデバッギングをご紹介します。

著者プロフィール

酒井克幸(さかいかつゆき)

フリーのテクノロジーコンサルタント。サーバー選定やネットワーク設計などハードウェアレイヤーから,Webアプリケーションの実装(サーバーサイド,クライアントサイド共)などのソフトウェアレイヤーまでの幅広い経験を活かし,クライアント企業のWebアプリケーション構築支援を行っている。殊にAdobe製品(特にMacromedia)製品には精通している。

ブログcyano(シアノ)