jQuery AJAX загрузка файлов на сервер

Как загружать любые файлы, например, картинки на сервер с помощью AJAX и jQuery? Делается это довольно просто! И ниже мы все обстоятельно разберем.

В те «древние» времена, когда еще не было jQuery, а может он был, но браузеры были не так наворочены, загрузка файла на сайт с помощью AJAX была делом муторным: через всякие костыли вроде iframe. Я те время не застал, да и кому это теперь интересно. А интересно теперь другое — что сохранение файлов на сайт делается очень просто. Даже не обладающий опытом и пониманием, того как работает AJAX, вебмастер, сможет быстро разобраться что-куда. А эта статья ему в помощь. Если подкрепить эти возможности функциями WordPress, то безопасная обработка и загрузка файлов на сервер становится совсем плевым и даже интересным делом (пример с WordPress смотрите в конце статьи).

Однако, как бы все просто не было, нужно заметить, что минимальный опыт работы с файлами и базовые знания в Javascript, jQuery и PHP все же необходимы! Минимум, нужно представлять как загружаются файлы на сервер, как в общих чертах работает AJAX и хоть немного надо уметь читать и понимать код.

Описанный ниже метод довольно стабилен, и по сути опирается на Javascript объект new FormData(), базовая поддержка которого есть во всех браузерах.

Для более понятного восприятия материала, он разделен на шаги. На этом все, полетели…

AJAX Загрузка файлов: общий пример

Начинается все с наличия на сайте input поля типа file. Нет необходимости, чтобы это поле было частью формы (тега <form>).

Таким образом, у нас есть HTML код с file полем и кнопкой «Загрузить файлы».


<input type="file" multiple="multiple" accept=".txt,image/*">
<a href="#" class="upload_files button">Загрузить файлы</a>
<div class="ajax-reply"></div>

Шаг 1. Данные из поля file

Первым шагом, нужно получить данные загружаемых файлов.

При клике на file-поле, появляется окно выбора файлов, после выбора, данные о них сохраняются в input поле, а нам нужно их от туда «забрать». Для этого повесим на событие change JS функцию, которая будет сохранять имеющиеся данные file-поля в JS переменную files:

var files; // переменная. будет содержать данные файлов // заполняем переменную данными, при изменении значения поля file $('input[type=file] 
').on('change', function(){ files = this.files;
});

Шаг 2. Создаем AJAX запрос (по клику)

Данные файлов у нас есть, теперь их нужно отправить через AJAX. Вешаем это событие на клик по кнопке «Загрузить файлы».

В момент клика создаем новый объект new formData() и добавляем в него данные из переменной files. С помощью formData() мы добьемся того, что отправляемые данные будут выглядеть, как если бы мы просто сабмитили форму в браузере.

Далее, из имеющихся данных формы создаем нестандартный AJAX запрос, в котором передаем файлы в стандартном для сервера формате: $_FILES.

Чтобы такой запрос состоялся, в 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(); // остановка дефолтного события для текущего элемента - клик для <a> тега // ничего не делаем если 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 +'<br>'; } ) $('.ajax-reply').html( html ); } // ошибка else { console.log('ОШИБКА: ' + respond.error ); } }, // функция ошибки ответа сервера error: function( jqXHR, status, errorThrown ){ console.log( 'ОШИБКА AJAX запроса: ' + status, jqXHR ); } }); });

Шаг 3. Обрабатываем запрос: загружаем файлы на сервер

Теперь последний шаг: нужно обработать отправленный запрос.

Чтобы было наглядно обработаем запрос без дополнительных проверок для файлов, т.е. просто сохраним полученные файлы в нужную папку. Хотя, для безопасности, отправляемые файлы обязательно нужно проверять, хотя бы расширение (тип) файла…

Создадим файл submit.php с таким кодом (предполагается что submit.php лежит в той же папке, где и файл, с которого отправляется AJAX запрос):

<?php if( isset( $_POST['my_file_upload']  ) ){ // ВАЖНО! тут должны быть все проверки безопасности передавемых файлов и вывести ошибки если нужно $uploaddir = './uploads'; // . - текущая папка где находится submit.php // cоздадим папку если её нет if( ! is_dir( $uploaddir ) ) mkdir( $uploaddir, 0777 ); $files = $_FILES; // полученные файлы $done_files = array(); // переместим файлы из временной директории в указанную foreach( $files as $file ){ $file_name = $file['name'] ; if( move_uploaded_file( $file['tmp_name'] , "$uploaddir/$file_name" ) ){ $done_files[] 
 = realpath( "$uploaddir/$file_name" ); } } $data = $done_files ? array('files' => $done_files ) : array('error' => 'Ошибка загрузки файлов.'); die( json_encode( $data ) );
}

