AJAX. Обмен данными между клиентом и сервером, закачка на сервер файлов без перезагрузки страницы при помощи библиотеки jQuery.
Submitted by Ромка on Ср, 05/09/2007 - 15:44
Задача
Разработать веб-страницу, позволяющую обмениваться данными и закачивать файлы на сервер без перезагрузки страницы.
Средства
Frontend (клиентская часть) – библиотека jQuery версии 1.1.4 и плагин к ней ajaxUpload;
Backend (серверная часть) – Apache (любой версии), PHP 5.2.3, MySQL. В PHP 5.2.0 появились встроенные средства для работы с данными в формате JSON, которые используются в этом примере, если на вашем хостинге установлена более старая версия PHP, то эти функции придется написать самостоятельно.
Решение
Блок-схема работы скрипта изображена на рисунке (большая картинка по клику). Пунктиром обозначен момент обмена данными между клиентом и сервером.
Теперь та же логика, только словами:
1. Сначала пользователь заполняет форму и жмет кнопку "Отправить", затем клиентский скрипт (frontend) передает серверному (backend) текст из формы (передается только текст, без файла, логика простая – зачем передавать файл, если уже в тексте может быть ошибка?).
2. Серверный скрипт проверяет текст на наличие ошибок и возвращает результат клиентскому скрипту (в этом случае в формате html).
3. Клиентский скрипт обрабатывает ответ от сервера, если в ответе передана ошибка, то выводится соответствующее сообщение и скрипт завершает работу, если ошибок нет, то клиентский скрипт отдает серверному файл, выбранный пользователем.
4. Серверный скрипт проверяет корректность файла (размер, тип и т.п.) и отдает ответ клиентскому скрипту (на этот раз в формате JSON).
5. Клиентский скрипт обрабатывает полученный ответ и выводит на экран соответствующий результат.
Исходники и комментарии
В конце статьи будут даны ссылки на полные исходные коды всех файлов. Ниже приведены комментарии к самым важным участкам кода.
Форма запроса (html, файл add.php)
В тэгах head подключаем библиотеку jQuery, плагин ajaxUpload и файл с нашим frontend'ом:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="ajaxupload.js"></script> <script type="text/javascript" src="scriptik.js"></script>
Далее рисуем форму, для отправки текста и файла:
<form enctype="multipart/form-data" method=post name=jklm> <input name=m1 value=""><br> <input name=m2 value=""><br> <input type="file" name="img"> <input type=button value="Добавить сообщение" onclick="javascript:ajax(this.form.m1.value, this.form.m2.value, this.form);" class=subm> </form>
M1 и m2 – это два текстовых поля, данные из которых будут записаны в БД на сервере, img – поле для выбора закачиваемого файла, в данном примере рассмотен вариант с закачкой картинки.
В инпуте типа button, на событие onclick установлена функция, отправляющая данные на сервер. Этой функции передается содержимое текстовых полей и название формы. Сама функция будет описана ниже.
Далее рисуем два слоя, в одном будет выводиться сообщение вида "Подождите идет загрузка", во втором – все остальные сообщения, в том числе и сообщение об успешном завершении работы скрипта:
<div id=loading><img src=loading.gif></div> <div class="m"></div>
Картинка loading.gif должна лежать в той же папке, что и текущий файл (или пропишите в тэге img соответствующий путь).
Все, больше ничего важного в форме запроса нет, остальной код в этом файле – украшательства, не влияющие на работу примера.
Frontend (Javascript, файл scriptik.js)
Здесь описаны только функции из файла scriptik.js, отвечающие за передачу/прием данных от сервера, остальные функции носят чисто украшательский характер и их описание выходит за рамки этой статьи.
Передаем backend файлу insert.php данные из текстовых полей:
$.ajax( { type: "POST", url: "insert.php", data: "x1=" + m1 + "&x2=" + m2,
Обрабатываем ответ сервера. Логика работы серверного скрипта такая: если в переданном клиентом тексте были найдены ошибки, то, в зависимости от ошибки, будет возвращено какое-либо отрицательное число. Если в переданном тексте ошибок нет, то в ответе от сервера придет положительное число – id записи в БД, с которым сохранился этот текст:
success: function(data){ if(data <= -1)show_error_message(data); else { if(formname.img.value != ""){ $.ajaxUpload({ url:'imageupload.php?k=' + data, secureuri:false, uploadform: formname, dataType: 'json',
То есть, если мы получили отрицательный результат, то выводим сообщение об ошибке, если получили положительный результат, то приступаем к закачке файла на сервер. Imageupload.php – backend, отвечающий за закачку файла и его соответствие некоторым требованиям. Скрипту imageupload.php методом GET передается id, под которым на сервере был сохранен переданный текст, чтобы с тем же id сохранить и файл.
Опять обрабатываем ответ сервера, теперь уже ответ приходит в формате JSON, по этому к переменным, пришедшим в ответе можно получить доступ используя объект вида result.var1, result.var2 и т.д.
success: function (img_upload, status){ $("div#loading").hide(); if(img_upload.result == "IMG_UPLOAD_OK")$("div.m").html("Сообщение успешно добавлено"); else $("div.m").html("Сообщение успешно добавлено, но картинку закачать не удалось."); $('div.m').animate({height: 'show'}, 500); }, error: function (data, status, e){ $("div.m").html("Ошибка добавления данных. " + e);
img_upload – это объект, в котором сохраняется результат. Сервер передает клиенту две переменные: img_upload.result – информация о том закачалась картинка или нет, img_upload.name – имя, под которым картинка сохранена на сервере.
Backend (PHP, файлы insert.php и imageupload.php)
Здесь также описаны только функции для взаимодействия сервера с клиентом, описания вспомогательных функций опущены.
insert.php – проверка на корректность, запись в БД переданного клиентом текста и передача ответа клиенту.
Для безопасности проверяем пришел запрос через XMLHttpRequest или нет:
<?php if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){ ?>
Пишем данные в базу и отдаем ответ клиенту:
<?php if(mysql_query("INSERT INTO messages (m1, m2, date) VALUES ('" . htmlspecialchars($_POST["x1"]) . "', '" . htmlspecialchars($_POST["x2"]) . "', NOW())")){ $last_id = mysql_insert_id(); echo $last_id; } else echo "-2";// Ошибка подключения к БД ?>
imageupload.php – проверка на корректность закачанного файла, копирование файла в нужную папку и передача ответа клиенту.
<?php // Проверяем переданный id записи на то, чтобы в нем содержались только цифры $id = $_GET['k']; $id = preg_replace("/\D/", "", $id); if(intval($id)!= $id){ $arr = array ('result'=>"IMG_UPLOAD_ERROR_3:" . intval($id) . ":" . $id); exit (json_encode($arr)); } $id = intval($id); // Проверяем, что закачана картинка, если закачана не картинка, то возвращаем ошибку if(is_uploaded_file($_FILES['img']['tmp_name'])){ if($_FILES['img']['type'] != "image/bmp" && $_FILES['img']['type'] != "image/jpeg" && $_FILES['img']['type'] != "image/gif" && $_FILES['img']['type'] != "image/png" && $_FILES['img']['type'] != "image/pjpeg"){ $arr = array ('result'=>"IMG_UPLOAD_ERROR_WRONG_FILE_TYPE"); exit (json_encode($arr)); } // Проверяем размер файла if($_FILES['img']['size'] >= 100000){ $arr = array ('result'=>"IMG_UPLOAD_ERROR_IMAGE_TO_BIG"); exit (json_encode($arr)); } $name = $_FILES['img']['name']; $dot = strrpos($name, "."); $dot = strlen($name) - $dot; $dot = -$dot; $ext = substr($name, $dot); // Перемещаем закачанный файл из временной папки и возвращаем результат frontend'у if(move_uploaded_file($_FILES['img']['tmp_name'], $_SERVER['DOCUMENT_ROOT'] . "/uploadimages/" . $id . $ext)){ $arr = array ('result'=>'IMG_UPLOAD_OK','name'=> $id . $ext); echo json_encode($arr); } else { $arr = array ('result'=>"IMG_UPLOAD_ERROR_1: " . $_FILES['img']['tmp_name']); exit (json_encode($arr)); } } else { $arr = array ('result'=>"IMG_UPLOAD_ERROR_2"); exit (json_encode($arr)); } ?>
Вот собственно и все. Готов ответить на любые вопросы.
Все исходники в аттаче, не забудьте в файле db_connect.php прописать свои настройки для доступа к БД, а также, перед началом работы создать базу данных из sql-файла, который лежит в архиве.
Вложение | Размер |
---|---|
ajax-jquery-upload-sources.zip | 23.88 KB |
44 Comments
Добрый
Submitted by Anonymous (не проверено) on
Добрый день.
Интересная статья, а главное нужная в данный момент.
Возникает только один вопрос - а где ссылка на аттач ?
Очень
Submitted by Anonymous (не проверено) on
Очень интересно!!!
Особенно удивляет тот момент, что на многих форумах пишут, что мол через аякс нельзя загрузить файлы :)
Но все-таки хотелось посмотреть живые файлы, которые вы прикрипили, но их не видно :(
Буду очень вам благодарен за них.
Денис
открываем http://fiv
Submitted by Anonymous (не проверено) on
открываем
http://fivethreeo.dynalias.org/media/ajaxupload.js
if(window.ActiveXObject) {
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
.....
}
else {
var io = document.createElement('iframe');
.....
Чуда не произошло :-)
Эээ... это
Submitted by Ромка on
Эээ... это вообще к чему?
Исправил глюк,
Submitted by Ромка on
Исправил глюк, сейчас файл должен быть доступен для скачивания (ссылка внизу первого поста).
Есть вопрос.
Submitted by Anonymous (не проверено) on
Есть вопрос. Дело втом что после сабмита выбрасывает иногда на разные страницы в чем модет ьыть дело???
Хмм... А как
Submitted by Ромка on
Хмм... А как сабмитишь? Форму приведи тут... И, желательно, клиентский и серверный скрипты, в том виде, в котором ты их используешь... Просто фронтэнд после сабмита вообще никуда тебя перебрасывать не должен, все делается в пределах одной страницы, без перезагрузки...
Отличная
Submitted by Anonymous (не проверено) on
Отличная статья!
Ошибка кстати в
Submitted by Anonymous (не проверено) on
Ошибка кстати в библятеке этой ajaxUpload. Там
s.uploadform.target" = frameId надо заменить на
s.uploadform.attr("target", frameId); (строка128 или где-то в этом районе). В противном случае страничка перегружается
Хммм... Честно
Submitted by Ромка on
Хммм... Честно говоря, у меня все корректно работает и без правки ядра jQuery и ее плагинов...
Факт! Надо фиксить
Submitted by Anonymous (не проверено) on
Тоже нашёл такой баг! Самое интересное проявляется не всегда!
После указанного выше фикса всё встало на свои места!
Спасибо!
Браузер какой?
Submitted by Ромка on
Браузер какой?
Не помогло!
Submitted by Anonymous (не проверено) on
Кстате не помогло! Пришлось делать перед сабмитом
document.frm.action = '';
document.frm.target = '';
document.frm.submit();
:( Изгаляется гад на target как хочет!
а у меня
Submitted by Гость (не проверено) on
а у меня почемуто в БД не пишет
По такому
Submitted by Ромка on
По такому малоинформативному сообщениию сложно выводы делать. Какой код используете? Какие ошибки выдаются? Есть ли доступ к логам?
З.Ы. А вообще целью этого примера было показать как с использованием AJAX закачивать файлы на сервер, а не как писать данные в БД, по базам данных в интернете немало документации.
а у меня все
Submitted by Гость (не проверено) on
а у меня все делает кромк как закачивает саму картинку и в базу пишет и картинка загрузки выводит, но файл не пишет. В чем может быть проблема?
Какую при этом
Submitted by Ромка on
Какую при этом выдает ошибку сам скрипт? Он должен писать что-то вроде "Сообщение успешно добавлено, однако картинку закачать не удалось, по этому используется картинка по умолчанию. Сообщение об ошибке: IMG_UPLOAD_ERROR_IMAGE_TO_BIG". Сообщения, разумеется, могут быть разными. Какие ошибки пишутся в лог веб-сервера? Без этой информации определить в чем проблема не получится.
Перепробовал
Submitted by Sr (не проверено) on
Перепробовал всё. БД обновляется, но значок загрузки крутиться не перестаёт, а картинка не аплоадится
Попробуй
Submitted by Ромка on
Попробуй поставить браузер Firefox и расширение к нему Firebug. Потом запусти в браузере страницу со скриптом и в правом нижнем углу браузера щелкни по зеленой галочке (или, в случае если скрипт выполняется с ошибками, вместо зеленой галочки может находиться красный крестик). В появившемся окне на вкладке "Console" будут показаны все запросы переданные браузером серверу и все ответы сервера. Попробуй выяснить на каком этапе случается сбой...
Кстати, только сейчас в голову идея пришла! А включена ли поддержка JSON в PHP? Очень похоже что нет. Проверить это можно в phpinfo().
Good Article, Author -
Submitted by Anonymous (не проверено) on
Good Article, Author - Thanks!
Спасибо за
Submitted by Smak on
Спасибо за отличную статью!
Очень хорошо всё показано на блок схеме.
Какой софт использовал для её создания?
:)) Вообще-то это
Submitted by Ромка on
:)) Вообще-то это Ворд с его автофигурами :)) Тогда под рукой ничего более подходящего не оказалось :))
Драстя. Недавно
Submitted by Roman [Yollopukki] (не проверено) on
Драстя. Недавно начал изучать принципы ajax, а с jQuery всего второй день. Как оно работает впринципе понять не сложно, а вот как закинуть на сервер файло (а то и несколько файло) при этом не выкидывая пользователя со страницы, до настоящего момента оставалось загадкой. Но все оказалось как незя проще. Спасибо за пример. Great Respect и Уважуха.
Супер!
Submitted by Гость (не проверено) on
Супер!
И все-таки он грузит через
Submitted by Anonymous (не проверено) on
И все-таки он грузит через iframe:
ajaxfileupload.js:
Думаю не стоит объяснять, что значит конструкция
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
Респектую тебе Ромка статья
Submitted by Anonymous (не проверено) on
Респектую тебе Ромка статья зачот.
Спасибо за статью! А архив
Submitted by Anonymous (не проверено) on
Спасибо за статью! А архив недоступен для скачивания? Запрашиваемая страница не найдена
интересно а как ты не через
Submitted by wanders.32 (не проверено) on
интересно а как ты не через iframe загрузишь файл? или с перезагрузкой всей страницы, или через фрейм. разве есть другие какие-то способы?
Аттач
Submitted by Solven (не проверено) on
Мега респект! =)
Как раз то что нужно для галереи ))
Только аттач не работает, перезалейте плиз...
Отзыв
Submitted by Валера М. (не проверено) on
Статья нормуль, сам скрипт не запускал, могу только пару замечаний:
1) "onclick="javascript:ajax(t"
Это не есть гуд, т.к. считается old-style и невалидно вроде как, используйте id и addEvent function
2) Неплохо бы сделать progress-bar, чтобы было видно сколько еще осталось качать
Возникла необходимость в
Submitted by Сергей (не проверено) on
Возникла необходимость в похожем функционале, но не знаю как это использовать с друпал 6.10
мне нужно:
1. вывести форму в которую человек вводит число
2. число отправляется на сервер и проверяется по массиву (скажем из 10 чисел)
3. в случае совпадения выводится число из другого массива
что получается:
в ноду вставляю код:
Мы приглашаем Вас принять участие в нашем опросе
Введите число из 12 цифр:
//Здесь, я так понимаю, должны вызываться фунцкии описанные в файле scriptik.js отвечающие за прием передачу от сервера.
//в файл insert.php передаются данные (должна проводиться проверка на коректность и запись в БД) и обрабатывается ответ от сервера
который выводит приглашение и форму для ввода.
ввожу число, крутится картинка loading.gif и ничего не происходит.
наверно где-то на уровне insert.php (или раньше в scriptik.js) происходит ошибка, но как отследить ее не знаю.
Подскажите пожалуйста. сам я новичек, но очень хочется разобраться :)
код забыл добавить
Submitted by Сергей (не проверено) on
Плагин на эту тему был бы очень полезен
Submitted by masster (не проверено) on
Плагин на эту тему был бы очень полезен, именно в той логике, что в статье и конечно с прогресс баром. А за статью - спасибо!
Открывается новое окно
Submitted by zver911 (не проверено) on
Здравствуйте, очень хорошая статья и я использовал ее у себя в проекте.
Возникла проблема, Input Files находится в форме, которая содержит много другой информации, которая обрабатывается PHP с последующим Redirect после добавления в БД. Все работает, только результат выводится в новое окно и, похоже, обрабатывается повторно (выдает мою ошибку, что объект уже существует) но в БД записывается 1 раз.
Чтото не работает
Submitted by vladex (не проверено) on
Установил все как надо.
Только сменил название таблицы messages на messagi
Во первых не понимается кодировка, но это пол беды.
Если нажать на кнопку для загрузки фотки, на выбирая фото, то сообщения добавляются, и внизу формы выезжает картинка с надписями сверху и снизу.
Но если я выберу картинку для загрузки и нажму ЗАГРУЗИТЬ то картинка закачки крутиться, и все.
Ничего не грузит на сервер.
В настройках апача json включен.
Вопрос пока без ответа
Submitted by Alexx (не проверено) on
Здравствуйте , Ромка !
Буду краток. Нужно проверить размер файла НЕПРЕМЕННО ДО загрузки. Как ?
Буду очень признателен...
Автор, в чем ты рисовал
Submitted by Anonymous (не проверено) on
Автор, в чем ты рисовал блок-схему?
read or die
Submitted by Anonymous (не проверено) on
MS Office 2007 Visio
Есть, конечно, на разных
Submitted by rangerover on
Есть, конечно, на разных должностях в здесь, но я не нашел этой должности в связи с проектами, как cfa practice test... Если кто-то информация о нем, скажи! Ну, все обновления, связанные с этой позиции? Если да, то скажите мне! На самом деле я пришел сюда во время путешествия по сети для получения данных, относящихся к cfp practice test проектов и нашли эту должность в другой ... Есть ли кто, располагающие информацией о cgfns practice test , chmm practice test? Если да, то что делать, скажите! Мне кажется, другой тип пост ... Тот, кто не знает об этом раньше можно получить полезную информацию из этого поста ... Ну, я хочу сказать, что, как вы пытались объяснить некоторые из должностей, здесь я думаю, разные ...
!
Submitted by Максим Кредшев on
Добрый день!
Смотрим как работает модуль с уведомление отправкой!
Фрейм... :-)
Submitted by Коня (не проверено) on
Я тоже понадеялся на чудо. Но увы...
Сразу же бросился в глаза доктайп 1.0 Strict.
Т.к. он НИ ПОД КАКИМ СОУСОМ не воспримет фрейм, подумал, что реализовано без фреймов. А на деле просто ошибочный доктайп. Не говоря уже о куче мелочей, т.к.
пишется с закрытым тегом () впрочем как и любые другие тэги в этом доктайпе. Про формы и не говорю... . Измени доктайп, а то люди путаются... Загрузить без фрейма по-любому никак всё равно. А сам скрипт хороший, задолбался искать такой. Молодец. Здорово сократил мне время работы.
очень красивая схема. именно.
Submitted by человек (не проверено) on
очень красивая схема. именно.
НЕ работает скрипт в Chrome
Submitted by wonderer22 (не проверено) on
В Firefox все нормально, в chrome не работает
при загрузке страницы сразу крутится loading.gif
кнопка добавить не нажимается :(
менял тип кнопки на submit, кнопка оживает
значит chrome не понимает конструкцию вида
?
serialize
Submitted by Sanyame (не проверено) on
А как можно передать данные m1 и m2 с помощью функции serialize? чтобы сделать пример универсальным