hats 23 июля 2013 в 13:09
Пишем SOAP клиент-серверное приложение на PHP
- PHP
- Tutorial
Всем привет!
Так случилось, что в последнее время я стал заниматься разработкой веб-сервисов. Но сегодня топик не обо мне, а о том, как нам написать свой XML Web Service основанный на протоколе SOAP 1.2.
Я надеюсь, что после прочтения топика вы сможете самостоятельно:
- написать свою собственную серверную реализацию веб-приложения;
- написать свою собственную клиентскую реализацию веб-приложения;
- написать свое собственное описание веб-сервиса (WSDL);
- отправлять клиентом массивы однотипных данных на сервер.
1 Постановка задачи
1.1 Границы
В начале предлагаю разобраться с тем результатом, которого мы достигнем в конце топика. Как было объявлено выше, мы будем писать сервис по отправке sms-сообщений, а если еще точнее, то к нам будут поступать сообщения из разных источников по протоколу SOAP. После чего, мы рассматрим в каком виде они приходят на сервер. Сам процесс постановки сообщений в очередь для их дальнейшей отправки провайдеру, к сожалению, выходит за рамки данного поста по многим причинам.1.2 Какими данными будем меняться?
Отлично, с границами мы определились! Следующий шаг, который необходимо сделать – решить какими данными мы будем обмениваться между сервером и клиентом. На эту тему предлагаю долго не мудрить и сразу для себя ответить на главные вопросы:- Какой минимум данных надо посылать на сервер, чтобы отправить sms-сообщение абоненту?
- Какой минимум данных надо посылать с сервера, чтобы удовлетворить потребности клиента?
- номер мобильного телефона, а также
- текст sms-сообщения.
- дату отправки sms-сообщения.
- Тип сообщения.
И все же, я что-то забыл! Если еще немного порефлексировать, то стоит отметить, что клиент за раз может отправить на сервер как одно sms-сообщение, так и некоторое их количество. Другими словами, в одном пакете данных может быть от одного до бесконечности сообщений.
В результате мы получаем, что для отправки sms-сообщения нам необходимы следующие данные:
- номер мобильного телефона,
- текст sms-сообщения,
- время отправки sms-сообщения абоненту,
- тип сообщения.
На первый вопрос мы ответили, теперь необходимо ответить на второй вопрос. И пожалуй, я позволю себе немного с халтурить. Поэтому, с сервера мы будем присылать только булевы данные, значение которых имеет следующий смысл:
- TRUE – пакет успешно дошел до сервера, прошел аутентификацию и встал в очередь для отправки sms-провайдеру
- FALSE – во всех остальных случаях
На этом мы закончили описание постановки задачи! И наконец-то приступим к самому интересному – будем разбираться что за диковинный зверь этот SOAP!
2 С чем есть SOAP?
Вообще, изначально я не планировал ничего писать о том, что такое SOAP и хотел ограничиться ссылками на сайт w3.org с нужными спецификациями, а также ссылками на Wikipedia. Но в самом конце решил написать коротенькую справочку об этом протоколе.И начну я свое повествование с того, что данный протокол обмена данными относится к подмножеству протоколов основанных на так называемой парадигме RPC (Remote Procedure Call, удалённый вызов процедур) антиподом которой является REST (Representational State Transfer, передача репрезентативного состояния). Более подробно об этом можно прочесть в Wikipedia, ссылки на статьи находятся в самом конце топика. Из этих статей нам надо уяснить следующее: «Подход RPC позволяет использовать небольшое количество сетевых ресурсов с большим количеством методов и сложным протоколом. При подходе REST количество методов и сложность протокола строго ограничены, из-за чего количество отдельных ресурсов может быть большим». Т.е., применительно к нам это означает, что на сайте в случае RPC подхода будет всегда один вход (ссылка) на сервис и какую процедуру вызывать для обработки поступающих данных мы передаем вместе с данными, в то время как при REST подходе на нашем сайте есть много входов (ссылок), каждая из которых принимает и обрабатывает только определенные данные. Если кто-то из читающих знает, как еще проще объяснить различие в данных подходах, то обязательно пишите в комментариях!
Следующее, что нам надо узнать про SOAP – данный протокол в качестве транспорта использует тот самый XML, что с одной стороны очень хорошо, т.к. сразу же в наш арсенал попадает вся мощь стека технологий основанных на данном языке разметки, а именно XML-Schema – язык описания структуры XML-документа (спасибо Wikipedia!), который позволяет производит автоматическую валидацию поступающих на сервер данных от клиентов.
И так, теперь мы знаем, что SOAP – протокол используемый для реализации удаленного вызова процедур и в качестве транспорта он использует XML! Если почитать статью на Wikipedia, то оттуда можно узнать еще и о том, что он может использоваться поверх любого протокола прикладного уровня, а не только в паре с HTTP (к сожалению, в данном топике мы будем рассматривать только SOAP поверх HTTP). И знаете, что мне во всем этом больше всего нравится? Если нет никаких догадок, то я дам подсказку – SOAP!… Всеравно не появилось догадок?… Вы точно прочли статью на Wikipedia?… В общем, не буду вас дальше мучить. Поэтому, сразу перейду к ответу: «SOAP (от англ. Simple Object Access Protocol - простой протокол доступа к объектам; вплоть до спецификации 1.2 )». Самое примечательное в этой строчке выделено курсивом! Я не знаю какие выводы сделали вы из всего этого, но мне видится следующее – поскольку данный протокол ну никак нельзя назвать «простым» (и видимо с этим согласны даже в w3), то с версии 1.2 он вообще перестал как-то расшифровываться! И стал называться SOAP, просто SOAP и точка.
Ну да ладно, прошу меня извинить, занесло немного в сторону. Как я писал ранее, в качестве транспорта используется XML, а пакеты, которые курсируют между клиентом и сервером называются SOAP-конвертами. Если рассматривать обобщенную структуру конверта, то он вам покажется очень знакомым, т.к. напоминает структуру HTML-страницы. В нем есть основной раздел – Envelop
, который включает разделы Header
и Body
, либо Fault
. В Body
передаются данные и он является обязательным разделом конверта, в то время как Header
является опциональным. В Header
может передаваться авторизация, либо какие-либо иные данные, которые на прямую не относятся к входным данным процедур веб-сервиса. Про Fault
особо рассказывать нечего, кроме того, что он приходит в клиент с сервера в случае возникновения каких-либо ошибок.
На этом мой обзорный рассказ про протокол SOAP заканчивается (более детально сами конверты и их структуру мы рассмотрим когда наши клиент и сервер наконец-то научатся запускать их друг в друга) и начинается новый – про компаньона SOAP под названием WSDL (Web Services Description Language). Да-да, это та самая штука, которая отпугивает большинство из нас от самой попытки взять и реализовать свое API на данном протоколе. В результате чего, мы обычно изобретаем свой велосипед с JSON в качестве транспорта. И так, что такое WSDL? WSDL – язык описания веб-сервисов и доступа к ним, основанный на языке XML (с) Wikipedia. Если из этого определения вам не становится понятным весь сакральный смысл данной технологии, то я попытаюсь описать его своими словами!
WSDL предназначен для того, чтобы наши клиенты могли нормально общаться с сервером. Для этого в файле с расширением «*.wsdl» описывается следующая информация:
- Какие пространства имен использовались,
- Какие схемы данных использовались,
- Какие типы сообщений веб-сервис ждет от клиентов,
- Какие данные принадлежат каким процедурам веб-сервиса,
- Какие процедуры содержит веб-сервис,
- Каким образом клиент должен вызывать процедуры веб-сервиса,
- На какой адрес должны отправляться вызовы клиента.
3 Введение в XML-Schema
Теперь мы много чего знаем о то, что такое SOAP, что находится у него внутри и имеем обзорное представление о том, какой стек технологий его окружает. Поскольку, прежде всего SOAP представляет собой способ взаимодействия между клиентом и сервером, и в качестве транспорта для него используется язык разметки XML, то в данном разделе мы немного разберемся каким образом происходит автоматическая валидация данных посредством XML-схем.Основная задачи схемы – описать структуру данных которые мы собираемся обрабатывать. Все данные в XML-схемах делятся на простые (скалярные) и коплексные (структуры) типы. К простым типам относятся такие типы как:
- строка,
- число,
- булево значение,
- дата.
Предлагаю далеко не ходить и написать XML-схему для нашего sms-сообщения! Ниже представлено xml-описание sms-сообщения:
Схема нашего комплексного типа будет выглядеть следующим образом:
Эта запись читается следующим образом: у нас есть переменная «message
» типа «Message
» и есть комплексный тип с именем «Message
», который состоит из последовательного набора элементов «phone
» типа string
, «text
» типа string
, «date
» типа dateTime
, «type
» типа decimal
. Эти типы простые и уже определены в описании схемы. Поздравляю! Мы только что написали нашу первую XML-схему!
Думаю, что значение элементов «element » и «complexType » вам стало все более-менее понятно, поэтому не будем на них больше заострять внимание и переключимся сразу же на элемент-композитор «sequence ». Когда мы используем элемент-композитор «sequence » мы сообщаем о том, что элементы включенные в него должны всегда располагаться в указанной в схеме последовательности, а также все из них являются обязательными. Но не стоит отчаиваться! В XML-схемах есть еще два элемента-композитора: «choice » и «all ». Композитор «choice » сообщает о том, что должен быть какой-то один из перечисленных в нем элементов, а композитор «all » – любая комбинация перечисленных элементов.
Как вы помните, то в первом разделе топика мы договорились о том, что в пакете может передаваться от одного до бесконечности sms-сообщений. Поэтому предлагаю разобраться как такие данные декларируются в XML-схеме. Общая структура пакета может выглядеть следующим образом:
Схема для такого комплексного типа будет выглядеть так:
В первом блоке идет знакомое нам декларирование комплексного типа «Message
». Если вы заметили, то в каждом простом типе, входящем в «Message
», были добавлены новые уточняющие атрибуты «minOccurs
» и «maxOccurs
». Как не трудно догадаться из названия, первый (minOccurs
) сообщает о том, что в данной последовательности должно быть минимум по одному элементу типа «phone
», «text
», «date
» и «type
», в то время как следующий (maxOccurs
) атрибут нам декларирует, что таких элементов в нашей последовательности максимум по-одному. В результате, когда мы пишем свои схемы для каких-либо данных, нам предоставляется широчайший выбор по их настройке!
Второй блок схемы декларирует элемент «messageList » типа «MessageList ». Видно, что «MessageList » представляет собой комплексный тип, который включает минимум один элемент «message », но максимальное число таких элементов не ограничено!
4 Пишем свой WSDL
Вы помните о том, что WSDL и есть наш веб-сервис? Надеюсь, что помните! Как мы его напишем, так на нем наш маленький веб-сервис и поплывет. Поэтому, предлагаю не халтурить.Вообще, для того, чтобы у нас все работало правильно нам надо передавать клиенту WSDL-файл с правильным MIME-типом. Для этого необходимо настроить ваш веб-сервер соответствующим образом, а именно – установить для файлов с расширением «*.wsdl» MIME-тип равный следующей строке:
Application/wsdl+xml
Но на практике, я обычно отправлял посредством PHP HTTP-заголовок«text/xml
»:
Header("Content-Type: text/xml; charset=utf-8");
и все прекрасно работало!
Хочу сразу предупредить, наш простенький веб-сервис будет иметь довольно внушительное описание, поэтому не пугайтесь, т.к. большая часть текста является обязательной водой и написав ее один раз можно постоянно копировать от одного веб-сервиса к другому!
Поскольку WSDL – это XML, то в самой первой строке необходимо прямо об этом и написать. Корневой элемент файла всегда должен называться «definitions »:
Обычно, WSDL состоит из 4-5 основных блоков. Самый первый блок – определение веб-сервиса или другими словами – точки входа.
Здесь написано, что у нас есть сервис, который называется – «SmsService
». В принципе, все имена в WSDL-файле могут быть вами изменены на какие только пожелаете, т.к. они не играют абсолютно никакой роли.
После этого мы объявляем о том, что в нашем веб-сервисе «SmsService » есть точка входа («port»), которая называется «SmsServicePort ». Именно в эту точку входа и будут отправляться все запросы от клиентов к серверу. И указываем в элементе «address » ссылку на файл-обработчик, который будет принимать запросы.
После того, как мы определили веб-сервис и указали для него точку входа – необходимо привязать к нему поддерживаемые процедуры:
Для этого перечисляется какие операции и в каком виде у будут вызываться. Т.е. для порта «SmsServicePort
» определена привязка под именем «SmsServiceBinding
», которая имеет тип вызова «rpc
» и в качестве протокола передачи (транспорта) используется HTTP. Т.о., мы здесь указали, что будем осуществлять RPC вызов поверх HTTP. После этого мы описываем какие процедуры (operation
) поддерживаются в веб-сервисе. Мы будем поддерживать всего одну процедуру – «sendSms
». Через эту процедуру будут отправляться на сервер наши замечательные сообщения! После того, как была объявлена процедура, необходимо указать в каком виде будут передаваться данные. В данном случае указано, что будут использоваться стандартные SOAP-конверты.
После этого нам необходимо привязать процедуру к сообщениям:
Для этого мы указываем, что наша привязка («binding») имеет тип «SmsServicePortType
» и в элементе «portType
» с одноименным типу именем указываем привязку процедур к сообщениям. И так, входящее сообщение (от клиента к серверу) будет называться «sendSmsRequest
», а исходящее (от сервера к клиенту) «sendSmsResponse
». Как и все имена в WSDL, имена входящих и исходящих сообщения – произвольные.
Теперь нам необходимо описать сами сообщения, т.е. входящие и исходящие:
Для этого мы добавляем элементы «message
» с именами «sendSmsRequest
» и «sendSmsResponse
» соответственно. В них мы указываем, что на вход должен прийти конверт, структура которого соответствует типу данных «Request
». После чего с сервера возвращается конверт содержащий тип данных – «Response
».
Теперь надо сделать самую малость – добавить описание данных типов в наш WSDL-файл! И как вы думаете, как описываются в WSDL входящие и исходящие данные? Думаю, что вы уже все давно поняли и сказали сами себе, что при помощи XML-схем! И вы будете абсолютно правы!
Можно нас поздравить! Наш первый WSDL был написан! И мы еще на один шаг приблизились к достижению поставленной цели.
Далее мы разберемся с тем, что нам предоставляет PHP для разработки собственных распределенных приложений.
5 Наш первый SOAP-сервер
Ранее я писал, что для создания SOAP-сервера на PHP мы будем использовать встроенный класс SoapServer. Для того, чтобы все дальнейшие действия происходили также как и у меня, вам понадобиться немного подкрутить свой PHP. Если быть еще точнее, то необходимо убедиться, что у вас установлено расширение «php-soap». Как его поставить на ваш веб-сервере лучше всего прочитать на официальном сайте PHP (см. список литературы).После того, как все было установлено и настроено нам необходимо будет создать в корневой папке вашего хостинга файл «smsservice.php » со следующим содержанием:
setClass("SoapSmsGateWay");
//Запускаем сервер
$server->handle();
То, что находится выше строчки с функцией «ini_set», надеюсь, что объяснять не надо. Т.к. там определяется какие HTTP-заголовки мы будем отправлять с сервера клиенту и настраивается окружение. В строчке с «ini_set» мы отключаем кеширование WSDL-файла для того, чтобы наши изменения в нем сразу же вступали в действие на клиенте.
Теперь мы подошли к серверу! Как видим, весь SOAP-сервер занимает всего лишь три строки! В первой строке мы создаем новый экземпляр объекта SoapServer и передаем ему в конструктор адрес нашего WSDL-описания веб-сервиса. Теперь мы знаем, что он будет располагаться в корне хостинга в файле с говорящим именем «smsservice.wsdl.php ». Во второй строке мы сообщаем SOAP-серверу какой класс необходимо дергать для того, чтобы обработать поступивший с клиента конверт и вернуть конверт с ответом. Как вы могли догадаться, именно в этом классе будет описан наш единственный метод sendSms . В третьей строке мы запускаем сервер! Все, наш сервер готов! С чем я нас всех и поздравляю!
Теперь нам необходимо создать WSDL-файл. Для этого можно либо просто скопировать его содержимое из предыдущего раздела, либо позволить себе вольности и немного его «шаблонизировать»:
";
?>
На этом этапе получившийся сервер нас должен устроить полностью, т.к. поступающие к нему конверты мы можем логировать и потом спокойно анализировать приходящие данные. Для того, чтобы мы могли что-либо получать на сервер, нам необходим клиент. Поэтому давайте им и займемся!
6 SOAP-клиент на подходе
Прежде всего нам надо создать файл, в котором будем писать клиент. Как обычно, мы его создадим в корне хоста и назовем «client.php », а внутри напишем следующее: messageList = new MessageList();
$req->messageList->message = new Message();
$req->messageList->message->phone = "79871234567";
$req->messageList->message->text = "Тестовое сообщение 1";
$req->messageList->message->date = "2013-07-21T15:00:00.26";
$req->messageList->message->type = 15;
$client = new SoapClient("http://{$_SERVER["HTTP_HOST"]}/smsservice.wsdl.php",
array("soap_version" => SOAP_1_2));
var_dump($client->sendSms($req));
Опишем наши объекты. Когда мы писали WSDL в нем для входящего на сервер конверта описывались три сущности: Request
, MessageList
и Message
. Соответственно классы Request
, MessageList
и Message
являются отражениями этих сущностей в нашем PHP-скрипте.
После того, как мы определили объекты, нам необходимо создать объект ($req
), который будем отправлять на сервер. После чего идут две самые заветные для нас строки! Наш SOAP-клиент! Верите или нет, но этого достаточно для того, чтобы на наш сервер начали сыпаться сообщения от клиента, а также для того, чтобы наш сервер успешно их принимал и обрабатывал! В первой из них мы создаем экземпляр класса SoapClient и передаем в его конструктор адрес расположения WSDL-файла, а в параметрах явно указываем, что работать мы будем по протоколу SOAP версии 1.2. В следующей строке мы вызываем метод sendSms
объекта $client
и сразу же выводим в браузере результат.
Давайте запусти и посмотрим что-же у нас наконец-то получилось!
Мне с сервера вернулся следующий объект:
Object(stdClass)
public "status" => boolean true
И это замечательно, т.к. теперь мы точно знаем о том, что наш сервер работает и не просто работает, но еще и может возвращать на клиент какие-то значения!
Теперь посмотрим на лог, который мы предусмотрительно ведем на серверной стороне! В первой его части мы видим необработанные данные, которые поступили на сервер:
Это и есть конверт. Теперь вы знаете как он выглядит! Но постоянно на него любоваться нам вряд ли будет интересно, поэтому давайте десереализуем объект из лог-файла и посмотрим все ли у нас хорошо:
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
Как видим, объект десериализовался правильно, с чем я нас всех хочу поздравить! Далее нас ждет что-то более интересно! А именно – мы будем отправлять клиентом на сервер не одно sms-сообщение, а целую пачку (если быть точнее, то целых три)!
7 Отправляем сложные объекты
Давайте подумаем над тем, как же нам передать целую пачку сообщений на сервер в одном пакете? Наверно, самым простым способом будет организация массива внутри элемента messageList! Давайте это сделаем: // создаем объект для отправки на сервер
$req = new Request();
$req->messageList = new MessageList();
$msg1 = new Message();
$msg1->phone = "79871234567";
$msg1->text = "Тестовое сообщение 1";
$msg1->date = "2013-07-21T15:00:00.26";
$msg1->type = 15;
$msg2 = new Message();
$msg2->phone = "79871234567";
$msg2->text = "Тестовое сообщение 2";
$msg2->date = "2014-08-22T16:01:10";
$msg2->type = 16;
$msg3 = new Message();
$msg3->phone = "79871234567";
$msg3->text = "Тестовое сообщение 3";
$msg3->date = "2014-08-22T16:01:10";
$msg3->type = 17;
$req->messageList->message = $msg1;
$req->messageList->message = $msg2;
$req->messageList->message = $msg3;
В наших логах числится, что пришел следующий пакет от клиента:
Что за ерунда, скажете вы? И будете правы в некотором смысле, т.к. только что мы узнали о том, что какой объект ушел от клиента, то абсолютно в том же виде он пришел к нам на сервер в виде конверта. Правда, sms-сообщения сериализовались в XML не так, как нам было необходимо – они должны были быть обернуты в элементы message
, а не в Struct
. Теперь посмотрим в каком виде приходит такой объект в метод sendSms
:
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "Struct" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
Что нам дает это знание? Только то, что выбранный нами путь не является верным и мы не получили ответа на вопрос – «Как нам на сервере получить правильную структуру данных?». Но я предлагаю не отчаиваться и попробовать привести наш массив к типу объект
:
$req->messageList->message = (object)$req->messageList->message;
В этом случае, нам придет уже другой конверт:
Пришедший в метод sendSms
объект имеет следующую структуру:
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "BOGUS" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
Как по мне, то «от перемены мест слагаемых – сумма не меняется» (с). Что BOGUS
, что Struct
– цель нами до сих пор не достигнута! А для ее достижения нам необходимо сделать так, чтобы вместо этих непонятных названий отображалось наше родное message
. Но как этого добиться, автору пока не известно. Поэтому единственное, что мы можем сделать – избавить от лишнего контейнера. Другими словами, мы сейчас сделаем так, чтобы вместо message
стал BOGUS
! Для этого изменим объект следующим образом:
// создаем объект для отправки на сервер
$req = new Request();
$msg1 = new Message();
$msg1->phone = "79871234567";
$msg1->text = "Тестовое сообщение 1";
$msg1->date = "2013-07-21T15:00:00.26";
$msg1->type = 15;
$msg2 = new Message();
$msg2->phone = "79871234567";
$msg2->text = "Тестовое сообщение 2";
$msg2->date = "2014-08-22T16:01:10";
$msg2->type = 16;
$msg3 = new Message();
$msg3->phone = "79871234567";
$msg3->text = "Тестовое сообщение 3";
$msg3->date = "2014-08-22T16:01:10";
$msg3->type = 17;
$req->messageList = $msg1;
$req->messageList = $msg2;
$req->messageList = $msg3;
$req->messageList = (object)$req->messageList;
Вдруг нам повезет и из схемы подтянется правильное название? Для этого посмотрим на пришедший конверт:
Да, чуда не произошло! BOGUS
– не победим! Пришедший в sendSms
объект в этом случае будет выглядеть следующим образом:
Object(stdClass)
public "messageList" =>
object(stdClass)
public "BOGUS" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
Как говорится – «Почти»! На этой (немного печальной) ноте предлагаю потихонечку закругляться и сделать некоторые для себя выводы.
8 Заключение
Наконец-то мы добрались сюда! Давайте определимся с тем, что вы теперь умеете делать:- вам по силам написать необходимый для вашего веб-сервиса WSDL-файл;
- вы без всяких проблем можете написать свой собственный клиент способный общаться с сервером по протоколу SOAP;
- вы можете написать свой собственный сервер общающийся с окружающим миром по SOAP;
- вы можете отправлять массивы однотипных объектов на сервер со своего клиента (с некоторыми ограничениями).
- нативный класс SoapClient не умеет правильно сериализовывать однотипные структуры данных в XML;
- при сериализации массива в XML он создает лишний элемент с именем Struct ;
- при сериализации объекта в XML он создает лишний элемент с именем BOGUS ;
- BOGUS меньшее зло чем Struct из-за того, что конверт получается компактнее (не добавляются лишние namespace"ы в XML заголовке конверта);
- к сожалению, класс SoapServer автоматически не валидирует данные конверта нашей XML-схемой (возможно, и другие сервера этого не делают).
Для создания SOAP web-службы на PHP прежде всего необходимо провести установку и настройку PHP, а также локального HTTP-сервера. В данном проекте был использован пакет XAMP, позволяющий провести быструю установку HTTP-сервера Apache и PHP.
Отдельно необходимо внести правки в конфигурационные файлы Apache и PHP.
В конфигурационном файле HTTP-сервера Apache httpd.conf необходимо найти приведенный ниже фрагмент кода:
Для запуска PHP-скриптов на локальном сервере необходимо хранить их в корневой директории сервера Apache, по умолчанию, папка htdocs в корневой папке Apache.
Для изменения корневой директории сайта необходимо внести изменения в файл httpd.conf в строку, приведенную ниже:
Для подключения поддержки PHP в файл httpd.conf необходимо внести следующие строки:
Для запуска HTTP-сервера Apache можно использовать консольные команды, либо контрольную панель XAMMP, позволяющую управлять состоянием Apache, а также проводить его конфигурацию.
Вид данной утилиты приведен на рисунке 2.
Рисунок 2. - Утилита XAMMP Control Panel:
Для создания SOAP web-службы необходимо написать PHP документы, реализующие клиентскую и серверную стороны приложения, а также WSDL-страницу, для описания web-сервиса.
Создадим web-службу, которая предоставляет одну web-услугу, возвращающую клиенту результат выполнения арифметической операции над двумя числами. Входными элементами являются два числа, задаваемые клиентом, а также символьная переменная, определяющая арифметическую операцию.
Клиентская сторона реализована двумя PHP-документами. В файле form.php при помощи элемента