Вот и все!

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

Чтобы не собирать по частям вышеописанный код загрузки, предлагаю его скачать.

ajax-file-upload.zip

Полный, готовый к работе код из этой статьи.

Скачано: 22, размер: 3.2 KB, дата: 19 дней назад


Скопируйте содержимое архива на ваш php сервер, зайдите в главную паку (в браузере) и попробуйте загрузить файлы. Так, вы «в живую» увидите что и как работает.

Читайте также:

AJAX Загрузка файлов: пример для WordPress

Для WordPress обрабатывать AJAX запрос в разы проще, потому что есть готовые функции, например media_handle_upload().

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

Чтобы код ниже начал работать, его нужно добавить в файл темы functions.php. Далее, создать страницу с ярлыком ajax_file_upload и зайти на эту страницу. В контенте вы увидите форму для добавления файла. Выбираете файлы и проверяете все ли загрузилось…

Это полноценный пример того, как безопасно загрузить файлы на сервер в среде WordPress.














<?php // форма
add_action( 'the_content', 'ajax_file_upload_html' ); // скрипт
add_action( 'wp_footer', 'ajax_file_upload_jscode' ); // AJAX обработчик
add_action( 'wp_ajax_'.'ajax_fileload', 'ajax_file_upload_callback' );
add_action( 'wp_ajax_nopriv_'.'ajax_fileload', 'ajax_file_upload_callback' ); // HTML код формы
function ajax_file_upload_html( $text ){ // выходим не наша страница... if( $GLOBALS['post'] 

->post_name !== 'ajax_file_upload' ) return $text; return $text .= ' <input type="file" multiple="multiple" accept="image/*"> <button class="upload_files">Загрузить файл</button> <div class="ajax-reply"></div> ';
} // JS код
function ajax_file_upload_jscode(){ ?> <script> jQuery(document).ready(function($){ // ссылка на файл AJAX обработчик var ajaxurl = '<?= admin_url('admin-ajax.php') ?>'; var nonce = '<?= wp_create_nonce('uplfile') ?>'; var files; // переменная. будет содержать данные файлов // заполняем переменную данными, при изменении значения поля file $('input[type=file] ').on('change', function(){ files = this.files; }); // обработка и отправка AJAX запроса при клике на кнопку upload_files $('.upload_files').on( 'click', function( event ){ event.stopPropagation(); // остановка всех текущих JS событий event.preventDefault(); // остановка дефолтного события для текущего элемента - клик для <a> тега // ничего не делаем если 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-([0-9] +)/)[1] 

 ); 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( '<p>'+ val +'</p>' ); } ); } // error else { $reply.text( 'ОШИБКА: ' + respond.error ); } }, // функция ошибки ответа сервера error: function( jqXHR, status, errorThrown ){ $reply.text( 'ОШИБКА AJAX запроса: ' + status ); } }); }); }) </script> <?php
} // обработчик AJAX запроса
function ajax_file_upload_callback(){ check_ajax_referer( 'uplfile', 'nonce' ); // защита if( empty($_FILES) ) wp_send_json_error( 'Файлов нет...' ); $post_id = (int) $_POST['post_id'] ; // ограничим размер загружаемой картинки $sizedata = getimagesize( $_FILES['upfile'] ['tmp_name']  ); $max_size = 2000; if( $sizedata[0] /*width*/ > $max_size || $sizedata[1] /*height*/ > $max_size ) wp_send_json_error( __('Картинка не может быть больше чем '. $max_size .'px в ширину или высоту...','km') ); // обрабатываем загрузку файла require_once ABSPATH . 'wp-admin/includes/image.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; // фильтр допустимых типов файлов - разрешим только картинки add_filter( 'upload_mimes', function( $mimes ){ return [ 'jpg|jpeg|jpe' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', ] ; } ); $uploaded_imgs = array(); foreach( $_FILES as $file_id => $data ){ $attach_id = media_handle_upload( $file_id, $post_id ); // ошибка if( is_wp_error( $attach_id ) ) $uploaded_imgs[]  = 'Ошибка загрузки файла `'. $data['name']  .'`: '. $attach_id->get_error_message(); else $uploaded_imgs[]  = wp_get_attachment_url( $attach_id ); } wp_send_json_success( $uploaded_imgs ); }

Статьи до этого: AJAX