====== SWFUpload. AJAX загрузка файлов на сервер ====== ===== Введение ===== Асинхронные запросы в web-разработке не редкость. Принцип очень прост: - Формируем в JavaScript необходимые данные. - Оправляем на сервер. - Получаем ответ и перестраиваем страницу опять же с помощью JavaScript. Но все меняется когда мы начинаем говорить о AJAX передаче данных. Чтобы понять суть проблемы достаточно взглянуть на обычную передачу файла на сервер - в POST параметрах передается тело файла. А как известно JavaScript не может получить доступ к файлам, соответственно передать тело файла в AJAX запрос мы не можем. Одним из вариантов решения данной проблемы является использование flesh-загрузчиков, которых сегодня огромное множество. Однако у многих есть два существенных ограничения (сугубо по моему личному мнению): * Загрузка только одного файла. Сюда же отнесем загрузчики, которые передает на сервер несколько файлов, но открывают по одному за раз. Другими словами для загрузки 10 файлов, приходится 10 раз открывать форму выбора файла. * Стандартный внешний вид загрузчика и вид отображения загрузки файлов. Такой загрузчик не всегда можно встроить в дизайн сайта. {{ :development:swfupload_1.jpg?200|Пример загрузки SWFUpload}} Вся прелесть SWFUpload заключается в том, что он позволяет выбирать и загружать сразу несколько файлов, а внешним видом flash является только одна картинка кнопки загрузки. При этом flash передает всю информацию о загружаемых файлах в JavaScript, на основании, которой можно построить абсолютно любое отображение процесса загрузки файлов. И еще одна маленький бонус - можно настроить фильтрацию файлов по типам и размеру еще до отправки файлов на сервер. ---- ===== О SWFUpload ===== Сайт разработчиков: [[http://code.google.com/p/swfupload/|swfupload.org]]\\ Полная документация: [[http://demo.swfupload.org/Documentation|swfupload documentation]] Для работы с загрузчиком необходимо по крайней мере следующие файлы: * ''swfupload.js'' - собственно сама библиотека. * ''swfupload.swf'' - flash-загрузчик. * ''swfupload_handlers.js'' - скрипты обработчиков событий (этот файл мы создадим сами). * ''ajax.php'' - обработчик файлов на стороне сервера (его мы тоже напишем сами). * ''button_sprite.png'' - картинка кнопки (четыре кадра). ---- ===== Инициализация ===== Для инициализации загрузчика необходимо подключить библиотеку ''swfupload.js'' и разместить следующий код: JavaScript: var loader = new SWFUpload({ button_placeholder_id: "loader" }); HTML:
---- ===== Настройка ===== Настройка загрузчика происходит путем передачи объекта с параметрами при инициализации (комплексная настройка) или путем задания отдельных параметров, используя методы самого SWFUpload (эти методы здесь рассмотрены не будут, поэтому при необходимости, обратитесь к [[http://demo.swfupload.org/Documentation|документации]]). Рассмотрим наиболее часто-используемые параметры, разбив их по смысловым группам. ==== Общие параметры ==== * debug - включает окно отладчика, в котором отображаются все текущие настройки загрузчика и все изменения его состояния. * upload_url - путь до обработчика на сервере. * flash_url - путь до flesh загрузчика. Пример: JavaScript: var loader = new SWFUpload({ debug: true, upload_url: "/ajax.php", flash_url: "/swfupload.swf" }); ==== Параметры внешнего вида ==== Как я уже отмечал, внешний вид flesh загрузчика представляет собой картинку. Единственная особенность этой картинки в том, что она состоит из четырех кадров, отображающих различные состояния кнопки (обычное, наведение курсора, нажатие мыши и еще какое-то :-)). * button_placeholder_id - идентификатор HTML-элемента, который будет выступать загрузчиком (пожалуй единственный обязательный параметр). * button_image_url - путь до картинки кнопки. * button_width - ширина картинки. * button_height - высота одного кадра картинки. * button_text - текст на кнопке. Пример: JavaScript: var loader = new SWFUpload({ button_placeholder_id: "loader", button_image_url: "/button_sprite.png", button_width: 60, button_height: 23, button_text: "Click here" }); ==== Параметры загружаемых файлов ==== * file_post_name - ключ в массиве $_FILES по которому будут передаваться файлы на сервер. * file_types - список допустимых типов файлов для загрузке. * file_types_description - описание типов файлов. * file_size_limit - максимальный размер загружаемого файла. Пример: JavaScript: var loader = new SWFUpload({ file_post_name: "filedata", file_types: "*.jpg;*.gif;*.png", file_types_description: "Фотографии", file_size_limit: "2 MB" }); ==== Параметры обработчиков событий ==== Параметры обработчиков по своей сути являются именами функций, которые должны будут обрабатывать эти события. * file_queued_handler - задет обработчик события "файл поставлен в очередь закачки". * file_queue_error_handler - задет обработчик события "ошибка постановки файла в очередь". * file_dialog_complete_handler - задет обработчик события "диалоговое окно выбора файла закрыто и файлы поставлены в очередь". * upload_start_handler - задет обработчик события "загрузка началась". * upload_progress_handler - задет обработчик события "процесс загрузки". * upload_error_handler - задет обработчик события "ошибка при загрузке". * upload_success_handler - задет обработчик события "файл загружен". * upload_complete_handler - задет обработчик события "загрузка завершена". Вызывается сразу после события "файл загружен" или "ошибка при загрузке". Пример: JavaScript: var loader = new SWFUpload({ file_queued_handler: myFileQueuedFunction, file_queue_error_handler: myFileQueueErrorFunction, file_dialog_complete_handler: myFileDialogCompleteFunction, upload_start_handler: myUploadStartFunction, upload_progress_handler: myUploadProgressFunction, upload_error_handler: myUploadErrorFunction, upload_success_handler: myUploadSuccessFunction, upload_complete_handler: myUploadCompleteFunction }); Здесь я привожу только параметры обработчиков, которые я наиболее часто использую, все они связаны с процессом загрузки файла. Полный список обработчиков ищите в [[http://demo.swfupload.org/Documentation|документации]]. Подробное описание представленных обработчиков находится в разделе [[development:ajax-files:swfuload#События|События]]. Хотя это и не обязательно, но практика показала, что лучше определять все обработчики событий связанных с загрузкой. ==== Пользовательские параметры ==== При желании, можно задать какие-либо свои параметры. Параметры передаются обычным объектом, содержащим наборы ключ:значение. Пример: JavaScript: var loader = new SWFUpload({ custom_settings: { my_setting_1: "my_value_1", my_setting_2: "my_value_2", my_setting_3: "my_value_3" } }); Здесь приведен частичный список параметров, за полным перечнем параметров обратитесь к [[http://demo.swfupload.org/Documentation|официальной документации]]. ---- ===== Методы ===== Здесь мы рассмотрим лишь малую часть методов SWFUpload. По большому счету для большинства приложений достаточно использовать всего лишь два метода (оба метода приведены в примерах обработчиков событий). ==== startUpload(file_id) ==== Запускает загрузку файла. __Входные параметры:__ * file_id - идентификатор файла. Если параметр не задан, то загружается первый в очереди файл. __Выходные параметры:__ Не возвращает данных. ==== cancelUpload(file_id, trigger_error_event) ==== Отменяет загрузку файла и убирает его из очереди. __Входные параметры:__ * file_id - идентификатор файла. Если параметр не задан, то отменяется загрузка первого в очереди файла. * trigger_error_event - необязательный параметр, если задан как false, то событие [[development:ajax-files:swfuload#uploadError|uploadError]] подавляется. __Выходные параметры:__ Не возвращает данных. ==== stopUpload() ==== Останавливает текущую загрузку файла и заново помещает его в очередь. __Входные параметры:__ Нет входных параметров. __Выходные параметры:__ Не возвращает данных. ==== getStats() ==== Возвращает статистические данные. __Входные параметры:__ Нет входных параметров. __Выходные параметры:__ * object.in_progress - число, 1 или 0, показывающее идет ли сейчас загрузка файлов. * object.files_queued - число файлов в очереди. * object.successful_uploads - число успешно загруженных файлов. * object.upload_errors - число ошибок при загрузке файлов. * object.upload_cancelled - число отмененных файлов. * object.queue_errors - число ошибок при постановке файлов в очередь загрузки. ==== getFile(file_id|index) ==== Возвращает данные о файле. __Входные параметры:__ * file_id|index - идентификатор файла или его индекс. __Выходные параметры:__ * object.id- строка, идентификатор файла. * object.index - число, индекс файла. * object.name - строка, имя файла. * object.size - число, размер файла в байтах. * object.type - строка, тип файла. * object.creationdate - дата, дата создания файла. * object.modificationdate - дата, дата последнего изменения файла. * object.filestatus - число, код статус файла. Коды статусов находятся в константах [[http://demo.swfupload.org/Documentation/#file_status|SWFUpload.FILE_STATUS]]. ---- ===== События ===== При каждом изменении состояния flesh генерирует соответствующее событие. Именно создание своих обработчиков этих событий и делает SWFUpload невероятно гибким инструментом. И так чтобы показать все картину целиком я покажу в каком порядке появляются события. * flashReady() - единственное событие которое нельзя переопределить - flash сообщает библиотеке, что она готова принимать комманды. * swfUploadLoaded() - вызывается сразу после события flashReady() и сообщает, что можно использовать методы SWFUpload. * fileDialogStart() - возникает перед отображением диалогового окна загрузки файлов. * fileQueued() - возникает при удачной постановке файла в очередь загрузки. * fileQueueError() - возникает при ошибке в процессе постановки файла в очередь загрузки. * fileDialogComplete() - возникает сразу после закрытия диалогового окна загрузки файлов и обработки файлов (постановки в очередь загрузки). * uploadStart() - возникает непосредственно перед загрузкой файла. * uploadProgress() - периодически возникает в процессе загрузки файла. * uploadError() - возникает в случаи ошибки загрузки файла. * uploadSuccess() - возникает после удачной загрузки файла. * uploadComplete() - всегда возникает в конце цикла загрузки файла, не зависимо от исхода. * debug() - возникает при любом изменении состояния, если задан параметр debug. Давайте рассмотрим обработчики основных событий. ==== fileQueued ==== Событие fileQueued возникает при удачной постановке файла в очередь загрузки. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. Пример: JavaScript: function myFileQueuedFunction(file) { try { //вывод данных о файле на страницу //к примеру, создаем элемент

содержащий имя файла и добавляем его в

var filelist = document.getElementById('filelist'); var p = document.createElement('P'); p.innerHTML = file.name; filelist .appendChild(p); } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== fileQueueError ==== Событие fileQueueError возникает при появлении ошибки в процессе постановки файла в очередь загрузки. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. * error_code - код ошибки. * message - текстовое описание ошибки. Советую ориентироваться на код ошибки, а не на текст. Коды ошибок находятся в константах [[http://demo.swfupload.org/Documentation/#queue_error|SWFUpload.QUEUE_ERROR]]. Пример: JavaScript: function myFileQueueErrorFunction(file, code, message) { try { //вывод ошибки на страницу //к примеру, создаем элемент

содержащий имя файла и текст ошибки и добавляем его в

var filelist = document.getElementById('filelist'); var p = document.createElement('P'); var error; switch(code) { case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT: error = 'Превышен допустимый размер файла'; break; case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE: error = 'Пустой файл'; break; case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE: error = 'Недопустимое расширение файла'; break; case SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED: error = 'Превышен установленный предел количества загрузок'; break; default: error = 'Неизвестная ошибка'; break; } p.innerHTML = file.name + ' - ' + error; filelist .appendChild(p); } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== fileDialogComplete ==== Событие fileDialogComplete возникает после закрытия и постановки файлов в очередь. Событие передает обработчику следующую информацию: * number_of_files_selected - количество выбранных файлов в текущей загрузке. * number_of_files_queued - количество файлов поставленных в очередь в текущей загрузке. * total_number_of_files_in_the_queued - общее количество поставленных файлов в очередь (можно запускать несколько загрузок подряд). Если вы хотите, чтобы загрузка файлов началась автоматически после закрытия диалогового окна, то это событие подходит идеально. Пример: JavaScript: function myFileDialogCompleteFunction(selected, queued, queued_total) { try { //к примеру, запускаем загрузку файлов this.startUpload(); } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== uploadStart ==== Событие возникает непосредственно перед загрузкой файла. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. Пример: JavaScript: function myUploadStartFunction(file) { try { //вывод данных о файле на страницу //к примеру, выводим размер файла и статус "Загружается" в
var status = document.getElementById('filestatus'); status.innerHTML = "Размер файла: " + file.size + " байт. Загружается..."; } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== uploadProgress ==== Событие периодически возникает в процессе загрузки файла. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. * bytes_complete - байт загружено. * total_bytes - байт всего. Пример: JavaScript: function myUploadProgressFunction(file, loaded, total) { try { //вывод данных о прогрессе загрузке файла //к примеру, выводим процент загрузки в
var progress = document.getElementById('fileprogress'); var percent = Math.round(100 * loaded / total); progress.innerHTML = "Загружено: " + percent + "%"; } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== uploadError ==== Событие uploadError возникает при появлении ошибки в процессе загрузки файлов. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. * error_code - код ошибки. * message - текстовое описание ошибки. Советую ориентироваться на код ошибки, а не на текст. Коды ошибок находятся в константах [[http://demo.swfupload.org/Documentation/#upload_error|SWFUpload.UPLOAD_ERROR]]. Пример: JavaScript: function myUploadErrorFunction(file, code, message) { try { //вывод ошибки на страницу //к примеру, выводим текст ошибки в
var status = document.getElementById('filestatus'); status.innerHTML = "Ошибка: " + message; } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== uploadSuccess ==== Событие uploadSuccess возникает при удачной загрузке файла Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. * server_data - содержит ответ сервера. * received_response - признак получения ответа. Если по каким-либо причинам после удачной загрузки файла не вызвано событие uploadSuccess, то через определенное время (assume_success_timeout) событие все равно будет вызвано, при этом received_response будет содержать false. Пример: JavaScript: function myUploadSuccessFunction(file, serverData, rr) { try { //вывод сообщения о загрузке файла //к примеру, выводим сообщения в
var status = document.getElementById('filestatus'); status.innerHTML = "Файл " + file.name + " загружен."; } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ==== uploadComplete ==== Событие всегда возникает в конце цикла загрузки файла, сразу после uploadSuccess или uploadError. Событие передает обработчику следующую информацию: * file_object - информация о файле в виде объекта. Вызов события показывает, что цикл загрузки файла завершен. Это отличное место для автоматического запуска загрузки следующего файла. Пример: JavaScript: function myUploadCompleteFunction(file) { try { //вывод сообщения о загрузке файла //к примеру, проверяем есть ли еще файлы в очереди и запускаем их загрузку if (this.getStats().files_queued != 0) { this.startUpload(); } } catch (ex) { //обрабатываем ошибку //к примеру, выводим в debug this.debug(ex); } }; ===== Резюме ===== SWFUplaod очень гибкий инструмент для AJAX-загрузки файлов, но при этом требует более глубоких знаний в области программирования. Я рассказал лишь о части методов и привел простенькие примеры обработчиков событий, но надеюсь что этот материал поможет вам сэкономить время на начальном этапе изучения SWFUpload. Полное описание всех настроек, методов и событий представлено в [[http://demo.swfupload.org/Documentation|официальной документации]] на [[http://code.google.com/p/swfupload/|сайте разработчика]].