Generated with Avocode. Generated with Avocode. Generated with Avocode. Group 15 close hat Generated with Avocode. Generated with Avocode. Generated with Avocode. Generated with Avocode. Generated with Avocode. Generated with Avocode. path40

Загрузка файлов на сайт: PHP, AJAX, HTML5 и Drag’n’Drop

Скучные формы загрузки — прошлый век. HTML5 дает возможности, чтобы добавить Drag’n’Drop, а AJAX позволяет загружать файлы без обновления страницы.

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

Программисту нужно позаботиться о том, чтобы посетитель смог сделать это максимально удобно. Загрузить файл на сайт можно и с помощью обычной формы и обработчика на PHP, но с выходом HTML5 появились другие интересные возможности — в этой статье мы поговорим и о базовых функциях, и о нововведениях.

Загрузка файлов на PHP

Начать следует с создания формы:

<form method='post' action="/file.php" enctype="multipart/form-data">

<input type="hidden" name="MAX_FILE_SIZE" value="5000000">

<input type='file' name='file[]' class='file-drop' id='file-drop' multiple required><br>

<input type='submit' value='Загрузить' >

</form>

<div class='message-div message-div_hidden' id='message-div'></div>

Для тега <form> мы указываются следующие атрибуты:

  • method — метод отправки данных (в нашем случае post);
  • action — путь к обработчику;
  • ectype — тип формы; ult значение multipart/form-data дает браузеру понять, что с ее помощью будут отправляться сразу несколько файлов.

Далее в форме создается скрытое поле MAX_FILE_SIZE , где указан максимальный объем загружаемых файлов в байтах. Поле должно предшествовать самому полю для выбора файлов. Это нужно для того, чтобы пользователь узнал, что превысил допустимый лимит на размер файла до того, как дождется загрузки 200-мегабайтного ролика. Но основная проверка все равно должна проводиться обработчиком, потому что значение этого поля можно изменить в браузере.

Во второй тег <input> добавляется атрибут multiple и имя file[] — это позволит с помощью одного поля загрузить сразу несколько файлов. Также в коде присутствует div, в который позже будет выводиться сообщение.

Далее указываются стили CSS:

.file-drop {

background:#fff;

margin:auto;

padding:200px 200px;

border:2px solid #333;

}

.file-drop_dragover {

border:2px dashed #333;

}

.file-drop__input {

border:0;

}

.message-div {

background:#fefefe;

border:2px solid #333;

color:#333;

width:350px;

height:150px;

position:fixed;

bottom:25px;

right:25px;

font-size:15px;

padding:5px;

z-index:99999;

box-shadow: 0 0 10px rgba(0,0,0,0.5);

}

.message-div_hidden {

right:-9999999999999999999px;

}

И вот как это выглядит:

Форма уже функционирует: можно выбирать или перетаскивать файлы, а после нажатия на кнопку «Загрузить» данные отправятся в обработчик. Там они попадают в многомерный супермассив $_FILES. Его структура выглядит так:

  • имя поля, через которое загружен файл;
  • name — имя загружаемого файла;
  • type — тип в формате MIME-type;
  • size — объем в байтах;
  • tmp_name — временный адрес;
  • error — номер ошибки, если она произошла.

Если через одно поле загружается сразу несколько файлов, то получение доступа к какому-то конкретному происходит следующим образом: $_FILES['file']['name'][0] — индекс файла находится в самом конце.

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

Вот как выглядит обработчик:

<?

if(isset($_FILES)) {

$allowedTypes = array('image/jpeg','image/png','image/gif');

$uploadDir = "files/"; //Директория загрузки. Если она не существует, обработчик не сможет загрузить файлы и выдаст ошибку

for($i = 0; $i < count($_FILES['file']['name']); $i++) { //Перебираем загруженные файлы

$uploadFile[$i] = $uploadDir . basename($_FILES['file']['name'][$i]);

$fileChecked[$i] = false;

echo $_FILES['file']['name'][$i]." | ".$_FILES['file']['type'][$i]." — ";

for($j = 0; $j < count($allowedTypes); $j++) { //Проверяем на соответствие допустимым форматам

if($_FILES['file']['type'][$i] == $allowedTypes[$j]) {

$fileChecked[$i] = true;

break;

}

}

if($fileChecked[$i]) { //Если формат допустим, перемещаем файл по указанному адресу

if(move_uploaded_file($_FILES['file']['tmp_name'][$i], $uploadFile[$i])) {

echo "Успешно загружен <br>";

} else {

echo "Ошибка ".$_FILES['file']['error'][$i]."<br>";

}

} else {

echo "Недопустимый формат <br>";

}

}

} else {

echo "Вы не прислали файл!" ;

}

?>

Если загрузка прошла успешно, создается массив разрешенных типов, по которому проверяется соответствие форматов. Затем, если валидация пройдена, с помощью функции move_uploaded_file файл перемещается из временного хранилища в указанную директорию.

