Загрузка файлов через jQuery AJAX

В преведущей статье был приведен пример отправки файлов через AJAX с помощью плагина «jQuery Form Plugin». Но файлы можно отправить и обычным методом jQuery $.ajax().

Для примера возьмем поле <input type="file"> и элемент div с id="result" для вывода результата.

Чтобы отправить файл нужно отправить его бинарный данные, для этого есть объект FormData, поддерживается он всеми современными браузерами.

<input type="file" id="js-file">

<div id="result">
	<!-- Результат из upload.php -->
</div>

<script src="/jquery.min.js"></script>
<script>
$("#js-file").change(function(){
	if (window.FormData === undefined) {
		alert('В вашем браузере FormData не поддерживается')
	} else {
		var formData = new FormData();
		formData.append('file', $("#js-file")[0].files[0]);

		$.ajax({
			type: "POST",
			url: '/upload.php',
			cache: false,
			contentType: false,
			processData: false,
			data: formData,
			dataType : 'json',
			success: function(msg){
				if (msg.error == '') {
					$("#js-file").hide();
					$('#result').html(msg.success);
				} else {
					$('#result').html(msg.error);
				}
			}
		});
	}
});
</script>
HTML

Помимо использования formData, в настройках $.ajax нужно указать параметры contentType: false и processData: false т.к. без них файл не отправится.

Код скрипта upload.php

<?php

// Название <input type="file">
$input_name = 'file';
 
// Разрешенные расширения файлов.
$allow = array();
 
// Запрещенные расширения файлов.
$deny = array(
	'phtml', 'php', 'php3', 'php4', 'php5', 'php6', 'php7', 'phps', 'cgi', 'pl', 'asp', 
	'aspx', 'shtml', 'shtm', 'htaccess', 'htpasswd', 'ini', 'log', 'sh', 'js', 'html', 
	'htm', 'css', 'sql', 'spl', 'scgi', 'fcgi', 'exe'
);
 
// Директория куда будут загружаться файлы.
$path = __DIR__ . '/uploads/';


$error = $success = '';
if (!isset($_FILES[$input_name])) {
	$error = 'Файл не загружен.';
} else {
	$file = $_FILES[$input_name];

	// Проверим на ошибки загрузки.
	if (!empty($file['error']) || empty($file['tmp_name'])) {
		$error = 'Не удалось загрузить файл.';
	} elseif ($file['tmp_name'] == 'none' || !is_uploaded_file($file['tmp_name'])) {
		$error = 'Не удалось загрузить файл.';
	} else {
		// Оставляем в имени файла только буквы, цифры и некоторые символы.
		$pattern = "[^a-zа-яё0-9,~!@#%^-_\$\?\(\)\{\}\[\]\.]";
		$name = mb_eregi_replace($pattern, '-', $file['name']);
		$name = mb_ereg_replace('[-]+', '-', $name);
		$parts = pathinfo($name);
 
		if (empty($name) || empty($parts['extension'])) {
			$error = 'Недопустимый тип файла';
		} elseif (!empty($allow) && !in_array(strtolower($parts['extension']), $allow)) {
			$error = 'Недопустимый тип файла';
		} elseif (!empty($deny) && in_array(strtolower($parts['extension']), $deny)) {
			$error = 'Недопустимый тип файла';
		} else {
			// Перемещаем файл в директорию.
			if (move_uploaded_file($file['tmp_name'], $path . $name)) {
				// Далее можно сохранить название файла в БД и т.п.
				$success = '<p style="color: green">Файл «' . $name . '» успешно загружен.</p>';
			} else {
				$error = 'Не удалось загрузить файл.';
			}
		}
	}
}

// Вывод сообщения о результате загрузки.
if (!empty($error)) {
	$error = '<p style="color: red">' . $error . '</p>';  
}

$data = array(
	'error'   => $error,
	'success' => $success,
);

header('Content-Type: application/json');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit();
PHP

Пример работы:

Для одновременной загрузки файлов элементу input file нужно добавить атрибут multiple, также изменится добавление данных в объект formData.

<input type="file" multiple id="js-file">

<div id="result">
	<!-- Результат из upload.php -->
</div>

<script src="/jquery.min.js"></script>
<script>
$("#js-file").change(function(){
	if (window.FormData === undefined){
		alert('В вашем браузере FormData не поддерживается')
	} else {
		var formData = new FormData();
		$.each($("#js-file")[0].files,function(key, input){
			formData.append('file[]', input);
		});

		$.ajax({
			type: "POST",
			url: '/upload.php',
			cache: false,
			contentType: false,
			processData: false,
			data: formData,
			dataType : 'json',
			success: function(data){
				data.forEach(function(msg) {
					$('#result').append(msg);
				});
			}
		});
	}
});
</script>
HTML

Код скрипта upload.php

<?php

// Название <input type="file">
$input_name = 'file';
 
// Разрешенные расширения файлов.
$allow = array();
 
// Запрещенные расширения файлов.
$deny = array(
	'phtml', 'php', 'php3', 'php4', 'php5', 'php6', 'php7', 'phps', 'cgi', 'pl', 'asp', 
	'aspx', 'shtml', 'shtm', 'htaccess', 'htpasswd', 'ini', 'log', 'sh', 'js', 'html', 
	'htm', 'css', 'sql', 'spl', 'scgi', 'fcgi', 'exe'
);
 
// Директория куда будут загружаться файлы.
$path = __DIR__ . '/uploads/';

$data = array();

if (!isset($_FILES[$input_name])) {
	$error = 'Файлы не загружены.';
} else {
	// Преобразуем массив $_FILES в удобный вид для перебора в foreach.
	$files = array();
	$diff = count($_FILES[$input_name]) - count($_FILES[$input_name], COUNT_RECURSIVE);
	if ($diff == 0) {
		$files = array($_FILES[$input_name]);
	} else {
		foreach($_FILES[$input_name] as $k => $l) {
			foreach($l as $i => $v) {
				$files[$i][$k] = $v;
			}
		}		
	}	

	foreach ($files as $file) {
		$error = $success = '';

		// Проверим на ошибки загрузки.
		if (!empty($file['error']) || empty($file['tmp_name'])) {
			$error = 'Не удалось загрузить файл.';
		} elseif ($file['tmp_name'] == 'none' || !is_uploaded_file($file['tmp_name'])) {
			$error = 'Не удалось загрузить файл.';
		} else {
			// Оставляем в имени файла только буквы, цифры и некоторые символы.
			$pattern = "[^a-zа-яё0-9,~!@#%^-_\$\?\(\)\{\}\[\]\.]";
			$name = mb_eregi_replace($pattern, '-', $file['name']);
			$name = mb_ereg_replace('[-]+', '-', $name);
			$parts = pathinfo($name);
			
			if (empty($name) || empty($parts['extension'])) {
				$error = 'Недопустимый тип файла';
			} elseif (!empty($allow) && !in_array(strtolower($parts['extension']), $allow)) {
				$error = 'Недопустимый тип файла';
			} elseif (!empty($deny) && in_array(strtolower($parts['extension']), $deny)) {
				$error = 'Недопустимый тип файла';
			} else {
				// Перемещаем файл в директорию.
				if (move_uploaded_file($file['tmp_name'], $path . $name)) {
					// Далее можно сохранить название файла в БД и т.п.
					$success = 'Файл «' . $name . '» успешно загружен.';
				} else {
					$error = 'Не удалось загрузить файл.';
				}
			}
		}
		
		if (!empty($success)) {
			$data[] = '<p style="color: green">' . $success . '</p>';  
		}
		if (!empty($error)) {
			$data[] = '<p style="color: red">' . $error . '</p>';  
		}
	}
}

// Вывод сообщений о результате загрузки.
header('Content-Type: application/json');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit();
PHP

Пример работы:

Не забудьте в директории куда помещаются загруженные файлы запретить выполнение PHP-скриптов.

07.10.2020, обновлено 11.02.2022
35600
Предыдущая запись Склонение числительных в JS
Следующая запись Input type number

Комментарии 2

Макс Муртов Макс Муртов
8 апреля 2021 в 15:04
+2
А как на почту отравить? можно образец пожалуйста, с отпр-й файлов на почту
Alexander Sarychev Alexander Sarychev
10 июня 2021 в 03:04
+1
Проверять файл на расширение плохое решение. Нужно MIME использовать. Для этого есть простая Fileinfo.

, чтобы добавить комментарий.

Другие публикации

Загрузка файлов на сервер PHP
В статье приведен пример формы и php-скрипта для безопасной загрузки файлов на сервер, возможные ошибки и рекомендации при работе с данной темой.
53765
+20
Загрузка файлов через AJAX с помощью jQuery Form Plugin
Пример загрузки изображений через AJAX с помощью плагина jQuery Form Plugin.
16145
+6
Разрешить AJAX с другого домена
Если отправить кроссдоменный AJAX запрос, возникает ошибка...
5479
+2
Работа с JSON в PHP
JSON (JavaScript Object Notation) – текстовый формат обмена данными, основанный на JavaScript, который представляет собой набор пар {ключ: значение}. Значение может быть массивом, числом, строкой и...
78241
+11
Автоматическое сжатие и оптимизация картинок на сайте
Изображения нужно сжимать для ускорения скорости загрузки сайта, но как это сделать? На многих хостингах нет...
19293
+8
Local Storage и Session Storage в JavaScript
Web Storage API это набор методов, при помощи которых в браузере можно хранить данные в виде пар ключ=значение на...
9231
+3