|
Krasland.ru - красноярский интернет-портал
Интернет-аукцион Asta24.ru:
позволяет выгодно покупать и продавать свои товары, при этом сервис не требует никакой комиссии!
Информация: новости · погода · курсы валют · валютный рынок · справки · телефоны · мобильная связь · о проекте.
Журнал: авто · кино · музыка · мода · секс · спорт · технологии · бытовая техника · кулинария · сделай сам · я и мир · творчество.
Сервисы: каталог сайтов · рейтинг · поиск · работа · объявления · голосования · SMS · рассылка.
Досуг: фотогалерея · гороскопы · открытки · он-лайн игры · знакомства · анекдоты · тосты · чаты · конкурсы.

СПОРТ: 10 главных матчей футбольного сезона 2012/2013

МУЗЫКА: 50 главных песен 2013!

КИНО 2013: 10 лучших DVD в октябре 2013

ВОКРУГ СВЕТА: О путешествии в Лион

КИНО: Лучшие фильмы 2013! TOP-30!
Настроить панель ПОИСК:
 
Советы Что ищут?
Веб-разработка | К списку статей

Практическое использование SOAP в PHP 5

Автор: Корнеев Михаил
Источник: PHP в деталях

Предполагаемая аудитория

В этой статье описано новое SOAP-расширение для PHP. Статья предназначена для разработчиков, которые хотят создавать собственные веб-сервисы, либо работать с уже существующими. Статья предполагает, что читателю знакомы такие понятия как веб-сервис, SOAP и WSDL (Web Services Description Language).

Введение

SOAP (Simple Object Access Protocol) представляет из себя основанный на XML протокол, предназначенный для обмена структурированной информацией между распределенными приложениями поверх существующих в веб протоколов, например HTTP. Спецификация SOAP определяет формат, используемый XML-сообщениями, то, как они должны обрабатываться набор правил кодирования для стандарта, типы данных а также соглашения для вызова удаленных процедур и ответы на вызовы.

Веб-сервисы - это модная и современная технология. Список технологий, относящихся к веб-сервисам увеличивается практически ежедневно, но SOAP является, вероятно, наиболее важной из них. Он стремительно становится стандартным протоколом доступа к веб-сервисам. Он использует XML-сообщения для обмена информацией между конечными точками, и в тоже время предоставляет некоторые преимущества бинарных протоколов. Поддержка RPC (Remote Procedure Calls) в начале была одной из незначительных возможностей протокола SOAP, но сейчас она превратилась в одну из наиболее часто используемых возможностей.

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

В расширении SOAP реализованы большие подмножества спецификаций SOAP 1.1, SOAP 1.2 и WSDL 1.1. Главная цель - максимально использовать RPC-возможности SOAP. Везде, где это возможно используется WSDL, чтобы сделать реализацию веб-сервисов более простой.

Первый SOAP-клиент

Чтобы продемонстрировать создание простого SOAP-клиента используем демонстрационный сервис "Delayed Stock Quote" с сайта XMethods. Перед тем как мы начнем писать PHP-код, необходимо собрать следующую информацию о данном конкретном сервисе:

  • Имя метода
  • URL по которому расположен этот сервис
  • Значение заголовка SOAPAction метода
  • Пространство имен метода
  • Имена и типы входных и выходных параметров метода

К счастью, вся эта информация доступна на сайте XMethods по адресу http://www.xmethods.com/ из RPC-профиля сервиса:

Имя метода getQuote
URL сервиса http://66.28.98.121:9090/soap
SOAPAction urn:xmethods-delayed-quotes#getQuote
Пространство имен метода urn:xmethods-delayed-quotes
Входные параметры Symbol (String)
Выходные параметры Result (float)

Пример 1 (client1.php)

<?php

$client
= new SoapClient(NULL,
        array(
        
"location" => "http://66.28.98.121:9090/soap",
        
"uri"      => "urn:xmethods-delayed-quotes",
        
"style"    => SOAP_RPC,
        
"use"      => SOAP_ENCODED
           
));

print(
$client->__call(
        
/* Имя SOAP-метода */
        
"getQuote",
        
/* Параметры */
        
array(
            new
SoapParam(
                
/* Значение параметра */
                
"ibm",
                
/* Имя параметра */
                
"symbol"
        
)),
        
/* Опции */
        
array(
            
/* Пространство имен SOAP-метода */
            
"uri" => "urn:xmethods-delayed-quotes",
            
/* HTTP-заголовок SOAPAction  для SOAP-метода */
            
"soapaction" => "urn:xmethods-delayed-quotes#getQuote"
        
)). "\n");
?>

Как видите, решение этой простой задачи потребовало довольно много работы.

К счастью веб-сервисы могут описывать себя клиентам с помощью WSDL, в целом это довольно удобно. WSDL для сервиса "Delayed Stock Quote" представлен на его информационной страничке на сайте xmethods.com - http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl.

