Вот наконец-то и сподобился я на тему работы с XML-RPC в Delphi. Ещё с того самого момента, как испробовал для постинга в блог программу Zoundary Raven, заглядывался на этот протокол, но всё как-то было лень разбираться как и что писать, куда отправлять и т.д. А сегодня получил письмо от читателя блога с просьбой осветить этот вопрос, посоветовались с Altmer’ом и решили «Попытка — не пытка». Лишними такие знания точно не будут ни нам ни читателям «Delphi в Internet«.
Как и полагается, изучение вопроса начали с поиска достоверной информации в Сети. Надо сказать, что такого «изобилия» информации мне лично ещё не встречалось. Единственный всем известный компонент, разработанный для этих целей в далеком 2001 году, и тот сказочным образом пропал с sourceforge.net. Российские блоггеры и программисты тоже не особо красноречивы — в основном статьи на тему «XML-RPC в Delphi» сводятся к описанию проблем, но без каких-то конкретных выкладок, листингов и прочих атрибутов статей про программирование. В общем, то ли плохо искали, то ли действительно всё так плохо, но начинать пришлось с нуля. Может это и к лучшему — будем владеть вопросом так сказать на все 100. Может и сами какой-никакой модуль для Delphi со временем соберем. А пока начнем с основ.
1. Основы XML-RPC. Что это? И как с этим работать?
XML-RPC расшифровывается как Remote Procedure Call — удаленный вызов процедур с помощью XML
Разработчиком технологии XML-RPC является компания UserLand Software Inc. Основным транспортом в технологии является протокол HTTP, а форматом данных — XML. Это снимает ограничения, налагаемые как на конфигурацию сети, так и на маршрут следования пакетов — вызовы XML-RPC представляют собой простой тип данных text/xml и свободно проходят сквозь шлюзы везде, где допускается ретрансляция http-трафика.
Обобщенная схема работы XML-RPC выглядит следующим образом:
То есть не важно на чём вы будете строить свое клиентское приложение (хоть на Delphi, хоть на PHP), главное — верно составить запрос и верно транслировать ответ. И запрос и ответ представляют собой XML-документ строго определенного формата, который чётко прописан в спецификации протокола, который Вам необходимо будет изучить.
Вот, например типичный запрос к серверу XML-RPC:
POST /RPC2 HTTP/1.0 User-Agent: Frontier/5.1.2 (WinNT) Host: webdelphi.ru Content-Type: text/xml Content-length: 315 wp.getTags 1 admin_login password
Здесь мы обращаемся к хосту webdelphi.ru и запрашиваем у него данные методом POST. Сервер должен вернуть нам значение, выданное функцией wp.getTagsу которой в качестве входных параметров выступают id блога, логин и пароль администратора.
В ответ может вернуться либо результат выполнения запроса, либо данные об ошибке. В обоих случаях ответ сервера будет равен 200. То есть ответ сервера лишь говорит нам, что данные приняты и обработаны, а уж как они обработаны — тут надо покопаться самим в ответе.
Однако просто знание протокола не гарантирует Вам, что вы сию минуту сядите за Delphi и начнете штамповать блог-клиенты по сотне штук в день. Для такой работы надо как минимум знать API той CMS (движка сайта) с которым Вы хотите работать. Так что перейдем ко второй части — краткому знакомству с API WordPress.
2. XML-RPC WordPress. Первое знакомство
Если Вы владелец блога под управлением WordPress, то прекрасно знаете, что для использования протокола XML-RPC необходимо дать разрешение на его использование через админ.панель движка. Сам протокол для WP находится в файле xmlrpc.php, а класс для обработки данных расположен в /wp-includes/class-IXR.php. На всякий случай можете скачать эти файлы себе на компьютер т.к. они Вам очень сильно пригодятся при изучении протокола.
Вообще WordPress поддерживает несколько API для XML-RPC:
Blogger API,
metaWeblog API
Movable Type API
и свой родной WordPress API
все методы, используемые этими интерфейсами Вы можете найти в xmlrpc.php, начиная со строки номер 132. Как можно увидеть, возможности для удаленного управления блогом WordPress достаточно широки. Давайте, например, вызовем самый простой метод sayHello:
function sayHello($args) { return 'Hello!'; }
Для демонстрационного примера воспользуемся компонентами Indy. Открываем Delphi, укладываем на главную форму приложения компонент idHTTP, кнопку для отправки запроса и Memo для показа ответа сервера.
Судя, по всему, при успешном выполнении запроса сервер с нами «поздоровается».
Составляем XML-запрос для отправки на сервер:
demo.sayHello проверка
Название метода пишем так, как оно определено в xmlrpc.php. Теперь желательно сразу сохранить этот запрос в текстовый файл, чтобы потом просто немного его редактировать и грузить в работающее приложение.
Обработчик кнопки будет выглядеть следующим образом:
procedure TForm2.Button1Click(Sender: TObject); var Txt : TStringStream; //данные для POST Responce: TStringStream; //ответ сервера begin txt:=TStringStream.Create; txt.LoadFromFile(ExtractFilePath(Application.ExeName)+'text.txt'); IdHTTP1.Request.ContentLength:=txt.Size; Memo1.Lines.Add(txt.DataString); Memo1.Lines.Add('++++++++++++++++++++++++++'); Memo1.Lines.Add(IdHTTP1.Post('http://vash_domen.com/xmlrpc.php',txt)); end;
В результате выполнения запроса, при включенной возможности использования XML-RPC в Вашем блоге, Вы получите вот такой ответ:
Hello!
Значит сервер работает, что и следовало доказать. Теперь пройдем немного дальше и попробуем посмотреть данные о пользователе. Для этого воспользуемся методом wp.getUsersBlogs
Входными параметрами являются строковые значения: логин и пароль пользователя.
Оформляем запрос:
wp.getUsersBlogs Login password
Отправляем на сервер и получаем ответ (для администратора блога):
isAdmin1 urlhttp://webdelphi.ru/ blogid1 blogNameDelphi ?? Internet xmlrpchttp://webdelphi.ru/xmlrpc.php
Как видите в ответ пришла структура данных, состоящая из нескольких типов:
isAdmin тип boolean, если пользователь администратор, то возвращается 1
и далее строковые данные: URL блога, BlogId, название блога и адрес xml-rpc.
В случае ошибочного задания логина и пароля вернется ответ, содержащий ошибку:
faultCode 403 faultString Bad login/pass combination.
Ну, и для порядка, можете отправить на свой блог, например вот такой запрос:
wp.getTags 1 login password
Если блог довольно старый — ответ устанете читать :) Т.к. в результате вам вернется список всех тегов блога.
В заключении следует сказать, что все возвращаемые данные имеют кодировку UTF-8, что следует учитывать при работе с протоколом.
Ну и ссылки для более глубокого ознакомления с вопросом:
1. Вводная статья про XML-RPC
2. Спецификация XML-RPC
3. XML-RPC WordPress API
Пока пишется и переписывается Хронометр посмотрим, что можно сделать полезного с XML-RPC для Delphi. Если у Вас есть желание идеи поучаствовать в разработке чего-то нового — не стесняйтесь, пишите — BuBa Group всегда рада Вас принять в свои ряды ;)
сервер отвечает: parse error. not well formed
Првада пришлось заменить TStringStream на TStringList, с первым не заработал
Отправьте запрос на сервер без первой строки описания протокола — просто чистый запрос.
Странно, что с потоком не работает. Какие ошибки были до смены на TStringList?
До смены на TStringList:
1. txt:=TStringStream.Create; переделал в txt:=TStringStream.Create(»); странно почему у Вас работало.
2. txt.LoadFromFile(ExtractFilePath(Application.ExeName)+’text.txt’); После этого на эту строку ругается:[Error] Unit1.pas(34): Undeclared identifier: ‘LoadFromFile’
Нету процедуры LoadFromFile. У меня Delphi 7, а у Вас?
Проблема решена! Все дело в «руках»:) В текстовом файле написал запрос в одну строчку без пробелов и получил ответ от сервера. Спасибо
Не за что. Всегда рад помочь :) Я сейчас пишу всё только на Delphi 2010 может поэтому и поток у меня создается без лишних (»). И, кстати, чтобы не было непонятных ошибок наподобие parse error. not well formed , а выписывалась конкретная ошибка можно раскоментировать пару строк в модуле где описаны все процедуры XML-RPC и пока пишите программу — получать нормальные сообщения. Потом закомментируете обратно. Если надо — могу вечером посмотреть и точно сказать какой модуль, где лежит и какие строки расскомментировать (сейчас на работе, пассов от фтп под рукой нету)
С TStringStream не работает в 7ой делфи. Попробую скачать сегодня Delphi 2010 и испытать там
Сейчас допишу одну небольшую утилиту для теста XML-RPC блога. Думаю, что всё заработает ;)
txt:=TStringStream.Create(»);
memo1.Lines.LoadFromFile(ExtractFilePath(Application.ExeName)+’text.txt’);
memo1.Lines.SaveToStream(txt);
memo1.Clear;
IdHTTP1.Request.ContentLength:=txt.Size;
Memo1.Lines.Add(txt.DataString);
Memo1.Lines.Add(‘++++++++++++++++++++++++++’);
Memo1.Lines.Add(IdHTTP1.Post(‘http://joomla.local/xmlrpc/index.php’,txt));
Вот таким макаром получилось запихнуть текст в поток :)
:) довольно интересный «макар». Как раз сейчас делаю пример без потоков. Посмотрим пригодиться ли он..
Кстати говоря, выше, в примерах, отсутсвуют итемы xml
<methodCall>
<methodName>
Поэтому-то у меня и не получалось ничего..
Да, сейчас заметил…почему-то WordPress начал как-то странно обрезать листинги. Статью придётся немного переделать и добавить ещё парочку примеров по работе.
И кстати, при работе с TStringList следует следить за тем, чтобы ContentLength в запросе соответствовал действительности. У меня, например, Stream.Length и Length(List.Text) имеют различные значения — отличаются на 2
Я только в самом первом примере заметил вот это
POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: webdelphi.ru
Content-Type: text/xml
Content-length: 315
В ЛЮБЫХ запросах нужно использовать этот заголовок?
Вообще желательно писать полный заголовок (естественно с измененным значением хост), НО обязательным должно быть только поле Content-length и причём поле это должно быть заполнено корректно. Пока писал тестировщика запросов (см. в конце поста под UPDATE) заметил такую штуку — если поле Content-length отличается хотя бы 2 от того, что есть в теле запроса в действительности — сервер выкидывает ошибку -3600
Понятно :)
Еще вопросик возник, может быть в курсе: пробую создать новый пост, обычный текст — без проблем. Но не могу вставить теги, сервер ругается в ответ.
Может в курсе, как быть?
Текст «ругани» сервера в студию плз :) И желательно листинг процедуры отправки
Разобрался!
Нужно теги заключать в <![CDATA]… (написал по памяти) :)
:) Отлично. Спасибо, Максим, за полезную информацию!
Вам спасибо, за подсказки :)
А есть пример XML файла для добавления поста в блог на wordpress ? В студию :-)
Достаточно прочитать описание API WordPress и потребность в примере отпадёт сама собой :)
Цитата:
А как-же это?
http://sourceforge.net/projects/delphixml-rpc/
Хотя,
Может оно и к лучшему…
Спасибо.
Ну вот и ссылка объявилась. Но мне уже компонент не интересен — хочу собрать что-нибудь сам :) А другие, если надо — пусть пользуются на здоровье
Компонент по ссылке http://sourceforge.net/projects/delphixml-rpc/ перед скачиванием показывает:
Я еще не видел ни одной библиотеки хуже Indy, там всё сделано через задний проход, начиная от забитых константами разделителей дробных чисел (которые зависят от винды) и заканчивая вызовами несуществующих объектов (и соотвественно крушением приложения) при работе с SSL через прокси. Ну соотвественно и компонент точно такая же какашка, раз базируется на этой библиотеке.
Лучше ICS и голова, и всё будет :)
PS:
ICS кстати определяет кодировки и перед тем, как отдать контент, перекодирует в текущую локаль.
[…] кстати, по работе XML-RPC в Delphi можно почитать на блоге webdelphi.ru. На котором, кроме […]
выложите пожалуйста какой нидь исходник для примера
Доброго.
Коллега, а если у меня пока задача попроще: есть некие тексты в базе, я их считываю, потом их надо отформатировать, между ними вставить некие разделители типа *** и все это красиво оформить, чтобы даже просто руками потом результат вставить. Я пока чайник, тем не менее, с получением данных из базы проблем нет, а вот с форматированием… понимаю, что надо использовать что-то типа tMemo, но справиться не могу. Никаких цветовых и шрифтовых игр не планируется.