Вы находитесь на устаревшей версии сайта romka.eu. Она оставлена здесь на случай если я захочу поностальгировать по тому как выглядел интернет в 2012 году :) Так этот сайт выглядел с июня 2012 по февраль 2023. Эта версия сайта не обновляется, комментирование материалов отключено. Обновленная версия сайта доступна по адресу http://romka.eu.

AJAX. Обмен данными между клиентом и сервером, закачка на сервер файлов без перезагрузки страницы при помощи библиотеки jQuery.

Submitted by Ромка on Ср, 05/09/2007 - 15:44

Ромка аватар
13759
Vote up!

Задача

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

Средства

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'ом:

  1. <script type="text/javascript" src="jquery.js"></script>
  2. <script type="text/javascript" src="ajaxupload.js"></script>
  3. <script type="text/javascript" src="scriptik.js"></script>

Далее рисуем форму, для отправки текста и файла:

  1. <form enctype="multipart/form-data" method=post name=jklm>
  2. <input name=m1 value=""><br>
  3. <input name=m2 value=""><br>
  4. <input type="file" name="img">
  5. <input type=button value="Добавить сообщение" onclick="javascript:ajax(this.form.m1.value, this.form.m2.value, this.form);" class=subm>
  6. </form>

M1 и m2 – это два текстовых поля, данные из которых будут записаны в БД на сервере, img – поле для выбора закачиваемого файла, в данном примере рассмотен вариант с закачкой картинки.

В инпуте типа button, на событие onclick установлена функция, отправляющая данные на сервер. Этой функции передается содержимое текстовых полей и название формы. Сама функция будет описана ниже.

Далее рисуем два слоя, в одном будет выводиться сообщение вида "Подождите идет загрузка", во втором – все остальные сообщения, в том числе и сообщение об успешном завершении работы скрипта:

  1. <div id=loading><img src=loading.gif></div>
  2. <div class="m"></div>

Картинка loading.gif должна лежать в той же папке, что и текущий файл (или пропишите в тэге img соответствующий путь).

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

Frontend (Javascript, файл scriptik.js)

Здесь описаны только функции из файла scriptik.js, отвечающие за передачу/прием данных от сервера, остальные функции носят чисто украшательский характер и их описание выходит за рамки этой статьи.

