【2021年改訂版】PHPでファイルをダウンロードさせるダウンローダーの実装

こんにちは。ritです。

2017年に以下のような記事を出しました。

※この記事は情報が古く、別の方法の方がより正確です。別記事にて改訂済みなため、以下リンクの記事を参考にしてください。 こ...

この記事で紹介したソースの解説が雑だったのと、特に現代のブラウザで動作させるのにはよろしくない記述があったので、改めて新しくソースを紹介するとともに、細かく解説し直そうと思います。

一部上級者向けの内容を含みますが、使うだけであればここで紹介しているコードをそのままコピーして固有の変数だけ変更すれば問題なく使用できると思います。

スポンサーリンク
ブログ大

とりあえず新しいソース(コピーしてそのまま使用可)

<?php

//--------------------ここを書き換える--------------------

// 設置元のドメイン名
$domain_name = '○○○.com(自分のドメイン)';

// カウンタ用のテキストファイルのパスを指定
// ※テキストには数字で[0]のみ書いておく
$count_path = './count.txt';

// ダウンロードさせたいファイルのパスを指定
$file_path = './download_contents.zip';

// ダウンロードさせたときのファイル名の指定(拡張子もつける)
$file_name = 'software.zip';

// ファイルのMIMEタイプを指定
$mime_type = 'application/octet-stream';

//------------------------ここまで------------------------



// POSTの送信元のURLを調べる
$host = $_SERVER['HTTP_REFERER'];

// URLを構成要素別に分解する
$str = parse_url($host);

// 送信元URLのドメイン名が、指定したドメインと一致するか調べる
if(stristr($str['host'], $domain_name))
{
	// 一致しているのでダウンロード処理に進む
	
	// ファイルが存在し、読み込み可能であるか調べる
	if(is_readable($file_path))
	{
		// 読み込み成功したのでダウンロード処理続行
		
		// ダウンロードカウントの増加
		if(is_readable($count_path))
		{
			// ファイルを読み込みモードで開く
			$fp = fopen($count_path, "r");
			
			// 1行読み込む
			$count_str = fgets($fp);
			
			// ファイルを閉じる
			fclose($fp);
			
			
			// 読み込んだ文字列を整数として扱う
			$count = intval($count_str);
			
			// カウント増加
			$count++;
			
			// ファイルを上書きモードで開く
			$fp = fopen($count_path, "w");
			
			// 更新後のカウントを書き込む
			fwrite($fp, $count);
			
			// ファイルを閉じる
			fclose($fp);
		}
		
		// ダウンロード用のHTTPヘッダを設定する
		
		// MIMEタイプの設定
		header('Content-Type: ' . $mime_type);
		
		// ブラウザによるMIMEタイプスニッフィングを禁止する
		header('X-Content-Type-Options: nosniff');
		
		// ダウンロードファイルのサイズを設定
		header('Content-Length: ' . filesize($file_path));
		
		// ファイルを指定した名前でダウンロードを実行させるように設定
		header('Content-Disposition: attachment; filename="' . $file_name . '"');
		
		// 出力バッファリングの無効化
		while (ob_get_level())
		{
			ob_end_clean();
		}
		
		// 出力する
		readfile($file_path);
	}
	else
	{
		// 読み込みに失敗したのでエラーメッセージを出して終了
		echo 'ダウンロードに失敗しました。時間を置いて再度お試しください。\n何度も表示される場合は管理者に確認してください。';
	}
}
else
{
	// ドメインが一致していないので警告を出して中断する
	echo '不正なアクセスです。正規なページリンクからアクセスしてください。';
}
?>

以上のコードでは、「○○○.com」というドメイン上に存在するページからアクセスされた場合に、同じディレクトリに存在する「count.txt」というテキストファイルに書かれた数字を1増やして更新し、更に同じ場所の「download_contents.zip」というファイルを「software.zip」という名前でダウンロードさせるという動作を行うようになっています。

「MIMEタイプ」については後述します。

では、このスクリプトを実際に使用するためにはどうすれば良いのかを順番に説明します。

下準備

以下のファイルを用意します。

  1. スクリプトにアクセスするためのダウンロードページ
  2. はじめに紹介したコードを記述したphpファイル(ここではdownload_script.php)
  3. カウンタ用テキストファイル(ここではcount.txt)
  4. ダウンロードさせたいファイル(ここではdownload_contents.zip)

順番に説明していきます。

1. スクリプトにアクセスするためのダウンロードページ

download_script.phpはダウンロードを実行させるためのプログラムのみを記述したファイルなので、別にダウンロード用ページを用意して、そこからアクセスさせる必要があります。簡単でよくある方法としては<form>タグを使用してボタンを押したらダウンロード開始させるようなやり方があります。

