PHP 2016. Уровень 3.4: PHP + XML Web servises
Сервисно-ориентированная разработка программного обеспечения. конспект-памятка видеокурса 'Программирование на PHP 2016'. Лектор Борисов Игорь Олегович. Учебный Центр «Специалист» при МГТУ им. Н.Э.Баумана.
конспектировал Капустин Яков
оглавление
- 01 XML Web Services. Обзор технологии
- 02 SOAP
- 03 Пример использования SOAP. процедурный стиль
- 04 Пример использования SOAP. объектный стиль
- 05 Лабораторная работа №3.4.1 Использование SOAP веб-службы
- 06 Использование XML-RPC
- 07 Контекст потока
- 08 Лабораторная работа №3.4.2 Использование XML-RPC службы
01XML Web Services. Обзор технологии
XML Web services - программы, доступ к которым осуществляется по протоколу HTTP, а обмен данными происходит в формате XML.
По мере развития информационных технологий возникали разные подходы к написанию программ: модульное программирование, событийно-ориентированное программирование, компонентно-ориентированное программирование и проектирование. Логическим продолжением этих подходов стала сервисно-ориентированная разработка программного обеспечения.
Применение сервисно-ориентированных подходов позволяет говорить о повторном использовании (reuse) на макро-уровне (уровне сервисов), в отличие от микро-уровня (уровня объектов). Сервисно-ориентированный подход предполагает использование простых и общепринятых стандартов, что позволяет самым разным приложениям использовать функциональность друг друга. Сервисы могут быть написаны с использованием самых разных языков программирования, на различных платформах. Кроме того, сервисы могут быть развернуты отдельно или в рамках программного комплекса в любой точке земного шара и будут таким образом предоставлять доступ к своей функциональности по сети.
В отличие от традиционного web-приложения, у web-сервиса нет пользовательского интерфейса. Вместо этого у него есть программный интерфейс, то есть web-сервис предоставляет функции (web-методы), которые могут быть вызваны удаленно (например, по сети Internet). Web-сервис не предназначен для обслуживания конечных пользователей. Его задача - предоставление услуг другим приложениям, будь то web-приложения, приложения с графическим пользовательским интерфейсом или консольные приложения.
Remote Procedure Call- подход, позволяющий программе вызывать процедуры из другого адресного пространства.
Реализации RPC:
- XML-RPC - текстовый протокол на базе HTTP (RFC-3529);
- SOAP - текстовый протокол на базе HTTP (RFC-4227);
- JSON-RPC - текстовый протокол на базе HTTP (RFC-4627);
- .NET Remoting - бинарный протокол на базе TCP, UDP, HTTP
- DCOM - MSRPC Microsoft Remote Procedure Call;
- Java RMI.
02SOAP
SOAP (от англ. Simple Object Access Protocol — простой протокол доступа к объектам) — протокол обмена структурированными сообщениями в распределённой вычислительной среде. Первоначально SOAP предназначался в основном для реализации удалённого вызова процедур (RPC). Сейчас протокол используется для обмена произвольными сообщениями в формате XML, а не только для вызова процедур. Официальная спецификация последней версии 1.2 протокола никак не расшифровывает название SOAP. SOAP является расширением протокола XML-RPC.
SOAP может использоваться с любым протоколом прикладного уровня: SMTP, FTP, HTTP, HTTPS и др. Однако его взаимодействие с каждым из этих протоколов имеет свои особенности, которые должны быть определены отдельно. Чаще всего SOAP используется поверх HTTP.
SOAP является одним из стандартов, на которых базируются технологии веб-служб.
Использование SOAP для передачи сообщений увеличивает их объём и снижает скорость обработки. В системах, где скорость важна, чаще используется пересылка XML-документов через HTTP напрямую, где параметры запроса передаются как обычные HTTP-параметры.
Для работы необходим подключенный модуль php_soap.dll. Основные SOAP классы: SoapServer, SoapClient.
https://proselyte.net/tutorials/soap-tutorial/element-fault/.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// клиент
// Создание SOAP клиента
$client=new SoapClient("stock.wsdl"); // Web Services Description Language
// Вызов метода SOAP сервера
$result=$client->getStock("3");
echo "Товаров на полке: " . $result;
// Получение информации о методах сервера
var_dump($client -> __getFunctions());
// сервер
// Создание сервера
$server = new SoapServer("stock.wsdl");
// Добавление функции, которая будет видна клиенту
$server->addFunction("getStock");
// Обработка SOAP-запроса (запуск сервера)
$server->handle();
// Если функций больше, чем одна, то
$funcs = ["getStock", "setStock"];
$server->addFunction($funcs);
// Если служба является классом, то
$server->setClass("StockService");
03Пример использования SOAP. процедурный стиль
Напишем небольшой пример создания SOAP-службы, используя процедурный стиль.
Создание SOAP-сервера.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Описание функции web-сервиса
function getStock($id){
$stock=array(
"1"=>100,
"2"=>200,
"3"=>300,
"4"=>400,
"5"=>500,
);
if(isset($stock[$id])){
$quantity=$stock[$id];
return $quantity;
}else{
throw new SoapFault("Server","Несуществующий id товара");
//return 0;
}
}
// echo getStock(5)."\n<br>";
// echo getStock(8)."\n<br>";
// Отключение кэширования WSDL-документа на время разработки
ini_set("soap.wsdl_cache_enabled","0");
// Создание SOAP-сервера
$server=new SoapServer("https://yakoffka.ru/src/conspects/_php34/_classes/stock.wsdl");
// Добавление функции, которая будет видна клиенту
$server->addFunction("getStock");
// Запуск сервера
$server->handle();
?>
Создание файла stock.wsdl. Передираю весь код не особо заморачиваясь.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<definitions name='Stock'
targetNamespace='https://yakoffka.ru/soap'
xmlns:tns='https://yakoffka.ru/soap'
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='getStockRequest'>
<part name='id' type='xsd:string'/>
</message>
<message name='getStockResponse'>
<part name='Result' type='xsd:integer'/>
</message>
<portType name='StockPortType'>
<operation name='getStock'>
<input message='tns:getStockRequest'/>
<output message='tns:getStockResponse'/>
</operation>
</portType>
<binding name='StockBinding' type='tns:StockPortType'>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='getStock' />
</binding>
<service name='StockService'>
<port name='StockPort' binding='StockBinding'>
<!--soap:address location='http://mysite.local/demo/soap/server.php'/-->
<soap:address location='https://yakoffka.ru/src/conspects/_php34/_classes/server.php'/>
</port>
</service>
</definitions>
Создание SOAP-клиента.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
try{
// Создание SOAP-клиента
$client=new SoapClient("https://yakoffka.ru/src/conspects/_php34/_classes/stock.wsdl");
// теперь операции, указанные в файле stock.wsdl становятся методами объекта $client
// Посылка SOAP-запроса с получением результата
$result=$client->getStock("3");
echo "в наличии $result шт.";
}catch(SoapFault $exception){
echo $exception->getMessage();
}
unset($server,$client,$result);
Проверка работы php-класса SoapFault.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
try{
// Создание SOAP-клиента
$client=new SoapClient("https://yakoffka.ru/src/conspects/_php34/_classes/stock.wsdl");
// теперь операции, указанные в файле stock.wsdl становятся методами объекта $client
// Посылка SOAP-запроса с получением результата
$result=$client->getStock("7");
echo "в наличии $result шт.";
}catch(SoapFault $exception){
echo $exception->getMessage();
}
unset($server,$client,$result);
04Пример использования SOAP. объектный стиль
Напишем небольшой пример создания SOAP-службы, используя объектный стиль. На сервере изменяется только одна строка: '$server->addFunction("getStock");' заменяется на '$server->setClass("StockService");'.
Создание SOAP-сервера.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class StockService_o{
// Описание метода web-сервиса
function getStock($id){
$stock=array(
"1"=>100,
"2"=>200,
"3"=>300,
"4"=>400,
"5"=>500,
);
if(isset($stock[$id])){
$quantity=$stock[$id];
return $quantity;
}else{
throw new SoapFault("Server","Несуществующий id товара");
//return 0;
}
}
}
// Отключение кэширования WSDL-документа на время разработки
ini_set("soap.wsdl_cache_enabled","0");
// Создание SOAP-сервера
$server=new SoapServer("https://yakoffka.ru/src/conspects/_php34/_classes/stock_o.wsdl");
// // Добавление функции, которая будет видна клиенту
// $server->addFunction("getStock");
// Добавление класса к SOAP-серверу
// $server->setClass("WrongClass");// намеренная ошибка!!!!
$server->setClass("StockService_o");
// Запуск сервера
$server->handle();
?>
Создание файла stock_o.wsdl. Меняем ссылку на SOAP-сервер.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<definitions name='Stock'
targetNamespace='https://yakoffka.ru/soap'
xmlns:tns='https://yakoffka.ru/soap'
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='getStockRequest'>
<part name='id' type='xsd:string'/>
</message>
<message name='getStockResponse'>
<part name='Result' type='xsd:integer'/>
</message>
<portType name='StockPortType'>
<operation name='getStock'>
<input message='tns:getStockRequest'/>
<output message='tns:getStockResponse'/>
</operation>
</portType>
<binding name='StockBinding' type='tns:StockPortType'>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='getStock' />
</binding>
<service name='StockService_o'>
<port name='StockPort' binding='StockBinding'>
<soap:address location='https://yakoffka.ru/src/conspects/_php34/_classes/server_o.php'/><!-- меняем ссылку на SOAP-сервер -->
</port>
</service>
</definitions>
Создание SOAP-клиента.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
try{
// Создание SOAP-клиента
$client=new SoapClient("https://yakoffka.ru/src/conspects/_php34/_classes/stock_o.wsdl");
// теперь операции, указанные в файле stock_o.wsdl становятся методами объекта $client
// Посылка SOAP-запроса с получением результата
$result=$client->getStock("3");
echo "в наличии $result шт.";
}catch(SoapFault $exception){
echo $exception->getMessage();
}
unset($server,$client,$result);
Получение информации о методах сервера и проверка работы php-класса SoapFault.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
try{
// Создание SOAP-клиента
$client=new SoapClient("https://yakoffka.ru/src/conspects/_php34/_classes/stock_o.wsdl");
// теперь операции, указанные в файле stock_o.wsdl становятся методами объекта $client
// Получение информации о методах сервера
$res=print_r($client -> __getFunctions(),true);
echo "<pre>$res</pre>";
// Посылка SOAP-запроса с получением результата
$result=$client->getStock("7");
echo "в наличии $result шт.";
}catch(SoapFault $exception){
echo $exception->getMessage();
}
unset($server,$client,$result);
Array ( [0] => integer getStock(string $id) )Несуществующий id товара
05Лабораторная работа №3.4.1 Использование SOAP веб-службы
Упражнение 1: Создание SOAP-сервера
- В текстовом редакторе откройте файл soap\soap-server.php
- Ознакомьтесь с содержимым службы NewsService
- В нижней части файла после описания класса введите следующий текст:
// Отключение кеширования wsdl-документа ini_set("soap.wsdl_cache_enabled", "0"); // Создание SOAP-сервера $server = new SoapServer("http://mysite.local/soap/news.wsdl"); // Регистрация класса $server->setClass("NewsService"); // Запуск сервера $server->handle();
- Сохраните файл soap\soap-server.php
- В текстовом редакторе откройте файл soap\soap-client.php
- Пересохраните этот файл как C:\Users\Public\OpenServer\domains\localhost\soap-client.php
- В файле введите следующий текст:
$client = new SoapClient("http://mysite.local/soap/news.wsdl"); try{ // Сколько новостей в категории Политика? $result = $client->getNewsCountByCat(1); echo "<p>Всего новостей в категории Политика: // Сколько новостей всего?<br> $result = $client->getNewsCount(); echo "<p>Всего новостей: $result</p>"; $result</p>"; // Покажем конкретную новость $result = $client->getNewsById(1); $news = unserialize(base64_decode($result)); var_dump($news); }catch(SoapFault $e){ echo 'Операция '.$e->faultcode.' вернула ошибку: '.$e->getMessage(); }
- Сохраните файл soap-client.php
Подготовительные операции: копирование файлов новостной ленты, не требующих изменения и бездумное копирование news.wsdl - заменяем лишь адрес сервера.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$res="";
$arr_cf=array(
"/_classes/INewsDB.class.php",
"/_classes/NewsDB.class.php",
);
// проверка существования директории "/full/path/to/_php34_classes/"
$pd="/full/path/to/_php34/_classes";
if(!is_dir($pd)){if(!mkdir($pd,0777,true)){$res.="Не удалось создать директорию $pd.<br>\n";}}
foreach($arr_cf as $nf){
$source="/full/path/to/_php32$nf";
$dest="/full/path/to/_php34$nf";
if(is_file($source)){
if(copy($source,$dest)){
$res.="Файл $nf скопирован успешно.<br>\n";
}else{$res.="Не удалось скопировать файл $nf.<br>\n";}
}else{$res.="Файл $nf не найден.<br>\n";}
}
echo $res;
Файл /_classes/NewsDB.class.php скопирован успешно.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<definitions name="News"
targetNamespace='https://yakoffka.ru/news'
xmlns:tns='https://yakoffka.ru/news'
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="getNewsByIdRequest">
<part name="id" type="xsd:integer"/>
</message>
<message name="getNewsByIdResponse">
<part name="item" type="xsd:base64Binary"/>
</message>
<message name="getNewsCountResponse">
<part name="count" type="xsd:integer"/>
</message>
<message name="getNewsCountByCatRequest">
<part name="cat_id" type="xsd:integer"/>
</message>
<message name="getNewsCountByCatResponse">
<part name="count" type="xsd:integer"/>
</message>
<portType name="NewsPortType">
<operation name="getNewsById">
<input message="tns:getNewsByIdRequest"/>
<output message="tns:getNewsByIdResponse"/>
</operation>
<operation name="getNewsCount">
<output message="tns:getNewsCountResponse"/>
</operation>
<operation name="getNewsCountByCat">
<input message="tns:getNewsCountByCatRequest"/>
<output message="tns:getNewsCountByCatResponse"/>
</operation>
</portType>
<binding name="NewsBinding" type="tns:NewsPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getNewsById" />
<operation name="getNewsCount" />
<operation name="getNewsCountByCat" />
</binding>
<service name="NewsService">
<port name="NewsPort" binding="NewsBinding">
<soap:address location='https://yakoffka.ru/src/conspects/_php34/_classes/soap-server.php'/>
</port>
</service>
</definitions>
Создание SOAP-сервера: файл soap-server.php.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// реализуем метод автозагрузки
spl_autoload_register(function($class){
include("/full/path/to/_php34/_classes/$class.class.php");
});
// require "/full/path/to/_php34/_classes/NewsDB.class.php";
class NewsService extends NewsDB{
/* Метод возвращает новость по её идентификатору */
function getNewsById($id){
try{
$sql = "SELECT id, title,
(SELECT name FROM category WHERE category.id=msgs.category) as category, description, source, datetime
FROM msgs
WHERE id = $id";
$result = $this->_db->query($sql);
if (!is_object($result))
throw new Exception($this->_db->lastErrorMsg());
return base64_encode(serialize($this->db2arr($result)));
}catch(Exception $e){
throw new SoapFault('getNewsById', $e->getMessage());
}
}
/* Метод считает количество всех новостей */
function getNewsCount(){
try{
$sql = "SELECT count(*) FROM msgs";
$result = $this->_db->querySingle($sql);
if (!$result)
throw new Exception($this->_db->lastErrorMsg());
return $result;
}catch(Exception $e){
throw new SoapFault('getNewsCount', $e->getMessage());
}
}
/* Метод считает количество новостей в указанной категории */
function getNewsCountByCat($cat_id){
try{
$sql = "SELECT count(*) FROM msgs WHERE category=$cat_id";
$result = $this->_db->querySingle($sql);
if (!$result)
throw new Exception($this->_db->lastErrorMsg());
return $result;
}catch(Exception $e){
throw new SoapFault('getNewsCountByCat', $e->getMessage());
}
}
}
// Отключение кеширования wsdl-документа
ini_set("soap.wsdl_cache_enabled", "0");
// Создание SOAP-сервера
$server = new SoapServer("https://yakoffka.ru/src/conspects/_php34/_classes/news.wsdl");
// Регистрация класса
$server->setClass("NewsService");
// Запуск сервера
$server->handle();
?>
Создание SOAP-клиента: файл laboratory_3.4.1.php.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// // реализуем метод автозагрузки
// spl_autoload_register(function($class){
// include "/full/path/to/_php34/_classes/$class.class.php");
// });
$errMsg="";
$res="";
$client = new SoapClient("https://yakoffka.ru/src/conspects/_php34/_classes/news.wsdl");
try{
// Получение информации о методах сервера
$print_r=print_r($client -> __getFunctions(),true);
$res.="<pre>$print_r</pre>";
// // Вызов несуществующего метода<br>
// $result = $client->wrongMethod();
// $res.="<p>Как тебе такое, Илон?</p>";
// // Операция Client вернула ошибку: Function ("wrongMethod") is not a valid method for this service
// Сколько новостей всего?<br>
$result = $client->getNewsCount();
$res.="<p>Всего новостей: $result</p>";
// Сколько новостей в категории Политика?
$result = $client->getNewsCountByCat(1);
$res.="<p>Всего новостей в категории Политика: $result</p>";
// Покажем конкретную новость
$result = $client->getNewsById(48);
$news = unserialize(base64_decode($result));
$res.=print_r($news,true);
}catch(SoapFault $e){
$errMsg.='Операция '.$e->faultcode.' вернула ошибку: '.$e->getMessage().';';
}
unset($server,$client,$result);
$mc.="
<?php
// Вывод результата
echo \"<p class='err_mess'>\$errMsg</p>\";
// Вывод результата
echo \$res;
// phpinfo();
?>
";
06Использование XML-RPC
2
3
4
5
6
7
8
9
10
<methodCall>
<methodName>getStock</methodName>
<params>
<param>
<value><i4>3</i4></value>
</param>
</params>
</methodCall>
02
03
04
05
06
07
08
09
10
11
12
<methodResponse>
<params>
<param>
<value><i4>300</i4></value>
</param>
<param>
<value><string>Sony Vayo</string></value>
</param>
</params>
</methodResponse>
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Описание службы
$stock = [
"a"=>100,
"b"=>200,
"c"=>300,
"d"=>400,
"e"=>500
];
function get_stock($methodName, $arguments, $extra){
global $stock;
$code = $arguments[0];
if(is_set($stock[$code])){
return $stock[$code];
}else{
return ["faultCode" => 1, "faultString" => "Нет такой полки"];
}
}
// Создание сервера
$server = xmlrpc_server_create();
// Добавление функции, которая будет видна клиенту
xmlrpc_server_register_method($server, "getStock", "get_stock");
// Приём запроса
$request = file_get_contents("php://input");
// Обработка запроса
echo xmlrpc_server_call_method($server, $request, null);
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// Создание запроса
$server = xmlrpc_encode_request("getStock", "b");
// XML-RPC запрос и получение ответа
$response = запрос_любым_способом_методом_POST("URL");
// Декодирование ответа
$result = xmlrpc_decode("URL");
if(xmlrpc_is_fault($result)){
echo $result["faultString"];
}else{
echo $result;
}
07Контекст потока
Контекст - это набор параметров и зависящих от контекста опций, который изменяет или расширяет поведение потока. Контексты создаются при помощи функции stream_context_create() и могут быть переданы большинству функций файловой системы, связанных с созданием потоков (например, fopen(), file(), file_get_contents(), и т. д...).
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Формирование необходимых данных
$options = [
"http"=> [ // указание протокола
"method" => "GET",
"header" => "User-Agent: PHPBot\r\n".
"Cookie: user=John\r\n"
]
];
// Создание контекста потока
$context = stream_context_create($options);
// Запрос с использованием созданного контекста потока
echo file_get_contents("http://mysite.local/xml-rpc/server.php", false, $context);
// Получение ответа при использовании fopen()
$f = fopen("http://mysite.local/xml-rpc/server.php", "r", false, $context);
echo stream_get_contents($f);
// Получение заголовков ответа
print_r(stream_get_meta_data($f));
08Лабораторная работа №3.4.2 Использование XML-RPC службы
Упражнение 1: Создание XML-RPC сервера
- В текстовом редакторе откройте файл xml-rpc\xml-rpc-server.php
- Ознакомьтесь с содержимым службы NewsService
- В нижней части файла после описания класса введите следующий текст:
/* Читаем запрос */ $request = file_get_contents("php://input"); /* Создаем XML-RPC сервер */ $server = xmlrpc_server_create(); /* Регистрируем метод класса */ xmlrpc_server_register_method($server, "getNewsById", [new NewsService, "xmlRpcGetNewsById"]); /*Отдаем правильный заголовок*/ header('Content-Type: text/xml;charset=utf-8'); /* Отдаем результат */ print xmlrpc_server_call_method($server, $request, null);
- Сохраните файл xml-rpc\xml-rpc-server.php
- В текстовом редакторе откройте файл xml-rpc\xml-rpc-client.php
- Пересохраните этот файл как C:\Users\Public\OpenServer\domains\localhost\xml-rpc-client.php
- В файле введите следующий текст:
header('Content-Type: text/html;charset=utf-8'); /* Сюда приходят данные с сервера */ $output = []; /* Основная функция */ function make_request($xml, &$output){ /* НАЧАЛО ЗАПРОСА */ $options = [ 'http'=>[ 'method' => "POST", 'header' => "User-Agent: PHPRPC/1.0\r\n" . "Content-Type: text/xml\r\n" . "Content-length: " . strlen($xml) . "\r\n", 'content' => "$xml" ] ]; $context = stream_context_create($options); $retval = file_get_contents('http://mysite.local/xml-rpc/xml-rpc-server.php', false, $context); /* КОНЕЦ ЗАПРОСА */ $data = xmlrpc_decode($retval); if (is_array($data) && xmlrpc_is_fault($data)){ $output = $data; }else{ $output = unserialize(base64_decode($data)); } } /* Идентификатор статьи */ $id = 1; $request_xml = xmlrpc_encode_request('getNewsById',array($id));make_request($request_xml, $output); /* Вывод результата */ var_dump($output);
- Сохраните файл xml-rpc-client.php
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
error_reporting(0);
// реализуем метод автозагрузки
spl_autoload_register(function($class){
include("/full/path/to/_php34/_classes/$class.class.php");
});
class NewsServiceRPC extends NewsDB{
/* Метод возвращает новость по её идентификатору */
function getNewsById($id){
try{
$sql = "SELECT id, title,
(SELECT name FROM category WHERE category.id=msgs.category) as category, description, source, datetime
FROM msgs
WHERE id = $id";
$result = $this->_db->query($sql);
//var_dump($result);
if (!is_object($result))
throw new Exception($this->_db->lastErrorMsg());
return $this->db2arr($result);
}catch(Exception $e){
return $e->getMessage();
}
}
function xmlRpcGetNewsById($method_name, $args, $extra) {
if (!is_array($args) || count($args) <> 1){
return array('faultCode'=>-3, 'faultString'=>'Неверное количество параметров!');
}
$id = $args[0];
$result = $this->getNewsById($id);
if(!is_array($result)){
return array('faultCode'=>-2, 'faultString'=>"Ошибка: $result!");
}elseif(empty($result)){
return array('faultCode'=>-1, 'faultString'=>"Новость с идентификатором $id отсутствует!");
}else{
return base64_encode(serialize($result));
}
}
}
/* Читаем запрос */
$request = file_get_contents("php://input");
/* Создаем XML-RPC сервер */
$server = xmlrpc_server_create();
/* Регистрируем метод класса */
xmlrpc_server_register_method($server, "getNewsById", [new NewsServiceRPC, "xmlRpcGetNewsById"]);
/*Отдаем правильный заголовок*/
header('Content-Type: text/xml;charset=utf-8');
/* Отдаем результат */
print xmlrpc_server_call_method($server, $request, null);
?>
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Сюда приходят данные с сервера */
$output = [];
/* Основная функция */
function make_request($xml, &$output){
/* НАЧАЛО ЗАПРОСА */
$options = [
'http'=>[
'method' => "POST",
'header' => "User-Agent: PHPRPC/1.0\r\n" .
"Content-Type: text/xml\r\n" .
"Content-length: " . strlen($xml) . "\r\n",
'content' => "$xml"
]
];
$context = stream_context_create($options);
$retval = file_get_contents('https://yakoffka.ru/src/conspects/_php34/_classes/xml-rpc-server.php', false, $context);
/* КОНЕЦ ЗАПРОСА */
$data = xmlrpc_decode($retval);
if (is_array($data) && xmlrpc_is_fault($data)){
$output = $data;
}else{
$output = unserialize(base64_decode($data));
}
}
/* Идентификатор статьи */
$id = 30;
$request_xml = xmlrpc_encode_request('getNewsById',array($id));make_request($request_xml, $output);
/* Вывод результата */
echo "Идентификатор статьи id = $id;<br>";
var_dump($output);
array(2) { ["faultCode"]=> int(-1) ["faultString"]=> string(75) "Новость с идентификатором 30 отсутствует!" }
Создание XML-RPC-клиента: файл laboratory_3.4.2.php.
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
header('Content-Type: text/html;charset=utf-8');
/* Сюда приходят данные с сервера */
$output = [];
/* Основная функция */
function make_request($xml, &$output){
/* НАЧАЛО ЗАПРОСА */
$options = [
'http'=>[
'method' => "POST",
'header' => "User-Agent: PHPRPC/1.0\r\n" .
"Content-Type: text/xml\r\n" .
"Content-length: " . strlen($xml) . "\r\n",
'content' => "$xml"
]
];
$context = stream_context_create($options);
$retval = file_get_contents('https://yakoffka.ru/src/conspects/_php34/_classes/xml-rpc-server.php', false, $context);
/* КОНЕЦ ЗАПРОСА */
$data = xmlrpc_decode($retval);
if (is_array($data) && xmlrpc_is_fault($data)){
$output = $data;
}else{
$output = unserialize(base64_decode($data));
}
}
$mc.="
<?php
/* Идентификатор статьи */
\$id = 30;
\$request_xml = xmlrpc_encode_request('getNewsById',array(\$id));make_request(\$request_xml, \$output);
/* Вывод результата */
echo \"Идентификатор статьи id = \$id;<br>\";
var_dump(\$output);
?>
";
Капустин Яков (2019.01.12 01:22)