→

PHP программирование →  Пишем веб-сервис с использованием протокола SOAP

В главных ролях:
— фреймворк CodeIgniter
— протокол SOAP
— методы getCategories() и getVideos($params = array()) — придуманы для примера
— сайт www.videobox.su используется просто, как заглушка, просто не хотел писать yourdomain.com

Для чего нам нужен SOAP


У нас есть ресурс с определенными данными, например, это будет видео ресурс. Мы хотим дать возможность другим ресурсам тянуть данные с нашего сайта. Было бы хорошо дать возможность сторонним программистам вызывать наши методы. Именно с вызовом удаленных процедур нам поможет SOAP.

Структура сей системы:

— Клиент
— Сервер

Пишем сервер


Мы хотим отдать на доступ два метода getCategories(), который будет возвращать список всех категорий нашего сайта и getVideos($params = array()) — он будет отдавать список видео с информацией в зависимости от входящих параметров $params.

Для начала нам необходимо создать WSDL документ, который опишет два наших метода (имеа методов, входящие данные и возвращаемые данные), по сути это файл в обычном XML формате.
Назовем наш файл webservice.wsdl и положим его по адресу http://videobox.su/webservice/webservice.wsdl
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='webservice'
targetNamespace='uri:webservice'
xmlns:tns='uro:webservice'
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/'>

<types>
<!-- описываем тип данных ArrayOfParams, т.к. просто входящим параметром данные типа Array SOAP принимать не умеет -->
        <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2000/10/XMLSchema">
                <complexType name="ArrayOfParams">
                        <complexContent>
                                <restriction base="soapenc:Array">
                                        <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
                                </restriction>
                        </complexContent>
                </complexType>
        </schema>
</types>
<message name='getVideosRequest'>
        <part name='params' type='xsd:ArrayOfParams'/>
</message>
<message name='getVideosResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<!-- т.к. входящих параметров для метода getCategories() нет, мы не описываем Request -->
<message name='getCategoriesResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<portType name='webservicePortType'>
        <operation name='getVideos'>
                <input message='tns:getVideosRequest'/>
                <output message='tns:getVideosResponse'/>
        </operation>
        <operation name='getCategories'>
                <input message='tns:getCategoriesRequest'/>
                <output message='tns:getCategoriesResponse'/>
        </operation>
</portType>
<binding name='webserviceBinding' type='tns:webservicePortType'>
  <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
  <operation name='getVideos'>
    <soap:operation soapAction='urn:webservice-video#getVideos'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
  <operation name='getCategories'>
    <soap:operation soapAction='urn:webservice-video#getCategories'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
</binding>
<service name='webserviceService'>
        <port name='webservicePort' binding='webserviceBinding'>
<!-- URL к нашему серверу -->
                <soap:address location='http://videobox.su/webservice/'/>
        </port>
</service>
</definitions>


Создадим контроллер, который и будет являться нашим сервером.
<?
class Webservice extends Controller{
        function __construct(){
                parent::Controller();
                $this->load->model("video");
                $this->load->model("category");

        }
        function index(){
                function getVideos($params) {
                        $CI = &get_instance ();
                        $videos = array();
//проверка входящих данных
                        if(!is_array($params) || sizeof($params) == 0) {
                                throw new SoapFault("Server:", '$params' . " has wrong format. Can be Array();");
                        }
                        else {
                                return $CI->video->getVideo($params); // выборка данных по видео, здесь можно описать свой код, для краткости сделан вызов из модели
                        }

                }
                function getCategories() {
                        return $CI->category->getAll();  // выборка данных по категориям, здесь можно описать свой код, для краткости сделан вызов из модели
                }

                ini_set("soap.wsdl_cache_enabled", "0"); // отключение кеширования wsdl файла
                $server = new SoapServer("http://videobox.su/webservice/webservice.wsdl?" . rand()); // случайное число добавляем для дебага, т.к. wsdl файл сразуже кешируется и не всегда есть доступ к php.ini или к функции ini_set для отключения кеширования на кремя дебага
                $server->addFunction("getVideos");
                $server->addFunction("getCategories");
                $server->handle();
        }

?>

Наш сервер готов и доступен по адресу http://videobox.su/webservice/.

Пишем клиент


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

Опять же, создаем контроллер Webserviceclient (если клиент использует CodeIgniter) или не создаем, а а просто используем код, который описан в методе контроллера index(). В любом случае он будет доступен там, где вы его создали.

<?
class Webserviceclient extends Controller{
  function __construct(){
      parent::Controller();
  }
 
        function index(){
                try {
                        $client = new SoapClient("http://videobox.su/webservice/webservice.wsdl?" . rand(),
                                                                                array(
                                                                                        "trace"      => 1,
                                                                                        "exceptions" => 0
                                                                                )
                                                                        );//второй параметр необходим для отладки, является не обязательным
                $params = array(
                        "vid" => 64, //выбираем видео с ID = 64
                );
                print "<pre>";
                print_r($client->getVideos($params)); // вызов метода сервера на выборку данных по видео
                //print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
"; // показать запрос к серверу (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
"; // показать ответ сервера (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                print_r($client->getCategories()); // вызов метода сервера на выборку доступных категорий
                //print "
Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
";
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
";
                print "
</pre>";
                }
                catch (Exception $e){
                        print $e;
                        echo 'Error Caught';
                }
        }
 
}
?>


В результате мы получим вывод двух массивов данных или в чем придумаете выдачу данных в своей реализации.

Статья была написана в качестве примера, т.к. в интернете не было найдено ничего толкового, а именно были описаны абстрактные примеры, которые трудно соединить в систему, так же сложно было найти, как передать массив в качестве параметра:)
0
7