Передаем backend файлу insert.php данные из текстовых полей:

  1. $.ajax(
  2. {
  3. type: "POST",
  4. url: "insert.php",
  5. data: "x1=" + m1 + "&x2=" + m2,

Обрабатываем ответ сервера. Логика работы серверного скрипта такая: если в переданном клиентом тексте были найдены ошибки, то, в зависимости от ошибки, будет возвращено какое-либо отрицательное число. Если в переданном тексте ошибок нет, то в ответе от сервера придет положительное число – id записи в БД, с которым сохранился этот текст:

  1. success: function(data){
  2. if(data <= -1)show_error_message(data);
  3. else {
  4. if(formname.img.value != ""){
  5. $.ajaxUpload({
  6. url:'imageupload.php?k=' + data,
  7. secureuri:false,
  8. uploadform: formname,
  9. dataType: 'json',

То есть, если мы получили отрицательный результат, то выводим сообщение об ошибке, если получили положительный результат, то приступаем к закачке файла на сервер. Imageupload.php – backend, отвечающий за закачку файла и его соответствие некоторым требованиям. Скрипту imageupload.php методом GET передается id, под которым на сервере был сохранен переданный текст, чтобы с тем же id сохранить и файл.

Опять обрабатываем ответ сервера, теперь уже ответ приходит в формате JSON, по этому к переменным, пришедшим в ответе можно получить доступ используя объект вида result.var1, result.var2 и т.д.

  1. success: function (img_upload, status){
  2. $("div#loading").hide();
  3. if(img_upload.result == "IMG_UPLOAD_OK")$("div.m").html("Сообщение успешно добавлено");
  4. else $("div.m").html("Сообщение успешно добавлено, но картинку закачать не удалось.");
  5. $('div.m').animate({height: 'show'}, 500);
  6. },
  7. error: function (data, status, e){
  8. $("div.m").html("Ошибка добавления данных. " + e);

img_upload – это объект, в котором сохраняется результат. Сервер передает клиенту две переменные: img_upload.result – информация о том закачалась картинка или нет, img_upload.name – имя, под которым картинка сохранена на сервере.

Backend (PHP, файлы insert.php и imageupload.php)

Здесь также описаны только функции для взаимодействия сервера с клиентом, описания вспомогательных функций опущены.

insert.php – проверка на корректность, запись в БД переданного клиентом текста и передача ответа клиенту.

Для безопасности проверяем пришел запрос через XMLHttpRequest или нет:

  1. <?php
  2. if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
  3. ?>

Пишем данные в базу и отдаем ответ клиенту:

  1. <?php
  2. if(mysql_query("INSERT INTO messages (m1, m2, date) VALUES ('" . htmlspecialchars($_POST["x1"]) . "', '" . htmlspecialchars($_POST["x2"]) . "', NOW())")){
  3. $last_id = mysql_insert_id();
  4. echo $last_id;
  5. }
  6. else echo "-2";// Ошибка подключения к БД
  7. ?>

imageupload.php – проверка на корректность закачанного файла, копирование файла в нужную папку и передача ответа клиенту.

  1. <?php
  2. // Проверяем переданный id записи на то, чтобы в нем содержались только цифры
  3. $id = $_GET['k'];
  4. $id = preg_replace("/\D/", "", $id);
  5. if(intval($id)!= $id){
  6. $arr = array ('result'=>"IMG_UPLOAD_ERROR_3:" . intval($id) . ":" . $id);
  7. exit (json_encode($arr));
  8. }
  9. $id = intval($id);
  10.  
  11. // Проверяем, что закачана картинка, если закачана не картинка, то возвращаем ошибку
  12. if(is_uploaded_file($_FILES['img']['tmp_name'])){
  13. 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"){
  14. $arr = array ('result'=>"IMG_UPLOAD_ERROR_WRONG_FILE_TYPE");
  15. exit (json_encode($arr));
  16. }
  17. // Проверяем размер файла
  18. if($_FILES['img']['size'] >= 100000){
  19. $arr = array ('result'=>"IMG_UPLOAD_ERROR_IMAGE_TO_BIG");
  20. exit (json_encode($arr));
  21. }
  22. $name = $_FILES['img']['name'];
  23. $dot = strrpos($name, ".");
  24. $dot = strlen($name) - $dot;
  25. $dot = -$dot;
  26. $ext = substr($name, $dot);
  27. // Перемещаем закачанный файл из временной папки и возвращаем результат frontend'у
  28. if(move_uploaded_file($_FILES['img']['tmp_name'], $_SERVER['DOCUMENT_ROOT'] . "/uploadimages/" . $id . $ext)){
  29. $arr = array ('result'=>'IMG_UPLOAD_OK','name'=> $id . $ext);
  30. echo json_encode($arr);
  31. } else {
  32. $arr = array ('result'=>"IMG_UPLOAD_ERROR_1: " . $_FILES['img']['tmp_name']);
  33. exit (json_encode($arr));
  34. }
  35. } else {
  36. $arr = array ('result'=>"IMG_UPLOAD_ERROR_2");
  37. exit (json_encode($arr));
  38. }
  39. ?>

Вот собственно и все. Готов ответить на любые вопросы.

Все исходники в аттаче, не забудьте в файле db_connect.php прописать свои настройки для доступа к БД, а также, перед началом работы создать базу данных из sql-файла, который лежит в архиве.

ВложениеРазмер
Package icon ajax-jquery-upload-sources.zip23.88 KB

44 Comments

Добрый

Добрый день.
Интересная статья, а главное нужная в данный момент.
Возникает только один вопрос - а где ссылка на аттач ?

Очень

Очень интересно!!!
Особенно удивляет тот момент, что на многих форумах пишут, что мол через аякс нельзя загрузить файлы :)

Но все-таки хотелось посмотреть живые файлы, которые вы прикрипили, но их не видно :(
Буду очень вам благодарен за них.

Денис

открываем http://fiv

открываем
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');
.....
Чуда не произошло :-)
 

Ромка аватар

Исправил глюк,

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

Есть вопрос.

Есть вопрос. Дело втом что после сабмита выбрасывает иногда на разные страницы в чем модет ьыть дело???

Ромка аватар

Хмм... А как

Хмм... А как сабмитишь? Форму приведи тут... И, желательно, клиентский и серверный  скрипты, в том виде, в котором ты их используешь... Просто фронтэнд после сабмита вообще никуда тебя перебрасывать не должен, все делается в пределах одной страницы, без перезагрузки...

Отличная

Отличная статья!

Ошибка кстати в

Ошибка кстати в библятеке этой ajaxUpload. Там
 s.uploadform.target" = frameId надо заменить на
s.uploadform.attr("target", frameId); (строка128 или где-то в этом районе). В противном случае страничка перегружается

Ромка аватар

Хммм... Честно

Хммм... Честно говоря, у меня все корректно работает и без правки ядра jQuery и ее плагинов...

Факт! Надо фиксить

Тоже нашёл такой баг! Самое интересное проявляется не всегда!
После указанного выше фикса всё встало на свои места!
Спасибо!

Не помогло!

Кстате не помогло! Пришлось делать перед сабмитом
document.frm.action = '';
document.frm.target = '';
document.frm.submit();
:( Изгаляется гад на target как хочет!

а у меня

а у меня почемуто в БД не пишет

Ромка аватар

По такому

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

З.Ы. А вообще целью этого примера было показать как с использованием AJAX закачивать файлы на сервер, а не как писать данные в БД, по базам данных в интернете немало документации.

а у меня все

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

Ромка аватар

Какую при этом

Какую при этом выдает ошибку сам скрипт? Он должен писать что-то вроде "Сообщение успешно добавлено, однако картинку закачать не удалось, по этому используется картинка по умолчанию. Сообщение об ошибке: IMG_UPLOAD_ERROR_IMAGE_TO_BIG". Сообщения, разумеется, могут быть разными. Какие ошибки пишутся в лог веб-сервера? Без этой информации определить в чем проблема не получится.

Перепробовал

Перепробовал всё. БД обновляется, но значок загрузки крутиться не перестаёт, а картинка не аплоадится

Ромка аватар

Попробуй

Попробуй поставить браузер Firefox и расширение к нему Firebug. Потом запусти в браузере страницу со скриптом и в правом нижнем углу браузера щелкни по зеленой галочке (или, в случае если скрипт выполняется с ошибками, вместо зеленой галочки может находиться красный крестик). В появившемся окне на вкладке "Console" будут показаны все запросы переданные браузером серверу и все ответы сервера. Попробуй выяснить на каком этапе случается сбой...

Кстати, только сейчас в голову идея пришла! А включена ли поддержка JSON в PHP? Очень похоже что нет. Проверить это можно в phpinfo().

Good Article, Author -

Good Article, Author - Thanks!

Спасибо за

Спасибо за отличную статью!
Очень хорошо всё показано на блок схеме.
Какой софт использовал для её создания?

Ромка аватар

:)) Вообще-то это

:)) Вообще-то это Ворд с его автофигурами :)) Тогда под рукой ничего более подходящего не оказалось :))

