|
ダウンロード専用フォルダというのをつくってみた |
2013年2月1日 | 2014年2月20日 更新 |
ファイルをダウンロードで提供したいことが時折あります。個別に強制ダウンロードを設定するのはめんどうなのでダウンロード専用フォルダというのを作ってみました。 この中にファイルを置くかリンクするだけでクリック一発!、そのファイルを強制ダウンロードさせることができます。 |
写真などの画像ファイルについてはいちいち面倒をみなくてもブラウザの右クリックで「画像(あるいはリンク先)をファイルに保存する」などで簡単にできるが、プログラムファイルについてはそうはいかない。
ダウンロードが容易かどうかというだけの問題ではなく、phpやperlなどのcgiプログラムファイルについてはダウンロード以前に実行されてしまい、その実行結果しか保存されない。場合によってはダウンロードだけさせてそのファイルを実行させたくない場合もあり、その場合強制ダウンロードを設定しなくてはならないが、都度.htaccessなどを編集して設定するのもこれまためんどうだし、そのファイルを表示と兼用している場合はそれもできない。
そのためファイルを.zipや.tar、.tgzなどでアーカイブしておくことになるのだが、やっぱりこれもめんどう。(不精の極みと言われれば決して反論はいたしませんが。)
そこでダウンロード専用フォルダというのを設置して、その中のファイルはとにかく強制ダウンロードさせるようにしてみた。
実はホームページを担当している同期会のサイトには数千の写真や資料があり、それのダウンロード用にはWebShareというHTTPで接続できるファイルブラウザを導入しているが、それほどでもなく数十程度のファイルならダウンロード専用フォルダで充分だろうと思った。
ダウンロード専用フォルダをつくる
名前はわかりやすいように "download" としましょう。
ダウンロード用スクリプトを書く
名前を "index.php" としてこのフォルダに置きましょう。
→ ダウンロード専用フォルダ:名付けて「ダウンロードの小部屋」
使い方は簡単。単にダウンロードさせたいファイルをここに置くかリンクするだけ。
さらにフォルダに分けて入れてもいいしフォルダをリンクしてもいい。
もちろん上記ダウンロード専用スクリプトもここから生で(アーカイブされずに)ダウンロードできます。他にお薦めのがいくつか置いてあります。
気が向いたらどうぞ覗いてみてください。
(表示はapacheのインデックス風にしてみました。)
ちょっと欠点は今のところまだダウンロードの中断、再開には対応していません。
→いちおう対応してみました。動作確認が充分とは言えませんが... (2013年2月3日)
ただし以下はHTTPサーバーはApache/2.2.3, ブラウザは主にFirefox10での話。すべてのブラウザで試すほどの元気はなし。
基本的なやりかたの検討
(1) | 一番最初に検討したのは.htaccessにすべてのファイルを強制ダウンロードするようにヘッダーを仕掛けておき、apacheのIndex機能でファイルリストを表示する方法。即試せるが試して即ボツ。 |
(強制ダウンロード用ヘッダーとしては"Header set content-disposition attachment"を使用。) | |
● | Indexを表示するたびに.htaccessへのアクセスは禁止されているとかいったエラーを吐く。自分でアクセスしておいてなんなんだ。 |
● | ごく簡単なファイルの説明などを表示したいがそれができない。 |
● | 各ブラウザでいろんなファイルを試しているうち画像ファイル(写真)によっては強制ダウンロードが効かず表示されてしまう場合がある。(これについては後述。) |
(2) | 次に上記の.htaccessの強制ダウンロード用ヘッダーの設定はそのまま使ってインデックスはphpプログラムで行い、単なるリンクでポイントしてあとはapacheにダウンロード処理を任せる方法。 |
● | (1)と同様に一部の画像がダウンロードされずに表示されてしまう現象が起こる。 |
△ | ダウンロードフォルダ内にさらにフォルダを作った場合、そのフォルダにも同様にインデックスプログラムを置いていかなくてはいけない。初期のダウンロードさせたいファイルを置くだけでという指針に反するし、めんどい。内部にさらにフォルダは作らないことにすればいいのだが、作りたくなるかもしれない。 |
(3) | インデックスプログラムでインデックス(ファイルリスト)とダウンロード処理を両方やってしまう。 |
○ | 試した範囲ではどのファイルも問題なく強制ダウンロードできる。 |
○ | 使い方はファイルやフォルダ、あるいはそのリンクをおくだけ。とても楽。 |
○ | 今後も含めていろんな要求には最も柔軟にこたえられる。 |
たとえばこれを使って普通なら表示されてしまうファイルをダウンロードさせるリンクなども簡単に設置可能。 |
.htaccessによる方法がうまくいかなかったわけ
強制ダウンロードの指定は、
ところが、一部の画像ファイル(写真)がそのまま表示されてしまいダウンロードにならない。当初その原因がまったくわからなかった。
Header set content-type application/octet-stream
という再生アプリを決定できないファイルタイプを指定したり、あるいは
Header set content-type application/force-downroad
といった存在しないファイルタイプを指定してみたりする手法が流行ってしまったようだ。
再生アプリケーションがなければダウンロードになるということなのだが...。
もっとも当初私もよくわからないままこれらもやってはいた。
で、この現象をじっくり調べようと別の日に試してみると、再現されない。
そのまま表示されていたファイルもちゃんとダウンロードされる。
ここで思いあたった。ははん、キャッシュだな。
さらに上流の.htaccessで画像ファイルなどについては表示スピードを上げるためにわざわざキャッシュするように指定している。いったん無効に。
で、まず次のヘッダーで試す。
実際にダウンロード指定を外していったん写真を表示させてしまったら再度ダウンロード指定を入れても、ブラウザからは
If-Modified-Since: Tue, 06 Nov 2007 11:11:06 GMT
といった問い合わせが発せられ、これに対しサーバーは
HTTP/1.1 304 Not Modified
と答えている。つまりファイルそのものが更新されたか否かという話だけで、ヘッダーがダウンロード指定に変更されたことなど全く無視されている。
それではとさらに強力なやつで試してみる。
最初これを使うとダウンロードの中断再開はできないかもしれないと思っていたがそれもちゃんとできる。
ということで結局.htaccessによる強制ダウンロード用ヘッダーとしていまのところ最適と思われるのは、
Header set Cache-Control no-store
さらに私の場合は上流でキャッシュ指示した打ち消しも必要。
Header set Cache-Control no-store
</FilesMatch>
とにかくダウンロードを確実に実行させるには絶対にキャッシュさせてはならない。
で、phpスクリプトでファイル名の表示とダウンロードを実行させることにした。
以下、その中でいろいろ検討してわかったこと。ただし書き方はもうphpスクリプトでの表現になっています。
ファイルタイプの指定
phpからダウンロードさせる場合httpサーバーはこのめんどうを見てくれませんから、拡張子などから自分で決める必要があります。今回はファイルタイプのリストをつくり、それを参照して決めるようにしました。独自のあるいは規格化されていない部分もかなりあるようですが、普通使われるファイルなら特に問題はなさそうです。必要なら追加すればいいし。
表示するかダウンロードするかの指定
そのまま表示させるならヘッダーは、
検索ロボット制御
特にhtmlファイルに対しこれをしておかないと、サンプルとして書いたアドレスやファイルへのアクセスが行われエラーになります。また書いておけば写真等がさらされるのがある程度防げます。
ただ現在対応しているロボットはgoogle,yahooなど一部のようですので、別途robots.txtなどでもガードしておいた方がいいと思われます。
キャッシュコントロール
ただ世にいろいろ言われているように、このブラウザにはこれ効かないとかいうのがあるようで、とりあえず以下のを書いておきました。
header('Cache-Control: no-store,no-cache,must-revalidate,post-check=0,pre-check=0');
部分ダウンロード
Accept-Ranges
部分ダウンロードをバイト単位で受け付ける場合、
一方部分ダウンロードを受け入れないなら、
.htaccessでhttpサーバーにダウンロードを任せる場合には部分ダウンロード用のモジュールが入っていてそれが有効になっているかどうかで自動的に送出されるだろうからいらないと思う(たぶん)。
HTTP_RANGE
bytes=1000-2000
bytes=1000-
bytes=-2000
1番目と2番めは直感的に問題はない。1000バイト目から2000バイト目までと、1000バイト目から最後まで。
問題は-2000の場合。直感的には最初から2000バイト目まで(0-2000と同じ)と思うだろうが、そうではない。
これは最後の2000バイトの要求。データが5000バイトあったら3000-4999と同じ。
しかしこれを0-2000と解釈してプログラムを書いて公開しているサイトが実際にあって最初あやうくそれを鵜呑みにしてしまうところだった。
こんなリクエストはめったにないとは思うが、もしあったらバイト数はちゃんと一致しているのでエラーにもならず全く変なデータを正しいものとして渡してしまうことになる。画像みたいなものならともかく、プログラムだったら何が起こるかわからない。あなおそろしや。
スクリプトもここに置いてあります。
なお今回のスクリプトではフォルダごとダウンロードするのには対応していません。
都度アーカイブしてダウンロードさせるのは余計な負荷がかかりますし、先にアーカイブファイルを作って置けばいいだけなので。必要を感じたらやることにしましょう。