Вот вариант этого же клиента, переписанный для работы с помощью этого WSDL-документа. Здесь нам уже не нужно указывать URI-сервера, пространство имен, заголовок SOAPAction, способ кодирования и типы параметров. Вся эта информация берется из WSDL файла.

Пример 2 (client2.php)

<?php
$client
= new
    
SoapClient(
        
"http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl"
    
);

print(
$client->getQuote("ibm"));
?>

Так несколько проще, правда?

Какие проблемы возникают при использовании WSDL? Единственный аргумент против его использования состоит в том, что клиент должен прочитать WSDL с сервера до того, как можно будет вызвать какую-нибудь процедуру, а в веб это может занять довольно много времени. Для того, чтобы ускорить работу в SOAP-расширении предусмотрены следующие параметры конфигурации: soap.wsdl_cache_enabled, soap.wsdl_cache_dir and soap.wsdl_cache_ttl. Их можно задать в файле php.ini или с помощью ini_set()(см. Пример 4). По умолчанию кэширование WSDL включено и WSDL-файлы кэшируются на 1 день.

Вот раздел SOAP файла php.ini с значениями по умолчанию. Вы можете скопировать их в свой php.ini.

[soap]

soap.wsdl_cache_enabled = "1"
; включает или выключает кэширование WSDL

soap
.wsdl_cache_dir = "/tmp"
; задает имя директории в которой SOAP-расширение будет хранить кэшированные файлы

soap
.wsdl_cache_ttl = "86400"
; (время жизни) устанавливает время(в секундах) которое файлы из кэша могут использоваться

Первый SOAP-сервер

Попробуем написать собственный SOAP веб-сервис, который будет делать тоже, что и сервис "Delayed Stock Quote" с XMethods.

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

Раздел message определяет два сообщения. Первое - getQuoteRequest, которое передает сообщение getQuote и принимает одностроковый параметр с именем symbol. Второе сообщение - getQuoteResponse, ответ на запрос getQuote, передающий одно значение типа float с именем Result.

Раздел portType определяет единственную операцию getQuote, которая указывает, какое из описанных в разделе message будет использоваться для запроса, а какое для ответа.

В разделе binding определяется как сообщение должно кодироваться и передаваться. В данном случае в нем указано, что мы пошлем RPC-запрос через HTTP, используя SOAP-кодирование. Здесь также определены пространство имен и значение заголовка SOAPAction для метода getQuote.

И наконец в разделе service определяется URL по которому находится сервис.

Пример 3 (stockquote.wsdl)


<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='StockQuote'
 targetNamespace='http://example.org/StockQuote'
 xmlns:tns=' http://example.org/StockQuote '
 xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
 xmlns:xsd='http://www.w3.org/2001/XMLSchema'
 xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
 xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
 xmlns='http://schemas.xmlsoap.org/wsdl/'>

<message name='getQuoteRequest'>
 <part name='symbol' type='xsd:string'/>
</message>
<message name='getQuoteResponse'>
 <part name='Result' type='xsd:float'/>
</message>

<portType name='StockQuotePortType'>
 <operation name='getQuote'>
  <input message='tns:getQuoteRequest'/>
  <output message='tns:getQuoteResponse'/>
 </operation>
</portType>

<binding name='StockQuoteBinding' type='tns:StockQuotePortType'>
 <soap:binding style='rpc'
  transport='http://schemas.xmlsoap.org/soap/http'/>
 <operation name='getQuote'>
  <soap:operation soapAction='urn:xmethods-delayed-quotes#getQuote'/>
  <input>
   <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
    encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
  </input>
  <output>
   <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
    encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
  </output>
 </operation>
</binding>

<service name='StockQuoteService'>
 <port name='StockQuotePort' binding='StockQuoteBinding'>
  <soap:address location='http://[insert real path here]/stockquote1.php'/>
 </port>
</service>
</definitions>

Замечание: по умолчанию кэширование WSDL включено. На время разработки и отладки вашего WSDL, кэширование лучше отключить.

Теперь самое время приступить к созданию нашего сервера.

Прежде всего мы разработаем функцию getQuote(), которая будет обрабатывать входящие запросы из веб. Далее мы создадим объект класса SoapServer и присоединим к нему нашу функцию с помощью метода SoapServer::addFunction(). Как вы увидите в дальнейшем, у конструктора SoapServer() есть только один параметр - путь к WSDL-документу, описывающему сервис.

Пример 4 (server1. php)

<?php
$quotes
= array(
  
"ibm" => 98.42
);   

function
getQuote($symbol) {
  global
$quotes;
  return
$quotes[$symbol];
}

ini_set("soap.wsdl_cache_enabled", "0"); // отключаем кэширование WSDL
$server = new SoapServer("stockquote1.wsdl");
$server->addFunction("getQuote");
$server->handle();
?>

