質問に直接無関係な面もありますが,セキュリティ等改善すべき点がいくつかあるので,遅いながら回答させていただきます.
評価基準
★☆☆: よりよい書き方が考えられる
★★☆: エラーリスクがある
★★★: 脆弱性がある
★★☆ $_FILES['file']
が存在していても期待した構造とは限らない
html
1<input type="file" name="file">
から送信された場合,
php
1$_FILES = [
2 'file' => [
3 'error' => ...,
4 'tmp_name' => '...',
5 ...
6 ],
7];
のような構造になりますが,HTTPリクエストはこのHTMLフォームから送信されるとは限りません.任意のプログラムから悪意のあるリクエストを飛ばすことも簡単にできます.そのため,例えば
html
1<input type="file" name="file[x][y][z]">`
に相当するリクエストが飛んできたとしましょう.このとき,$_FILES
の構造はこのようになってしまいます.
php
1$_FILES = [
2 'file' => [
3 'error' => [
4 'x' => [
5 'y' => [
6 'z' => [
7 ...,
8 ],
9 ],
10 ],
11 ],
12 'tmp_name' => [
13 'x' => [
14 'y' => [
15 'z' => [
16 ...,
17 ],
18 ],
19 ],
20 ],
21 ...
22 ],
23];
こんなリクエストに対して具体的に「ここがおかしいよ!」とまで律儀なエラーメッセージを出す必要はありませんが,少なくともどんなリクエストがきてもサーバ側でエラーが発生しないようにコードを書くべきです.簡易的な解決策としては,isset
のチェックを以下のように変更することが挙げられるでしょう.
php
1if (isset($_FILES['file']) && is_int($_FILES['file']['error'])) {
2 ...
3}
より詳しい方法については「ファイルアップロードの例外処理はこれぐらいしないと気が済まない」でまとめています.
★★☆ アップロードのエラーはチェックする
上記の構造のチェックに加えて, $_FILES['file']['error']
が UPLOAD_ERR_OK
になっているかどうかの確認も必要です.失敗している場合は move_uploaded_file
のコールでエラーが発生するでしょう.
★☆☆ 拡張子を信じてはいけない
拡張子はあくまで参考程度の情報で,偽装されている場合やそもそもファイル名にドットが含まれていない場合すら考えられます.必ずしも中身までチェックする必要はないですが,簡易的にデータタイプをチェックしておきたいならばmime_content_type
関数を使うとよいでしょう.
php
1$mime = mime_content_type($_FILES['file']['tmp_name']); // "video/mp4"
但し…
- ファイルを設置するためにその拡張子を使うのであれば,拡張子のチェックは必須です.
.php
などアクセスするだけで何かが実行されてしまう拡張子は除外する必要がありますが,どちらかというと提示されているコードのように.mp4
だけを認める,といった感じでホワイトリスト式にするほうが正解です.この点は評価できると思います.
$_FILES['file']['type']
にもMIMEタイプが含まれていますが,こちらはWebブラウザの自己申告に基づくものなので,信用できる値ではありません.
rand
は言うほどランダムではない
- せっかくアルファベットも使えるのに,数字だけにしてしまうとランダム性**(エントロピー)**が小さくなってしまいます.
rand
は乱数の精度が悪いと言われています.
ランダムなファイル名を作りたいのであれば,「ランダムなパスワードを1行で生成する with openssl」のようにするといいかと思います.
また,ファイルデータを削除不可,あるいは共有している人間がいなくなるまで実体の削除は行わないようにする場合,重複したアップロードで二重にファイルを作らせないこともできます.ファイルデータから一意なハッシュ値を取ってファイル名に使いましょう.
php
1$hash = sha1_file($_FILES['file']['tmp_name']);
★★★ データベース関連の扱いが不適切
「PHPでデータベースに接続するときのまとめ」の「初心者がやりがちなミス」をご覧ください.
- データベースで使用する文字コードの指定をしていない
"SELECT * FROM users WHERE id = '$id'"
のように変数展開を使ってSQL文を組み立てている
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2016/08/01 16:54