例として、同意するチェックボックスにチェックを付けたらボタンが有効になり、連打対策として1度ボタンを押したらボタンが消えるようなコードをご紹介しておきます。

<!-- 同意ボタンの設定とダウンロードボタン消滅のjavascript -->
<script type="text/javascript">
function checkValue(check){
	var btn = document.getElementById('btn');
	if (check.checked) {
		btn.removeAttribute('disabled');
	} else {
		btn.setAttribute('disabled', 'disabled');
	}
}
	
function btnCollapse(){
	document.getElementById("btn").style.visibility = "collapse";
}
</script>

<!-- 同意するチェックボックスとダウンロードボタンの設置 -->
<form method="post" action="./download_script.php">
	<input id="check" type="checkbox" onclick="checkValue(this)"> 同意する<br>
	<button id="btn" type="submit" disabled="disabled" onclick="btnCllapse();">規約に同意してダウンロード</button>
</form>

一例ですので、このコードでなくてもdownload_script.phpにページから直接アクセスできれば何でも構いません。

利用規約などを書いた下にこのコードを書いておけば、理想的なダウンロードページになると思います。

2. download_script.php

一番上の「ここを書き換える」と記述してある部分の「”」の中を書き換えます。

i. 設置元のドメイン名 $domain_name

ここで指定したドメイン以外からdownload_script.phpにアクセスされた場合にはダウンロードできなくなります。関係ないページから直リンクされて勝手にダウンロードされることを防ぎます。

https://を除いてそれ以下の.comや.jpなどのドメインの末尾までを記述します。このサイトの場合「ritvia.jp」と記述するような感じになります。

ii. カウンタ用のテキストファイルのパス $count_path

ダウンロード回数を保存するためのテキストファイルまでのパスを設定します。

iii. ダウンロードさせたいファイルのパス $file_path

ダウンロードさせたいファイルまでのパスを設定します。

iv. ダウンロードさせた時のファイル名 $file_name

ダウンロードするファイルの名前を設定します。ダウンロード時にここでつけた名前でダウンロードされます。必ず拡張子までつけます。

サーバー上での名前と同じ名前にしても構いませんが、こちらはパスではないのでご注意ください。

v. MIMEタイプの設定 $mime_type

ブラウザ等に通知するメディア種別を設定します。

application/octet-stream」を設定しておくことで基本的にはダウンロードされますが、どのような種類のファイルをダウンロードさせたいのか作成する側は分かっているはずなので、出来れば正しいMIMEタイプを指定しておきたいです。

サンプルではあえて「application/octet-stream」を採用していますが、本来は例えばzipファイルであれば「application/zip」と記述するのがより正しいです。

この辺りの話はややこしくなるので後日別記します。

↓詳細記事出来ました

こんにちは。ritです。今回の記事は前回の「PHPでファイルをダウンロードさせるダウンローダーの実装」記事の補足説明的な記事となりますので...

3. カウンタ用テキストファイル

用意するテキストファイル内には、予め「0」とだけ書いておきましょう。

ダウンロードされる度にこのテキスト内の数字が1ずつ増えていきます。

ダウンロード回数をページ上に表示させたい場合は、このテキストを読み込んでechoなどで出力することで自動的に回数が表示できます。

<?php
// ダウンロード数を取得する
$fp = fopen("./count.txt", "r"); // カウンタファイルのパスを設定
$count = fgets($fp);
fclose($fp);
?>


<!-- ダウンロード回数を表示させたい場所に以下を記述 -->
<p>ダウンロード数:<?php echo "$count"; ?></p>

phpを記述するファイルの拡張子は必ず.phpにしておきましょう。

4. ダウンロードさせたいファイル

目的のダウンロードさせたいファイルです。サーバーにアップするので半角英数字で名前をつけておくと良いです。

ダウンロードされた時の名前は設定できるようになっているので、アップする方の名前は違う名前でも必要に応じてそちらで別の名前をつければ問題ないです。

ダウンローダーの設置

1~4のそれぞれのファイルをサーバーにアップロードします。このときdownload_script.phpで指定した場所にそれぞれアップロードするように注意してください。

ここで紹介したものは、全て同じディレクトリにアップロードしたものとしています。

パーミッションの設定

ダウンロードさせたいファイルのパーミッション(アクセス許可設定・属性)は必ずオーナーのみが読み込み出来るようにしてください。

具体的にはr – – – – – – – – (400)になります。

これを設定しておかないと、ファイルへの直リンクでダウンロードや表示などが可能になってしまう可能性があります。設定することで設置したスクリプトを経由せずにダウンロードされるのを防ぐことが出来ます。

以上でダウンローダーの実装は問題なく出来ると思います。

スポンサーリンク
ブログ大

シェアする

  • このエントリーをはてなブックマークに追加
スポンサーリンク
ブログ大