Драстя. Недавно

Драстя. Недавно начал изучать принципы ajax, а с jQuery всего второй день. Как оно работает впринципе понять не сложно, а вот как закинуть на сервер файло (а то и несколько файло) при этом не выкидывая пользователя со страницы, до настоящего момента оставалось загадкой. Но все оказалось как незя проще. Спасибо за пример. Great Respect и Уважуха.

Супер!

Супер!

И все-таки он грузит через

И все-таки он грузит через iframe:
ajaxfileupload.js:

  1. createUploadIframe: function(id, uri)
  2. {
  3. //create frame
  4. var frameId = 'jUploadFrame' + id;
  5.  
  6. if(window.ActiveXObject) {
  7. var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
  8. if(typeof uri== 'boolean'){
  9. io.src = 'javascript:false';
  10. }
  11. else if(typeof uri== 'string'){
  12. io.src = uri;
  13. }
  14. }
  15. ....

Думаю не стоит объяснять, что значит конструкция
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');

Спасибо за статью! А архив

Спасибо за статью! А архив недоступен для скачивания? Запрашиваемая страница не найдена

интересно а как ты не через

интересно а как ты не через iframe загрузишь файл? или с перезагрузкой всей страницы, или через фрейм. разве есть другие какие-то способы?

Аттач

Мега респект! =)
Как раз то что нужно для галереи ))
Только аттач не работает, перезалейте плиз...

Отзыв

Статья нормуль, сам скрипт не запускал, могу только пару замечаний:

1) "onclick="javascript:ajax(t"

Это не есть гуд, т.к. считается old-style и невалидно вроде как, используйте id и addEvent function

2) Неплохо бы сделать progress-bar, чтобы было видно сколько еще осталось качать

Возникла необходимость в

Возникла необходимость в похожем функционале, но не знаю как это использовать с друпал 6.10
мне нужно:
1. вывести форму в которую человек вводит число
2. число отправляется на сервер и проверяется по массиву (скажем из 10 чисел)
3. в случае совпадения выводится число из другого массива

что получается:

в ноду вставляю код:

Мы приглашаем Вас принять участие в нашем опросе
Введите число из 12 цифр:

//Здесь, я так понимаю, должны вызываться фунцкии описанные в файле scriptik.js отвечающие за прием передачу от сервера.
//в файл insert.php передаются данные (должна проводиться проверка на коректность и запись в БД) и обрабатывается ответ от сервера

