* サーバ側で作成したPDFの表示とクライアントPCへの保存時のファイル名の指定 [#a9ba6dfa]
#setlinebreak(on)
#contents

関連 : [[サーブレットでファイルダウンロード]]

** やりたいこと [#p3afb117]
+サーバ側でPDFを生成し、そのままブラウザウィンドウ内に表示する。(開く or 保存のダイアログを出さずに)
+表示したPDFファイルをクライアントに保存する時のファイル名を指定する。

 《メモ》
 上記(1) は Content-Disposition に inline を指定するだけで実現可能なので、何も難しい事はない。※ただし Content-Type の指定は必須。
 上記(2) はブラウザ環境によって挙動が異なるため、けっこう難問。※調べて分かったが問題なのは IE だけ。

#html(<table style="margin:0px 0px 20px 0px;"><tr><td>)
#html(<p style="padding-left:40px;">ブラウザに表示したPDFを保存する時に・・</p>)
#ref(exp1.png,nolink)
#html(</td><td align="left">)
#html(<p style="padding-left:40px;">↓ こうではなくて・・</p>)
#ref(exp2.png,nolink)
#html(<p style="padding-left:40px;">↓ こうなって欲しい</p>)
#ref(exp3.png,nolink)
#html(</td></tr></table>)

** 問題点 [#ve7c5791]
+クライアント環境(ブラウザ)によっては、Content-Disposition が inline の時は、指定した filename が効かない場合がある。
+ブラウザによってファイル名のエンコードが必要な場合と、逆にエンコードしない方が良い場合がある。

 以降は、特に問題点(1)について記載する。

** どのブラウザが問題? [#z0cf9c5b]
#html(<div style="padding:0px 0px 10px 10px;">)
Content-Disposition が inline 時に filename が効かないブラウザがどれかを調べてみた。(ついでにファイル名のエンコードも)
※ バージョンが - のものは 2013年2月時点の最新を使用。
※ PDFリーダーは2013年2月時点の最新を使用。
#html(</div>)
|OS|ブラウザ|バージョン|inline時のfilename|日本語ファイル名のエンコード|h
|WinXP|Internet Explorer|6|&color(red){無効};|&color(red){エンコードが必要};|
|WinXP|Internet Explorer|7|&color(red){無効};|&color(green){どちらでもOK};|
|WinXP|Internet Explorer|8|&color(red){無効};|&color(green){どちらでもOK};|
|Win7|Internet Explorer|9|&color(red){無効};|&color(green){どちらでもOK};|
|WinXP/7|Google Chrome|-|&color(green){有効};|&color(green){どちらでもOK};|
|WinXP/7|Mozilla Firefox|-|&color(green){有効};|&color(red){エンコードしちゃダメ};|
|Mac|Safari|-|&color(green){有効};|&color(red){エンコードしちゃダメ};|
|Mac|Google Chrome|-|&color(green){有効};|&color(green){どちらでもOK};|
|Mac|Mozilla Firefox|-|>|面倒くさそうなので省略&br;(アドオン設定が正しくされていればたぶんWindowsと同じ)|

#html(<div style="padding-left:10px;">)
こうやって見ると、やっぱり Google Chrome はかなり優秀。
IEはどのバージョンでも filename 属性は無効。※IE10は調べてないけど変わってるのかな?

※検証に使用したコード : http://www.magata.net/test/download_pdf/

#html(</div>)

** Content-Disposition で指定したfilenameが有効な環境の場合 [#k3406116]
#html(<div style="padding-left:10px;">)
以下のとおり実装する。特に難しい所はなし。
#html(</div>)

#html(<div style="padding-left:10px;">)
*** 実装サンプル(PHPの場合) [#q72eedb7]
 // PDFの作成
 $data = pdfデータを作成する関数();
 
 // PDFファイル名の指定
 pdf_fname = urlencode("xxxx.pdf");
 
 // HTTPヘッダを出力
 header("Content-Type: application/pdf");
 header("Content-Disposition: inline;filename=\"${pdf_fname}\"");
 
 // PDFデータを出力
 echo $data;
 exit;
#html(</div>)

** Content-Disposition で指定したfilenameが無効な環境の場合 [#kd108b65]

#html(<div style="padding-left:10px;">)
この場合は、HTTPヘッダで指定したファイル名でなく、その時に表示しているURLが保存時のファイル名になってしまうので、少し工夫が必要になる。

《案1》
 Content-Disposition に attachment を指定し、いったんダウンロードダイアログを表示する。
 ※いちどダウンロードダイアログを表示すると、filename 属性が有効な状態で開くので、
  開いた後に保存をした場合にも filename で指定したファイル名で保存ができる。

《案2》
 リダイレクトと mode_rewrite などを駆使して、URLが保存時のファイル名になるようにする。

案1で妥協できる場合は、inline を attachment に変えるだけなので、詳細は省略。
以降では、案2について記載するが、ここまでやりますか?という感じがしなくもない。


*** 実装イメージ [#l5e84f98]
#html(<div style="padding:10px 0px 10px 10px;">)
保存時に使用したいファイル名がURLになるように、リクエストを行うようにする(リダイレクトさせる)。
つまり、 xxxx.pdf にアクセスした時に、PDF生成/取得処理が行われるようにする。
ただし、そのまま xxxx.pdf にアクセスすると、xxxx.pdf をそのまま表示してしまうので、
*.pdf  へのリクエストを PDF取得用のプログラムのPATHに動的に変換する。
(下記では mod_rewrite を使用しているが、JAVAなどの場合は web.xml に同じ意味合いの記述を行っても良い。)
#html(</div>)

#ref(image.png,nolink)

#html(<div style="padding-left:40px;">)
上図の(C) の時点で、ブラウザがアクセスしている URL は xxxx.pdf となるので、
表示しているページを保存しようとした場合には、xxxx.pdf というファイル名で保存を行う事ができる。
※ サーバ上にpdfを生成して直接アクセスしても良いけど、マルチユーザを考慮し、動的処理にしたうえでセッションを利用。
※ load_pdf.php で全部やっても良いけど、生成するファイルの内容に応じてファイル名を動的に変えたいケースを考慮して、生成と取得を分けてみた。
#html(</div>)

*** 実装サンプル(PHPの場合) [#q72eedb7]

#html(<div style="padding-left:10px;">)
※デモ・サンプル : http://www.magata.net/test/download_pdf/
#html(</div>)

#html(<p style="padding-left:10px;">create_pdf.php</p>)
 session_start();
 
 // PDFの作成
 $data = PDFを作成する関数();
 
 // PDFをセッションに格納
 $_SESSION["download_pdf"] = $data;
 
 // リダイレクト
 $pdf_fname = urlencode("xxxx.pdf");
 header("Location: " . "http://" . $_SERVER["HTTP_HOST"] . "/test/download_pdf/" . $pdf_fname);

#html(<p style="padding-left:10px;">.htaccess (mod_rewriteの定義)</p>)
 RewriteEngine On
 
 # PATH変換(pdf -> php)
 RewriteRule ^.*\.pdf$ load_pdf.php [L] 

#html(<p style="padding-left:10px;">load_pdf.php</p>)
 session_start();
 
 // HTTPヘッダに指定するPDFファイル名( filenameが有効な環境用)
 $pdf_fname = urlencode("xxxx.pdf");
 
 // セッションに退避しておいたPDFデータを出力
 header("Content-Type: application/pdf");
 header("Content-Disposition: inline;filename=\"${pdf_fname}\"");
 echo $_SESSION["download_pdf"];
 exit;

#html(</div>)

上記までで、とりあえず問題点(1)は解決。

トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS