Карта сайта Хакер в RSS Энциклопедия Хакера PDA версия сайта Почтовые рассылки Хакера    Хакер в Twitter Хакер в ВКонтакте Приложение Хакер для Facebook Хакер на Formspring.me
Журнал Новости Форум Видео Life Xakep Live (блоги)
Bugtrack Статьи Блог Поиск English
Трюки с phpinfo Трюки с phpinfo
Совсем недавно в паблике появилась информация о новом интересном подходе к эксплуатации уязвимостей класса LFI с помощью бесполезной на первый взгляд функции phpinfo() и временных загрузочных файлов. Берем на вооружение этот полезный прием....
Интервью с создателем NGINX Игорем Сысоевым Интервью с создателем NGINX Игорем Сысоевым
Легкий веб-сервер NGINX буквально только что вышел на 2 место по популярности в интернете. А незадолго до этого создатель NGINX привлек 3 млн. долларов инвестиций и основал одноименную компанию. В общем, поводов для общения с Игорем Сысоевым у нас была масса....

Хакер № 02/07 (98)


Содержание
номера

Три богатыря

Борис Вольфсон

Хакер, номер #098, стр. 130

(borisvolfson@gmail.com, http://splendot.com)

Обзор AJAX-библиотек для PHP с практическими примерами

Как известно, писать приложения в идеологии AJAX сложно по многим причинам, начиная довольно трудоемкой отладкой и заканчивая разработкой функций для рутинных действий. А зачем это делать заново, ведь есть готовые библиотеки для PHP!? В этой статье я расскажу о том, как разрабатывать AJAX-приложения, не сходя при этом с ума.

Ищем подопытных

Для этого обзора я выбрал 3 довольно сильно различающихся по функционалу библиотеки. Почему только 3? Дело в том, что другие интересные AJAX-решения обычно являются частью полноценных фреймворков для создания сайтов, поэтому их обзор занял бы слишком много места. Стало быть, о них – в следующий раз, а пока мы познакомимся с участниками сегодняшнего состязания.

Итак, внимание на сцену! Первым выступает представитель легкой весовой категории – Sajax, за ним уверенно двигается крепкий середнячок – Xajax, и, наконец, могучий тяжеловес, жонглер гирями, способный удержать на своей груди платформу с роялем, оркестром и взводом королевских мушкетеров, – Projax.

А что делать-то будем?

Сколько «пустых» статей и других материалов об AJAX и втором поколении веб-технологии публикуются ежедневно? Трудно сосчитать :). В них популярно и доказательно обосновывается, что все это очень круто и прогрессивно, но при этом авторы забывают рассказать нам одну малость – как всего этого добиться. Чтобы не быть голословным, я покажу тебе все это на конкретных примерах, часть из которых ты сможешь сразу использовать на своих веб-сайтах. Начнем с самой простой библиотеки – Sajax.

Sajax

Sajax – довольно простая библиотека, поэтому серверный и клиентский код мы можем (и будем :)) писать в одном файле. Функционал у нашей первой программы будет очень простым: мы нажимаем кнопку, и в текстовое поле загружается текст, разумеется, без перезагрузки страницы.

Для начала сделаем серверную часть, в которой будет экспортироваться функция, возвращающая текст для клиента:

ЯЗЫК: PHP

ОПИСАНИЕ: Серверная часть скрипта

<?

require("Sajax.php");

function hello_world() {

return "Hello, world!";

}

sajax_init();

// Раскомментировать для отладочного режима

// $sajax_debug_mode = 1;

sajax_export("hello_world");

sajax_handle_client_request();

?>

Последняя строка этого скрипта автоматически обрабатывает запросы клиента.

Ну что же, перейдем к клиентской части, которой надо выдать HTML и JavaScript (поместим мы ее в тот же файл, сразу за закрывающимся тэгом PHP).

Для автоматической генерации JavaScript мы воспользуемся библиотечной функцией sajax_show_javascript(), а для асинхронной работы JavaScript - определим функцию do_hello_world, которая будет вызываться при нажатии кнопки, и функцию do_hello_world_callback, которая сработает при получении ответа сервера и положит результат в текстовое поле.

Вся соль библиотеки Sajax кроется в работе do_hello_world, которая вызывает автоматически сгенерированную x_hello_world. Фактически, мы из JavaScript вызываем функцию, которая написана на PHP и хранится на сервере, а в качестве параметра передаем ей функцию обратного вызова:

ЯЗЫК: HTML и JavaScript

ОПИСАНИЕ: Клиентская часть скрипта

<html>

<head>

<title>Hello, world! by sAJAX</title>

<script>

<?php sajax_show_javascript(); ?>

function do_hello_world_callback(result) {

document.getElementById("return_string").value = result;

}

function do_hello_world() {

x_hello_world(do_hello_world_callback);

}

</script>

</head>

<body>

<input type="text" id="return_string" value="Здесь будет результат запроса">

<input type="button" value="Послать запрос" onclick="do_hello_world(); return false;">

</body>

</html>

Запустим скрипт и посмотрим описание функции x_hello_world, которое автоматически генерируется при вызове PHP-функции sajax_export(«hello_world»):

ЯЗЫК: JavaScript

ОПИСАНИЕ: Функция x_hello_world, сгенерированная библиотекой Sajax

// wrapper for hello_world

function x_hello_world() {

sajax_do_call("hello_world", x_hello_world.arguments);

}

В результате происходит прозрачный вызов PHP-функции, которая хранится на сервере. Теперь попробуем вызвать серверную функцию с параметрами, для чего напишем гостевую книгу, в которую сообщения будут добавляться без перезагрузки страницы, а отображение новых сообщений будет происходить автоматически. Для простоты я предположу, что у нас есть API для работы с сообщениями. Это может быть программный интерфейс к базе данных или XML-хранилищу. В нем нам нужны 3 функции:

«Название функции» и «Описание функции»

messages_api_print_messages() печать всех сообщений в виде HTML

messages_api_add_message($message)добавление сообщения

messages_api_get_messages() возврат всех сообщений в виде HTML

Теперь напишем серверную часть, в которой изменится только описание функции и ее экспорт:

ЯЗЫК: PHP

ОПИСАНИЕ: Серверная часть скрипта

<?

require("Sajax.php");

require("messages_api.php");

function add_message($message) {

messages_api_add_message($message);

return messages_api_get_messages();

}

sajax_init();

sajax_export("add_message");

sajax_handle_client_request();

?>

На стороне клиента у нас будет поле для ввода текста и кнопка для отправления. Сообщения будут отображаться ниже:

ЯЗЫК: HTML, JavaScript, PHP

ОПИСАНИЕ: Клиентская часть скрипта

<html>

<head>

<title>Гостевая книга by sAJAX</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script>

<?php sajax_show_javascript(); ?>

function do_add_message_callback(result) {

document.getElementById("messages").innerHTML = unescape(result);

}

function do_add_message() {

message = document.getElementById("message").value;

x_add_message(message, do_add_message_callback);

}

</script>

</head>

<body>

<textarea id="message"></textarea><br />

<input type="button" value="Отправить" onclick="do_add_message(); return false;">

<hr />

<div id="messages">

<?php

messages_api_print_messages();

?>

</div>

</body>

</html>

При нажатии на кнопку «Отправить» вызывается функция x_add_message, которой в качестве параметра передается не только функция обратного вызова, но и содержимое текстового поля. Надеюсь, внимательный читатель обратил внимание и на вызов функции unescape(result) для нормального отображения кириллических символов. Если нет желания каждый раз вызывать ее, можно пропатчить саму библиотеку.

Xajax

Несмотря на то что эта библиотека чуть мощнее предыдущей, работать с ней не намного сложнее. Чтобы быстро войти в курс дела, посмотрим, как можно с помощью Xajax загрузить файл по нажатию кнопки:

ЯЗЫК: HTML, JavaScript, PHP

ОПИСАНИЕ: Загрузка файла при помощи Xajax

<?php

require ('xajax.inc.php');

function loadFile($file)

{

$objResponse = new xajaxResponse();

$objResponse->addAssign("result", "innerHTML", file_get_contents($file));

$objResponse->addAssign("result", "style.visibility", 'visible');

return $objResponse;

}

$xajax = new xajax();

// Раскомментировать для отладки

//$xajax->debugOn();

$xajax->registerFunction("loadFile");

$xajax->processRequests();

?>

<html>

<head>

<title>Загрузка файла</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<?php $xajax->printJavascript(''); ?>

</head>

<body style="text-align: center;">

<button onclick="xajax_loadFile('file.data')">Загрузить файл</button>

<div style="border: 1px solid black; visibility:hidden;" id="result"></div>

<br/>

</body>

</html>

Первое, что бросается в глаза при прочтении кода, - поддержка ООП в Xajax, ведь мы работаем не с функциями, а с классами и объектами, которые при желании можно расширить. Общая схема работы аналогична Sajax, по-другому идет разве что отправка ответа с сервера клиенту – для этого используется объект $objResponse класса xajaxResponse. Я использовал метод addAssign, который ищет объект HTML с заданным id и определенному полю присваивает нужное значение. То есть мы можем не только прозрачно вызывать серверные функции на клиенте, но и прозрачно модифицировать HTML с сервера (и добавлять JavaScript).

Кстати, помнится, я обещал продемонстрировать, как надо разделять AJAX-систему на клиента и сервер. Настало время исполнить обещание, а заодно – показать, как Xajax умеет автоматически отсылать формы на сервер.

На каждом сайте, который поддерживает создание сетевого сообщества, имеется процедура регистрации с помощью специальной формы. Чтобы зарегистрироваться, надо потратить немало сил: то пароль слишком легкий, то логин занят - проще просто бросить это дело. Попробуем сделать эту процедуру безболезненной, быстрой и интерактивной.

Логин, введенный пользователем, должен быть незанятым и отвечать некоторым требованиям, например состоять более чем из трех символов. На пароль мы наложим только ограничение по длине: 6 символов. Дополнительные проверки можешь придумать сам – все зависит от твоей фантазии ;). Вся система будет содержать 3 файла:

«Имя файла» и «Описание»

register.common.phpобщий функционал для клиента и сервера

register.server.phpсерверная часть для проверки логина, пароля и обработки формы

register.phpклиентская часть с интерактивной формой ввода

Начнем с общей части для клиента и сервера, в которой будут регистрироваться 3 функции для проверки логина, пароля и для приема данных с клиента. Поскольку серверная часть будет у нас в отдельном файле, это надо указать в конструкторе объекта $xajax:

ЯЗЫК: PHP

ОПИСАНИЕ: register.common.php

<?php

require ('xajax.inc.php');

$xajax = new xajax("register.server.php");

// Раскомментировать для отладки

//$xajax->debugOn();

$xajax->registerFunction("checkUserName");

$xajax->registerFunction("checkUserPass");

$xajax->registerFunction("submitForm");

$xajax->processRequests();

?>

Функции для проверки я предлагаю описать отдельно, так как они будут вызываться у нас в двух случаях: когда форма будет передана на сервер и когда по мере набора текста пользователем будет происходить автоматическая проверка:

ЯЗЫК: PHP

ОПИСАНИЕ: Функции для проверки логина и пароля (register.server.php)

function isUserNameGood($userName)

{

// Их надо брать из базы ;)

$users = array("bill", "john", "vasya");

if (strlen($userName) <= 3)

return array(false, "Имя пользователя должно быть длиннее трех символов");

foreach ($users as $user)

if ($user == $userName)

return array(false, "Имя пользователя уже используется");

return array(true, "Имя пользователя подходит");

}

function isUserPassGood($userPass)

{

$objResponse = new xajaxResponse();

if (strlen($userPass) <= 6)

return array(false, "Пароль должен быть длиннее шести символов");

return array(true, "Пароль подходит");

}

Обе функции возвращают 2 значения, первое имеет булевский тип и определяет, подходят ли логин и пароль соответственно, а второе содержит пояснительный текст. Теперь реализовать функции, которые будут вызываться клиентом, не составит труда:

ЯЗЫК: PHP

ОПИСАНИЕ: Функции, которые будут вызываться из JavaScript (register.server.php)

function checkUserName($userName)

{

$objResponse = new xajaxResponse();

list($isUserNameGood, $message) = isUserNameGood($userName);

$objResponse->addAssign("userNameOk", "innerHTML", $message);

return $objResponse;

}

function checkUserPass($userPass)

{

$objResponse = new xajaxResponse();

list($isUserPassGood, $message) = isUserPassGood($userPass);

$objResponse->addAssign("userPassOk", "innerHTML", $message);

return $objResponse;

}

Отмечу, что результат у меня помещается в специальные ячейки в таблице с айдишниками - userNameOk и userPassOk, которые мы опишем на стороне клиента. И последнее, что нам осталось сделать на сервере, - это создать функцию, которая будет обрабатывать данные из формы для регистрации пользователя. Все содержимое передается этой функции в виде параметра, который представляет собой ассоциативный массив (аналог $_POST и $_GET):

