Статьи

Веб-сервисы Amazon с PHP и nuSoap

Вступление

[РЕДАКТИРОВАТЬ] — Это перефразирование документа, который я написал пару лет назад. В библиотеку nuSOAP были внесены изменения, и я хотел задокументировать обновления, относящиеся к серии учебников. Кроме того, мне нужно исправить множество неработающих ссылок и списков кодов, поскольку я меняю провайдеров хостинга с тех пор, как эта статья была впервые написана.

Эта статья относится к выпуску nuSOAP 0.9.5 2011-01-13. Этот урок был обновлен 22 сентября 2011 года.

Когда-то мой босс поручил мне разработать веб-сервисы в качестве точки интеграции между нашим производственным приложением и отделом продаж. На данный момент, хотя я слышал о веб-сервисах … вроде … разве Amazon не использовал веб-сервисы для чего-то? Тем не менее, я никогда не кодировал приложения на основе веб-сервисов.

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

В свое время сетевые сервисы (семафоры, каналы, потоки, очереди сообщений и другие формы IPC) были написаны на заказ и назначены / подчинены уникальным сетевым портам для доступа к определенным демонам сервисов. Конечно, в то время Интернет был более добрым, более мягким местом … и на данном сервере могли быть открыты десятки или даже сотни нестандартных портов, которые прослушивали и ждали запросов сетевых служб. Или попытки взлома.

Сегодня веб-сервисы являются заменой выделенным сетевым приложениям — все они обрабатываются вашим веб-сервером и обслуживаются через один и тот же сетевой порт: порт 80. Поскольку порт 80 является стандартным портом и, как правило, уже открыт на веб-сервере дополнительные риски для безопасности за счет открытия новых нестандартных портов для сетевых служб предотвращены. Ваш веб-сервер, такой как Apache, теперь отвечает за обработку запроса и доставку результатов клиенту.

Компонент веб-сервисов — это набор написанных вами функций, которые предоставляют удаленным клиентам доступ к вашей системе. Эти функции доступны только через платформу веб-сервисов, и, хотя они могут быть продублированы из специализированного и традиционного веб-приложения, каркас веб-сервисов разработан как отдельное программное обеспечение.   Думайте о части веб-сервисов как о уровне обработки данных вашего приложения минус уровень представления. «М» и «С» модели «MVC».

Первоначально, когда мне поставили задачу подобного рода задачи, я сначала попробовал xml-rpc. Это привело меня к кроличьей норе, которая занимала почти неделю моего времени с конечным результатом — оставлением. Я ударил дорожные блоки с помощью xml-rpc через проверку подлинности сервера и прохождение сложных объектов. В целом проблема усугубляется тем, что xml-rpc кажется устаревшей технологией — мне было трудно найти ресурсы, которые были недавно.

Затем я наткнулся на nuSOAP — он бесплатный через sourceForge , стабильный и, используя цитату из sourceForge:

«NuSOAP — это переписанный SOAPx4, предоставленный NuSphere и Dietrich Ayala. Это набор классов PHP — не требующих расширений PHP — которые позволяют разработчикам создавать и использовать веб-службы на основе SOAP 1.1, WSDL 1.1 и HTTP 1.0 / 1.1 ».

Похоже, в nuSOAP было больше всего: учебники, примеры, статьи, посты в блогах. Когда я начал реализацию с nuSOAP, первым делом я получил помощь по аутентификации на уровне сервера. Я был в состоянии немедленно проверить мои удаленные запросы веб-сервером и передать модулю веб-сервисов!

Для меня главное преимущество nuSOAP в том, что nuSOAP самодокументируется. Как часть функциональности API, nuSOAP генерирует HTML-страницы, которые документируют предоставляемые сервисы через WSDL, а также предоставляет вам полный файл определения XSLT!

Прежде всего, скачайте и установите библиотеки nuSOAP — я предоставил ссылку на сайт sourceForge пару абзацев назад — и распакуйте архив. В итоге вы получите каталог (мой называется: ./nuSOAP), и в этом каталоге вы найдете единственный файл: nusoap.php .

