質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.01%

PDFを表示してから保存する方法

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,253

SystemAjisai

score 150

 前提・実現したいこと

CodeIgniter2を使ったWebシステムで、PDFを作るプログラムを作成しています。
目指している挙動は

  1. ユーザがダウンロードボタンを押す
  2. PHPでPDFを作成
  3. 作成したPDFを別ウインドウで表示
  4. 保存したければ保存してもらう

となります。
対象ブラウザはGoogleChromeのみです。
4.のPDFの保存は、ブラウザ上でPDFを表示した際に「ダウンロード」というアイコンが出るので、
その機能を使ってもらう予定にしています。
イメージ説明
※指の形のカーソルが出てるアイコンの事です

 発生している問題・エラーメッセージ

3のPDF表示までは上手くいっていますが、その後ダウンロードアイコンを押すと、
「失敗-ネットワークエラー-」と表示されてしまい、ダウンロードできません。
イメージ説明

表示できているのにダウンロードで失敗する場合、どこを疑えばいいのかもよくわかっていない状態です。
ネットワークエラーと表示されているので何かしらPHPのプログラムに問題があるのでは?と調査しているのですが、有用な情報を見つけることができません。

また、ブラウザ上に表示されるファイル名(画像で塗りつぶしている箇所)について
下記ソースの通り「sample.pdf」になるのを期待していますが、実際にはパラメータ名(※1)になってしまっています。
ここに拡張子が付いていないのが問題かと思い、試しにパラメーターに.pdfを付けてみましたが、結果は同じでした。

どうすれば表示したPDFを保存できるようになるのでしょうか。
ブレイクポイントを設定してダウンロードアイコンを押してみましたが、PHPが呼ばれていなかったため、最初にPDFを表示した時のレスポンスの設定が怪しいと思い、該当箇所のソースを載せています。
見当違いの場合は、お手数ですが指摘して頂ければ助かります。

(※1)
CodeIgniterを使用しているので、パラメーターを渡す場合urlの関数名の後ろに/paramという形で加えます。

http://~~~/download/aaa

の場合、表示されるファイル名が「aaa」になってしまいます。

 該当のソースコード

以下がPDFを返している処理です。

function download($param){
    :
    :
  $html = $this->load->view(PDF化したいviewのパス, $result, TRUE);
  $pdf = new Knp\Snappy\Pdf(wkhtmltopdfのパス);
  $pdf->setOption('encoding', 'utf-8');
  $this->output
        ->set_header('Content-Disposition: inline; filename="sample.pdf"')
        ->set_content_type("application/pdf")
        ->set_output($pdf->getOutputFromHtml($html));
}

 試したこと

その1
PDFに問題があるのか調査するため、Content-Dispositionをattachmentにしてどうなるか試してみました。

function download($param){
    :
    :
  $this->output
    ->set_header('Content-Disposition: attachment; filename="sample.pdf"')
    ->set_content_type("application/pdf")
    ->set_output($pdf->getOutputFromHtml($html));
}


ファイルがダウンロードされ、開くこともできました。
一応ダウンロードアイコンを押してみましたが、ちゃんとダウンロードできました。

その2
作成したPDFは実体のファイルになっていないのが原因ではないかと思い、
一旦サーバーに実ファイルを作成して、ファイルをダウンロードするようにしてみました。

function download($param){
    :
 $this->load->helper('file');
 $data = read_file("作成したPDFファイルのパス");

  $this->output
    ->set_header('Content-Disposition: inline; filename="sample.pdf"')
    ->set_content_type("application/pdf")
    ->set_output($data);
}


実ファイルを作成する前と同様、
ファイルの内容は表示されるけど、ダウンロードを押すとネットワークエラーになってしまいました。
またブラウザ上に表示されるファイル名もsample.pdfではなくパラメーター名になってしまいました。

 (追記) 解決した設定

asahina1979さんにご指摘頂いて、作成したPDFがキャッシュされるように指定を加えました。

 $this->output
     ->set_content_type("application/pdf")
         ->set_header('Content-Disposition: inline; filename=sample.pdf')
// 追加ここから
         ->set_header('Last-Modified: Fri Jan 01 2010 00:00:00 GMT') 
         ->set_header('Expires: Fri Jan 01 2019 00:00:00 GMT') // お試しで未来日を入れる
         ->set_header('Cache-Control: private, max-age=86400') // お試しで1日にしてみる
// 追加ここまで
         ->set_output($pdf->getOutputFromHtml($html));

インラインで表示後ダウンロードアイコンを押して正常にダウンロードされるようになりました。
ファイル名についてもキャッシュの設定を加えることで反映されるようになり、sample.pdfとしてダウンロードできました。
ありがとうございました!

 補足情報(FW/ツールのバージョンなど)

PHP 7.1
CodeIgniter 2
GoogleChrome
wkhtmltopdf(PDF作成用)
Snappy(PDF作成の元ネタHTML作成用)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SystemAjisai

    2018/02/22 09:29

    キャッシュというのは何も設定していませんでした。動的に作ってるPDFだけどURL一緒だから同じものとして扱われて再取得が行われないのでは?という意味かなと思って、PDFを返す時のset_headerでCache-Controlをno-store,no-cashe、Apacheのhttpd.confにもキャッシュさせないための設定を調べて入れてみたのですが、同じ状態になってしまいました。。。

    キャンセル

  • asahina1979

    2018/02/22 09:32

    通信してないということはキャッシュからとってきてるのではとおもったから無効化が原因なのではと思った次第(なんで 来年指定などで)

    キャンセル

  • SystemAjisai

    2018/02/22 09:52

    すみません!真逆にとらえてしまいました! レスポンスのset_headerでキャッシュを残す設定というのを調べて入れて、さっき追加したApacheのキャッシュさせない設定も削除したら無事にダウンロードすることができました!! おまけに設定しても無視されていたfilenameの指定も受け付けてもらうことができました。ベストアンサーにしたいので回答の方に記載して頂けると嬉しいです。直した内容は質問文に追記します。本当にありがとうございます!

    キャンセル

回答 1

checkベストアンサー

0

通信ログがないということはキャシュから取得していると思われるので
キャッシュを未来日に設定してはいかがでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/22 12:59

    本当に色々とありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる