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

Это устаревший пост, перенесённый из старой версии сайта. Ссылки, примеры кода и другая информация в нём, вероятнее всего, потеряли актуальность.

Задача

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

Средства

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