Загрузка пользовательских файлов на сервер
http://belarusweb.net
Основы создания сайтов

Загрузка пользовательских файлов на сервер

Довольно часто возникает необходимость отправки на сервер не только текстовых данных, но и отдельных пользовательских файлов, например, фотографий. В таком случае алгоритм действий также довольно прост и понятен, однако несколько сложнее передачи простых текстовых данных. Код формы с полем для загрузки файла на сервер показан в примере 10.7.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">	
	<title>Загрузка одиночных файлов</title>
</head>
<body>
	<form action="example_10_8.php" method="POST" enctype="multipart/form-data"> 
		<input type="hidden" name="MAX_FILE_SIZE" value="3000000">
		Загрузите аватарку (не более 3Мб):<br><br>
		<input type="file" name="userFile"><br><br>
		<button type="submit" name="submit" value="send">Отправить</button>
	</form>
</body>
</html>

Пример 10.7. Код формы с полем для загрузки одиночных файлов на сервер

Скрытое поле должно предшествовать полю для выбора файла. Его атрибуты name = "MAX_FILE_SIZE" и value = "30000" задают максимально допустимый размер загружаемого файла. Рекомендуется всегда использовать данные параметры, т.к. это предотвращает ненужное ожидание пользователей при передаче огромных файлов только для того, чтобы узнать, что файл слишком большой и его передача не состоялась. Конечно, обойти это ограничение на стороне браузера достаточно просто, следовательно, не стоит полагаться на то, что все файлы большего размера будут блокированы при помощи этой возможности. Однако на сервере настройки касательно максимального размера загружаемых файлов обойти практически невозможно.

Если в поле для отправки файлов задать атрибут accept, то в дополнение к ограничению на размер передаваемого файла будет наложено ограничение и на возможные типы передаваемых файлов. Если файл не будет соответствовать фильтру, устанавливаемому данным атрибутом, пользователь не увидит его в окне выбора файлов. Если атрибут не применяется, то в окне выбора файлов будут показываться все файлы, доступные для просмотра.

Следует отметить, что для отправки файлов нужно обязательно указывать значение атрибута enctype = "multipart/form-data", вместо значения enctype = "application/x-www-form-urlencoded" элемента 'form', иначе загрузка файлов на сервер выполняться не будет.

После загрузки файла на сервер всю информацию о нем можно узнать из глобального массива $_FILES:

  • $_FILES['userfile']['name'] – оригинальное имя файла на компьютере клиента;
  • $_FILES['userfile']['type']mime-тип файла, например, "image/gif"; полагаться на его значение без проверки не стоит;
  • $_FILES['userfile']['size'] – размер в байтах принятого файла;
  • $_FILES['userfile']['tmp_name'] – временное имя, с которым принятый файл был сохранен на сервере (точнее путь к файлу во временной папке, где ему присваивается временное имя);
  • $_FILES['userfile']['error'] – код ошибки, которая может возникнуть при загрузке файла:
    • UPLOAD_ERR_OK – значение: 0; файл был успешно загружен на сервер;
    • UPLOAD_ERR_INI_SIZE – значение: 1; размер принятого файла превысил максимально допустимый размер, который установлен в директиве upload_max_filesize конфигурационного файла php.ini;
    • UPLOAD_ERR_FORM_SIZE – значение: 2; размер загружаемого файла превысил значение "MAX_FILE_SIZE", указанное в HTML-форме;
    • UPLOAD_ERR_PARTIAL – значение: 3; загружаемый файл был получен только частично;
    • UPLOAD_ERR_NO_FILE – значение: 4; файл не был загружен;
    • UPLOAD_ERR_NO_TMP_DIR – значение: 6; отсутствует временная папка;
    • UPLOAD_ERR_CANT_WRITE – значение: 7; не удалось записать файл на диск;
    • UPLOAD_ERR_EXTENSION – значение: 8; какое-то из PHP-расширений остановило загрузку файла, при этом PHP не предоставляет способа определить, какое именно; в этом может помочь просмотр списка загруженных расширений из phpinfo().

Использование суперглобального массива $_FILES показано в примере 10.8.

<?php
	//Предполагается, что файл был успешно загружен
	$userFile = $_FILES['userFile']['name'];
	echo 'Имя вашего файла: '.$userFile.'<br>';

	$userFileType = $_FILES['userFile']['type'];
	echo 'Тип вашего файла: '.$userFileType.'<br>';
	
	$userFileSize = $_FILES['userFile']['size'];
	echo 'Размер вашего файла: '.$userFileSize.' байт'.'<br>';
	
	$userFileTmp = $_FILES['userFile']['tmp_name'];
	echo 'Временное имя файла на сервере: '.$userFileTmp.'<br>';
	
	$userFileError = $_FILES['userFile']['error'];
	echo 'Код ошибки: '.$userFileError.'<br>';
?>

Пример 10.8. Обработка данных, переданных на сервер формой примера 10.7

Если нужно загрузить несколько файлов, то можно либо использовать в поле для отправки файлов атрибут multiple (см. пример 10.9), либо не одно, а несколько соответствующих элементов 'input'. При этом, если размер какого-либо из файлов превысит значение "MAX_FILE_SIZE", он загружен не будет. Однако это не повлияет на загрузку остальных файлов, поэтому желательно сообщать о такой ситуации пользователю выводом соответствующего сообщения.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">	
	<title>Загрузка нескольких файлов</title>
