PDF(等)のファイルをブラウザで開かせずにダウンロード形式にさせる。

Advertisement


あんまり無いんですけど、PDFをブラウザではなくてダウンロードさせる形にする方法です。ターゲット的にZIPをユーザーに使わせたくなかったので、どうしてもPDFをダウンロードさせたかったんです。以前htacessでやった記憶があるのですが、サーバにモジュールが無いのか、上手くいかなかったので備忘録。

.htaccess記述方式

確かこれでいけたと思ったのですが、
サーバがアレなせいか、この方式だと上手くいきませんでした。

AddType application/octet-stream pdf

PHP通す方式

なのでこんな感じでPHPファイルを作って、
そこを介してあげたら出来ました。

<?php
$Filename = 'donload01.pdf';
$ContentType = 'application/pdf';
$TargetFile = fopen($Filename, 'rb');
if ($TargetFile)
{
header("Content-Type: $ContentType");
header("Content-Disposition: attachment; filename=$Filename");
while (!feof($TargetFile))
{
print fread($TargetFile, 1024);
}
fclose($TargetFile);
}
else
{
header('Status: 500 Internal Server Error');
header('Content-Type: text/plain');
print('Failed to open the file.');
}
?>

でもこれって
<a href="donload01.php" target="_blank">ダウンロード</a>
みたいにしなきゃいけないんですよね。

なんとなく面倒な感じですが、
PDFで閲覧させるリンクと、ダウンロードさせるリンクを併用させたかったので、結果オーライだったかも。

タイトルを(等)と入れたのは、
Filename
ContentType
を変えればJPGでもepsでも、データ関連は使えるかなと思います。
(これこそ使う機会少ないですけど)


追記

@aWebprogrammerさんが、
PHPの方、もうちょっと良くできるとの事でコード書いてくれました。
<?php
//download.php
//※要ディレクトリトラバーサル対策
$file = realpath($_GET["file"]);
if($file && isset($file) && file_exists($file)) {
  header("Content-length: ".filesize($file));
  header('Content-Type: application/octet-stream');
  header('Content-Disposition: 
 attachment; filename="' . $file . '"');
  readfile("$file");
} else {
  echo "No file selected";
}
/*
こんな感じで呼び出し
<a href="download.php?file=[ここにダウンロードするファイル名を入れる]">
*/
?>

追記20130819

以下の様なお問い合わせを頂きました。ご返答先の記載がありませんでしたので、代わりに追記という形で感謝申し上げます。

download.phpについてなのですが、ファイルの拡張子をフィルタリングした方が良いのではないでしょうか?
※ファイルのチェック部分にif( substr($file,strlen(".pdf")) == ".pdf" )を追加してフィルタリングしてはいかがでしょうか?
§download.phpをwww.sample.hpに設置したとして
 悪意ある人が、www.sample.hp/download.pho?file=index.phpを要求するとphpファイルがそのままダウンロードされてしまうのではないでしょうか?