HTMLのフォームからファイルをアップロードし保存する方法(PHP)

2025年 1月 9日 Posted 野々瀨(フロントエンドエンジニア)

ローカル上にあるファイルをWebサーバーへアップロードするには幾つかの方法があります。そのうちの一つとして、HTMLのフォームからファイルをアップロードする方法をご紹介します。ここではフォームの構築からWebサーバーへの保存方法までをご説明します。

前提条件

フォームを構築するのにHTMLの知識が必要ですが、Webサーバーへファイルを保存するためにはサーバーサイドの知識も必要です。ここでは、PHPというサーバーサイドの言語を用いますので、あらかじめ最低限の知識と環境をご用意ください。

HTMLでフォームを準備

ローカルからファイルを添付するためのフィールドと、送信ボタンを用意します。

<form action="upload.php" method="post" enctype="multipart/form-data">
	<p><input type="file" name="select_file"></p>
	<p><button>アップロード</button></p>
</form>

今回はPHPでファイル処理を行うスクリプトとして「upload.php」を用意しますので、form要素のaction属性に「upload.php」を指定しています。

ファイルをアップロードするため、method属性を「post」enctype属性を「multipart/form-data」に指定します。

PHPでの処理

HTMLでform要素のaction属性にて指定したファイルパスでPHPファイルを作成します。次のコードを記述します。

<?php
// アップロードされたファイルの情報を取得
$upload_file_info = $_FILES['select_file'];

// 保存先ファイルパス
$save_file_path = 'upload/'.$upload_file_info['name'];

// 保存
if (move_uploaded_file($upload_file_info['tmp_name'], $save_file_path)) {
	echo 'アップロードに成功しました。';
} else {
	echo 'アップロードに失敗しました。';
}
?>

input[type="file"]要素は$_FILES変数で情報を得ることができます。$_FILES変数は2次元連想配列で、1次元目はinput[type="file"]要素のname属性値をキーに、2次元目はファイルの情報となっています。ここでは二つの情報を使用していて、ファイル名をnameキーから、一時的に保存されているファイルのテンポラリーファイルパスをtmp_nameキーから得ています。なお、input[type="file"]要素でname属性が同じ複数ある場合や、mutiple属性が付与されている場合、$_FILES変数は3次元目に配列として選択されたファイル分のデータが格納されます。

move_uploaded_file関数でテンポラリーに一時保存されているファイルを移動させます。第一引数にファイルのテンポラリーファイルのパスを、第二引数に移動先のファイルパスを指定します。戻り値は成功するとtrue、失敗した場合はfalseを返します。

【参考リンク】

複数のファイルをアップロード

複数のファイルをアップロードする場合、まずHTML側はinput[type="file"]要素を増やすか、multiple属性を付与します。ここではinput[type="file"]要素にmultiple属性を付与することにします。また、name属性値は複数のデータとして扱うため、末尾に「[]」を指定します。

<form action="upload.php" method="post" enctype="multipart/form-data">
	<p><input type="file" name="select_files[]" mutiple></p>
	<p><button>アップロード</button></p>
</form>

次にPHPを複数ファイルに対応します。

<?php
// アップロードされたファイルの情報を取得
$upload_files_info = $_FILES['select_files'];

foreach ($upload_files_info['name'] as $i => $file_name) {
	// 保存先ファイルパス
	$save_file_path = 'upload/'.$file_name;

	// 保存
	if (move_uploaded_file($upload_files_info['tmp_name'][$i], $save_file_path)) {
		echo 'アップロードに成功しました。<br>';
	} else {
		echo 'アップロードに失敗しました。';
	}
}
?>

$_FILES変数はname属性が同じ複数ある場合や、mutiple属性が付与されている場合、$_FILES変数は3次元目に配列として選択されたファイル分のデータが格納されます。

Array(
	[select_files] => Array(
		[name] => Array(
			[0] => sample1.txt
			[1] => sample2.txt
		)

		[type] => Array(
			[0] => text/plain
			[1] => text/plain
		)

		[tmp_name] => Array(
			[0] => /tmp/phpDAB9.tmp
			[1] => /tmp/phpDABA.tmp
		)

		[error] => Array(
			[0] => 0
			[1] => 0
		)

		[size] => Array(
			[0] => 123
			[1] => 456
		)
	)
)

そのため、foreachを使用して、例えばnameキーを繰り返し処理します。nameキーの情報はforeachにより得られますので、インデックス番号を利用してtmp_nameキーの情報を得ます。

PHPのアップロードの制限設定

PHPはアップロード時のファイルの最大容量など、php.iniでさまざまな設定がされています。ファイルのアップロードに関する設定は主に次の項目です。

項目説明
upload_max_filesize ファイル一つあたりの最大容量。
post_max_size POSTデータの最大容量(リクエストされたデータ全体の容量)。
upload_tmp_dir アップロードされたファイルの一時保存先(テンポラリーディレクトリ)。
max_input_time スクリプトを処理する前にフォームから受け入れたデータ(入力)を解析するための最大時間。
memory_limit PHPが使用可能なメモリーの最大容量(上限)。

これらの設定は当然php.iniで設定変更可能ですが、.htaccessやPHPのini_set関数で設定変更することもできます。ただし、設定変更が許可されている場合に限ります。

【おまけ】JavaScriptによる非同期アップロード

JavaScriptによる非同期でのアップロード方法をご紹介します。

HTMLとPHPは、これまでのコードそのままで問題ありません。次のJavaScriptを記述します。

document.forms[0].addEventListener('submit', event => {
	event.preventDefault();

	fetch(event.target.action, {
		method : 'POST',
		body   : new FormData(event.target)
	}).then(res => res.text()).then(result => {
		alert(result);
	});
});

form要素のsubmitイベントが発火された時に処理しています。

preventDefaultメソッドは標準のsubmit機能を無効化しています。

fetchメソッドを使用してアップロードのためのリクエストを行います。第一引数にform要素のaction属性を指定し、第二引数のmethodプロパティに「POST」を、bodyプロパティにform要素のFormDataオブジェクトを指定します。FormDataオブジェクトはフィールドの情報が格納されています。

なお、フォームを送信するための「multipart/form-data」は、fetch API側で自動判別・設定するため、Content-Typeとして指定する必要はありません。