</head>
<body>
	<form action="example_9_10.php" method="POST" enctype="multipart/form-data"> 
		<input type="hidden" name="MAX_FILE_SIZE" value="3000000">
		Загрузите аватарки (не более 3Мб каждая):<br><br>
		<input type="file" name="userFile[]" multiple><br><br>
		<button type="submit" name="submit" value="send">Отправить</button>
	</form>
</body>
</html>

Пример 10.9. Код формы с полем для загрузки нескольких файлов на сервер

При использовании атрибута multiple в качестве значения атрибута name нужно использовать массив, иначе на сервере мы сможем получить данные только о последнем загруженном файле. После загрузки файлов на сервер доступ к ним может быть получен, опять же, через суперглобальный массив $_FILES, с учетом того, что файлам в массиве будут назначены числовые ключи согласно порядку их отправки (см. пример 10.10).

<?php
	//Будем считать, что как минимум один файл был загружен
	//Выводим информацию о первом из загруженных файлов
	$userFile = $_FILES['userFile']['name'][0];
	echo 'Имя вашего файла: '.$userFile.'<br>';

	$userFileType = $_FILES['userFile']['type'][0];
	echo 'Тип вашего файла: '.$userFileType.'<br>';
	
	$userFileSize = $_FILES['userFile']['size'][0];
	echo 'Размер вашего файла: '.$userFileSize.' байт'.'<br>';
	
	$userFileTmp = $_FILES['userFile']['tmp_name'][0];
	echo 'Временное имя файла на сервере: '.$userFileTmp.'<br>';
	
	$userFileError = $_FILES['userFile']['error'][0];
	echo 'Код ошибки: '.$userFileError.'<br>';
?>

Пример 10.10. Обработка данных, переданных на сервер формой примера 10.9

В случаях, когда необходимо по-разному ограничить размеры загружаемых файлов, следует выбирать второй вариант, используя несколько полей для отправки файлов и указывая перед каждым из них скрытое поле с требуемым ограничением размера (см. пример. 10.11). Кроме того, к файлам можно будет обращаться по их ключам, хотя можно поступить и предыдущим способом, просто объявив общий массив.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">	
	<title>Загрузка нескольких файлов</title>
</head>
<body>
	<form action="example_10_12.php" method="POST" enctype="multipart/form-data"> 
		Загрузите фото (не более 1Мб):
		<input type="hidden" name="MAX_FILE_SIZE" value="1000000">
		<input type="file"  name="file_1"><br><br>
		Загрузите аватарку (не более 50Кб):
		<input type="hidden" name="MAX_FILE_SIZE" value="50000">
		<input type="file"  name="file_2"><br><br>
		<button type="submit" name="submit" value="send">Отправить</button>
	</form>
</body>
</html>

Пример 10.11. Код формы с несколькими полями загрузки файлов

<?php
	//Будем считать, что оба файла были загружены
	//Выводим информацию о результатах загрузки файлов
	$fileName_1 = $_FILES['file_1']['name'];
	echo 'Имя вашего файла: '.$fileName_1.'<br>';

	$fileError_1 = $_FILES['file_1']['error'];
	echo 'Код ошибки: '.$fileError_1.'<br>'.'<br>';
		
	$fileName_2 = $_FILES['file_2']['name'];
	echo 'Имя вашего файла: '.$fileName_2.'<br>';

	$fileError_2 = $_FILES['file_2']['error'];
	echo 'Код ошибки: '.$fileError_2.'<br>'.'<br>';
?>

Пример 10.12. Обработка данных, переданных на сервер формой примера 10.11

В процессе загрузки файлов на сервер они помещаются во временную папку, которая задается в настройках конфигурационного файла php.ini (подробно рассмотрим позже). Для того, чтобы переместить файл из временной папки в нужное место, нужно использовать функцию move_uploaded_file(), которая проверяет, является ли файл загруженным на сервер по протоколу HTTP POST, и в случае удачи перемещает загруженный файл в новое место, возвращая при этом true (см. пример 10.13). Если же перемещение по каким-либо причинам невозможно, функция вернет false (см. раздел 'Расширения для работы с файловой системой' официального справочника).

<?php
//Переместим файл, загруженный при помощи формы примера 10.7, в папку loaded_files
//Сохраним путь к файлу во временной папке в переменной
$userFileTmp = $_FILES['userFile']['tmp_name'];

//Сохраним в переменной исходное имя загруженного файла
$file_name = $_FILES['userFile']['name'];
//Путь построим от корня сайта '/' и заменим временное имя файла обратно на свое
$my_dir="/loaded_files/{$file_name}";

//Если файл будет перемещен, функция вернет true
if(move_uploaded_file($userFileTmp, $my_dir)){
    echo "Файл корректен и был успешно перемещен.";
}else{
    echo "Файл не был перемещен!";
}
?>

Пример 10.13. Перемещение загруженных файлов из временной папки

Если требуется переместить сразу несколько файлов, загруженных при помощи поля с атрибутом multiple (см. пример 10.9 и пример 10.10), можно воспользоваться, например, циклом foreach, повторив процедуру перемещения для всех элементов массива.