ЯЗЫК: PHP

ОПИСАНИЕ: Функция для обработки формы (register.server.php)

function submitForm($formData)

{

$objResponse = new xajaxResponse();

list($isUserNameGood, $message) = isUserNameGood($formData['userName']);

$objResponse->addAssign("resultDiv", "innerHTML", $message);

list($isUserPassGood, $message) = isUserPassGood($formData['userPass']);

$objResponse->addAppend("resultDiv", "innerHTML", "<br/>" . $message);

if ($isUserNameGood && $isUserPassGood)

$objResponse->addAppend("resultDiv", "innerHTML", "<br/><strong>Регистрация прошла успешно</strong>");

else

$objResponse->addAppend("resultDiv", "innerHTML", "<br/><strong>Регистрация завершилась неудачей</strong>");

return $objResponse;

}

Обрати внимание, что в этих скриптах я нигде не использую базу данных или любое другое постоянное хранилище, чтобы код не потерял ясность. В реальных условиях при успешной регистрации пользователя обязательно надо сохранять его данные, да и получать список пользователей надо тоже из какого-то хранилища. Теперь напишем клиентский код, который будет описывать форму регистрации. Чтобы браузер отправил форму без перезагрузки страницы, нужно «обнулить» (точнее, «завойдить» :)) параметр action у формы и прописать событие onsubmit. При этом событии будет вызвана JavaScript-функция xajax_sumbitForm, которая является оберткой нашей серверной функции submitForm, а параметром будут как раз данные формы. Проверка данных формы во время их набора пользователем осуществляется при помощи вызова соответствующих функций по событию onkeyup:

ЯЗЫК: HTML, JavaScript, PHP

ОПИСАНИЕ: Клиентский код (register.php)

<?php

require ('register.common.php');

?>

<html>

<head>

<title>Регистрация пользователя</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<?php $xajax->printJavascript(''); ?>

<script type="text/javascript">

function submitForm()

{

xajax.$('submit').disabled=true;

xajax.$('submit').value="Регистрируется пользователь...";

xajax_submitForm(xajax.getFormValues("registrationForm"));

return false;

}

</script>

</head>

<body>

<form id="registrationForm" action="javascript:void(null);" onsubmit="submitForm();">

<table border="1" width="50%">

<tr>

<th width="40%">Имя пользователя </td>

<td><input onkeyup="xajax_checkUserName(this.value)" type="text" id="userName" name="userName" /></td>

</tr>

<tr>

<td id="userNameOk" colspan="2">  </td>

</tr>

<tr>

<th width="40%">Пароль</td>

<td><input type="text" onkeyup="xajax_checkUserPass(this.value)" id="userPass" name="userPass" /></td>

</tr>

<tr>

<td id="userPassOk" colspan="2">  </td>

</tr>

<tr>

<td> </td>

<td><input type="submit" id="submit" value="Submit" /></td>

</tr>

</table>

<div id="resultDiv"> </div>

</form>

</body>

</html>

Projax

Настало время десерта – самой мощной библиотеки в нашем обзоре. Я покажу ее возможности на очень распространенном сейчас виджете – поле ввода с автозавершением (a-ля Google Suggest). Для этого у нас есть все необходимое, остается только подключить JavaScript-файлы и вызвать метод text_field_with_auto_complete – на этом клиентская часть заканчивается.

ЯЗЫК: HTML, JavaScript, PHP

ОПИСАНИЕ: Клиентский код – «поле ввода с автозавершением»

<?php

include ("projax.php");

$projax= new Projax();

?>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Демонстрация автозавершения by Projax</title>

<script src="js/prototype.js" type="text/javascript"></script>

<script src="js/scriptaculous.js" type="text/javascript"></script>

</head>

<body>

Введите имя пользователя :<br />

<?=$projax->text_field_with_auto_complete('name', null, array('url'=>'get_names.php'));?>

</body>

</html>

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

ЯЗЫК: PHP

ОПИСАНИЕ: Серверная – «поле ввода с автозавершением» (get_names.php)

<?php

// Имена пользователей берутся из базы

$names = array('boris', 'vasya', 'bill');

foreach($names as $name)

$ret_val .= (strstr($name,$_POST['name'])) ? '<li>'.$name.'</li>':'';