В этом уроке есть две части — часть на стороне сервера и часть на стороне клиента. Хотя вы можете выполнять обе части из одной и той же среды (машины), обычно вы используете удаленный клиент для доступа к API-коду на стороне сервера.

Что не покрыто:

Apache. Конфигурация Apache для вашего vhost. Apache .htaccess. В этой статье предполагается, что у вас есть работающий сервер и что вы можете установить и получить доступ к файлам сервера через Apache. Даже если ваш сервер Apache имеет конфигурацию localhost, доступ к файлам на стороне сервера с помощью клиента localhost, проходящий через стек TCP локально, по-прежнему является допустимым методом тестирования приложения сервера веб-служб.

 

Пора засунуть рукава и начать работать над кодом сервера…

Сервер веб-сервисов

Сегодня мы собираемся написать ping-сервер, где у сервера есть открытый сервис (метод) с именем «ping», который принимает один аргумент (строку) и возвращает массив обратно вызывающему клиенту. Возвращаемый массив содержит два ассоциативных члена: логическое значение (которое всегда должно быть истинным — в противном случае возникают другие проблемы…) и строка, которая является модификацией исходной строки, чтобы доказать, что да, мы пошли туда и вернулись ,

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

Итак, если этот файл, который я назвал index.php , кажется маленьким, помните, что вы не просматриваете зависимые файлы (пока).

<pre><?php
/**
 *
 */

// setup...
require('./nuSOAP/nusoap.php');
// set namespace and initiate soap_server instance
$namespace = "http://myapi/index.php";
$server = new soap_server('');
// name the api
$server->configureWSDL("myapi");
// assign namespace
$server->wsdl->schemaTargetNamespace = $namespace;
// register services
require('myServiceRegistrations.php');
// load WSDL...
include('mywsdl.php');
// load services code modules...
require('myServicesModules.php');
// create HHTP listener:
$request = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($request);
exit();
?></pre>

Пока все хорошо — давайте посмотрим на то, что мы только что сделали:

  • мы включили библиотеку nu_soap …
  • объявил наше пространство имен (которое является URL-адресом сервера API)
  • инстанцировал новый экземпляр soap_server и назначил его переменной $ server
  • инициализировал WSDL
  • назначил переменную пространства имен для WSDL
  • загрузить и зарегистрировать наши услуги
  • загрузить WSDL
  • загрузить сервисный код
  • создать прослушиватель HTTP
  • вызвать запрашиваемую услугу
  • выход

Этот файл (index.php) является файлом на стороне сервера, который будет вызываться для ВСЕХ будущих вызовов API для службы. Он вызывает три управляющих файла, которые, в свою очередь, загружают сервисы (определения WSDL), определения переменных WSDL (воспринимаем их как входы и выходы для предоставляемых вами сервисов) и фактический код для всех сервисов и их поддерживающих функций. что вы собираетесь выставить через свой API.

Примечание: это файл, на который вы будете ссылаться в Apache, когда (желательно) создаете новый виртуальный хост для API. HTTP-запросы, которые разрешаются на ваш сервер, будут обслуживаться Apache, который, в свою очередь, будет передавать результаты этой программы клиенту.

Далее мы собираемся определить  файл myServiceRegistrations.php, который требуется для index.php . Этот файл содержит WSDL для каждой открытой службы, которую обслуживает API.

<pre><?php
/**
 *
 *
 */

