PHPを使用してWebサイトのフォームからファイルをアップロードするにはどのようにしたらよいのでしょう?
実はファイルPHPにはファイルアップロードに関する機能が備わっているので、特に難しいことはなくWebサイトのフォームからのファイルアップロードを実装できます。
サンプルコード
簡単なサンプルコードを紹介します。
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ファイルアップロード</title> </head> <body> <!-- 画像アップロードフォーム --> <form action="fileUpload.php" method="post" enctype="multipart/form-data"> <input type="file" name="image"> <input type="submit" value="アップロード"> </form> </body> </html> |
HTMLでのポイントは以下の3点になります。
- fromタグのmethod属性を「post」とする(「get」ではNG)
- formタグのenctype属性に「multipart/form-data」を指定する
- inputタグのtype属性を「file」にし、name属性を設定する
※type属性に「file」を指定することにより、ファイル選択ウインドウを呼び出すボタンができる
※name属性に設定した値が、PHP側の連想配列「$_FILE」のキーとなる
HTMLはこの3点させおさえておけばOKです。
formタグのactionタグは実際にファイルアップロード処理を行うPHPファイルを指定してください。(サンプルでは「fileUpload.php」としています。)
formタグのenctyp属性に指定する「multipart/form-data」はファイルをアップロードする「おまじない」のようなものだと思っておいてください。
これをきちんと理解しようとするとHTTPの歴史などにも踏み込んでいくので、初心者の状態で深追いすると痛い目をみます。(実際に痛い目をみました)
PHP
PHP側でアップロードしたファイルが$_FILEというグローバル変数に格納されます。
先にも書いた通り、$_FILESはtype属性に「file」を指定したinputタグのname属性の値がキーとなる連想配列となっており、ファイルアップロードに関する情報が格納されています。
上記のHTMLの例では「image」がキーとなるので、以下はそれを前提に記述します。
$_FILES[‘image’][‘name’] | クライアントマシン(アップロード元)でのファイル名 |
---|---|
$_FILES[‘image’][‘type’] | ファイルのMIME型(拡張子のようなイメージ) 例えばgifだと「image/gif」となる |
$_FILES[‘image’][‘size’] | ファイルのサイズ(単位はバイト) |
$_FILES[‘image’][‘tmp_name’]
|
アップロードされたファイルがサーバー上で保存されているテンポラリのファイル名
|
$_FILES[‘image’][‘error’]
|
ファイルアップロードに関するエラーコード
|
ファイルを単純にアップロードするだけであれば、「move_uploaded_file」関数を使用すればOKです。
1 2 3 4 5 |
move_uploaded_file(テンポラリのファイル名, ファイルのアップロード場所); 例) $savaFile = __DIR__ . /uploadImage/' . $_FILES['image']['name']; move_uploaded_file($_FILES['image']['tmp'], $savaFile); |
これでファイルアップロードが完了します。
以外と簡単ですよね?
しかし、上記のコードではファイル名をクライアントマシンのファイル名としているので、同じファイル名のファイルをアップロードされた場合はファイルが上書きされることになります。
また、ファイルのサイズや拡張子などのチェックも行わないため、不正なファイルや超巨大なファイルをアップロードされる恐れがあります。
ですので、一般的にはファイルアップロードを行う際は以下のような処理を行います。
- ファイルサイズのチェック
- ファイル拡張子のチェック
- ファイル名をユニーク(単一)となるように変更
順番にみていきます。
ファイルサイズのチェック
これは$_FILES[‘image’][‘size’]を使用してチェックします。
後述しましが、php.iniファイルの「upload_max_filesize」を設定しておくことで、フォームからアップロードした際にエラーとなります($_FILES[‘image’][‘error’]にエラーコードがセットされる)
ファイル拡張子のチェック
これは$_FILES[‘image’][‘type’]を使用してチェックします。
$_FILES[‘image’][‘type’]を引数に「exif_imagetype」関数を使用すると以下のような値が取得されます。
gif | IMAGETYPE_GIF(image/gif) |
---|---|
jpg | IMAGETPYE_JPEG(image/jpeg) |
png | IMAGETYPE_PNG(image/png) |
・ ・ ・ |
・ ・ ・ |
1 2 3 4 5 6 7 8 9 10 11 12 |
// チェック例 $imageType = exif_imagetype($_FILES['image']['tmp_name']); switch($imageType) { case IMAGETYPE_GIF: return 'gif'; case IMAGETYPE_JPEG: return 'jpg'; case IMAGETYPE_PNG: return 'png'; default: throw new Exception('PNG/JPEG/GIF only!'); } |
ファイル名をユニーク(単一)となるように変更
ファイル名は日付などをつけてユニーク(単一)となるようにします。
1 2 |
// ファイル名を単一にする例 $fileName = uniqid(date('YmdHis') . $_FILES['image']['name'] |
$_FILES[‘image’][‘error’]のエラーコード
$_FILES[‘image’][‘error’]にセットされるエラーコードは以下の通りです。
UPLOAD_ERR_OK(0) | エラーなし(アップロード成功) |
---|---|
UPLOAD_ERR_INI_SIZE(1) | アップロードファイルのサイズがphp.iniの「upload_max_filesize」の 値を超えている。 |
UPLOAD_ERR_FORM_SIZE (2) |
アップロードファイルのサイズがHTMLフォームで指定された「MAX_FILE_SIZE」を超えている。 |
UPLOAD_ERR_PARTIAL(3) | 一部のしかアップロードされていない |
UPLOAD_ERR_NO_FILE(4) | アップロードされていない |
UPLOAD_ERR_NO_TMP_DIR (6) |
テンポラリフォルダが存在しない |
UPLOAD_ERR_CANT_WRITE (7) |
ディスクへの書き込みに失敗 |
UPLOAD_ERR_EXTENSION (8) |
その他のエラー |
基本的に「UPLOAD_ERR_OK」以外はエラーなので、まずは$_FILES[‘image’][‘error’]の値が「UPLOAD_ERR_OK」であるかをチェックしましょう。
まとめ
いかがだったでしょうか?
ファイルをアップロードと聞くと難しく感じますが、単純にアップロードするだけならPHP側は1行ですんでしまうんですね。
実務ではセキュリティ上ファイル名を特定されにくいように暗号化した文字列を使うなど考えることは増えますが、だいたいの場合は今回紹介した内容を実施すれば問題ありません。
皆様の参考になれば幸いです。