Если вы следили за новостями на данную тему, у вас могло сложиться впечатление, что это всё – технологии высшего порядка, для больших компаний с немалым же бюджетом. Если вы так подумали, то вы ошиблись.
Принцип работы web-сервисов достаточно прост и в нашей сегодняшней статье мы довольно подробно рассмотрим все задействованные в этом технологии. Затем, с помощью нашего общего друга PHP мы напишем свой первый web-сервис.
Статья написана с расчётом на то, что читатели хоть немного знакомы с PHP, MySQL и XML, если вы не уверены в ваших познаниях, рекомендуем подчитать Building your own Database Driven Website using PHP & MySQL и XML – An Introduction.
Итак, что мы можем вам предложить:
Первое, что вам необходимо усвоить, – это то, что концепция web-сервисов совсем не нова. Если вы когда-либо использовали фиды RSS для получения новостей из другого сайта и размещения их на своём, то уже имеете неплохое представление о том, как работают web-сервисы (см. статью Кевина Йанка PHP and XML: Parsing RSS 1.0).
Web-сервисы применяются для обмена данными между сервером и клиентом; формат XML используется для "упаковывания" запросов и данных в целях взаимопонимания между обоими участниками общения. И сервер и клиент могут быть web-серверами или любыми другими электронными устройствами, которые вам понадобятся.
С точки зрения работы сети обмен данными с web-сервисами проходит по TCP через 80 порт и с использованием стандартного метода POST протокола http. Иными словами, работа web-сервисов – это почти отправка html-форм из браузера (методом POST) и получение странички в ответ. Единственная существенная разница – это то, что вместо HTML web-сервисы используют XML. А это всё означает, что web-сервисы доступны по всей Сети и через firewall-ы проходят так же, как обычные web-странички. Обмен данными проходит на уровне пакетирования.
Кроме обмена данными вам также может понадобиться информация, описывающая интерфейс сервиса (или API – программный интерфейс приложения). Эта информация делает web-сервис полезным для всего остального Интернета, позволяя другим разработчикам создавать приложения для доступа к вашему web-сервису. Этот называется уровнем описания, и стандарт WSDL (Web Services Description Language – Язык Описания Web-Сервисов), который этим займётся, в настоящее время разрабатывается.
На верхнем уровне располагается информация о типе и свойствах web-сервиса как такового (можно сравнить с META-тэгами в HTML) для категоризации и размещения в каталогах web-сервисов. Это уровень поиска, который находится под управлением реестра UDDI (Universal Description, Discovery, and Integration – Универсальное Описание, Поиск и Взаимодействие) .
И уровень описания, и уровень поиска представляют собой обычный XML, управляемый специальным форматом для выявления релевантной информации обо всех web-сервисах в Инете.
Возможно, причиной возросшего ажиотажа вокруг web-сервисов (ну, не считая поддержки благодаря пристрастиям Microsoft и IBM) является как раз разработка вышеупомянутых стандартов WSDL и UDDI. С их помощью будет возможна общая индексация всех web-сервисов Интернета и поддержка средствами разработки простого и предсказуемого доступа к сервисам. Не мешает напомнить, однако, что всё, что сегодня делают web-сервисы (с точки зрения обмена данными), было возможно и 5, а то и 10 лет назад с применением HTTP и XML любого существующего или разработанного вами формата (ближайший пример тому – фиды RSS). Единственная "горячая новость" на сегодня – это то, что теперь разработать и распространить web-сервис намного проще, чем было тогда.
В любом случае, если вы ищете объективную и свежую информацию по разработке web-сервисов, читайте XML Hack(Узрев слово оное да не возликует бес в душе твоей, ибо "hack" по-англицки есть не "систему взломать" но многия другия; здесь же больше "В ладах с XML"// прим. толмача :-)).
Прочую теорию мы пропустим, но достаточно сказать, что в нашей статье мы будем рассматривать уровень пакетирования, то есть способы построения web-сервиса и доступа к нему.
В своей статье "Web Services Demystified" Кевин пишет о стандарте SOAP, который применяется для "упаковывания" данных для обмена оными между двумя системами. В настоящее время технологии SOAP пытаются придать статус W3C-стандарта для web-сервисов, и если учесть, что этому процессу помогают Microsoft и IBM, есть все основания полагать, что заветный "Одобрям" будет скоро поставлен.
Однако для реализации тех же задач существует и другой стандарт: XML-RPC. Он был разработан около 1998, и хотя и не стал W3C-стандартом, нашёл себе широкое применение и мощную поддержку со стороны Open Source Projects. XML-RPC был разработан корпорацией Useful совместно с Microsoft и во многих отношениях может считаться предшественником SOAP, хотя шествие своё ещё не закончил.
Как мы убедимся по мере прочтения этой статьи, основная причина популярности XML-RPC – его простота. Это становится очевидным уже при одном взгляде на спецификацию XML-RPC (1 500 слов) в сравнении с талмудом по SOAP (11 000 слов и продолжает расти). Ещё одна хорошая новость: XML-RPC поддерживается в PHP и в разработках почти на всех языках, которые только можно припомнить.
Для детального сравнения стандартов XML-RPC и SOAP, рекомендуем вам почитать XML-RPC vs. SOAP. А если вкратце, то SOAP разрабатывался чтобы залатать дыры в XML-RPC, представляя собой тем самым разработку корпоративного уровня для обмена данными между системами. К примеру, многомерные массивы проще передавать через SOAP, нежели чем через XML-RPC. Но это вовсе не значит, что XML-RPC – это не прикольно и использовать его не стОит. Особенно если учесть, что XML-RPC – это стабильный стандарт, а SOAP в скором времени может ожидать серьёзная переработка.
Вы можете задаться вопросом: а стОит ли так напрягаться и изучать стандарт, который вот-вот будет вытеснен конкурирующей разработкой? Не волнуйтесь: с помощью XSLT вы без проблем сможете преобразовать SOAP-запрос в запрос XML-RPC, что и поможет вашему XML-RPC выжить в этой интернетовской грязи, где каждый убить готов ради этого обмылка SOAP. (прошу прощения, но один каламбур я себе таки позволил) (// можешь не извиняться, дружище, я твой каламбур всё равно в переводе похерил :) – прим. перев.)
Итак, как же работает XML-RPC? Как вы поймёте по мере прочтения этой статьи, вам не так уж и важно много знать о принципах работы стандарта XML-RPC, чтобы его использовать. Но подобной информации полно, рекомендую ознакомиться с XML-RPC для чайников. Сейчас мы вкратце рассмотрим, как работает XML-RPC, и потом научимся применять его в своей работе.
Две основных составляющих XML-RPC-"сообщения" – это методы и параметры. Методам мы можем поставить в примерное соответствие функции, которые мы определяем в PHP, а параметрам – переменные, которые мы нашим функциям передаём. Параметры могут быть разного типа: строки, целые числа, массивы, – всё очень похоже на то, к чему мы уже привыкли с PHP. Кроме того, в XML-RPC определены другие тэги для различных целей, таких как обработка ошибок, но мы оставим вам возможность всё это узнать из спецификаций, ибо, в большинстве случаев, беспокоиться нам об этом не придётся.
XML-RPC-"общение" между двумя системами начинается с запроса (request) от XML-RPC-клиента, которому сервер высылает ответ (response). Запрос содержит название метода, и, возможно, необходимые параметры. В ответе мы получаем набор параметров, в которых и содержатся запрашиваемые данные. Весь процесс очень напоминает использование функций в PHP-скриптах: вызываем функцию и передаём ей некоторые переменные. Потом функция в ответ возвращает несколько переменных.
Вот так, например, мог бы выглядеть типичный XML-RPC-запрос для сервера:
POST /xmlrpcInterface HTTP/1.0 User-Agent: Sitepoint XML-RPC Client 1.0 Host: xmlrpc.sitepoint.com Content-type: text/xml Content-length: 195 <?xml version="1.0"?> <methodCall> <methodName>forums.getNumTodaysThreads</methodName> <params> <param><value><string>PHP Development</string></value></param> </params> </methodCall>
А вот таким видит ваш XML-RPC-клиент ответ от сервера.
HTTP/1.1 200 OK Connection: close Content-Length: 148 content-Type: text/xml Date: Wed, Jul 28 1999 15:59:04 GMT Server: Sitepoint XML-RPC Server 1.0 <?xml version="1.0"?> <methodResponse> <params> <param> <value><int>42</int></value> </param> </params> </methodResponse>
Показанный в примере запрос может выяснить, сколько новых тем было открыто сегодня на форуме PHP Development. В ответе сервера содержится число, интересующее клиента. Но это пример очень прост: в метод отправляется один параметр, один параметр получаем при возврате. На самом же деле XML-RPC способен на большее, позволяя вам передавать серверу более сложные наборы данных (как, например, массивы) и получать очень подробные ответы, содержащие самые разные типы данных.
Если кому-нибудь интересно, то "RPC" в аббревиатуре XML-RPC расшифровывается как Remote Procedure Call (Удалённый Вызов Процедуры), то есть клиентская система "вызывает" "процедуру" (или метод) на удалённом сервере. Сама концепция Удалённого Вызова Процедуры применима при разработке ПО вообще, и данная технология может вам встретиться в самых различных областях девелопперства. XML-RPC – это XML-стандарт для обмена данных при Удалённом Вызове Процедуры.
XML-RPC находится на уровне пакетирования стека технологий, описанных Кевином в статье "Web Services Demystified" (и, как и было сказано выше, XML-RPC является альтернативой SOAP, который Кевин использовал в качестве примера для уровня пакетирования). Что будет происходить на уровне описания и уровне поиска – решать вам. Некоторые XML-RPC-разработки имеют дополнительные модули, которые позволяют проводить интроспекцию, – "самоописание" – и тем самым подниматься до уровня описания, предоставляя подробное описание методов и параметров, которые вы можете отправлять XML-RPC-серверу. Уровень поиска в XML-RPC отсутствует как таковой: не существует централизованного реестра XML-RPC-серверов, но, несомненно, при малейшей необходимости появятся расширения, отвечающие требованиям стандарта UDDI.
Ну хватит о самом XML-RPC! Если мы используем уже существующие решения для PHP, в подробности работы стандарта вдаваться не обязательно. Так что давайте посмотрим, что мы можем бесплатно получить для XML-RPC и PHP...
Чувствуется, у вас стали потеть ладони, значит, самая пора провести небольшой обзор проектов Open Source, которые могут облегчить вам жизнь, избавив от необходимости писать свой код для генерирования XML-RPC-запросов и ответов. Список кандидатов мы взяли со странички implementations сайта xmlrpc.com. Два основных "нагрузочных испытания" в нашем тестировании были:
XMLRPC-EPI изначально было разработан для внутреннего пользования в epinions и оказалось настолько успешным, что в настоящее время снабжает сам PHP экспериментальнымиXML-RPC функциями. По сути XMLRPC-EPI -это базовый класс, написанный в C++ (остальные написаны в PHP), а поэтому просто так, без root-а, установить на сервер его не удастся: потребуется перекомпилировать PHP.
Кроме того, приложение только лишь интерпретирует содержание запросов и ответов XML-RPC, но не посылает и не принимает их. Техруководство по использованию класса вы найдёте здесь.
Разработка Бэрда Фастарда (чувак, наверное, прётся от такой фамилии). Это XML-RPC класс, используемый в приложении ezPublish для получения запросов с её же локального клиента. Дизайн класса превосходен интуитивностью управления, кроме того, прекрасно описан в техруководстве, и позволяет проводить интроспекцию.
Всё прекрасно, но в одном класс нехорош: для его работы требуется, чтобы в конфигурации PHP был доступен и установлен xml parser (--with-qtdom). Для большинства инсталляций PHP это не типично, чаще встречается expat XML parser (--with-xml). А посему, с печалью в глазах, отправимся на дальнейшие поиски...
Документация на сайте неплоха, но при попытке установить, а затем запустить демонстрационный скрипт "server.php" получаем ошибку "class not found". Поскольку других кандидатур хватает, без разговоров снимаем проект с дистанции.
Класс с большим потенциалом. Разработчики не остановились на простой интерпретации и управлении запросами/ответами и предоставили пользователю более широкую функциональность, как, например, подключение к "абстрактной" базе данных. Последняя доступная версия – альфа 0.9, так что сейчас проект мы пропустим, но стоит быть в курсе его развития. Если у вас в планах большие проекты, этот класс мог бы серьёзно сэкономить ваше время.
Эта разработка корпорации Useful, самого создателя стандарта XML-RPC, очевидно содержит много полезного. По существу, приложение полностью поддерживает стандарт XML-RPC и, кроме того, предоставляет возможность отладки, которая (как мы увидим позже) может стать самой большой вашей проблемой при разработке web-сервиса.
Документация хорошая, много примеров, как и в руководстве по разработке клиента в той же системе. Однако для первого опыта в написании web-сервиса система далека от идеала: её можно порекомендовать только более опытным PHP-программерам, поэтому мы продолжаем искать...
Посетив домашнюю страничку проекта, сразу понимаем, что это лучшее начало. Код представляет собой не полный класс, а простой набор определённых пользователем функций, которые нужно инклюдить в скрипт.
В данной системе к XML-RPC-серверу и клиенту не предъявляется требование самим определять тип принимаемых XML-RPC параметров. Это значит, что XML-RPC-клиенту нужно более внимательно проверять получаемые данные, однако здесь вас будут беспокоить переменные PHP (а уж к ним то вы привыкли) а не параметрами XML-RPC. Документация тоже неплоха. А посему первый web-сервис мы напишем с помощью этого проекта.
Итак, начали. Напишем web-сервис для публикации новостей с вашего сайта, а заодно и строчки для фида RSS. Но вместо того, чтобы просто дать юзеру список заголовков и ссылок, которые всё равно его притащат на исходный ресурс, наш web-сервис будет делать всё так, как будто новости на самом деле живут на сайте, где установлен XML-RPC-клиент.
Для нашего использования определим два XML-RPC-метода: "news.getNewsList
", который выдаёт список новостей, и "news.viewNewsItem
", который отображает одну новость полностью. Также напишем метод "method_not_found
", на всякий случай. Каждый метод соответствует функции в PHP, и SQL-запросу, который делает выборку новостей с вашего сайта.
Предположим, что у вас PHP 4.1.0 или выше и доступ к БД MySQL (версия 3.23+). СтОит прочитать код и комментарии и ознакомиться с документацией к функциям XML-RPC Кейта.
Вроде бы всё. Закатали рукава и поехали...
CREATE TABLE kd_xmlrpc_news ( news_id mediumint(9) NOT NULL auto_increment, title varchar(255) default NULL, short_desc text, full_desc text, author varchar(100) default NULL, date datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (news_id) ) TYPE=MyISAM COMMENT='XML RPC News';
БД готова к действию. Теперь пишем скрипт сервера и называем его "server.php":
<?php
/* server.php */
/* Переменные для доступа к MySQL */
$dbserver= "localhost"; // Имя хоста MySQL-сервера
$db = "database_name"; // Имя БД
$dbuser = "username"; // Имя пользователя для доступа $db
$dbpassword = "password"; // Пароль пользователя
/* Подключаемся к MySQL-серверу */
$link = @mysql_connect ($dbserver, $dbuser, $dbpassword);
if (! $link){
echo ( "Unable to connect to db" );
exit();
}
/* Выбор БД */
if (!mysql_select_db ($db, $link) ){
exit ();
}
/* Инклюдим xml-rpc-библиотеку Кейта */
include("kd_xmlrpc.php");
/* Инклюдим файл,где определены все xml-rpc "методы" */
include("web_service_api.php");
/* Теперь используем функцию XMLRPC_parse чтобы забрать POST
данные, которые положил туда xml-rpc клиент, и преобразуем их
в нормальные PHP-переменные */
$xmlrpc_request = XMLRPC_parse($GLOBALS['HTTP_RAW_POST_DATA']);
/* Из полученных переменных PHP вычленим имя метода, то есть
как будто сервер спрашивает: "Чем могу помочь?" */
$methodName = XMLRPC_getMethodName($xmlrpc_request);
/* Получаем параметры, привязанные к этому методу,
т. е.: "Итак, вы желаете получить одну новость.
Какую же? Какой id#?" */
$params = XMLRPC_getParams($xmlrpc_request);
/* Отлов ошибок – если запрашиваемый метод не
существует, клиенту возвращаем сообщение об ошибке */
if(!isset($xmlrpc_methods[$methodName])){
$xmlrpc_methods['method_not_found']($methodName);
/* В противном случае передаём управление соответствующей
данному методу PHP-функции – заметьте, что функции сами
возвращают клиенту правильно отформатированный
xml-rpc-ответ */
}else{
/* Вызов метода – заметьте, что здесь $params[0], а не просто
$params, как указано в документации. */
$xmlrpc_methods[$methodName]($params[0]);
}
?>
Краткое описание того, что происходит в server.php:
$GLOBALS['HTTP_RAW_POST_DATA']
, где хранится запрос от XML-RPC-клиента, и переконвертировать параметры XML в PHP-переменные используем функцию XMLRPC_parse()
. XMLRPC_getMethodName()
. Мы хотим, чтобы наш XML-RPC-сервер мог выполнять больше чем одну задачу (здесь задача=метод=функция) и как раз здесь-то мы и определяем, какой из методов будет обрабатывать текущий запрос (например, "news.getNewsList
" или "news.viewNewsItem
"). id
новости). method_not_found
". Специфические XML-RPC-функции, задействованные в этом скрипте:
XMLRPC_parse()
: эта функция получает XML-данные и преобразует их в переменные PHP – то есть XML из запроса преобразован в удобоваримую для PHP форму. На данном этапе нет ничего, взятого непосредственно из спецификации стандарта XML-RPC: любые полученные XML-данные преобразуются в переменные PHP. XMLRPC_getMethodName()
: определяет, какой метод нужно задействовать, то есть мы узнаём, какую PHP-функцию вызывать. XMLRPC_getParams()
: получает XML-RPC-параметры и преобразует их в переменные PHP. Вот, в принципе, и всё: XML-RPC-сервер готов. В общей сложности, это всё, что вам нужно сделать при разработке любого нового XML-RPC-сервера. Несложно, да? Теперь всё, что нам нужно – это те PHP-функции, используемые в качестве XML-RPC-методов...
Теперь напишем PHP-функции, соответствующие XML-RPC-методам, и складываем их все в web_service_api.php:
<?php
/* web_service_api.php */
/* Определяем массив с именами xmlrpc-методов и
соответствующими им PHP-функциям */
$xmlrpc_methods = array();
$xmlrpc_methods['news.getNewsList'] = news_getNewsList;
$xmlrpc_methods['news.viewNewsItem'] = news_viewNewsItem;
$xmlrpc_methods['method_not_found'] = XMLRPC_method_not_found;
/* Теперь очень полезная функция для преобразования MySQL-поля дата-время
в UNIX timestamp, который потом будет использован
функцией XMLRPC_convert_timestamp_to_iso8601($timestamp).
Это не метод!
Взято из: http://www.zend.com/codex.php?id=176&single=1 */
function mysql_datetime_to_timestamp($dt) {
$yr=strval(substr($dt,0,4));
$mo=strval(substr($dt,5,2));
$da=strval(substr($dt,8,2));
$hr=strval(substr($dt,11,2));
$mi=strval(substr($dt,14,2));
$se=strval(substr($dt,17,2));
return mktime($hr,$mi,$se,$mo,$da,$yr);
}
/* Функция для печати списка новостей, соответствует
методу news.getNewsList Допускает сортировку по
имени столбца и ограничение выдаваемых строк до 20 */
function news_getNewsList ( $query_info=0 ) {
/* Определяем массив с именами столбцов, по которым
допускается сортировка ORDER BY в запросе */
$order_fields = array ( "author", "title" );
/* Теперь смотрим,имеет ли $query_info['order']
допустимое значение и приписываем корректное значение
переменной $order */
if ( ISSET ( $query_info['order'] ) &&
in_array ( $query_info['order'], $order_fields ) ) {
$order = "ORDER BY " . $query_info['order'] . ", date DESC ";
} else {
$order = "ORDER BY date DESC ";
}
/* Смотрим в $query_info['limit'] и определяем
количество новостей, которые отправим в ответ,
приписываем корректное значение переменной $limit */
if ( ISSET ( $query_info['limit'] ) && $query_info['limit'] < 20 ) {
$limit = "LIMIT 0, " . $query_info['limit'] . " ";
} else {
$limit = "LIMIT 0, 5 ";
}
/* Генерим запрос */
$query = "SELECT * FROM kd_xmlrpc_news " . $order . $limit;
$sql = mysql_query ( $query );
if ( $sql ) {
$news_items = array();
while ( $result = mysql_fetch_array ( $sql ) ) {
/* Из выборки вытягиваем нужные нам данные */
$news_item['news_id'] = $result['news_id'];
$news_item['date'] = XMLRPC_convert_timestamp_to_iso8601(
mysql_datetime_to_timestamp( $result['date'] )
);
$news_item['title'] = $result['title'];
$news_item['short_desc'] = $result['short_desc'];
$news_item['author'] = $result['author'];
/* Дополняем массив $news_items */
$news_items[] = $news_item;
}
/* Конвертим массив $news_items в набор
параметров XML-RPC и отвечаем в формате XML. */
XMLRPC_response(XMLRPC_prepare($news_items), KD_XMLRPC_USERAGENT);
} else {
/* Если была ошибка, шлём
сообщение об ошибке */
XMLRPC_error("1", "news_getNewsList() error: Unable to read news:". mysql_error() . "\nQuery was: " . $query, KD_XMLRPC_USERAGENT);
}
}
/* Функция для просмотра одной новости целиком, соответствует
методу news.viewNewsItem */
function news_viewNewsItem ( $news_id ) {
/* Определяем запрос одной новости */
$query = "SELECT * FROM kd_xmlrpc_news WHERE news_id = '" . $news_id . "'";
$sql = mysql_query ( $query );
if ( $result = mysql_fetch_array ( $sql ) ) {
/* Вычленяем переменные и
шлём их в ответ сервера */
$news_item['news_id'] = $result['news_id'];
$news_item['date'] = XMLRPC_convert_timestamp_to_iso8601 (mysql_datetime_to_timestamp( $result['date'] ) );
$news_item['title'] = $result['title'];
$news_item['full_desc'] = $result['full_desc'];
$news_item['author'] = $result['author'];
/* Отвечаем клиенту, высылая новость */
XMLRPC_response(XMLRPC_prepare($news_item), KD_XMLRPC_USERAGENT);
} else {
/* Если была ошибка,
вместо ответа шлём сообщение о ней */
XMLRPC_error("1", "news_viewNewsItem() error: Unable to read news:". mysql_error(), KD_XMLRPC_USERAGENT);
}
}
/* Функция на случай, если запрашиваемый
мметод не существует */
function XMLRPC_method_not_found($methodName){
XMLRPC_error("2", "The method you requested, " . $methodName
. ", was not found.", KD_XMLRPC_USERAGENT);
}
?>
Итак, что здесь, собственно, происходит:
$xmlrpc_methods
, где хранится список всех доступных XML-RPC-методов и соответствующих им функций PHP. mysql_datetime_to_timestamp()
по сути не является XML-RPC-методом; эта функция нужна для конвертирования MySQL-поля "дата-время" в формат, с которым сможет работать PHP. news_getNewsList()
для отправки запросов к таблице "kd_xmlrpc_news". Функция может принимать в качестве аргумента массив $query_info
, с параметрами, которые может послать XML-RPC-клиент. Как вы видите, эти параметры могут повлиять на запрос к БД, изменяя опции "ORDER BY
" и "LIMIT
". news_viewNewsItem()
используется для того, чтобы выдернуть из БД одну новость и принимает в аргумент только одну переменную/параметр: $news_id
, содержащий id новости в базе данных. XMLRPC_method_not_found()
– это функция по умолчанию, которая генерит ответ в том случае, когда клиент запрашивает несуществующий XML-RPC-метод. Специфические XML-RPC-функции, задействованные в этом скрипте:
XMLRPC_convert_timestamp_to_iso8601()
: XML-RPC использует особенный формат обозначения даты и времени. Данная функция просто берёт timestamp в PHP и преобразует его в формат, применяемый в XML-RPC. XMLRPC_prepare()
: эта функция берёт нобор переменных PHP и преобразует их в параметры XML-RPC. Функция определяет тип переменных и поэтому правильно преобразует в XML-RPC. Именно эта особенность делает интерфейс проекта Кевина Девенса дружественным: в большинстве случаев другие приложения требуют при генерации ответа на XML-RPC-запрос отдельных функций для массивов, целых чисел, строк и т. д. XMLRPC_response()
: данная функция используется для отправки ответа клиенту. Функция принимает два аргумента: XML-RPC-данные (сгенерённые функцией XMLRPC_prepare()
),. и факультативно имя XML-RPC-сервера или user agent, например, KD_XMLRPC_USERAGENT
– здесь можно поставить всё что угодно. XMLRPC_error()
: генерирует ответ XML-RPC-сервера с применением специальных тэгов с сообщением об ошибке, которые определены в спецификации стандарта. Если пожелаете, можете настроить ваш собственный набор кодов ошибок; очень помогает при отладке сервера. Готово! Мы написали PHP-функции, у нас есть таблица их соответствия XML-RPC-методам: наш XML-RPC-сервер готов к работе! Теперь, на десерт, напишем простенький клиент для доступа к новостям.
Поскольку это пример, скрипт клиента будем хранить в той же директории, где и сервер, но если у вас есть другой web-сервер, вы можете разместить клиента там, главное, убедитесь в том, что скрипт имеет доступ к библиотеке функций "kd_xmlrpc.php".
<?php
/* Подключаем библиотеку */
include ( "kd_xmlrpc.php" );
/* Определяем путь к xml-rpc серверу */
$site = "www.yourdomain.com";
$location = "/kd_xmlrpc/server.php";
/* Функция, возвращающая красивую дату */
function convert_date ( $date ) {
$date = date ( "D M y H:i:s",
XMLRPC_convert_iso8601_to_timestamp ( $date ) );
return ( $date );
}
?>
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> KD XML RPC News Client </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="HarryF">
<meta name="Keywords" content="XML RPC">
<meta name="Description" content="Gets news form server.php">
</head>
<body>
<?php
/* client.php */
/* Если юзер хочет видеть только одну новость, делаем это */
if ( ISSET ( $_GET['news_id'] ) ) {
/* $success равен 0 (неуспешно) / 1 ( успешно ).
XMLPRC_request шлёт скрипту сервера XML POST,
вызывая метод и отправляя корректные параметры
с помощью XMLRPC_prepare */
list($success, $response) = XMLRPC_request(
$site,
$location,
'news.viewNewsItem',
array(XMLRPC_prepare($_GET['news_id']),
'HarryFsXMLRPCClient')
);
/* Если всё хорошо, показываем эту новость */
if ($success) {
?>
<table align="center" width="600">
<tr valign="top">
<th colspan="2"><b><?php echo ( $response['title'] );?></b></th>
</tr>
<tr valign="top">
<th><?php echo ( $response['author'] );?></th>
<th><?php echo ( convert_date ( $response['date'] ) );?></th>
</tr>
<tr valign="top">
<td colspan="2">
<?php echo ( nl2br ( $response['full_desc'] ) );?>
</th>
</tr>
</table>
<?php
/* В противном случае поведаем юзеру об ошибке */
} else {
echo ( "<p>Error: " . nl2br ( $response['faultString'] ) );
}
} else {
/* Определяем параметры, передаваемые в
XML-RPC метод как массив PHP */
$query_info['limit'] = 10;
$query_info['order'] = "author";
/* XMLRPC_prepare обрабатывает массив и
преобразует в параметры XML-RPC */
list($success, $response) = XMLRPC_request(
$site,
$location,
'news.getNewsList',
array(XMLRPC_prepare($query_info),
'HarryFsXMLRPCClient')
);
/* При успешном завершении показываем список в виде HTML-таблицы */
if ($success) {
echo ( "<table align=\"center\" width=\"600\">\n" );
$count = 0;
while ( list ( $key, $val ) = each ( $response ) ) {
?>
<tr valign="top">
<td colspan="2">
<a href="<?php echo ( $_SERVER['PHP_SELF'] );?>?news_id=<?php echo ( $response[$count]['news_id'] ); ?>">
<?php echo ( $response[$count]['title'] ); ?>
</a>
</td>
</tr>
<tr valign="top">
<td colspan="2">
<?php echo ( $response[$count]['short_desc'] ); ?>
</td>
</tr>
<tr valign="top">
<td>
<?php echo ( $response[$count]['author'] ); ?>
</td>
<td>
<?php echo ( convert_date ( $response[$count]['date'] ) ); ?>
</td>
</tr>
<?php
$count++;
}
echo ( "</table>\n" );
/* Если ошибка */
} else {
echo ( "<p>Error: " . nl2br ( $response['faultString'] ) );
}
}
;?>
</body>
</html>
Что происходит в скрипте? Сам по себе, PHP-код – это простое ветвление if/else: то есть если мы решим просмотреть одну конкретную новость и используем переменную $_GET['news_id']
, то скрипт покажет эту новость. В противном случае будет показан список всех новостей.
Для просмотра списка новостей мы используем метод news.getNewsList
. Заметьте, что $query_info['limit']
выставлен на 10 (то есть нам нужно максимум 10 новостей), а $query_info['order']
– на значение "author" (то есть сортировка новостей по имени автора). Эти две переменные станут параметрами, которые отправит XML-RPC-клиент в своём запросе.
При просмотре одной новости целиком, в параметр мы преобразуем $_GET['news_id']
; по этому параметру сервер сможет определить, какую новость мы желаем получить.
Специфические XML-RPC-функции, задействованные в этом скрипте:
XMLRPC_prepare()
: раньше мы использовали её в сервере, и здесь также конвертируем переменные PHP в XML-RPC-параметры. Именно здесь мы фиксируем данные, которые понадобятся серверу для работы запрашиваемого метода. XMLRPC_request()
: данная функция принимает в качестве аргумента пять переменных и возвращает массив. Это, собственно, то, что делает клиента клиентом. Принимаются:$site
– доменное имя сервера $location
– путь к скрипту сервера от web-корня $methodName
– имя запрашиваемого XML-RPC-метода $params
– любые необходимые для работы метода переменные $user_agent
– необязательный аргумент, и здесь может быть всё, что вам заблагорассудится (например, HarryFsXMLRPCClient). XMLRPC_convert_iso8601_to_timestamp
: нашей функцией convert_date()
мы преобразуем дату и время из формата XML-RPC в нечто более приглядное, а timestamp от PHP используем в качестве перевалочного пункта. Подсказка: при написании XML-RPC-клиентов полезно рассматривать XML-RPC-сервер как базу данных – и то, и другое лишь источник данных. В ваших скриптах код обращений к серверу будет иметь структуру кода с запросами к MySQL.
Итак, всё готово! Направили браузер на http://www.yourdomain.com/kd_xmlrpc/client.php, и читаем себе новости.
Скачайте код: все используемые в данной статье скрипты и таблица MySQL находятся в этом .zip файле.
Итак, как вы уже убедились, используя XML-RPC-код Кейта Девенса, создать свой web-сервис достаточно просто. То есть можно сказать, что это и есть прекрасное начало нашего близкого знакомства с миром web-сервисов. Возможно, в качестве "домашнего задания" вы могли бы добавить функциональности клиенту, позволив пользователям выбирать способ сортировки отображаемых новостей (то есть по автору, теме или дате). Или, если у вас большие амбиции, вы могли бы расширить интерфейс клиента, позволив пользователям редактировать (UPDATE
) и добавлять (INSERT
) новости.
Если у вас далеко идущие планы по работе с web-сервисами, вам может быть небезынтересно взглянуть и на другие проекты, например, класс phpxmlrpc
от Userland, оптимизации кода ради. Но для и выполнения тех же задач вам вполне хватит разработки Кейта Девенса.
Но о двух небольших недоработках в коде Кейта вы должны знать.
Во-первых, функция XMLRPC_request()
"стирает" всю передаваемую в ответе XML-RPC информацию о типе каждого параметра, что может привести к лишнему коду в клиенте. Например, вы можете ждать массив, а получить скалярную (с одним значением) переменную – клиент должен учитывать оба варианта.
Кроме того, нет возможности интроспекции, которая позволяет другим разработчикам получить ваши API (то есть список допустимых методов и параметров вашего сервера). Впрочем, добавить возможность интроспекции будет несложно: просто надо использовать массив из web_service_api.php.
И, напоследок, это достаточно ограниченные средства отладки. Когда ваш единственный интерфейс – это клиент, выяснить, что именно там делает XML-RPC-сервер будет проблематично. Здесь вы, вероятно, захотите завести нечто вроде лога для сервера и можете задействовать ваш собственный отладчик ошибок в PHP; для ознакомления с этим аспектом, прочитайте эту статью про определённые пользователем обработчики ошибок.
Но, конечно, мы благодарим Кейта за замечательную разработку и содействие в удачном старте при освоении новой для нас технологии.
В статье мы не рассматривали два момента: систему безопасности и обработку транзакций. Если вам хочется чего-то "великого и ужасного", то можете прочитать это. В системе безопасности нужно предусмотреть три момента:
INSERT
) и редактирования (UPDATE
) новостей, то вам нужно будет найти способы авторизации удалённого сайта и/или пользователей этого сайта. И здесь вам решать, как вы поступите. Удалённый сайт вы можете проверить по имени хоста или IP-адресу. Для авторизации пользователей можно порекомендовать воспользоваться XML-RPC-сервером ещё как и средством проверки пользователей по базе данных: перед тем, как предоставить доступ к потенциально опасным методам, посредством специального метода (написанного вами и используемого только для целей авторизации) затребуйте логин-пассворд. В идеале, если вы так и поступите, соединение клиента с сервером необходимо будет закодировать через SSL, но это требует использования CURL-функций PHP при приёме/отправке данных (некоторые части приложения придётся переписать). При обработке транзакций задумайтесь, что будет, если вы потеряете соединение между клиентом и сервером в процессе XML-RPC-общения? Какие механизмы вы внедрите для обслуживания повторных попыток (повторная отправка запроса или ответа)? Может случиться так, что потеря данных будет недопустима для вашего web-сервиса, в этом случае необходимо предусмотреть механизм создания/управления очередью запросов и ответов. Для ознакомления с принципами обработки транзакций, читайте эту статью.
Но прочь страхи, вот вы и написали ваш первый web-сервис и, будем надеяться, неплохо разобрались с принципами работы технологии. Возникает закономерный вопрос: ну и что же делать с этим добром? Ставить новости – это здорово, но это делали уже и раньше. Что-нибудь ещё? Читаем следующую главу...
Вопрос немного из категории "на что мы способны с web-страничкой?". Единственное ограничение здесь – ваша фантазия. Максимально абстрактно можем сказать, что с XML-RPC и PHP вы можете вывести ваш ресурс за границы простой отправки документов пользователю. Ваш сайт будет в состоянии обмениваться данными с любой системой, а вы, принимая на вооружение столь распространённый стандарт, предоставите другим разработчикам интерфейс, с которым они будут рады работать.
Web-сервисы в самом широком смысле могут принести доход тем, кто владеет "ценной информацией". Например, если вы имеете прямой доступ к курсам обмена валют, то с PHP и XML-RPC вы можете предоставить другим сайтам услугу конвертирования валют. А вот ещё несколько идей и примеров: