Безопасная загрузка файла на сервер php ajax. Динамическая загрузка файлов на jQuery
Как загружать любые файлы, например, картинки на сервер с помощью AJAX и jQuery? Делается это довольно просто! И ниже мы все обстоятельно разберем.
В те «древние» времена, когда еще не было jQuery, а может он был, но браузеры были не так наворочены, загрузка файла на сайт с помощью AJAX была делом муторным: через всякие костыли вроде iframe. Я те время не застал, да и кому это теперь интересно. А интересно теперь другое - что сохранение файлов на сайт делается очень просто. Даже не обладающий опытом и пониманием, того как работает AJAX, вебмастер, сможет быстро разобраться что-куда. А эта статья ему в помощь. Если подкрепить эти возможности функциями WordPress , то безопасная обработка и загрузка файлов на сервер становится совсем плевым и даже интересным делом (пример с WordPress смотрите в конце статьи).
Однако, как бы все просто не было, нужно заметить, что минимальный опыт работы с файлами и базовые знания в Javascript, jQuery и PHP все же необходимы! Минимум, нужно представлять как загружаются файлы на сервер, как в общих чертах работает AJAX и хоть немного надо уметь читать и понимать код.
Описанный ниже метод довольно стабилен, и по сути опирается на Javascript объект new FormData() , базовая поддержка которого есть во всех браузерах.
Для более понятного восприятия материала, он разделен на шаги. На этом все, полетели...
AJAX Загрузка файлов: общий примерНачинается все с наличия на сайте input поля типа file . Нет необходимости, чтобы это поле было частью формы (тега ).
Таким образом, у нас есть HTML код с file полем и кнопкой «Загрузить файлы».
Загрузить файлы
Шаг 1. Данные из поля fileПервым шагом, нужно получить данные загружаемых файлов.
При клике на file-поле, появляется окно выбора файлов, после выбора, данные о них сохраняются в input поле, а нам нужно их от туда «забрать». Для этого повесим на событие change JS функцию, которая будет сохранять имеющиеся данные file-поля в JS переменную files:
Var files; // переменная. будет содержать данные файлов // заполняем переменную данными, при изменении значения поля file $("input").on("change", function(){ files = this.files; });
Шаг 2. Создаем AJAX запрос (по клику)Данные файлов у нас есть, теперь их нужно отправить через AJAX. Вешаем это событие на клик по кнопке «Загрузить файлы».
В момент клика создаем новый объект new formData() и добавляем в него данные из переменной files . С помощью formData() мы добьемся того, что отправляемые данные будут выглядеть, как если бы мы просто сабмитили форму в браузере.
Чтобы такой запрос состоялся, в jQuery нужно указать дополнительные AJAX параметры, поэтому привычная функция $.post() не подходит и мы используем более гибкий аналог: $.ajax() .
Два важных дополнительных параметра нужно установить в false:
ProcessData
Отключает обработку передаваемых данных. По умолчанию, например, для GET запросов jQuery собирает данные в строку запроса и добавляет эту строку в конец URL. Для POST данных делает другие преобразования. Нам любые изменения исходных данных будут мешать, поэтому отключаем эту опцию...
contentType
Отключает установку заголовка типа запроса. Дефолтная установка jQuery равна "application/x-www-form-urlencoded . Такой заголовок не предусматривает отправку файлов. Если установить этот параметр в "multipart/form-data" , PHP все равно не сможет распознать передаваемые данные и выведет предупреждение «Missing boundary in multipart/form-data»... В общем, проще всего отключить эту опция, тогда все работает!
// обработка и отправка AJAX запроса при клике на кнопку upload_files
$(".upload_files").on("click", function(event){
event.stopPropagation(); // остановка всех текущих JS событий
event.preventDefault(); // остановка дефолтного события для текущего элемента - клик для тега
// ничего не делаем если files пустой
if(typeof files == "undefined") return;
// создадим объект данных формы
var data = new FormData();
// заполняем объект данных файлами в подходящем для отправки формате
$.each(files, function(key, value){
data.append(key, value);
});
// добавим переменную для идентификации запроса
data.append("my_file_upload", 1);
// AJAX запрос
$.ajax({
url: "./submit.php",
type: "POST", // важно!
data: data,
cache: false,
dataType: "json",
// отключаем обработку передаваемых данных, пусть передаются как есть
processData: false,
// отключаем установку заголовка типа запроса. Так jQuery скажет серверу что это строковой запрос
contentType: false,
// функция успешного ответа сервера
success: function(respond, status, jqXHR){
// ОК - файлы загружены
if(typeof respond.error === "undefined"){
// выведем пути загруженных файлов в блок ".ajax-reply"
var files_path = respond.files;
var html = "";
$.each(files_path, function(key, val){
html += val +"
";
})
$(".ajax-reply").html(html);
}
// ошибка
else {
console.log("ОШИБКА: " + respond.error);
}
},
// функция ошибки ответа сервера
error: function(jqXHR, status, errorThrown){
console.log("ОШИБКА AJAX запроса: " + status, jqXHR);
}
});
});
Теперь последний шаг: нужно обработать отправленный запрос.
Чтобы было наглядно обработаем запрос без дополнительных проверок для файлов, т.е. просто сохраним полученные файлы в нужную папку. Хотя, для безопасности, отправляемые файлы обязательно нужно проверять, хотя бы расширение (тип) файла...
Создадим файл submit.php с таким кодом (предполагается что submit.php лежит в той же папке, где и файл, с которого отправляется AJAX запрос):
jQuery(document).ready(function($){
// ссылка на файл AJAX обработчик
var ajaxurl = "";
var nonce = "";
var files; // переменная. будет содержать данные файлов
// заполняем переменную данными, при изменении значения поля file
$("input").on("change", function(){
files = this.files;
});
// обработка и отправка AJAX запроса при клике на кнопку upload_files
$(".upload_files").on("click", function(event){
event.stopPropagation(); // остановка всех текущих JS событий
event.preventDefault(); // остановка дефолтного события для текущего элемента - клик для тега
// ничего не делаем если files пустой
if(typeof files == "undefined") return;
// создадим данные файлов в подходящем для отправки формате
var data = new FormData();
$.each(files, function(key, value){
data.append(key, value);
});
// добавим переменную идентификатор запроса
data.append("action", "ajax_fileload");
data.append("nonce", nonce);
data.append("post_id", $("body").attr("class").match(/postid-(+)/));
var $reply = $(".ajax-reply");
// AJAX запрос
$reply.text("Загружаю...");
$.ajax({
url: ajaxurl,
type: "POST",
data: data,
cache: false,
dataType: "json",
// отключаем обработку передаваемых данных, пусть передаются как есть
processData: false,
// отключаем установку заголовка типа запроса. Так jQuery скажет серверу что это строковой запрос
contentType: false,
// функция успешного ответа сервера
success: function(respond, status, jqXHR){
// ОК
if(respond.success){
$.each(respond.data, function(key, val){
$reply.append("");
});
}
// error
else {
$reply.text("ОШИБКА: " + respond.error);
}
},
// функция ошибки ответа сервера
error: function(jqXHR, status, errorThrown){
$reply.text("ОШИБКА AJAX запроса: " + status);
}
});
});
})
$(function() {
$("#file_upload").uploadify({
"formData" : {
"timestamp" : "",
"token" : ""
},
"uploader" : "uploadify.php"
});
});
Файл стилей стандартный для этого плагина, и он так же скачивается в общем наборе файлов с официального сайта. Безусловно, его можно менять на своё усмотрение.
Так же подключается jQuery и сам плагин. Дальше создаётся форма, а у input с type="file" ставится id , который затем уже будет использоваться в скрипте.
В самом скрипте передаются данные в formData . А именно текущее время и секретный токен . Вместо "unique_salt " может быть любая секретная строка. В свойстве "uploader " передаётся скрипт-обработчик. Теперь сам код этого обработчика:
Код я прокомментировал, поэтому, думаю, что в нём разобраться не составит труда. Единственное, что отмечу - проверок здесь недостаточно. Впрочем, про я писал в отдельной статье.
ProgressBar в этот плагин так же встроен, так что всё уже сделали за нас. В этом и состоит преимущество библиотеки jQuery и плагинов для неё. Очень сложные задачи, такие как динамическая загрузка файлов на сервер с ProgressBar , которые потребуют весь день на разработку, а потом ещё несколько дней на исправление ошибок, решаются за несколько минут с помощью готовых плагинов.
Наверное многие сталкивались с вопросом "Как загрузить файл на сервер с помощью JS и JQuery?".
И вероятно не у всех получилось это сделать. На самом деле все не так сложно как кажется.
В данном уроке я опишу процесс загрузки файла на сервер(хостинг) .
Для обмена данными между браузером и веб-сервером, используется технология ajax.
Версия JQuery используемая в рецепте: 2.2.2.
Создаем примитивную разметку из тегов html, head и body.
В теге head необходимо прописать путь до библиотеки jquery.
В примере я использую jquery с сервера google.
В теге body создаем форму, которая состоит из тега input и button.
С помощью input type="file" осуществляется выбор файла для загрузки.
Тег button необходим для запуска js кода на передачу файла.
Форме задаем name="uploader", enctype="multipart/form-data", method="POST".
Имя формы: name="uploader"
Способ кодирования данных формы: enctype="multipart/form-data"
Метод передачи данных: method="POST"
Отправить этот файл: Загрузить
Весь код html и js разметки:
Отправить этот файл:
Загрузить
Переходим к java script коду.
Для передачи файла необходимо передавать форму целиком:
$("form").submit(function(e) {
Считываем данные формы в переменную:
var formData = new FormData($(this));
Далее для передачи данных на веб-сервер используем технологию ajax.
В случае успешной передачи файла во всплывающем окне будет отображено соответствующее сообщение.
В случае возникновения ошибки или отсутствии файла будет отображено сообщение с текстом возникшей проблемы.
$.ajax({
url: "file.php",
type: "POST",
data: formData,
async: false,
success: function (msg) {
alert(msg);
},
error: function(msg) {
alert("Ошибка!");
},
cache: false,
contentType: false,
processData: false
});
Весь код на java script с использование jquery:
Теперь остался код на стороне сервера для приема данных с формы методом POST запроса.
Получаем корневую директорию сайта и назначаем папку для загрузки файлов:
$uploaddir = $_SERVER["DOCUMENT_ROOT"].DIRECTORY_SEPARATOR."uploads".DIRECTORY_SEPARATOR;
Считываем загружаемый файл:
$uploadfile = $uploaddir . basename($_FILES["userfile"]["name"]);
Проверяем загружен ли файл.
В соответствии с входящими данными назначаем сопровождающее сообщение.
Если файл не загружен, загружаем в директорию указанную в $uploadfile:
if (move_uploaded_file($_FILES["userfile"]["tmp_name"], $uploadfile)) {
$out = "Файл корректен и был успешно загружен.\n";
} else {
$out = "Возможная атака с помощью файловой загрузки!\n";
}
При выполнении указанных действий возвращается ответ.
Весь код на php:
Весь html код включая js:
Отправить этот файл: Загрузить $("form").submit(function(e) { var formData = new FormData($(this)); $.ajax({ url: "file.php", type: "POST", data: formData, async: false, success: function (msg) { alert(msg); }, error: function(msg) { alert("Ошибка!"); }, cache: false, contentType: false, processData: false }); e.preventDefault(); });
Скачать файл с исходным кодом:
В наше время веб-сайты становятся все более интерактивными. Это касается не только специализированных сервисов, но и обычных интернет магазинов, блогов и небольших сайтов. Основной особенностью является асинхронный JavaScript и XML сокращенно AJAX . Эта технология позволяет браузеру в фоновом режиме общаться с веб-сервером и при обновлении данных, веб-страница не перезагружается полностью. Другими словами, мы можем делать запросы и получать ответы от сервера не перезагружая страницу в браузере.
Поскольку наиболее популярным языком для разработки веб-приложений является PHP , то сегодня мы будем использовать связку AJAX и PHP . Пример будет хорош для понимания основных принципов работы с AJAX и PHP .
На самом деле особых сложностей быть не должно, алгоритм действий:
- Выбрать картинку
- Нажать кнопку “Отправить”
- Перехватить вызов формы с помощью JavaScript (jQuery)
- Передать содержимое в специальный php скрипт-обработчик
- Вернуть результат выполнения
- Обработать результат при помощи JavaScript (jQuery)
- Вывести пользователю информацию о загрузке
Немного отклонюсь от темы и объясню что такое jQuery . jQuery — это специальная JavaScript библиотека, которая помогает упростить разработку веб приложений в несколько раз, также данная библиотека предоставляет API для работы с AJAX . Простыми словами, мы напишем меньше кода, чем если бы это делали на чистом JS.
Ajax позволяет не перезагружая веб-страницу, обмениваться данными с веб-сервером и обновлять ее содержимое.
Я склоняюсь к тому, что если есть инструмент, который позволяет вам ускорить разработку без последствий, то почему бы его не использовать? Но чистый JS тоже не помешало бы знать(хоть и лично мой уровень владения JS равен уровню копипаста примеров со stackoverflow 🙂).
Мы разберем одну из проблем, которую мне однажды пришлось решать, а именно — загрузка изображения на сайт с предварительным просмотром. Если вы меняли аватарку в вконтакте, вы понимаете о чем я пишу.
Нам понадобится 3 простых файла, это:
- Страница с формой
- php обработчик
- файл js
Обычная html страница с формой. Обратите внимание на enctype="multipart/form-data" , это нужно для передачи файлов, параметр указывает на способ кодирования данных. Если передаете файлы, значение всегда должно быть multipart/form-data .
handler.php // Проверяем установлен ли массив файлов и массив с переданными данными if(isset($_FILES) && isset($_FILES["image"])) { //Переданный массив сохраняем в переменной $image = $_FILES["image"]; // Проверяем размер файла и если он превышает заданный размер // завершаем выполнение скрипта и выводим ошибку if ($image["size"] > 200000) { die("error"); } // Достаем формат изображения $imageFormat = explode(".", $image["name"]); $imageFormat = $imageFormat; // Генерируем новое имя для изображения. Можно сохранить и со старым // но это не рекомендуется делать $imageFullName = "./images/" . hash("crc32",time()) . "." . $imageFormat; // Сохраняем тип изображения в переменную $imageType = $image["type"]; // Сверяем доступные форматы изображений, если изображение соответствует, // копируем изображение в папку images if ($imageType == "image/jpeg" || $imageType == "image/png") { if (move_uploaded_file($image["tmp_name"],$imageFullName)) { echo "success"; } else { echo "error"; } } }Это очень упрощенный обработчик. Имя картинки я сгенерировал использовав функцию hash . Хорошей практикой считается изменять имена файлов при загрузке их на сервер.
ajaxupload.js $(document).ready(function () { function readImage (input) { if (input.files && input.files) { var reader = new FileReader(); reader.onload = function (e) { $("#preview").attr("src", e.target.result); } reader.readAsDataURL(input.files); } } function printMessage(destination, msg) { $(destination).removeClass(); if (msg == "success") { $(destination).addClass("alert alert-success").text("Файл успешно загружен."); } if (msg == "error") { $(destination).addClass("alert alert-danger").text("Произошла ошибка при загрузке файла."); } } $("#image").change(function(){ readImage(this); }); $("#upload-image").on("submit",(function(e) { e.preventDefault(); var formData = new FormData(this); $.ajax({ type:"POST", // Тип запроса url: "handler.php", // Скрипт обработчика data: formData, // Данные которые мы передаем cache:false, // В запросах POST отключено по умолчанию, но перестрахуемся contentType: false, // Тип кодирования данных мы задали в форме, это отключим processData: false, // Отключаем, так как передаем файл success:function(data){ printMessage("#result", data); }, error:function(data){ console.log(data); } }); })); });В этом скрипте происходит самое интересное. При помощи функции readImage() мы будем считывать файл с поля формы и передавать его в блок для предварительного просмотра. Создается объект FileReader . Он позволяет веб-приложению считывать содержимое файла на компьютере пользователя. Событие.onload сработает когда содержимое будет считано, при помощи этого события мы выведем изображение в блок предварительного просмотра.
И напоследок, метод.readAsDataURL() запускает процесс чтения файла, по завершению чтения будет выполнено событие.onload и картинка появится у вас на экране.
Функция printMessage создана для вывода информации об успешной или провалившейся попытке загрузки файла. Подробно не рассматриваем, ничего особенного не представляет.
Перехват формы и её обработка. При клике на кнопку «Отправить» событие будет перехвачено скриптом и при помощи функции.preventDefault() форма не отправит данные в index.html . .preventDefault() служит для отмены вызова каких-либо событий.
Объект FormData нужен нам для создания POST запроса к нашему скрипту, это намного проще чем вписывать каждый элемент формы в строку. Создали объект, заполнили данными, отдали в наш ajax .
Ну и собственно сам запрос AJAX . Поскольку мы используем библиотеку jQuery , составить и выполнить такой запрос не вызовет у вас никаких проблем.
Собственно, на этом и закончим. Изображение загружается, страница не перезагружается, все довольны. Если у вас возникают вопросы или предложения, пишите комментарии.
Хорошего дня и успехов 🙂