Menu

ファイルをダウンロードさせる

2015年9月13日17:42  投稿者 : PINION

ダウンロード

普通、サーバーに上がっているファイルにリンクを張ると、ブラウザーはそのまま表示しようとします。
PDFのように、そのままでは開けないようなファイルでも、プラグインを使ったり、ブラウザーに内臓されたビュワーを使って、ページに表示させるというのが一般的なブラウザーの挙動です。

もちろん、例えばWindowsならリンクを右クリックして「ファイルに保存」なんてやれば保存できますが、最初からリンクをクリックしたらダウンロードするようにしたい場合もありますよね。
保存して貰うにも、相手の環境によって手順が違ったりしますし、わざわざ「Macの方は~」「スマートフォンの方は~」なんてずらずら書くのも、あまり美しくありませんし。

そんな時は、PHPでヘッダー情報に「ダウンロードしろ」という情報を追加してから、ダウンロード対象のファイルを出力してやれば、ブラウザーはダウンロードしてくれます。
最小限の記述をすると、

<?php
	header('Content-Type: application/force-download');
	readfile(ファイル名);
?>

これだけでもダウンロード出来ます。
1行目がヘッダー情報、2行目がファイル送信です。
「PHP ファイル ダウンロード」なんかで検索をかけると沢山出てきますが、

header(‘Content-Type: application/octet-stream’);

となっている事が多く、しかしこれではブラウザーによってはうまくいかないようです。
また、上記は最小限の記述なので、やはり環境によってはうまくいかない事もあったり、別の問題があったりしますので、もう少し書き加えてみましょう。

<?php
	$file_path = "ファイルの場所";
	$file_name = "ファイル名";
	$file = $file_path . $file_name;
	header("Pragma: cache;");
	header("Cache-Control: public");
	header('Content-Type: application/force-download');
	header('Content-Length: ' . filesize($file));
	header('Content-disposition: attachment; filename="' . file_name . '"');
	readfile($file);
?>

1行目はダウンロードさせるファイルの場所。
これは、サーバー上での場所であってURLではないので、詳細は後述します。

2行目は、ダウンロードさせるファイルの名前。
3行目は、場所とファイル名を繋げたものを作っています。

4行目、5行目はキャッシュコントロールについての記述。
特に深く理解する必要はありませんが、古いIE(8以前)でSSL接続時には、これを記述してやらないとうまくダウンロードされないようです。
実際、私が業務でこれが無い状態で運用していたら、ダウンロード出来ないというお問い合わせがありました。

6行目は最初にあった「ダウンロードしてね」という記述ですね。

7行目は、ダウンロードするファイルのサイズを伝えています。無くても問題は無いようです。

8行目は、ダウンロードするファイルのファイル名を伝えています。
これがないと、例えばこのダウンロード用PHPファイルが「download.php」としてアップされている場合は、ダウンロードされたファイルが「download.php」という名前で保存されてしまいます。

9行目は、前述と同じく実際にファイルを出力しています。

さて、1行目のファイルの場所ですが、いわゆるサーバー上の「フルパス」を使用しましょう。
といっても、これはサーバーによって違うので、慣れないとよく判らないですよね。
FTPソフトで繋がったディレクトリーがトップではなく、その上にサーバー上のパスが存在するため、フルパスはサーバーによって異なりますので、取得してやる必要があります。

<?php
	echo dirname(__FILE__) . '/';
?>

上記のファイルを、ダウンロードファイルを保存しておく場所にアップロードしてアクセスします。
例えばこのサイトに「download」ディレクトリを作って「path.php」の名前でアップロードしておき、
http://www.mp-create.com/download/path.php
にアクセスすると、

/home/******/www/*****/download/

と表示されます。(一部*で伏字にしています。)
これがサーバー上のフルパスです。
これを、ダウンロード用プログラムの「ファイルの場所」の部分に記述してやると、そこにあるファイルを読みに行ってくれます。

パスの中にアカウントが入っていたりする事もありますし、サーバー構造を知られる事でセキュリティ上問題が起きたりする事もありますので、パスを確認したらサーバー上からpath.phpは削除しておきましょう。

最後に、ダウンロードの際に対象ファイルが無い時、PHPエラーが出ない様に、もう少しソースに工夫をしてみましょう。

<?php
	$file_path = "/home/******/www/*****/download/";
	$file_name = "sample.pdf";
	$file = $file_path . $file_name;

	if(!file_exists($file)) {
		// ファイルの存在チェック
		die($filename." がありません。");
	} else if(!($fp = fopen($file , "r"))) {
		// ファイルオープンチェック
		die($filename . " が開けません。");
	} else if(($content_length = filesize($file)) == 0) {
		// ファイルサイズチェック
		die($filename . " ファイルは空です。");
	}

	header("Pragma: cache;");
	header("Cache-Control: public");
	header('Content-Type: application/force-download');
	header('Content-Length: ' . filesize($file));
	header('Content-disposition: attachment; filename="' . file_name . '"');
	readfile($file);
?>

ファイルが存在しなければ「○○がありません。」
ファイルが開けなければ「○○が開けません。」
ファイルサイズが0ならば「○○ファイルは空です。」
というメッセージを表示すると共に、プログラムを終了しています。
(dieはメッセージ表示と共に処理を終了するという関数です。)

無くてもPHPエラーが出て止まるだけですので構わないのですが、PHPエラーが表示されるよりメッセージを用意しておいたほうが「ちゃんと処理してる」という感じがしますし、ダウンロード出来なかったお客様からお問い合わせがあった時にもPHPエラーを読んでもらうより、日本語のメッセージが出ていたほうが原因が判りやすいでしょう。

出来上がったら、「download.php」などの好きな名前を付けてサーバーにアップロードし、

<a href=”download.php”>サンプルダウンロード</a>

などという形で、このPHPへ普通にリンクを張ってやれば、ダウンロードされます。

コメントを残す

メールアドレスが公開されることはありません。

コメントフィード

トラックバックURL : http://www.mp-create.com/76.html/trackback

PHP & MySQLトップ