Такой код хоть и работает, но он довольно примитивен и его нужно расширять:

  • удалить из названия специальные символы и пробелы, а в идеале вообще задать имя самостоятельно;
  • занести информацию в базу данных;
  • проверить размер файла;
  • если это изображение — его можно сжать и так далее.

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

Загрузка файлов на сайт с помощью AJAX

Если добавить возможности JavaScript, форму можно сделать полезнее и красивее. Например, можно будет загружать файлы через AJAX, а также добавить анимацию при перетаскивании:

var fileDrop = document.getElementById('file-drop'); //Получаем объекты

var loadButton = document.getElementById('load-button');

var messageDiv = document.getElementById("message-div");

function dragOver() {//Меняем рамку, когда пользователь перетаскивает файл на поле

fileDrop.setAttribute('class','file-drop file-drop_dragover');

}

function dragOut() {//Возвращаем обычную рамку

fileDrop.setAttribute('class','file-drop');

}

function closeMessage() {//Закрываем сообщение

messageDiv.setAttribute('class','message-div message-div_hidden');

messageDiv.innerHTML = '';

}

function showMessage(data = 0) {//Показываем сообщение о том, что началась или закончилась загрузка

if(data == 0) {

data = "Загрузка...";

} else {

setTimeout(closeMessage,4000);

}

messageDiv.innerHTML = data;

messageDiv.setAttribute('class','message-div');

}

function uploadFile() { //Загружаем файл

dragOut();

var files = this.files;

var data = new FormData();

for(var i = 0; i < files.length; i++) { //Помещаем в дата массив с файлами

data.append(i, files[i]);

}

showMessage(); //Показываем сообщение, что загрузка началась

$.ajax({

url: "/file.php", //Ссылка на обработчик

type: 'POST', //Метод передачи

data: data, //Массив с файлами

cache: false, //Обязательно указать false

processData: false, //Обязательно указать false

contentType: false, // Обязательно указать false

success: function (data) {//В случае успеха показываем сообщение с результатом работы и очищаем поле

showMessage(data);

fileDrop.value = null;

}

});

}

//Указываем события для вызова функций

fileDrop.addEventListener('dragover',dragOver);

fileDrop.addEventListener('dragleave',dragOut);

fileDrop.addEventListener('change',uploadFile); //Отправляем файлы сразу после того, как они будут выбраны

Сначала поле передается в объект fileDrop, а затем создаются функции dragOver, dragOut, showMessage и closeMessage: первые две меняют рамку для тега <input>, а вторые показывают и скрывают сообщение. Затем создается функция uploadFile, которая отправляет файл через AJAX.

Функция получает файлы с помощью объекта FormData, затем показывает сообщение, что началась загрузка, и начинает отправлять файл.

Из-за измененного способа передачи структура супермассива $_FILES немного меняется: теперь сначала указывается индекс файла, а потом — необходимая ячейка.

<?

if(isset($_FILES)) {

$uploadDir = "files/";

$allowedTypes = array('image/jpeg','image/png','image/gif');

for($i = 0; $i < count($_FILES); $i++) {

$uploadFile[$i] = $uploadDir . basename($_FILES[$i]['name']);

$fileChecked[$i] = false;

echo $_FILES[$i]['name']." | ".$_FILES[$i]['type']." — ";

for($j = 0; $j < count($allowedTypes); $j++) {

if($_FILES[$i]['type'] == $allowedTypes[$j]) {

$fileChecked[$i] = true;

break;

}

}

if($fileChecked[$i]) {

if(move_uploaded_file($_FILES[$i]['tmp_name'], $uploadFile[$i])) {

echo "Успешно загружен <br>";

} else {

echo "Ошибка ".$_FILES[$i]['error']."<br>";

}

} else {

echo "Недопустимый формат <br>";

}

}

} else {

echo "Вы не прислали файл!";

}

?>

Вот как работает загрузка файлов на AJAX:

Заключение

Дальше с файлами можно делать все что угодно:

  • использовать изображения в статьях и в качестве аватарок;
  • добавить плеер, который будет воспроизводить видео и аудио;
  • создать текстовый, графический или аудио/видеоредактор;
  • разрешать скачивать файлы по ссылке и так далее.

Это лишь малая часть возможностей PHP — подробнее узнать о них всех можно из курса «PHP-разработчик», в котором сильная теоретическая база закрепляется сложными, но интересными практическими задачами.

Курс «PHP-разработчик»
Обширная программа для изучения PHP, состоящая из 4 курсов. Поможет с нуля овладеть популярным языком программирования, устроиться в IT-компанию вашей мечты или стать независимым разработчиком.
  • Живая обратная связь с преподавателями
  • Неограниченный доступ к материалам курса
  • Стажировка в компаниях-партнёрах
  • Дипломный проект от реального заказчика
  • Гарантия трудоустройства в компании-партнёры для выпускников, защитивших дипломные работы
Хочешь получать крутые статьи по программированию?
Подпишись на рассылку Skillbox
Новогодняя распродажа курсов