SoapServer может работать и без WSDL, примерно также как клиент, но у такого варианта нет никаких преимуществ, из-за которых стоило бы его использовать. Если вы все же хотите работать именно так, вы должны убедиться что возвращаемые значения - это объекты классов SoapParam и SoapVar(как в первом примере.

Вот клиент для доступа к нашему SOAP-серверу. По сравнению с предыдущим примером добавилась только ссылка на местонахождение WSDL. Предполагается, что файл "stockquote1.wsdl" лежит в той же директории что и SOAP-сервер.

Пример 5 (client3.php)

<?php
  $client
= new SoapClient("stockquote1.wsdl");
  print(
$client->getQuote("ibm"));
?>

Какие основные проблемы есть в наших клиенте и сервере?

Для начала, они не обрабатывают ошибки. Что происходит, когда сервер не находит подходящий результат для переданного ему значения переменной symbol? В SOAP существует специальный формат сообщений для сообщений об ошибках - SoapFault.Чтобы сгенерировать такое сообщение, сервер должен вызвать исключение с помощью объекта SoapFault. Первый параметр конструктора SoapFault() это строка с кодом ошибки, второй - строка с описанием ошибки. Клиент должен быть написан так, чтобы обрабатывать исключения SoapFault.

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

Пример 6 (server2.php)

<?php
class QuoteService {
  
private $quotes = array("ibm" => 98.42);   

  function
getQuote($symbol) {
    if (isset(
$this->quotes[$symbol])) {
      return
$this->quotes[$symbol];
    } else {
      
throw new SoapFault("Server","Unknown Symbol '$symbol'.");
    }
  }
}

$server = new SoapServer("stockquote2.wsdl");
$server->setClass("QuoteService");
$server->handle();
?>

Как видите, я использовал метод SoapServer::setClass() для соединения объекта SoapServer с классом QuoteService.

Пример 7 (client4.php)

<?php
  $client
= new SoapClient("stockquote2.wsdl");
  
try {
    echo
"<pre>\n";
    print(
$client->getQuote("ibm"));
    echo
"\n";
    print(
$client->getQuote("microsoft"));   
    echo
"\n</pre>\n";
  }
catch (SoapFault $exception) {
    echo
$exception;       
  }
?>

А что внутри?

Если вы хотите разобраться в формате SOAPсообщений, или хотите самостоятельно отлаживать SOAP-клиента, то этот раздел для вас.

Как вы видели в первом примере, конструктор SoapClient() принимает ассоциативный массив в качестве второго параметра. С помощью этого массива мы можем вызывать различные опции на сервере.

Посмотрим две из них:

  • trace - позволяет клиенту сохранять SOAP-запросы и ответы (по умолчанию выключено).
  • exceptions - позволяет клиенту контролировать механизм исключений (по умолчанию включено).

Посмотрим на следующий пример SOAP-клиента. Это доработанный клиент из Примера 5, в точности показывающий, что передается между клиентом и сервером. Для получения этой информации используются методы __getLastRequest() и __getLastResponse().

Пример 8 (client5.php)

<?php
  $client
= new SoapClient("stockquote1.wsdl",array(
    
"trace"      => 1,
    
"exceptions" => 0));
  
$client->getQuote("ibm");
  print
"<pre>\n";
  print
"Запрос :\n".htmlspecialchars($client->__getLastRequest()) ."\n";
  print
"Ответ:\n".htmlspecialchars($client->__getLastResponse())."\n";
  print
"</pre>";
?>

Вот вывод скрипта. Он немного изменен, для упрощения понимания.

Запрос:


<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:ns1="urn:xmethods-delayed-quotes"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
 <ns1:getQuote>
  <symbol xsi:type="xsd:string">ibm</symbol>
 </ns1:getQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Ответ:


<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:ns1="urn:xmethods-delayed-quotes"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
 <ns1:getQuoteResponse>
  <Result xsi:type="xsd:float">98.42</Result>
 </ns1:getQuoteResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Другие реализации SOAP для PHP

Все они написаны на PHP, а не на Си.

Резюме

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

  1. Поддержка комплексных типов данных (массивов, объектов)
  2. Поддержка SOAP - заголовков
  3. Динамическая поддержка SOAP 1.1 и SOAP 1.2

Возможно они будут более подробно рассмотрены в последующих статьях.

Подробная документация по SOAP-расширению расположена по адресу http://www.php.net/manual/en/ref.soap.php.

Разработка этого расширения находится на начальном этапе, поэтому ваши отзывы помогут сделать его более стабильным, надежным, удобным и быстрым. Пожалуйста сообщайте о всех возникающих при его использовании проблемах по адресу http://bugs.php.net/.

Ссылки

Об авторе

Дмитрий Стогов - один из авторов SOAP-расширения. Он также написал расширение PECL/perl и Turck MMCache. В настоящее время он проживает в Санкт Петербурге с женой и ребенком. Вы можете связаться с ним по адресу dmitry@zend.com.