$server->register('ping', array('testString' => 'xsd:string'),
                          array('return' => 'tns:aryReturn'),
                  $namespace, false, 'rpc', 'encoded',
'<p><strong>Summary</strong>: returns response to a ping request from the client.  Response
includes testString submitted.  Used to test Server response/connectivity.
</p>
<p>
<strong>Input</strong>: $testString (type: string) and random collection suffices.
</p>
<p>
<strong>Response</strong>: Service returns an array named $aryReturn with two associative
members: "status" and "data".<br />$aryReturn["status"] should
<i>always</i> return true.  (A time-out is an implicit false.)<br />If no value was passed
to the service via $testString, then the value of $aryReturn["data"] will be
empty.<br />Otherwise it will contain the string: "Rcvd: {yourString} (count)" to
show that the message was received and returned. (count) is a character count of the
passed string, also validating that the passed data was received and processed.
</p>
');</pre>

Этот код PHP регистрирует функцию ping с экземпляром сервера nuSOAP $. Второй параметр — это вход для функции. Обратите внимание, что все входные (и выходные) параметры должны быть объявлены как массив, даже если передается только одно значение. Также обратите внимание, что вам нужно привести тип к переменной, передаваемой с использованием типов данных XML. Для своих определений данных вы используете один из 44 встроенных типов данных, определенных в этом документе:  http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/ .

(Для получения дополнительной информации об объекте XSD и схеме XML, пожалуйста, посетите:  http://ws.apache.org/axis/cpp/arch/XSD_Objects.html .)

Третий аргумент метода «register» — это возвращаемый тип данных. Это сложная переменная под названием «aryReturn» — не беспокойтесь прямо сейчас, мы собираемся определить эту переменную сложного типа в другом файле конфигурации.

Следующие четыре аргумента:

  • наша переменная $ namespace мы устанавливаем в index.php
  • логическое значение false
  • ‘rpc’ для типа звонка
  • «Закодированы»

Используйте эти значения буквально.

Последняя переменная — это огромный блок HTML.
Этот блок HTML может быть настолько большим или настолько маленьким, насколько вам нужно. Это основа для документации WSDL, которую nuSOAP генерирует для ваших клиентских разработчиков.

Когда разработчики обращаются к URL-адресу сервера, им будет предоставлена ​​документация по API, которую nuSOAP создает из файла (ов) WSDL.
По мере роста вашего API открытые методы будут перечислены в поле синего цвета в левой части экрана. Нажатие на любой из методов покажет детали (требования) об этом методе, таким образом:

Хорошо, а?

Второй файл (который мы включили в наш источник: (mywsdl.php)) — это файл WSDL, который определяет наши структуры данных, которые используются в качестве входов, выходов или и того, и другого для предоставляемых сервисов. Еще одна вещь, которая мне нравится в SOAP и nuSOAP, это то, что она вводит слой строгой типизации в стек PHP. Вы можете сэкономить немного времени на отладку, требуя, чтобы вы вызывали метод с ТОЧНО этим и возвращали ТОЧНО это. Все остальное имеет тенденцию генерировать системную ошибку:

<pre>[Thu Sep 22 14:36:59 2011] [error] [client ::1] PHP Fatal error:  Call to a member function addComplexType() on a non-object in /htdocs/LL2/trunk/services/mywsdl.php on line 9
[Thu Sep 22 14:36:59 2011] [error] [client ::1] PHP Stack trace:
[Thu Sep 22 14:36:59 2011] [error] [client ::1] PHP   1. {main}() /htdocs/LL2/trunk/services/ll2wsdl.php:0</pre>
<pre>

Это сообщение об ошибке из журнала ошибок apache несколько запутано в своем значении. Я попытался вернуть только строку, а не возвращать массив (из двух элементов), который я сказал nuSOAP, что я вернусь для этой службы. Эта ошибка возникла из-за того, что типы (между кодом и WSDL) возвращаемой переменной (структуры) точно не совпадали.

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

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

При этом давайте посмотрим на WSDL для нашего сервиса ping:

<pre><?php
/**
 * WDSL control structures
 *
 * initially, while in dev, this will be one large file but, later, as the product
 * matures, the plan will be to break out the WSDL files into associative files based
 * on the object class being defined.
 */
$server->wsdl->addComplexType('aryReturn', 'complexType', 'struct', 'all', '',
            array('status' => array('name' => 'status', 'type' => 'xsd:boolean'),
                  'data'   => array('name' => 'data',   'type' => 'xsd:string')));</pre>

Мы вызываем метод nuSOAP addComplexType  для определения структуры WSDL в нашем пространстве имен таблиц  (tns). Для этого мы сначала определяем имя структуры, которую мы будем использовать: aryReturn,  а затем определяем состав этой структуры.

Объявление для этого выглядит во многом как стандартное объявление PHP для массива, за исключением XSD (определения схемы XML), добавляемого в конце объявления каждого элемента. (См. Ссылки, которые я вставил выше для объяснений и примеров правильного XSD.)

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

Таким образом, мы имеем ассоциативный массив с двумя элементами: «статус» и «данные». $ aryReturn [‘status’] и $ aryReturn [‘data’], и они имеют тип BOOL и STRING соответственно.

Наконец, обратите внимание, что эта структура переменных не ограничивается одноразовым использованием. Как только мы объявили об этом в наших tns , он будет доступен для любой открытой службы, где это необходимо. Это модель для моей общей структуры ошибок — логическое значение указывает на успешное или неудачное выполнение какой-либо операции службы, а компонент данных содержит относительную диагностическую информацию.

Третий и последний файл, который мы включаем в исходный код сервера, — это код для предоставляемой службы. Здесь вы пишете обработчики функций для ваших сервисов. Поскольку вы уже определили входные параметры и типы возвращаемых данных для службы ping, осталось сделать очень мало.

<pre><?php
/**
 * ping
 *
 * service that confirms server availability
 *
 * input: any string
 *
 * output: reformatted string:  "Rcvd: {string} (charcount{string})"
 *
 * @param string $testString
 * @return string
 */
function ping($testString = '') {
    return(array('status' => true, 'data' => 'Rcvd: ' . $testString . '(' . strlen($testString) . ')'));
}</pre>

Обратите внимание на следующее в коде нашего предоставляемого сервиса:

  • наш открытый метод называется ping,  потому что именно так мы зарегистрировали сервис (myServiceRegistrations.php)
  • мы предоставляем приведение типа по умолчанию для входного параметра строки в случае, если служба вызывается без входных параметров.
  • мы возвращаем BOOL true и добавляем «Rcvd:» к полученной строке и добавляем количество символов, чтобы доказать, что сервис успешно ответил на запрос клиента.
  • структура возврата точно  соответствует объявлению WSDL: имя элементов массива и типы элементов.

Если вы правильно установили и обратились (в своем PHP) к библиотекам nuSOAP, то вы сможете загрузить URL нового исходного файла сервера в ваш веб-браузер, чтобы увидеть сгенерированную nuSOAP документацию для ваших новых веб-сервисов.
Нажмите на сервисную функцию WSDL:
ping, чтобы увидеть подробное описание функции.

Если вы используете IE, то, нажав на ссылку WSDL, вы получите XML. Если вы используете Firefox, Chrome или другие браузеры, щелчок по WSDL отобразит сгенерированный XML для вашего сервиса.

Теперь, когда сервер работает сам по себе, он остается довольно бесполезным, пока мы не сможем заставить клиента подключиться к нему и вызвать его методы. Давайте работать над клиентом дальше …

Клиент веб-сервисов

Клиентское приложение веб-служб также будет написано на PHP.

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

В нашем клиенте мы не собираемся требовать удаленной аутентификации — но я вкратце расскажу, как бы вы включили это, на стороне клиента, если ваш сервер требует. аутентификация htaccess .

В nuSOAP есть клиентский метод setCredentials,  который позволяет вам указать имя пользователя и пароль .htaccess, а также схему аутентификации. Это одна строка кода, которая обычно используется для того, чтобы не только клиенты входили в систему для доступа к вашему API, но после идентификации вы можете ограничить набор доступных методов, доступных для отдельных клиентов или групп.

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

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

Итак, к клиентскому коду: (назовите этот файл: apiTestClient.php )

<pre><?php
// Pull in the NuSOAP code
require_once('./nuSOAP/nusoap.php');
$proxyhost = isset($_POST['proxyhost']) ? $_POST['proxyhost'] : '';
$proxyport = isset($_POST['proxyport']) ? $_POST['proxyport'] : '';
$proxyusername = isset($_POST['proxyusername']) ? $_POST['proxyusername'] : '';
$proxypassword = isset($_POST['proxypassword']) ? $_POST['proxypassword'] : '';
$useCURL = isset($_POST['usecurl']) ? $_POST['usecurl'] : '0';
$client = new nusoap_client('http://{YOURSERVERURLHERE}/index.php', false, $proxyhost, $proxyport, $proxyusername, $proxypassword);
$err = $client->getError();
if ($err) {
    echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
}
$client->setUseCurl($useCURL);
$client->useHTTPPersistentConnection();
// Call the SOAP method
$result = $client->call('ping', array('testString' => 'Argle'), 'http://localhost');
// Display the result
if (!$result) {
    echo "service returned false";
} else {
    print_r($result);
}
unset($client);</pre>
<pre>?></pre>

Первое, что мы делаем в нашем клиентском коде, это включаем библиотеки nuSOAP.

Следующие пять строк кода считываются из локальной среды POST, проверяется, установлен ли прокси-сервер для сервера веб-служб, и, если да, заполняет переменные прокси.

Следующая строка создает экземпляр клиента nuSOAP и связывает его с нашим удаленным сервером. Измените «YOURSERVERURLHERE» на имя URL-адреса вашего веб-сервера apache, на котором установлен код на стороне сервера. (например: localhost, myserver.com и т. д.)

Обратите внимание на имя вызова функции: newsoap_client () … в отличие от использования функции soapclient () . Это имя функции унаследовано от вызова экземпляра PHP 5.0: new soapclient () — расширение PHP SOAP использует то же имя функции создания экземпляра, что и библиотека nuSOAP. Если вы оба установили (расширение PHP 5.0 SOAP и библиотеки nuSOAP), выполнение клиента вернет ошибки, так как вы перегрузили функцию soapclient () . (Вы вызываете функцию PHP SOAP с параметрами функции nuSOAP.) Переименуйте функцию soapclient () в обратно совместимую функцию: newsoap_client () .

Следующие две строки сообщают клиенту nuSOAP об использовании Curl, когда это возможно, и, если это было ранее сохранено, и, если возможно, об использовании постоянных соединений HTTP.

Далее мы будем использовать веб-сервисы с сервера, вызвав метод nuSOAP: call () . Аргументы этого метода:

  1. название потребляемой услуги (ping)
  2. строка ввода (примечание: все входные данные должны быть переданы как массивы!)
  3. URI пространства имен (необязательно: WSDL может переопределять)

Сохраните результаты веб-служб в точно названной переменной $ results и оцените их по возвращении. Если клиентский вызов не был успешным, отобразите сообщение об ошибке.

Если клиентский вызов был успешным, отобразите содержимое возвращенного массива.

Обратите внимание, что этот клиентский код можно запустить либо из браузера, используя опцию «file: //», либо, если исходный код клиента доступен для Apache, вы можете отобразить его с помощью браузера.

Когда я запускаю это программное обеспечение на стороне клиента в браузере, у меня снова отображается:

Массив ([status] => 1 [data] => Rcvd: Argle (5))

Итак, как мы узнаем, что клиент вышел и успешно вернулся с сервера с данными? Все просто — в исходном коде клиента вы не найдете буквально «Rcvd:» нигде в источнике. Эти данные были предоставлены серверной функцией и возвращены клиенту. Это простой пример, но он обеспечивает подтверждение концепции, что мы успешно можем подключиться к удаленному веб-серверу и вернуть данные, созданные на удаленном сервере, обратно в клиентскую программу.

Давайте завернем это …

Резюме:

Это руководство (надеюсь) объяснило, что такое веб-сервисы, и предоставило вам практический пример расходного сервиса: ping () . Такой сервис обычно вызывается как средство тестирования доступности сервера.

Мы создали файл сервера веб-сервисов, используя библиотеку nuSOAP, определив сложную структуру (ассоциативный массив) и зарегистрировав метод на сервере nuSOAP. Метод принимает входной параметр, который, хотя и является единственным входным параметром, должен быть собран и передан в виде массива в метод сервера. Далее мы показали, что, загружая исходный код сервера в браузер, мы узнали, что nuSOAP предоставляет встроенную документацию для структур и методов ваших веб-сервисов. Что очень приятно иметь при создании документации для разработчиков! Затем мы создали файл исходного кода клиента веб-служб, который подключился к нашему удаленному серверу и вызвал метод сервера: hellow (). Если все работало правильно, вы отобразили строку, возвращенную с удаленного сервера, в окне браузера.

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

Спасибо за ваше терпение — надеюсь, эта статья помогла вам.