который выводит приглашение и форму для ввода.
ввожу число, крутится картинка loading.gif и ничего не происходит.
наверно где-то на уровне insert.php (или раньше в scriptik.js) происходит ошибка, но как отследить ее не знаю.

Подскажите пожалуйста. сам я новичек, но очень хочется разобраться :)

код забыл добавить

  1. <head>
  2. <script type="text/javascript" src="/misc/jquery.js"></script>
  3. <script type="text/javascript" src="/myscripts/scriptik.js"></script>
  4. </head>
  5. <body>
  6. <center><table width=600 cellpadding=10>
  7. <form enctype="multipart/form-data" method=post name=jklm>
  8. <tr><td>Мы приглашаем Вас принять участие в нашем опросе</td></tr>
  9. <td width=50%><br>Введите число из 12 цифр:<br><input name=m1 value="0"><br><br></td>
  10. <tr><td><div align=right><input type=button value="Отправить" onclick="javascript:ajax(this.form.m1.value);" class=subm></div>
  11. //Здесь, я так понимаю, должны вызываться фунцкии описанные в файле scriptik.js отвечающие за прием передачу от сервера.
  12. //в файл insert.php передаются данные (должна проводиться проверка на коректность и запись в БД) и обрабатывается ответ от сервера
  13.  
  14. </td></tr>
  15. </form>
  16. </table></center>
  17. <div id=loading style='position: absolute; left: 50%; width:50%;'><img src=/myscripts/loading.gif></div>
  18. <br><br>
  19. <div class="m" style='position: absolute; left: 50%; width:50%; margin-left:-25%;'></div>
  20. </body>
  21. </html>

Открывается новое окно

Здравствуйте, очень хорошая статья и я использовал ее у себя в проекте.
Возникла проблема, Input Files находится в форме, которая содержит много другой информации, которая обрабатывается PHP с последующим Redirect после добавления в БД. Все работает, только результат выводится в новое окно и, похоже, обрабатывается повторно (выдает мою ошибку, что объект уже существует) но в БД записывается 1 раз.

Чтото не работает

Установил все как надо.
Только сменил название таблицы messages на messagi
Во первых не понимается кодировка, но это пол беды.
Если нажать на кнопку для загрузки фотки, на выбирая фото, то сообщения добавляются, и внизу формы выезжает картинка с надписями сверху и снизу.
Но если я выберу картинку для загрузки и нажму ЗАГРУЗИТЬ то картинка закачки крутиться, и все.
Ничего не грузит на сервер.
В настройках апача json включен.

Вопрос пока без ответа

Здравствуйте , Ромка !

Буду краток. Нужно проверить размер файла НЕПРЕМЕННО ДО загрузки. Как ?
Буду очень признателен...

Есть, конечно, на разных

Есть, конечно, на разных должностях в здесь, но я не нашел этой должности в связи с проектами, как cfa practice test... Если кто-то информация о нем, скажи! Ну, все обновления, связанные с этой позиции? Если да, то скажите мне! На самом деле я пришел сюда во время путешествия по сети для получения данных, относящихся к cfp practice test проектов и нашли эту должность в другой ... Есть ли кто, располагающие информацией о cgfns practice test , chmm practice test? Если да, то что делать, скажите! Мне кажется, другой тип пост ... Тот, кто не знает об этом раньше можно получить полезную информацию из этого поста ... Ну, я хочу сказать, что, как вы пытались объяснить некоторые из должностей, здесь я думаю, разные ...

!

Добрый день!
Смотрим как работает модуль с уведомление отправкой!

Фрейм... :-)

Я тоже понадеялся на чудо. Но увы...
Сразу же бросился в глаза доктайп 1.0 Strict.
Т.к. он НИ ПОД КАКИМ СОУСОМ не воспримет фрейм, подумал, что реализовано без фреймов. А на деле просто ошибочный доктайп. Не говоря уже о куче мелочей, т.к.
пишется с закрытым тегом () впрочем как и любые другие тэги в этом доктайпе. Про формы и не говорю... . Измени доктайп, а то люди путаются... Загрузить без фрейма по-любому никак всё равно. А сам скрипт хороший, задолбался искать такой. Молодец. Здорово сократил мне время работы.

НЕ работает скрипт в Chrome

В Firefox все нормально, в chrome не работает
при загрузке страницы сразу крутится loading.gif
кнопка добавить не нажимается :(
менял тип кнопки на submit, кнопка оживает
значит chrome не понимает конструкцию вида

?

serialize

А как можно передать данные m1 и m2 с помощью функции serialize? чтобы сделать пример универсальным