本記事では、PHPを使用してフォームからファイルをアップロードする方法について解説します。
Webアプリケーション開発において、ユーザからファイルを受け取る機能を実装する場合、セキュリティ上のリスクがあります。危ないです、怖いです、何を送りつけられるか分かったもんじゃありません。本記事では、HTMLフォームの作成方法やファイルを受け取る方法、セキュリティ対策について詳しく説明します。
HTMLフォームの作成方法
ファイルをアップロードするためのHTMLフォームのコードは次のとおりです。
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="thefile">
<input type="submit" name="submit" value="アップロード">
</form>
<form>
には以下の属性が必要です。action
: フォームの送信先URL(ファイルアップロード処理をするPHPスクリプト)を指定します。method
:post
を指定します。enctype
: 送信データのエンコードタイプを指定します。ファイルを送信する場合は、multipart/form-data
を指定します。
<input>
には以下の属性が必要です。type
:file
を指定して、ファイルをアップロードするための選択ボックスを表示します。name
: 任意の名前を指定します。
ブラウザでは次のように表示されます。
PHPでファイルを受け取る方法
HTMLフォームから送信されたファイルを受け取るPHPスクリプトは次のようになります。
//ファイルを保存するディレクトリ
$upload_dir = './uploads/';
//アップロードされた一時ファイルを移動
if (move_uploaded_file($_FILES['thefile']['tmp_name'], $upload_dir . $_FILES['thefile']['name'])) {
echo 'アップロードは成功しました';
//移動に失敗した場合
} else {
echo 'アップロードは失敗しました';
}
アップロードされたファイルの情報は、スーパーグローバル変数$_FILES
に格納されます。
HTMLフォーム<input type="file" name="thefile">
から送信されたファイルの情報は次のような連想配列に格納されます。
$_FILES['thefile']['name'] | アップロードされたファイルの名前 |
$_FILES['thefile']['type'] | アップロードされたファイルのMIMEタイプ |
$_FILES['thefile']['size'] | アップロードされたファイルのサイズ 単位はバイト |
$_FILES['thefile']['tmp_name'] | アップロードされたファイルの一時保存パス |
$_FILES['thefile']['error'] | アップロード時のエラーコード(エラーコードの説明) |
$_FILES['thefile']['full_path'] | アップロードされたファイルのフルパス(PHP 8.1.0以降で利用可能) |
アップロードされたファイルは一時保存パス($_FILES['thefile']['tmp_name']
)に保存されます。この一時ファイルは、スクリプトの実行が終了すると削除されてしまうので、move_uploaded_file()
関数を使ってファイルを移動させる必要があります。
move_uploaded_file()
関数の第1引数は一時保存パス、第2引数は移動先のパスです。移動に成功したらtrue
、失敗したらfalse
を返します。
また、この関数は第1引数のファイルがPOSTメソッドによりアップロードされた有効なファイルかどうかをチェックしてくれます。有効なアップロードファイルでなければfalse
を返します。
無料で利用できるプログラミング学習サービスをお探しならば Code Lesson はいかがでしょうか。プロのエンジニアが監修した学習ロードマップで効率的に学習、AIに質問、最後にクイズで理解度をチェックできます。
セキュリティ対策
フォームから送信されるファイルはとても危険です。不正なファイルばかりです。この世にはあなたを騙そうとする人しかいないのです。なので、しっかりとセキュリティ対策をしましょう。
MIMEタイプのチェック
アップロードされるファイルのMIMEタイプをチェックすることで、想定外のファイルアップロードを防ぐことができます。MIMEタイプとは、ファイルの種類をあらわす情報です。
ならば$_FILES['thefile']['type']
を使うんだなと思ったあなた、残念!この変数に格納されるMIMEタイプは簡単に偽装することができます。例えば、テキストファイルにfile.jpg
という名前をつけてアップロードすると、MIMEタイプはimage/jpeg
になってしまいます。
そこで、Fileinfoクラスを使います。このクラスはファイルの拡張子ではなく内容からファイルの種類を推測してくれるので、より正確にMIMEタイプを判定できます。
//許可するMIMEタイプのリスト
$allowed_mime_types = [
'image/gif',
'image/jpeg',
'image/png'
];
//MIMEタイプのチェック
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['thefile']['tmp_name']);
if (!in_array($mime, $allowed_mime_types)) {
exit('許可されていないファイル形式です');
}
//ファイルを保存するディレクトリ
$upload_dir = './uploads/';
//アップロードされた一時ファイルを移動
if (move_uploaded_file($_FILES['thefile']['tmp_name'], $upload_dir . $_FILES['thefile']['name'])) {
echo 'アップロードは成功しました';
//移動に失敗した場合
} else {
echo 'アップロードは失敗しました';
}
ちなみに、おもなMIMEタイプには次のようなものがあります。
MIMEタイプ | 拡張子 | ファイルの種類 |
---|---|---|
image/gif | .gif | 画像 |
image/jpeg | .jpg .jpeg | 画像 |
image/png | .png | 画像 |
video/mpeg | .mpg .mpeg | 動画 |
video/mp4 | .mp4 | 動画 |
video/quicktime | .mov .qt | 動画 |
video/x-msvideo | .avi | 動画 |
audio/mpeg | .mp3 | 音声 |
audio/aac | .m4a | 音声 |
audio/midi | .mid .midi | 音声 |
audio/wav | .wav | 音声 |
text/plain | .txt | テキスト |
text/html | .htm .html | HTML |
application/zip | .zip | アーカイブ |
application/pdf | .pdf | PDFファイル |
application/msword | .doc | Wordファイル |
application/msexcel | .xls | Excelファイル |
ファイルサイズの制限
アップロードされるファイルのサイズを制限することで、サーバの負荷を軽減したり、ストレージの圧迫を避けることができます。
//許可するファイルサイズの上限
$max_file_size = 10 * 1024 * 1024; //10MB
//ファイルサイズをチェックする
if ($_FILES['thefile']['size'] > $max_file_size) {
exit('ファイルサイズが大きすぎます');
}
//ファイルを保存するディレクトリ
$upload_dir = './uploads/';
//アップロードされた一時ファイルを移動
if (move_uploaded_file($_FILES['thefile']['tmp_name'], $upload_dir . $_FILES['thefile']['name'])) {
echo 'アップロードは成功しました';
//移動に失敗した場合
} else {
echo 'アップロードは失敗しました';
}
ファイル名の変更
アップロードされるファイルの名前を変更することで、悪意のあるファイル名による攻撃を防ぐことができます。
また、move_uploaded_file()
関数は、アップロードされたファイルの名前が重複していたらファイルを上書きします。これを防ぐためにもファイル名は変更したほうがよいでしょう。
//ファイル名を変更する
$extension = pathinfo($_FILES['thefile']['name'], PATHINFO_EXTENSION);
$new_file_name = uniqid() . '.' . $extension;
//ファイルを保存するディレクトリ
$upload_dir = './uploads/';
//アップロードされた一時ファイルを移動
if (move_uploaded_file($_FILES['thefile']['tmp_name'], $upload_dir . $new_file_name)) {
echo 'アップロードは成功しました';
//移動に失敗した場合
} else {
echo 'アップロードは失敗しました';
}
ファイルアップロードに関連するPHPの設定
ファイルのアップロード処理に影響を与えるPHPの設定には、次のようなものがあります。
設定名 | 説明 | 初期値 | 設定場所 |
---|---|---|---|
upload_max_filesize | アップロードされるファイルの最大サイズ | 2MB | PHP_INI_PERDIR |
post_max_size | POSTメソッドで送信するデータの最大サイズ | 8MB | PHP_INI_PERDIR |
max_file_uploads | 同時にアップロードできるファイルの最大数 | 20 | PHP_INI_PERDIR |
upload_tmp_dir | アップロードされるファイルの一時保存ディレクトリ | NULL (/tmp) | PHP_INI_SYSTEM |
file_uploads | ファイルアップロードを許可するかどうか | 1 (有効) | PHP_INI_SYSTEM |
max_input_time | アップロードされたファイルの処理にかかる最大時間 | -1 (30秒) | PHP_INI_PERDIR |
max_execution_time | スクリプトの実行にかかる最大時間 | 30 | PHP_INI_ALL |
- PHP_INI_PERDIR:
ini_set()
,.user.ini
で設定可能 - PHP_INI_SYSTEM:
php.ini
,httpd.conf
で設定可能 - PHP_INI_ALL: どこでも設定可能
これらの設定は、php.ini
ファイルやini_set()
関数などで変更することができます。
でわでわ
無料で利用できるプログラミング学習サービスをお探しならば Code Lesson はいかがでしょうか。プロのエンジニアが監修した学習ロードマップで効率的に学習、AIに質問、最後にクイズで理解度をチェックできます。
コメント