JavaScriptでアップロードするファイルの拡張子をチェックするサンプル
に引き続き、ファイルのアップロードに関する記事です。
PHP側でもアップロードされる拡張子のチェックは当然するべきですが、アップロード処理が走る前にブラウザ側でチェックもしておきたいところ。これを無駄と感じるか、二重でもチェックはするべきと考えるかは人それぞれ。
例えば、アップロードを許可する拡張子の種類が変わった場合、JavaScriptとPHPの両方を修正しなければならないというメンテナンス上の問題もあります。
ちなみにぼくの場合はほとんどのサイトをPHPで作っているため、データベースのテーブルとかに許可する拡張子一覧を入れておいて、PHPでもJavaScriptでもそこを参照するような作りにすることが多いです。管理者しかアクセスできないようなページも作っておき、そこで拡張子の設定もできるようにしたり。
そういうのって作るときはうわっ面倒くせ…と思うのですが、Webサイトは運営している時間のほうがずっと長いですからね。ほんの一手間だと思っていたことが長い目で見ると膨大な作業時間になっていた、なんてことがよくあるため、しっかりとした管理ページを作るのは大事です。
っと、これはさすがに余談でした。
JavaScriptでファイル名の拡張子を取得する例
■ファイル名を渡したら拡張子を返す関数
//ファイル名から拡張子を取得する関数
function getExt(filename)
{
var pos = filename.lastIndexOf('.');
if (pos === -1) return '';
return filename.slice(pos + 1);
}
■解説
ファイル名の後ろからピリオド(.)を検索し、見つからなかったら空文字を、見つかったら次の文字以降(test.jpgだったらjpgのみ)を返す関数です。
「JavaScript 拡張子 取得」あたりで検索すればたくさんサンプルは出てくると思いますし、中には正規表現を使ったナウい(死語)例もあるかと思いますが、ぼくはlastIndexOfを使った超シンプルな例が好きです。だって、正規表現ってパッと見わかりづらいんだもの…。
JavaScriptで許可済の拡張子かどうかチェックする例
■ファイル名を渡したら許可された拡張子かどうか判断してtrueかfalseを返す関数
//アップロードを許可する拡張子
var allow_exts = new Array('jpg', 'jpeg', 'png');
//アップロード予定のファイル名の拡張子が許可されているか確認する関数
function checkExt(filename)
{
//比較のため小文字にする
var ext = getExt(filename).toLowerCase();
//許可する拡張子の一覧(allow_exts)から対象の拡張子があるか確認する
if (allow_exts.indexOf(ext) === -1) return false;
return true;
}
■解説
直接、
if (ext == 'jpg' || ext == 'jpeg' || ext == 'png') {
return true;
}
とか書いても良いのですが、見た目がイケてないのと、何より配列にしておいたほうが拡張性が高いのでそうしています。
外部ファイルに許可する拡張子の一覧を書いておいて、それを配列のallow_extsに読み込むように仕様変更したくなったときに修正が簡単ですしね。
JavaScriptで複数ファイル選択のファイル名をチェックする例
全体を見たほうがわかりやすいと思うので、先述の関数も、HTMLも含めて掲載します。
<html lang="ja">
<head><meta charset="utf-8"></head>
<body>
<h1>アップロード処理のサンプル</h1>
<form enctype="multipart/form-data" method="post" onsubmit="return checkForm();">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000">
<input name="file[]" type="file" multiple="multiple" accept="image/*">
<input type="submit" name="_upload" value="アップロード">
</form>
<script>
//アップロードを許可する拡張子
var allow_exts = new Array('jpg', 'jpeg', 'png');
//フォーム内容の確認をする関数
function checkForm()
{
var files = document.getElementsByName('file[]')[0].files;
//ファイルが選択されているか確認
if (files.length == 0) {
alert('ファイルを選択してください');
return false;
}
//指定されたファイルの数だけ拡張子をチェックする
for (var i = 0; i < files.length; i++) {
if (!checkExt(files[i].name)) {
alert(files[i].name+'はアップロードできません');
return false;
}
}
//チェックを通ったらtrueを返す
return true;
}
//アップロード予定のファイル名の拡張子が許可されているか確認する関数
function checkExt(filename)
{
//比較のため小文字にする
var ext = getExt(filename).toLowerCase();
//許可する拡張子の一覧(allow_exts)から対象の拡張子があるか確認する
if (allow_exts.indexOf(ext) === -1) return false;
return true;
}
//ファイル名から拡張子を取得する関数
function getExt(filename)
{
var pos = filename.lastIndexOf('.');
if (pos === -1) return '';
return filename.slice(pos + 1);
}
</script>
</body>
</html>
■解説
前々回の記事で書いたとおり、onsubmitイベントでcheckForm関数を呼び出して入力フォームのチェックを行っていますので、今回もその中で拡張子のチェックをしています。
ポイントとしては、
- 複数ファイル対応なので、inputタグのnameがfile[]になっていること。
- 複数ファイルの場合、input要素のfilesに配列として情報が格納されているため、files.lengthで個数の確認ができること。
- 同様に for (var i = 0; i < files.length; i++) { } として選択されたファイルを順次確認できること。
といったところでしょうか。
選択されたファイルがループ処理でひとつひとつチェックできるわけですから、あとは最初に作ったgetExt関数とcheckExt関数で良い感じに拡張子のチェックをするだけです。
まとめ
文字で書くと面倒な処理も、小さな単位で関数にすることでシンプルに出来ました。
- ファイル名から拡張子を取得する関数 (getExt)
- ファイル名の拡張子が許可されているか確認する関数 (checkExt)
- 入力フォームのチェックをする関数 (checkForm)
最初に書いたとおり、PHPでも同じことをしなければならないわけですが、それについてはまた別の機会に。