О загрузке файлов на серверрассказывается,
наверное, в каждой книге о веб разработке. Обычно при этом приводится
пример формы с тегом input type=file и объясняется, как работать с
массивом $_FILES
на стороне сервера. Это классический вариант. Он отлично работает, но имеет несколько ограничений.
1) Чтобы загрузить несколько файлов, нужно создать несколько теговinput
. При этом пользователь должен будет выбирать каждый файл отдельно, что довольно неудобно при большом количестве файлов.
2) Невозможно показать процент загрузки файла.
3) Загрузка нескольких файлов будет выполнена в одном запросе. Тут нет
ничего плохого, но может возникнуть проблема, если на сервере
установлены ограничения на максимальный объем запросов и время
выполнения скриптов.
4) Загрузка не будет асинхронной, т.е. произойдет перезагрузка страницы.
На сегодняшний день существует два основных варианта решения этих проблем. Использование iframe
или flash
(по-идее, silverlight
тоже можно использовать для этих целей).
Кстати, о решении с помощью iframe
я раньше рассказывал (Как реализовать асинхронную загрузку файлов с помощью JavaScript и PHP).
Сегодня речь пойдет об использовании flash
, а точнее библиотекиSWFUpload.
На мой взгляд, это одно из лучших решений, т.к. несмотря на то, что отправка файлов осуществляется с помощью flash, настройка, управление и отслеживание процесса загрузки выполняется с помощьюJavaScript.
Пересказывать возможности SWFUpload я не буду, просто покажу небольшой пример её использования.
Постановка задачи.
Допустим нам необходимо позволить пользователю загружать фотографии на
сервер. При этом, сразу после загрузки они должны появляться внизу
страницы.
Шаг 1. Создаём главную страницу (index.php).
- <!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.1//EN» «http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd»>
- <html xmlns=»http://www.w3.org/1999/xhtml» xml:lang=»en»>
- <head>
- <title>SWFUpload</title>
- <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
- </head>
- <body>
- <h1>SWFUpload</h1>
- <div id=»uploadButton»></div>
- <div id=»status»></div>
- <div id=»images»></div>
- <script type=»text/javascript» src=»»></script>
- <script type=»text/javascript» src=»»></script>
- <script type=»text/javascript» src=»»></script>
- <script type=»text/javascript» src=»»></script>
- </body>
- </html>
Здесь мы создали три блока.
uploadButton
— предназначен для размещения кнопки загрузчика.
status
— здесь мы будем выводить сообщения о процессе загрузки.
images
— в этом блоке будут показаны загруженные картинки.
В конце страницы подключены 4 js файла.
Первый — библиотека jquery (её использовать необязательно, я просто хотел немного сократить количество js кода в примере).
Второй — swfupload.js
. Это основной скрипт библиотеки SWFUpload. Именно он создаёт кнопку загрузки.
Третий — plugins/swfupload.queue.js
. Тоже входит в состав библиотеки. Позволяет загружать несколько файлов одновременно.
Четвёртый — main.js
. Здесь находится код настройки библиотеки и обработчики событий. Его мы сейчас и рассмотрим.
Шаг 2. Настраиваем SWFUpload.
Для того, чтобы подключить библиотеку, нужно создать объект SWFUpload и передать ему хеш с настройками.
Делается это следующим образом (код из файла main.js).
- var swfu = new SWFUpload(
- {
- upload_url : «»,
- flash_url : «»,
- button_placeholder_id : «uploadButton»,
- file_size_limit : «2 MB»,
- file_types : «*.jpg; *.png; *.jpeg; *.gif»,
- file_types_description : «Images»,
- file_upload_limit : «0»,
- debug: false,
- button_image_url: «»,
- button_width : 100,
- button_height : 30,
- button_text_left_padding: 15,
- button_text_top_padding: 2,
- button_text : «<span class=\»uploadBtn\»>Обзор…</span>»,
- button_text_style : «.uploadBtn { font-size: 18px; font-family: Arial; background-color: #FF0000; }»,
- file_dialog_complete_handler : fileDialogComplete,
- upload_success_handler : uploadSuccess,
- upload_complete_handler : uploadComplete,
- upload_start_handler : uploadStart,
- upload_progress_handler : uploadProgress
- }
- );
Думаю, названия большинства параметров говорят сами за себя, но хочу обратить ваше внимание на некоторые моменты.
В параметре upload_url
мы указываем адрес php скрипта, который принимает файлы.
С помощью параметров flash_url
и button_placeholder_id
указываем адрес флеш ролика, который создаёт кнопку загрузки и id
элемента на странице, в котором эта кнопка будет размещена.
Затем идет несколько параметров, устанавливающих ограничения на загрузку
файлов. Здесь указаны допустимые разрешения файлов, их максимальный
размер и количество файлов, которые можно загрузить за один раз (0
— любое количество).
После этого указываем параметры, настраивающие внешний вид кнопки
загрузки. Эта часть обязательная, т.к. по-умолчанию кнопка имеет размер
1х1 пиксель, и пользоваться ей будет невозможно.
Т.к. кнопка представляет собой флеш ролик, оформить её напрямую с помощью CSS не получится, но с помощью этих параметров вы можете указать фоновую картинку, шрифт и положения текста.
Оставшиеся параметры устанавливают обработчики событий. Рассмотрим их подробнее.
- function uploadSuccess(file, serverData) {
- $(‘#images’).append($(serverData));
- }
- function uploadComplete(file) {
- $(‘#status’).append($(‘<p>Загрузка ‘ + file.name + ‘ завершена</p>’));
- }
- function uploadStart(file) {
- $(‘#status’).append($(‘<p>Начата загрузка файла ‘ + file.name + ‘</p>’));
- return true;
- }
- function uploadProgress(file, bytesLoaded, bytesTotal) {
- $(‘#status’).append($(‘<p>Загружено ‘ + Math.round(bytesLoaded/bytesTotal*100) + ‘% файла ‘ + file.name + ‘</p>’));
- }
- function fileDialogComplete(numFilesSelected, numFilesQueued) {
- $(‘#status’).html($(‘<p>Выбрано ‘ + numFilesSelected + ‘ файл(ов), начинаем загрузку</p>’));
- this.startUpload();
- }
Сразу хочу обратить ваше внимание. В этом примере использованы не все
события, более полные примеры вы найдете на официальном сайте
библиотеки.
Начнем с события file_dialog_complete
. Оно возникает, когда пользователь выбирает файлы и нажимает кнопку «Open». В его обработчике (fileDialogComplete
) вам обязательно нужно запустить загрузку (сама по себе она не начнётся!).
this.startUpload();
Также обратите внимание, что обработчик события upload_start
должен возвращать true
, для того, чтобы загрузка началась.
Большинство из приведённых здесь обработчиков, получают объект file
в первом параметре. Как несложно догадаться в нём содержится информация о загружаемом файле. Имя файла можно получить так —file.name
.
Ещё один интересный момент — разница между событиямиupload_success
и upload_complete
.
Первое срабатывает после того, как flash ролик завершает отправку
файла, второе — после того как приходит ответ сервера. Учтите, что если
вы после загрузки картинки на сервер будете выполнять её обработку
(масштабирование, например), то задержка между этими событиями будет
заметной.
В данном случае сервер просто возвращает тег img
для загруженной картинки.
Шаг 3. Создаём серверный скрипт ().
- <?php
- $uploadDir = ‘uploads/’; //папка для хранения файлов
- $allowedExt = array(‘jpg’, ‘jpeg’, ‘png’, ‘gif’);
- $maxFileSize = 2 * 1024 * 1024; //1 MB
- //если получен файл
- if (isset($_FILES)) {
- //проверяем размер и тип файла
- $ext = end(explode(‘.’, strtolower($_FILES[‘Filedata’][‘name’])));
- if (!in_array($ext, $allowedExt)) {
- return;
- }
- if ($maxFileSize < $_FILES[‘Filedata’][‘size’]) {
- return;
- }
- if (is_uploaded_file($_FILES[‘Filedata’][‘tmp_name’])) {
- $fileName = $uploadDir.$_FILES[‘Filedata’][‘name’];
- //если файл с таким именем уже существует…
- if (file_exists($fileName)) {
- //…добавляем текущее время к имени файла
- $nameParts = explode(‘.’, $_FILES[‘Filedata’][‘name’]);
- $nameParts[count($nameParts)-2] .= time();
- $fileName = $uploadDir.implode(‘.’, $nameParts);
- }
- move_uploaded_file($_FILES[‘Filedata’][‘tmp_name’], $fileName);
- echo ‘<img src=»‘.$fileName.'» alt=»‘.$fileName.'» />’;
- }
- }
В принципе, это один из самых простых вариантов скрипта загрузки файлов. Я уже упоминал, что SWFUpload отправляет файлы в отдельных запросах, поэтому в массиве $_FILES
может быть только один файл.
Вначале скрипта указываем папку для загрузки файлов, допустимые
расширения и размер. Эти же параметры указаны и при настройке flash
загрузчика, но напоминаю, что доверять полученным от клиента данным
нельзя.
Затем выполняем проверки (строки 11-18) и с помощью функцииmove_uploaded_file
копируем загруженный файл в указанную папку.
Если файл с таким же именем уже был загружен, то добавляем к имени файла текущее время.
После этого, формируем тег img
и отправляем его браузеру.
Как видите, ничего сложного. Использование библиотеки сводит количество
вашего кода к минимуму. Хотя, если вы захотите создать красивый
интерфейс, наглядно иллюстрирующий процесс загрузки, то поработать всё
же придется
Если хотите поэкспериментировать, качайте архив с этим примером.
Вы можете распаковать его в любую папку на вашем сервере. Только убедитесь, что папка uploads доступна для записи.