PDFダウンロードでPDFが壊れてしまう現象の解決方法

このQ&Aのポイント
  • PHPからのPDFダウンロードでPDFが壊れてしまうという現象が顧客環境で発生しています。サーバー側の設定に問題がある可能性があります。
  • 問題は特定のPDFファイルにのみ発生しており、MacOSやiPhoneからの接続では問題なく閲覧できます。
  • Apacheの設定を見直すことで問題が解決する可能性があります。具体的な解決方法については詳細な情報が必要です。
回答を見る
  • ベストアンサー

PDF ダウンロード

お世話になってます。 PHPからのPDFダウンロードで以下の様な現象が起きておりまして、 助言を頂きたいと思います。 管理者ページからPDFを添付してお知らせを入力し、 一般ユーザはお知らせを見たりPDFをダウンロードしたりする機能があります。 開発機では、まったく問題なくアップロード・ダウンロードができるのですが、 顧客環境では正常にアップロードができていることは確認ができますが、 Windows環境でダウンロードし、Acrobat Readerで確認するとPDFが壊れているという現象が起きています。 (実際にサーバーにアップロードされたファイルを確認しておりますのでアップロードは正常です。) またそれは、全てのPDFファイルではなく1部のファイルにそのような現象が起きていて さらには、MacOS 及び iPhoneから接続しダウンロードを行い閲覧するには問題はありません。 おそらくサーバー側のApacheのどこかに何か設定があるのかと思いますが検討がつきません。 環境は、CentOS5.9 + Apache 2.2.3 PHPのコードは、以下の通りです。 header("Cache-Control: public"); header("Pragma: public"); header("Content-Type: application/octet-stream; charset=UTF8"); header('Content-Disposition: attachment; filename="'. $file_name .'"'); header('Content-Length: ' . filesize($filepath)); readfile($filepath); 以上、どなたかお分かりのかたいらっしゃいましたら助言を頂けますでしょうか。 よろしくお願い致します。

  • PHP
  • 回答数6
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.3

たとえばこんな感じ <?PHP $filepath="hogehoge.pdf"; $file_name="fugafuga.pdf"; header("Content-type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"{$file_name}\""); header("Content-Length: ".filesize($filepath)); $fp=fopen($filepath,"r"); while (!feof($fp)) { print fread($fp,1024); } fclose($fp); exit;

sadoru
質問者

お礼

ご丁寧にソースをご提供頂きありがとうございます。 確認させて頂きたいと思います。 ちなみに、大変申し訳ございませんがもしご存じであれば教えて頂きたいのですが、 アップロード・ダウンロードが正常にできるPDFとできないPDFでは何が異なるのでしょうか? できるPDFは何度試してもできますし、 できないPDFは何度試してもできません。 PDFを作成する際の環境(バージョン等?)に左右されるのでしょうか?

その他の回答 (5)

回答No.6

BOM付きUTF-8で書かれてるとか? そうであれば全部の場合で失敗すると推測されるから違うか・・・

sadoru
質問者

お礼

ご連絡ありがとうございました。 BOM付きUTF-8ではなかったです。ささいなことでもご指摘頂きありがとうございます。 yambejp様提供のソースで問題なくダウンロードできました。 バイナリセーフではなかったことが原因のようでした。 ありがとうございました。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.5

>正常にできるPDFとできないPDFでは何が異なるのでしょうか? なんでしょうね? とりあえずファイルサイズが一緒だというのであれば WindowsのFCコマンドなどでバイナリベースで比較をして 本当に完全に一致しているか確認するところからでしょうね。 また別解にもあったようにバイナリエディタで開き 特に先頭あたりにゴミがついていないかを見てみるとよいかもしれません。 header関数のContent-Lengthをコメントアウトすると、ファイルサイズが 変わるようであれば、ファイルの入出力のロジックに問題があるかも

sadoru
質問者

お礼

ご連絡ありがとうございました。 ご提供のソースで問題なくダウンロードできました。 ご指摘通り、バイナリセーフではなかったことが原因のようでした。 ありがとうございました。

noname#244856
noname#244856
回答No.4

PHPの関数でバイナリセーフではないものと言えば「ファイル名」を扱う場所だけだと思います。読み取り対象データはereg、ereg_replaceなどの関数を除けばバイナリセーフであったはずです。 壊れたファイルをエディタで見てみると何か分かるかもしれません。バイナリデータの中にエラーメッセージが混入している可能性はあります。

noname#244856
noname#244856
回答No.2

バイナリセーフでないとはこういうことですね。 http://www.asahi-net.or.jp/~wv7y-kmr/memo/php_security.html 要は$filepathにNULLバイトが入ってるとマズいということです。 (そんなこと早々ないと思いますが) 但し$filepathをユーザーから受け取る場合はフィルタリングが必ず必要です。

