Работа с уеб услуги

Никитин Иван ZCE, MCSD ivan[at]nikitin.org

В статията http://www.phpworld.ru/articles/soapclient.php Леонид Лукин показа много добре колко просто и лесно е да създадете клиент на уеб услуга, който да извиква отдалечена услуга и да получава данни от външен сървър. Просто бих искал да допълня тази статия с някои практически примери.

Microsoft .Net уеб услуги

Напоследък уеб услугите станаха доста широко разпространени и се използват по различни начини: от просто предоставяне на референтни данни в мрежата, например данни за пристигането на самолети (уеб услуга на летище Шереметиево), обменни курсове и ценни метали (Централна банка на България) до работа с кредитни карти (асистиращ център за обработка) и онлайн текстови преводи (бърза уеб услуга). Има още повече корпоративни уеб услуги, които решават различни корпоративни задачи.

Мисля, че технологията .Net на Microsoft е допринесла много за това широко използване на уеб услугите. Факт е, че създаването на уеб услуга в същото Microsoft Visual Studio .Net 2003 е невероятно просто. Грубо казано, достатъчно е да напишете свой собствен клас, наследен от класа System.Web.Services.WebService и да декларирате неговите методи като Web методи. И това е! Компилирайте, прехвърлете на производствен сървър и вашата нова уеб услуга е готова за работа!

Всичко това значително улеснява разработката и затова повечето уеб услуги, поне в България, са написани на някакъв .Net език и работят на .Net платформата.

Запознаването с уеб услугата .Net е достатъчно лесно. Първо, файлът, до който се осъществява достъп, има разширение asmx, и второ, при обикновен достъп до този файл (методът GET), уеб услугата .Net генерира HTML страница сописание на техните методи, което също е доста удобно. В допълнение, .Net Web Services могат да отговарят не само на SOAP заявки, но и на редовни POST и GET заявки. Но това са повече допълнителни функции, „функции“, които освен това могат да бъдат деактивирани от разработчика и ние не се разглеждаме тук.

Въпреки това, когато се опитва да използва .Net Web Services, PHP разработчикът може да срещне редица проблеми, чието решение ще покажем тук. Като пример ще създадем PHP клиент за уеб услугата на Централна банка на България и ще получаваме от него текущи обменни курсове за всяка дата.

Писането на всяка уеб услуга започва с изучаване на WSDL документа - описание на самата уеб услуга, нейните методи, параметри на метода и типове данни. За .Net WSDL уеб услуги описанието се генерира автоматично, просто отворете уеб услугата с параметъра "?wsdl" в URL реда: http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl

За да получите данни за обменните курсове, ще използвате метода на уеб услугата GetCursOnDateXML, който, съдейки по описанието, трябва да реализира „Получаване на дневни обменни курсове (като XMLDocument)“. Намерете този метод в WSDL описанието:

Получавайте дневни обменни курсове (като XMLдокумент)

Обърнете внимание на описанието на входните и изходните съобщения, тоест какви параметри и какъв тип изисква тази уеб услуга при извикване и какво всъщност ще ви върне. Помислете за тези съобщения:

Моля, имайте предвид, че и двете съобщения са complexType (сложен тип), който се състои от последователност (последователност) от елементи. С други думи, това са обекти с набор от свойства.

Факт е, че за да обедини описанието на своите методи, платформата .Net използва техника, при която се приема, чевсеки метод получава един параметър при извикване и този параметър е обект, който има свойства, дефинирани с имената на аргументите на извикването - това всъщност са самите аргументи на извикването. При отговор методът ще ви върне обект, който има едно свойство, наречено MethodNameResult. Типът на това свойство зависи от описанието на уеб метода, по-точно от това какво ви връща. Ако е прост тип, тогава ще бъде дефиниран като скаларен тип (низ, число, булево), ако е сложен (например масив от данни), тогава ще бъде дефиниран като асоциативен масив с произволен елемент или отделна схема на данни (например, ако уеб услугата върне набор от данни System.Data.Dataset).

Ако в описанието на отговора видите нещо подобно:

Тогава най-вероятно говорим за връщане на класа Dataset при вас, чийто анализ, макар и не труден, все още е тема на отделна статия. Нека се опитаме да приложим извикване на .Net Web услуга на практика и ще видим, че е много просто.

Уеб услуга клиент на Централна банка на България

И така, имаме нужда от PHP5 за това със свързан SOAP модул. Нека създадем CBR клас:

клас CBR // Централна банкова услуга WSDL const WSDL = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL"; // Екземпляр на клас SoapClient защитен $soap; // Инициализация публична функция __construct() $this->soap = new SoapClient(CBR::WSDL); > >

Метод за извикване на уеб услуга

За да извикаме метода GetCursOnDateXML, трябва да му предадем параметъра On_date, а този параметър е от типа dateTime. Това може да се види от WSDL описанието:

