Приветствую вас дорогие читатели блога. На повестке дня загрузка файлов на сервер через php скрипт. Поехали!
Для начала создадим обычную html форму.
<form method="post" action="server.php" enctype="multipart/form-data">
<input name="name" placeholder="Введите имя" type="text" required/>
<input name="email" placeholder="Введите email" type="email" required/>
<label>Загрузите фото</label>
<input type="file" name="img"/>
<button>Отправить</button>
</form>
В ней пользователю необходимо указать имя, email и файл который должен быть загружен на сервер. Важный момент! В теге формы обязательно должен быть указан такой атрибут enctype="multipart/form-data", иначе файл не отправиться на сервер. Это важно запомнить! Файл загружается с помощью поля input с типом file. Здесь также необходимо указать атрибут name.
После заполнения всех полей и выбора файла для загрузки, нажимая кнопку отправить, данные передаются на php обработчик server.php. В самом файле содержится такой код:
<?php
define('EXT', array('png', 'gif', 'jpg', 'jpeg'));
define('SIZE_MB', 5);
if(count($_FILES) === 0 || count($_POST) === 0){
echo'Переданы не все данные';
die();
}
if(!isset($_POST['name']) || !isset($_POST['email']) || trim($_POST['name']) === "" || trim($_POST['email']) === ""){
echo 'Не передано имя и/или email';
die();
}
if(!isset($_FILES['img']) || trim($_FILES['img']['name']) === "" || trim($_FILES['img']['type']) === "" ||
trim($_FILES['img']['tmp_name']) === "" || (int)$_FILES['img']['size'] === 0 || $_FILES['img']['error'] !== 0){
echo 'Не удалось получить загруженный файл';
die();
}
$ext = pathinfo($_FILES['img']['name'], PATHINFO_EXTENSION);
if(!in_array($ext, EXT)){
echo 'Допускаются файлы с расширением png, gif, jpg, jpeg';
die();
}
$size = $_FILES['img']['size'] / 1000000;
if($size >= SIZE_MB){
echo 'Допускается размер файла не больше 5 Мб';
die();
}
$path = $_SERVER['DOCUMENT_ROOT'].'/upload/'.base64_encode(openssl_random_pseudo_bytes(10)).'.'.$ext;
if(!move_uploaded_file($_FILES['img']['tmp_name'], $path)){
echo 'Не удалось загрузить файл!';
die();
}
echo 'Файл успешно загружен';
$referer = $_SERVER['HTTP_REFERER'];
if($referer === null){
$referer = '/';
}
header("Location: ".$referer);
Разберем что здесь происходит!
define('EXT', array('png', 'gif', 'jpg', 'jpeg'));
define('SIZE_MB', 5);
В константах 'EXT' и 'SIZE_MB' указываются допустимые расширения файлов и размер в мегабайтах для загрузки.
Далее идут проверки на заполнение всех полей формы и наличия прикрепленного файла.
if(count($_FILES) === 0 || count($_POST) === 0){
echo'Переданы не все данные';
die();
}
if(!isset($_POST['name']) || !isset($_POST['email']) || trim($_POST['name']) === "" || trim($_POST['email']) === ""){
echo 'Не передано имя и/или email';
die();
}
if(!isset($_FILES['img']) || trim($_FILES['img']['name']) === "" || trim($_FILES['img']['type']) === "" ||
trim($_FILES['img']['tmp_name']) === "" || (int)$_FILES['img']['size'] === 0 || $_FILES['img']['error'] !== 0){
echo 'Не удалось получить загруженный файл';
die();
}
Обратите внимание что наличие файла проверяется в суперглобальном массиве $_FILES, то есть все данные по файлу который был загружен через поле 'file' будут отображаться в данном массиве. Суперглобальный массив $_POST может содержать только текстовые данные.
В самом начале проверяются суперглобальные массивы на пустоту. Затем идет проверка заполнения текстовых полей 'Имя' и 'Email'. Ну и наконец проверка наличия прикрепленного файла. Здесь рассмотрим подробнее.
Массив $_FILES содержит в виде ключа название поля с типом file у нас название 'img'.
<input type="file" name="img"/>
По этому ключу мы получаем доступ к еще одному массиву со стандартными ключами 'name', 'type', 'tmp_name', 'size', 'error'.
name - имя загружаемого файла
type - тип файла
tmp_name - путь к временному хранилищу файла (нужен для того чтобы загрузить файл).
size - размер файла(в байтах)
error - код ошибки( 0 - без ошибок)
Содержание первых трех ключей(name, type, tmp_name) просто проверяем чтобы они не были пустыми. Содержание ключа size не должно быть равно 0, а ключ error наоборот должен равняться 0. Если проверка пройдена идем дальше.
$ext = pathinfo($_FILES['img']['name'], PATHINFO_EXTENSION);
if(!in_array($ext, EXT)){
echo 'Допускаются файлы с расширением png, gif, jpg, jpeg';
die();
}
Проверяем допустимость расширения загружаемого файла по константе 'EXT'.
$size = $_FILES['img']['size'] / 1000000;
if($size >= SIZE_MB){
echo 'Допускается размер файла не больше 5 Мб';
die();
}
Проверяем допустимость размера загружаемого файла по константе 'SIZE_MB'. Обратите внимание что размер в байтах $size мы перевели в мегабайты разделив на 1000000.
После того как все проверки пройдены, формируем путь загрузки и загружаем файл.
$path = $_SERVER['DOCUMENT_ROOT'].'/upload/'.base64_encode(openssl_random_pseudo_bytes(10)).'.'.$ext;
if(!move_uploaded_file($_FILES['img']['tmp_name'], $path)){
echo 'Не удалось загрузить файл!';
die();
}
Файл загружается в папку upload в корне сайта. Обратите внимание что в качестве названия файла мы формируем токен base64_encode(openssl_random_pseudo_bytes(10)) и прибавляем к нему расширение файла. Это делается для того чтобы пресечь вероятность перезаписи файла на сервере при совпадении названий.
Загрузка осуществляется с помощью функции move_uploaded_file() в которую передается два параметра - временный путь к хранилищу файла и путь куда он будет загружен. При успешной загрузке функция возвращает true.
Вот в принципе и все что нужно знать о загрузке файлов на php. Если у вас сервер на apache то желательно еще в папку загрузки поместить файл .htaccess со следующим содержимым:
AddDefaultCharset UTF-8
<FilesMatch "\.(php|cgi|pl|php3|php4|php5|php6|phps|phtml|shtml|py|php|php3|php4|php5|php6|phtml|pl|asp|aspx|cgi|dll|exe|ico|shtm|shtml|fcg|fcgi|fpl|asmx|pht|py|psp|plx|pl|cgi|ppl|perl|shtml)$">
Order allow,deny
Deny from all
</FilesMatch>
<IfModule mod_mime.c>
RemoveHandler php .php3 .php4 .php5 .php6 .phtml .pl .asp .aspx .cgi .dll .exe .ico .shtm .shtml .fcg .fcgi .fpl .asmx .pht .py .psp .plx .pl .cgi .ppl .perl .shtml
AddType text/plain php .php3 .php4 .php5 .php6 .phtml .pl .asp .aspx .cgi .dll .exe .ico .shtm .shtml .fcg .fcgi .fpl .asmx .pht .py .psp .plx .pl .cgi .ppl .perl .shtml
</IfModule>
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
Данная конфигурация исключает исполнение всех перечисленных исполняемых файлов в вашей папке загрузки. Если вы не используете проверку расширения файла или вам нужно допустить загрузку любого из этого списка исполняемого файла, то важно исключить возможность их запуска прямо на сервере. Но вообще я рекомендую данную конфигурацию применять для того чтобы обезопасить себя от взлома, даже при наличии конкретных проверок расширений как у меня.
Бывает нужна возможность загрузки нескольких файлов одновременно. Для этого необходимо немного изменить поле file.
К примеру так.
<label>
Загрузить картинку 1
<input type="file" name="img[]" />
</label>
<label>
Загрузить картинку 2
<input type="file" name="img[]" />
</label>
Здесь мы создали сразу несколько полей file и присвоили им общее название 'img[]'. Если нужно сделать возможность загрузки нескольких файлов через одно поле, то можно просто добавить атрибут 'multiple'.
<input type="file" name="img[]" multiple/>
Данный атрибут позволяет выбирать в окне выбора сразу несколько файлов одновременно!
На сервере структура кода также поменяется.
<?php
define('EXT', array('png', 'gif', 'jpg', 'jpeg'));
define('SIZE_MB', 5);
if(count($_FILES) === 0 || count($_POST) === 0){
echo'Переданы не все данные';
die();
}
if(!isset($_POST['name']) || !isset($_POST['email']) || trim($_POST['name']) === "" || trim($_POST['email']) === ""){
echo 'Не передано имя и/или email';
die();
}
if(!isset($_FILES['img'])){
echo 'Не удалось получить загруженный файл';
die();
}
for($i = 0; $i < count($_FILES['img']['tmp_name']); $i++){
if(trim($_FILES['img']['name'][$i]) === ''){
continue;
}
if(trim($_FILES['img']['type'][$i]) === ''){
continue;
}
if(trim($_FILES['img']['tmp_name'][$i]) === ''){
continue;
}
$ext = pathinfo($_FILES['img']['name'][$i], PATHINFO_EXTENSION);
if(!in_array($ext, EXT)){
continue;
}
$size = $_FILES['img']['size'][$i] / 1000000;
if($size >= SIZE_MB){
continue;
}
$path = $_SERVER['DOCUMENT_ROOT'].'/upload/'.base64_encode(openssl_random_pseudo_bytes(10)).'.'.$ext;
if(!move_uploaded_file($_FILES['img']['tmp_name'][$i], $path)){
continue;
}
}
$referer = $_SERVER['HTTP_REFERER'];
if($referer === null){
$referer = '/';
}
header("Location: ".$referer);
С помощью данного кода можно загружать несколько файлов одновременно. Подробно разбирать его не буду, оставлю вам в качестве домашнего задания.
В бонус к этой статье разберем загрузку файлов через ajax, так как у некоторых это вызывает затруднения.
На клиенте напишем код:
<form method="post" action="server.php" enctype="multipart/form-data">
<input name="name" placeholder="Введите имя" type="text" required/>
<input name="email" placeholder="Введите email" type="email" required/>
<label>Загрузите фото</label>
<input type="file" name="img[]" multiple/>
<button>Отправить</button>
</form>
<script>
document.querySelector('form').addEventListener('submit', function(e){
e.preventDefault();
var data = new FormData(this);
fetch('/server.php', {method: 'post', body: data}).then(function(response){
return response.json();
}).then(function(res){
alert(res['message']);
if(res['message'] === 'Данные успешно отправлены'){
document.querySelector('form').reset();
}
}).catch(function(err){
alert('Соединение с интернетом разорвано!');
});
});
</script>
Ajax запрос будем делать через метод fetch и ответ от сервера будем выводить в модальном окне alert().
Серверная часть также немного подкоректируется.
<?php
define('EXT', array('png', 'gif', 'jpg', 'jpeg'));
define('SIZE_MB', 5);
if(count($_FILES) === 0 || count($_POST) === 0){
echo json_encode(array('message'=> 'Переданы не все данные'), true);
die();
}
if(!isset($_POST['name']) || !isset($_POST['email']) || trim($_POST['name']) === "" || trim($_POST['email']) === ""){
echo json_encode(array('message'=> 'Не передано имя и/или email'), true);
die();
}
if(!isset($_FILES['img'])){
echo json_encode(array('message'=> 'Не удалось получить загруженный файл'), true);
die();
}
$count_file = 0;
for($i = 0; $i < count($_FILES['img']['tmp_name']); $i++){
if(trim($_FILES['img']['name'][$i]) === ''){
continue;
}
if(trim($_FILES['img']['type'][$i]) === ''){
continue;
}
if(trim($_FILES['img']['tmp_name'][$i]) === ''){
continue;
}
$ext = pathinfo($_FILES['img']['name'][$i], PATHINFO_EXTENSION);
if(!in_array($ext, EXT)){
continue;
}
$size = $_FILES['img']['size'][$i] / 1000000;
if($size >= SIZE_MB){
continue;
}
$path = $_SERVER['DOCUMENT_ROOT'].'/upload/'.base64_encode(openssl_random_pseudo_bytes(10)).'.'.$ext;
if(!move_uploaded_file($_FILES['img']['tmp_name'][$i], $path)){
continue;
}
$count_file++;
}
if($count_file === 0){
echo json_encode(array('message'=> 'Файлы не были загружены'), true);
die();
}
echo json_encode(array('message'=> 'Данные успешно отправлены'), true);
Здесь мы сделали в качестве вывода строку json которую будет принимать в ответе метод fetch на клиенте. И в результате теперь мы сможем загружать файлы на сервер без перезагрузки страницы.
На сегодня у меня все! Пользуйтесь данным кодом для загрузки файлов на php и не забывайте про безопасность!
Всем удачи!
Группа Вконтакте: https://vk.com/webfanatcom
Канал Youtube: https://www.youtube.com/c/WebFanat