echo '<ul>' . $ret_val . '</ul>';

?>

Как видишь, всего несколько строк кода - и мы уже у цели (посмотри на скрин «Поле с автозавершением» и возрадуйся – у тебя будет такой же :)).

Le Fin

В этой статье мы рассмотрели 3 библиотеки, которые позволяют быстро писать эффективные приложения в связке PHP и JavaScript, реализуя таким образом методологию AJAX. Каждая из этих библиотек имеет как плюсы, так и минусы, которые надо знать, чтобы выбрать нужную из них для конкретного проекта. Поэтому мой вердикт таков – срочно бери с диска библиотеки и материалы к этой статье и ковыряй их до выхода в свет следующего «Кодинга» :).

Sajax

Sajax (Simple Ajax Toolkit) – это простая библиотека для создания AJAX-приложений на PHP путем прозрачного вызова серверных функций с клиента. Общий вес клиентского и серверного кода составляет чуть меньше 9 Кб, что делает библиотеку незаменимой для небольших и быстрых приложений. Ее можно посоветовать использовать тем, кто собирается переделывать свое AJAX-приложение без использования фреймворков, поскольку Sajax - довольно низкоуровневая библиотека, не содержащая лишних наворотов. В комплект поставки входят фреймворки для следующих языков: ASP, Cold Fusion, Io, Lua, Perl, PHP, Python и Ruby. К минусам библиотеки можно отнести некорректную работу с кириллицей (правда, проблема довольно просто решается).

Xajax

Для 90% всех веб-проектов хватит библиотеки Xajax, которая обеспечивает полностью прозрачное взаимодействие клиента и сервера (причем в обе стороны). Размер клиентской части в сжатом виде составляет 15 Кб, что вполне приемлемо для библиотеки с таким функционалом. В дистрибутив входят примеры (в том числе XUL-приложение для Mozilla Firefox) и тесты для этой библиотеки. Кроме того, хочу отметить наличие в интернете большого количества документации и сообщества, которое сложилось вокруг этого проекта. По моему очень скромному мнению, эта библиотека является наиболее сбалансированной по параметрам «функционал» и «легкость использования». Выбор редакции, так сказать ;).

Projax

Projax представляет собой порт проекта Prototype, который был первоначально написан для Ruby on Rails и проекта script.aculo.us. Такой мощный функционал объясняет общий размер клиентской части - более 170 Кб кода JavaScript. За эти «деньги» мы получаем полную «корзину фруктов» - от манипуляций с DOM до визуальных эффектов. Projax идеально подходит для «суперинтерактивных» проектов, например, онлайн-игр, где нужен мощный функционал на стороне пользователя. Минусом опять же является некоторая сложность этой библиотеки, которую ты, конечно, не заметишь, если раньше работал с Prototype и script.aculo.us

INFO

Библиотеки обычно содержат отладочный режим, при включении которого выдаются сообщения о ходе выполнения программы.

Для эффективной отладки AJAX-приложений необходимо настроить отладку как серверного PHP-кода, так и клиентского JavaScript.

Для отладки JavaScript проще всего использовать расширения для Mozilla Firefox - JavaScript Debugger и FireBug.

DVD

На нашем диске ты найдешь материалы и исходники к статье.

Содержание


ВИДЕО К ЭТОМУ НОМЕРУ

Скулы на ринге
В мире свободных программ так повелось: мы говорим "база данных" - подразумеваем "мускуль". А чем нам, спрашивается, не угодила PostgreSQL - открытая (даже более открытая, чем MySQL), свободная, с мощнейшей функционал...

Недетский взлом
Зачастую получается так, что стандартные методы проведения sql-injection не проходят. Этот ролик показывает как раз один из таких геморройных случаев, когда в запросе было невозможно использовать буквы. Однако, хакер успешно справился с...

Властелин обновлений - создание новой группы и обновление компьютера
А в этом ролике мы покажем, как создать новую группу и обновить компьютер, а также как создать отчет и где найти все настройки WSUS. Начало смотри в этом ролике....

Властелин обновлений - установка WSUS
Своевременная установка обновлений и исправлений является одним из факторов, обеспечивающих надежную защиту информационной системы. Индивидуальное обновление систем приведет к существенному увеличению трафика и потребует большего внимания...

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





Предыдущие номера


    Rambler's Top100