Представянето на дата и час за SOAP повиквания е описано в документаhttp://www.w3.org/TR/xmlschema-2/#dateTime, ще напишем функция, която ще направи такава трансформация:

// Параметри: // $timeStamp - дата/час в UNIX формат // $withTime - незадължително, ако е вярно, // след това преобразуване заедно с час от деня, // в противен случай само дата функция getSOAPDate($timeStamp, $withTime = false) $soapDate = date("Y-m-d", $timeStamp); връщане ($withTime)? $soapDate. "T" . date("H:i:s", $timeStamp) : $soapDate. "T00:00:00"; >

Сега всъщност можете да се обадите на уеб услугата

// Методът връща XML низ с резултатите от извикването на уеб услугата // Параметри: // $date - датата, за която е направена заявката function getXML($date) // Низът с дата, за която е направено извикването $currentDate = $this->getSOAPDate($date); // Формиране на масив от параметри $params["On_date"] = $currentDate; // Извикване на уеб услугата $response = $this->soap->GetCursOnDateXML($params); // Връщане на резултата return $response->GetCursOnDateXMLResult-> ;всеки; > ;

Моля, обърнете внимание, че параметърът за повикване On_date се формира като елемент от асоциативния масив $params, който се предава на уеб услугата. Ние четем отговора (XML низ) от $response->GetCursOnDateXMLResult->any свойство, което е дефинирано от WSDL описанието.

В получения код леко усложних този метод: запазвам получената дата в свойство на класа и също запазвам отговора на услугата и преди извикване просто проверявам дали предишното повикване е било на същата дата и ако е така, тогава не се прави истинското повикване, а се връща само предишният (записан) резултат. Това се прави, за да се ускори работата: всяко повикване на уеб услуга е доста бавно мрежово взаимодействие с отдалечен сървър. Освен това е силноПрепоръчвам да активирате кеширането на WSDL документи за SOAP модула. Това може да стане в настройките на php.ini или във файла .htaccess:

[сапун] ; Активира или деактивира функцията за кеширане на WSDL. soap.wsdl_cache_enabled=1 ; Задава името на директорията, където SOAP разширението ще поставя кеш файлове. soap.wsdl_cache_dir="C:WindowsTemp" ; (време за живот) Задава броя секунди, докато се използва кешираният файл ; вместо оригинален. soap.wsdl_cache_ttl=86400

В този случай, при всяка инициализация на вашия клас (при създаване на екземпляр на класа SoapClient), PHP няма да изисква WSDL от отдалечения сървър, а ще го взема от кеша, което също ще има положителен ефект върху производителността.

Разбор на XML низ - отговор на уеб услугата И така, получихме XML низ в резултат на извикване на уеб услугата на Централна банка на България. Този XML документ съдържа данни за обменните курсове за определена дата. Ако просто отпечатате резултата на екрана (или изведете във файл), можете да видите неговата структура: Австралийски долар 1 20,8448 36 AUD . . .

Както се казва, обясненията са излишни. Нека се опитаме да го анализираме и да получим данните за необходимата валута. За да анализирам този XML документ, използвах модула SimpleXML, който идва с PHP5. Избрах модула SimpleXML по две причини: първо, той е бърз и удобен за просто анализиране на XML документи, и второ, има много удобен XPath метод, който ви позволява да избирате възли на документа чрез XPath израз. Разбира се, същото може да се направи със стандартен DOM анализ, но с SimpleXML кодът е по-кратък. Нека напишем функция за избор на валутен курс по нейния код:

// Параметри: // $currencyCode - код на валутата: USD, EUR и др. // $date - незадължително, датата, на коятозаявка, // 0 - днес функция getRate($currencyCode, $date = 0) if (!$date) $date = time(); $xml = simplexml_load_string($this->getXML($date)); $xPath = "/ValuteData/ValuteCursOnDate[VchCode=''$currencyCode'']"; $резултат = $xml->xpath($xPath); if (count($result) == 0) върне 0; връща $result[0]->Vcurs / $result[0]->Vnom; >

Вижда се, че получаваме два параметъра: код на валута и дата (датата не е задължителна), правим заявка с помощта на функцията getXML и зареждаме отговора в SimpleXML обект. След това формираме XPath израз за избиране на възела ValuteCursOnDate чрез стойността на възела VchCode. В резултат на това методът $xml->xpath връща масив от избраните възли. Ако масивът е празен, тогава няма такъв код на валута в отговора. Ако има код, тогава 0-ият елемент от масива е нашата валута. Нека вземем неговия курс и го разделим на номиналната стойност.

Всичко, текущата ставка е получена.

Във финалния код написах и метод, който формира асоциативен масив от кодове на валути и техните имена в класа. Този метод се извиква в конструктора на класа, който незабавно създава един вид препратка към валутен код като свойство на класа (например $cbr-> currencyCodes). Удобно е да го използвате, например, за такава страница: