Статья к Друпалу имеет очень косвенное отношение (пример использует js-библиотеку 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="ajaxupload.js"></script>
<script type="text/javascript" src="scriptik.js"></script>
Далее рисуем форму, для отправки текста и файла:
<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 class="m"></div>
Картинка loading.gif должна лежать в той же папке, что и текущий файл (или пропишите в тэге img соответствующий путь).
Все, больше ничего важного в форме запроса нет, остальной код в этом файле – украшательства, не влияющие на работу примера.
Frontend (Javascript, файл scriptik.js)
Здесь описаны только функции из файла scriptik.js, отвечающие за передачу/прием данных от сервера, остальные функции носят чисто украшательский характер и их описание выходит за рамки этой статьи.
Передаем frontend файлу insert.php данные из текстовых полей:
Обрабатываем ответ сервера. Логика работы серверного скрипта такая: если в переданном клиентом тексте были найдены ошибки, то, в зависимости от ошибки, будет возвращено какое-либо отрицательное число. Если в переданном тексте ошибок нет, то в ответе от сервера придет положительное число – id записи в БД, с которым сохранился этот текст:
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 и т.д.
$("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 или нет:
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
?>
Пишем данные в базу и отдаем ответ клиенту:
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 – проверка на корректность закачанного файла, копирование файла в нужную папку и передача ответа клиенту.
// Проверяем переданный 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));
}
?>
Вот собственно и все. Готов ответить на любые вопросы, выслушать конструктивную критику и исправить все выявленные неточности и недочеты
Вложение | Размер |
---|---|
ajax-jquery-upload-sources.zip | 23.88 КБ |
Комментарии
Хоть не в тему, но Путешествие в Камбоджу понравилось Классно...
Ага, Камбоджа классная страна: красивая, гостеприимная, с доброжелательными жителями... И в ней не так много туристов как в Тае, хотя климат там такой же... Правда и развлечений для туристов, кроме небольшого количества экскурсий, там практически нет...
Сайт красивый. Покупали уже тему для Drupal или просто дизайн?
p.s. Текст на главной начинается с ошибок и опечаток - "добро пожаловть", "на инересные темы". И много повторений слова "мне", "мои" и т.п. Надо бы поправить.
Фото красивые, но большие. Имхо, миниатюры надо или под кат. А то левая колонка здоровая и на 15'' картинка уезжает вправо. Появляется горизонтальная прокрутка.
Спасибо
Покупал дизайн (кратинки и html-шаблон), а темплейтмонстре, макет нарезал сам. Был один неприятный сюрприз после покупки. На скриншоте-превьюшке не было видно, что шаблон заточен под фиксированную ширину колонки, причем под очень маленькую ширину. Пришлось попотеть в фотошопе, чтобы сделать шаблон резиновым.
За ошибки спасибо, сейчас исправлю... Мне это "мне-мне-мне" тоже в глаза бросилось, сейчас попробую перефразировать...
спасибо
[http://dklab.ru/lib/JsHttpRequest/manual.html JsHttpRequest] - отличная библиотека, где закача файла уже вшита и не является проблемой.
Лично пробовал - всё работает как часы.
И главное идея оригинальная! Мне как РНР-программисту очень по душе такой подход.
Библиотек для работы с AJAX море, важно выбрать наиболее удобную и универсальную из них. В jQuery закачка файлов также не является проблемой, но кроме того эта библиотека является мощным инструментом для создания визуальных эффектов и удобным обработчиком событий. Плюс у jQuery нет привязки к PHP-backend'у, на сервере может работать хоть программа написанная на вижуалбейсике.
Я, например, почти на всех своих сайтах использую jQuery для реализации тех или иных эффектов на стороне юзера, по этому мне нет резона устанавливать еще какую-то дополнительную библиотеку для работы с AJAX'ом. Людям использующим Друпал тоже нет смысла использовать альтернативные библиотеки, так как jQuery уже встроена в Друпал.
Уважаемый Роман!
А можете показать на базе этого примера но без привязки к БД и/или друпалу?
Реализация очень интересная.
Ммм... Так собственно привязки к Друпалу тут нет. Да и в БД данные пишутся чисто для примера, можно просто исключить весь код связанный с записью данных в БД из скрипта и все. Если хотите, то опишите подробно свою задачу, а я адаптирую под нее пример.
"и плагин к ней ajaxUpload;"
...
Введите имя пользователя и пароль для "Git" на http://fivethreeo.dynalias.org
Спасибо, очень нужная тема ...
А как можно сделать upload файлов используя только библиотеку Jquery без каких либо дополнительных плагинов? Хотелось бы взглянуть на код
Рисунок с блок-схемой перезалейте, пожалуйста.
Подскажите пожалуйста как использовать данное решение для друпал 6.10
в ajaxupload иногда возникает синтаксическая ошибка в if(type=="json")
eval("data = "+data);
Ошибка добавления данных. [Error: name: SyntaxError message: Statement on line 29: Syntax error Backtrace: Line 29 of inline#8 script in http://xxxxx/ eval("data = "+data);if(type=="html") Line 11 of inline#8 script in http://xxxxx/ if(xml||isTimeout=="timeout"){requestDone=true;var status;try{status=isTimeout!="timeout"?"success":"error";if(status!="error"){var data=jQuery.uploadHttpData(xml,s.dataType);if(s.success) ... ]
У меня на локальной машине так и не заработало. Картинка loading стоит и никуда не уходит, записи в базе появляются нормально. Попробую-ка на сервере..
upd: на сервере выдало такую ошибку: IMG_UPLOAD_ERROR_1: /var/www/clients/client56/web182/tmp/phpEcX5E0
объясните пожалуйста чтобы это могло означать?