sadoru
質問者

お礼

ご連絡ありがとうございました。 yambejp様提供のソースで問題なくダウンロードできました。 ご指摘通り、バイナリセーフではなかったことが原因のようでした。 ありがとうございました。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

>PDFが壊れている の状態次第ですね ・大幅にファイルサイズが大きい(小さい) ・微妙にファイルサイズが大きい(小さい) どんな感じなのでしょうか? readfileはバイナリセーフではないので、きちんとしたファイルI/Oで 開いて読んで出力してみてはいかがでしょうか?

sadoru
質問者

お礼

早速のご回答ありがとうございます。 ファイルサイズにつきましては、まったく同じです。 > readfileはバイナリセーフではないので、きちんとしたファイルI/Oで > 開いて読んで出力してみてはいかがでしょうか? とは、 file_put_contents() を利用した方が良いということでしょうか?

関連するQ&A

  • 画像をダウンロードさせたい。

    いろいろなファイルがサーバーにあがっているとして、 その一覧が<a href="">ファイル名</a>で表示されているとします。 ファイル名を押下した時にダウンロードさせたいと思っています。 -------------------------------------------------- header("Content-Disposition: inline; filename=".$fileDlName); header("Content-Length: ".$fileDlSize); header("Content-Type: application/octet-stream"); readfile($filePath) ------------------------------------------------- ↑でCSV,PDF,ZIPファイルなどはダウンロードできるようになりました。 が、JPEG,GIF,PNGなどはブラウザに表示されてしまい ダウンロードできません。 画像も強制でダウンロードさせたいのですがよい方法はありますか?? ブラウザ:IE7 PHP:5.2.3 Apache:2.0.59 以上、よろしくお願いいたしますm(_ _)m

    • ベストアンサー
    • PHP
  • PHPで複数ファイルのダウンロード

    はじめまして、PHPについて質問させていただきます。 PHPでファイルを複数ダウンロードできるようしたいと思っています。 色々調べ、header関数を使用し、以下のように記述すると ファイルのダウンロードは成功しました。 /*****************************************/ // ダウンロードさせる元ファイル(絶対パス) $filepath = 'test_01.pdf'; // 保存時のファイル名(デフォルト) $filename = 'download001.pdf'; // HTTPヘッダ送信 header("Content-length: " . filesize($filepath)); header("Content-type: application/pdf"); header("Content-Disposition: attachment; filename=\"{$filename}\""); // ファイルを読み込んで出力 readfile($filepath); /*****************************************/ 一つのファイルのダウンロードに成功したので、 次に複数のファイルを順番にダウンロードをさせる為にループ処理をしました。 /*****************************************/ //配列 複数ファイル $downfile = array("test_01","test_02","test_03"); //データ数 $max = count($downfile); // ダウンロードさせるディレクトリ(絶対パス) $filepath = "/home/sites/www.eshop-himawari.com/web/test_nihon/form_down/file/"; // 保存時のファイル名(デフォルト) $filename = "download"; $filetype = ".pdf"; $kazu = 1; //ループ処理 for( $i = 0; $i < count( $max ); $i++ ){ $downpath = $filepath.$downfile[$i].$filetype; $filename = $filename.$kazu.$filetype; $kazu = $kazu++; // HTTPヘッダ送信 header("Content-length: " . filesize($downpath)); header("Content-type: application/pdf"); header("Content-Disposition: attachment; filename=\"{$filename}\""); // ファイルを読み込んで出力 readfile($downpath); // $fp = fopen( "$downpath", "rb" ); // @fpassthru( $fp ); } /*****************************************/ しかし実行すると最初のファイルはダウンロードしますが 2つ目からのファイルはダウンロードされませんでした。 きちんとループ処理をされて、2つ目以降のファイルをダウンロード するには、どうすればいいのでしょうか?

    • 締切済み
    • PHP
  • ダウンロードが機能しない。

    html,php共に初心者です。教えて頂けますか? ダウンロードボタンを押すと、以下のphpファイルを開きダウンロードを行う様にしたのですが、mac safari ではダウンロード出来たのですが、 windows IE では ダウンロード出来ませんでした。 ファイルの構成は以下です。 /www/category/contentsList.php <-ダウンロードボタンがあります /www/category/downloader.php <-ダウンロードボタンを押すと呼ばれます。 /contentDirectory/ダウンロードするファイル.zip downloader.phpの記述は以下のみです。 <?php $serverDirectory = dirname($_SERVER['DOCUMENT_ROOT']); $contentDirectory = $_POST['contentDirectory']; $fileName = $_POST['fileName']; $filePath = $serverDirectory.'/'.$contentDirectory.'/'.$fileName; header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$fileName.'"'); header('Content-Length: '.filesize($filePath)); readfile($filePath); ?> どうすれば良いでしょうか? 大変申し訳ありません。よろしくお願いします。

    • ベストアンサー
    • PHP
  • PHPによるファイルのダウンロード

    初めまして最近ちょっとはまってしまっているので分る方がいましたらアドバイスお願いします。 PHPのheader関数を使ってブラウザのダイアログを表示させるファイルのダウンロードを実装した際に、ファイルサイズが大きいものをダウンロードしているとダウンロードが完了するまで他のアクセスが応答しなくなる場合があります。 基本的には $fp = fopen($filePath, "rb"); $contents = fread($fp, filesize($filePath)); fclose($fp); $len = strlen($contents); header("Content-type: application/octet-stream"); header('Content-disposition: inline; filename="' . $filename . '"'); header("Content-length: " . $len); echo $contents; というような一般的な書き方をしています。 ファイルのサイズ的には10MB前後です。 同じような現象を解決された方がいましたらアドバイス頂けると幸いです。

    • 締切済み
    • PHP
  • PHPでファイルのダウンロードすると開けません。

    PHPでファイルのダウンロードすると開けません。 文書を整理するために、アップロードして、必要に応じてダウンロードする仕組みを作っています。 PDFや画像のファイルは問題ないのですが、、 word文書(エクセルもダメでした)を、以下のファイルを作って、ダウンロードし開こうとすると 「ファイル******.docxは無いように問題があるため、開けませんでした。」となります。 ※エクセルでは、「Exelで****.xlsxを開くことが出来ません。ファイル形式またはファイルか拡張子が正しくありません。ファイル拡張子とファイル形式が一致していることを確認してください」  とダイアログが出てきます。 $file="アップロードしてある実ファイル名"; $file_name="ローカルに保存する際のファイル名"; ※ファイル名を変更しなくても同じなので、そこは関係ないと思います。 header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=$file_name"); header('Content-Length: '.filesize('$file')); readfile($file); リンクを張って開くのには何の問題もありません。 <a href="http://www.******.com/images/$file">$file_name</a> ダウンロードする際に名前を変更したいので、ダウンロード用のファイルを作ってダウンロードさせようとしています。 何か、ダウンロードをする前に処理が必要なのでしょうか? よろしくご教授お願いいたします。 ※ワード、エクセルは2010を使用しています。

    • ベストアンサー
    • PHP
  • pdfがダウンロードできません。

    サーバにpdfファイルをアップロードし、 ブラウザを通してダウンロードしていたのですが、 .htaccessにてBasic認証を行うようになってから そのpdfファイルがダウンロードできなくなりました。 (アクロバットのエンジンは起動しているようです。) ・ブラウザはIEとFirefoxを使用していますが共にNGです。 ・試しにpdfファイルが格納されているフォルダに  htmlファイルを格納した場合は正常に表示されます。 ・IEのセキュリティでそのサイトを信頼済みサイトに  してもNGです。 ・index.htmlに記載してあるリンクを右クリックダウンロード  にするとリンク先が見つかりませんというようなメッセージが  表示されます。 .htaccessにMIMEタイプを追加すればいいのでしょうか? よろしくお願いします。 ■階層 folder │ .htaccess │ passwd │ index.html(←閲覧可能) │ ├─folder1 │ test1.pdf │ ├─folder2 │ test2.pdf │ └─folder3 test3.pdf ■サーバ環境 OS:Linux Apache ■クライアント環境 OS:Windows2K

  • ファイルのダウンロードについて

    いつもお世話になっております。 ファイルのダウンロードについて質問です。    header('Content-Type: image/jpeg'); header('Content-Length: '.filesize($fpath)); header('Content-disposition: attachment; filename="'.$fname.'"'); readfile($fpath); headerを使っています。 ダウンロードしたいファイルは jpg,pdf,xls,xlsx,doc,ppt,などですが それぞれ Content-Type は 拡張子 xlsなら  header('Content-Type: application/vnd.ms-excel'); にと 変更しております。 エクセルを ダウンロードしますと、 「開こうとしているファイルは実際にはその拡張子が示すファイル形式ではありません。 このファイルを開く前にファイルが破損していないこと、信頼できる発行元からの ファイルであることを確認してください。ファイルを今すぐ開きますか?」 とメッセージが出てきて、「はい」とすると 文字化けしたエクセルが開きます。 ワードですと、開いて修復しますかとエラーが出た後 ⇒OK⇒ 正しく開けます。 PDFだと 問題なく開きます。 エクセルとワードは 下記のように書きますと <a href='files/ファイル名' target='_blank'> 正しく開くことができますが、この方法だと ダウンロードするファイル名を 変更できませんので、使うことができません。 上記のエラー解決方法はありますでしょうか。 また header 以外の方法で ファイル名を変更して ダウンロードする方法が ありましたら 教えていただけませんでしょうか。 情報不足でしたらすみません。 よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • バイナリファイルをダウンロードできなくなりました。

    バイナリファイルをダウンロードできなくなりました。 以下のように、fopen で取得したバイナリデータをブラウザにダウンロードさせていましたが、ある時からダウンロードできなくなりました。 ・プログラムコードは変更していません。 ・同様の処理をしている全ての箇所が失敗するようになりました。 ・いずれも、かつては正常に動作していました。 ・ApacheやPHPはエラーメッセージを出力していません。 Apacheの設定またはPHPの設定を変えてしまったのかな、と推測していますが、原因がつかめていません。 検討がつかないので困っています。推測できる原因をご提示ください。 [環境] CentOS 5.3 (ルート権限も持っている、完全にコントロールできる環境です) PHP 5.1.6 Apache 2.2.3 [問題のコード その1] $ret=''; $handle = @fopen($file_name, 'r'); if ($handle) { while (!feof($handle)) $ret.=fread($handle, 8192); fclose($handle); } header('Content-disposition: attachment; filename="'.$src.'"'); header('Content-type: audio/3gpp'); header('Cache-Control: private'); header('x-jphone-copyright: no-transfer'); die($ret); [問題のコード その2] $url = "http://chart.apis.google.com/chart?".http_build_query($query); $img = @imagecreatefrompng($urls); $img = @imagerotate($img,270,0); header('Content-Type: image/jpeg'); imagejpeg($img); [問題のコード その3] $url = "http://example.net/example.php"; $options = array('http' => array( "method" => 'POST', "header" => "Content-Type: application/x-www-form-urlencoded\r\n" "content" => http_build_query($data), )); $contents = @file_get_contents($url, false, stream_context_create($options)); //書きだし header('Content-Type: application/x-shockwave-flash'); header('Content-Length: '.strlen($contents)); print $contents;

    • 締切済み
    • PHP
  • 子ウィンドウを閉じる

    今、チェックボックスにチェックを入れると javascriptで子ウィンドウを開き pdfファイルをダウンロードできるようにしています。 ********************************* check.html でのjavascript function down() { if (document.f1.file001.checked == true) { newwin = window.open( "down.php?date=data1" ,"_blank","width=100,height=100"); } if (document.f1.file002.checked == true) { newwin = window.open( "down.php?date=data2" ,"_blank","width=100,height=100"); } if (document.f1.file003.checked == true) { newwin = window.open( "down.php?date=data3" ,"_blank","width=100,height=100"); } if (document.f1.file004.checked == true) { newwin = window.open( "down.php?date=data4 ,"_blank","width=100,height=100"); } } ************************************ 子ウィンドウで開く down.php <?php //ダウンロードするファイル $files = $_GET[date]; //ディレクトリ名 $datedir = "file/"; //拡張子 $filetype = ".pdf"; // ダウンロードさせる元ファイル $filepath = "{$datedir}{$files}{$filetype}"; // 保存時のファイル名(デフォルト) $filename = "{$files}{$filetype}"; // HTTPヘッダ送信 header("Content-length: " . filesize($filepath)); header("Content-type: application/pdf"); header("Content-Disposition: attachment; filename=\"{$filename}\""); // ファイルを読み込んで出力 readfile($filepath); fclose($filepath); ?> *************************** これだとファイルのダウンロードはできるのですが 子ウィンドウが残ってしまいます。 javascript で setTimeout("newwin.close()", 8000); と子ウィンドウを閉じるようにしていても 閉じてくれません。 どうすれば、子ウィンドウを閉じることができるでしょうか? また閉じれない場合は、子ウィンドウに閉じるボタンを つけたいのですが down.php には header関数でファイル出力をしている為 その後にhtmlを書いても無効になります。 親ウィンドウの方から子ウィンドウに文字を出させることは できるでしょうか?

  • PHPでのファイルダウンロードについて

    初めて質問させていただきます。 社内用でファイルのアップロード・ダウンロードができるシステムを開発しています。 PCからは問題なくアップロードもダウンロードも行えていたのですが、 スマホからアクセスしてダウンロードをすると失敗してしまいます。 下記のコードを使ってます。 ファイルの種類はいろいろなので、「application/octet-stream」にしてます。 が、それぞれのファイルタイプに合わせて変更させても状況は変わりませんでした。 -- header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$file_name.'"'); header('Content-Length: '.filesize($dl_file)); readfile($dl_file); exit; -- なにか解決策があるようでしたら、教えていただけないでしょうか。 よろしくお願いします。

    • ベストアンサー
    • PHP