GrabDuck

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

:

Задача

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

Средства

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-файла, который лежит в архиве.