サーバ側で作成したPDFの表示とクライアントPCへの保存時のファイル名の指定

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

やりたいこと

  1. サーバ側でPDFを生成し、そのままブラウザウィンドウ内に表示する。(開く or 保存のダイアログを出さずに)
  2. 表示したPDFファイルをクライアントに保存する時のファイル名を指定する。

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

いったんブラウザに表示したPDFを[Ctrl]+[S]等で保存する時に・・

exp1.png

↓ こうではなくて・・

exp2.png

↓ こうなって欲しい

exp3.png

RFC的にはどうなのか

これを実現するには、Content-Disposition: inline としながら、filename も指定する事になる。
※Content-Disposition: inline;filename="ファイル名"

でも、この組み合わせはありなのか?
RFCを調べてみた。

https://tools.ietf.org/html/rfc6266#section-4.3

4.3. Disposition Parameter: 'Filename'

The parameters "filename" and "filename*", to be matched case-
insensitively, provide information on how to construct a filename for
storing the message payload.

Depending on the disposition type, this information might be used
right away (in the "save as..." interaction caused for the
"attachment" disposition type), or later on (for instance, when the
user decides to save the contents of the current page being
displayed).

どうも、あり らしい。
表示した後でも filename パラメータが使用される可能性がある。と書いてある。

問題点

  1. RFC的には問題ない筈なのだが「Content-Disposition: inline;filename="ファイル名"」 を正しく処理してくれないブラウザがある。
    ※ Content-Disposition が inline の時は、指定した filename が効かない。
  2. ファイル名のURLエンコードが必要なブラウザと、逆にURLエンコードしない方が良いブラウザがある。
    ※ これもRFC的にはエンコードするのが正しい筈だが。

どのブラウザが問題?

Content-Disposition が inline 時に filename が効かないブラウザがどれかを調べてみた。(ついでにファイル名のエンコードも)
※ バージョンが - のものは 2013年2月時点の最新を使用。
※ PDFリーダーは2013年2月時点の最新を使用。

OSブラウザバージョンinline時のfilename日本語ファイル名のエンコード
WinXPInternet Explorer6無効エンコードが必要
WinXPInternet Explorer7無効どちらでもOK
WinXPInternet Explorer8無効どちらでもOK
Win7Internet Explorer9無効どちらでもOK
WinXP/7Google Chrome-有効どちらでもOK
WinXP/7Mozilla Firefox-有効エンコードしちゃダメ
MacSafari-有効エンコードしちゃダメ
MacGoogle Chrome-有効どちらでもOK
MacMozilla Firefox-面倒くさそうなので省略
(アドオン設定が正しくされていればたぶんWindowsと同じ)

こうやって見ると、やっぱり Google Chrome はかなり優秀。
IEはどのバージョンでも filename 属性は無効。※IE10は調べてないけど変わってるのかな?

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

Content-Disposition で指定したfilenameが有効な環境の場合

以下のとおり実装する。特に難しい所はなし。

実装サンプル(PHPの場合)

 // 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;

Content-Disposition で指定したfilenameが無効な環境の場合

この場合は、HTTPヘッダで指定したファイル名でなく、その時に表示しているURLが保存時のファイル名になってしまうので、少し工夫が必要になる。

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

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

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

実装イメージ

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

image.png

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

実装サンプル(PHPの場合)

※デモ・サンプル : http://www.magata.net/test/download_pdf/

create_pdf.php

 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);

.htaccess (mod_rewriteの定義)

 RewriteEngine On
 
 # PATH変換(pdf -> php)
 RewriteRule ^.*\.pdf$ load_pdf.php [L] 

load_pdf.php

 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;

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


添付ファイル: fileexp3.png 3件 [詳細] fileexp2.png 3件 [詳細] fileexp1.png 3件 [詳細] fileimage.png 4件 [詳細]

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2013-02-23 (土) 05:46:27 (2773d)