Библиотека XML-RPC, найденная в Интернете, очень полезна для разработки небольших внешних коммуникационных интерфейсов. Сохраните этот код как xml-rpc.inc.php
<?php.
/*
Библиотека XML-RPC, найденная в Интернете, очень полезна для разработки небольших внешних коммуникационных интерфейсов.
*/
функция & XML_serialize($data, $level = 0, $prior_key = NULL){
#предполагается хэш, ключи — это имена переменных
$xml_serialized_string = "";
while(list($key, $value) = каждый($data)){
$inline = ложь;
$numeric_array = ложь;
$атрибуты = "";
#echo "Мой текущий ключ — $key, вызывается с предыдущим ключом $prior_key<br>";
if(!strstr($key, " attr")){ #if это не атрибут
if(array_key_exists("$key attr", $data)){
while(list($attr_name, $attr_value) = каждый($data["$key attr"])){
#echo "Найден атрибут $attribute_name со значением $attribute_value<br>";
$attr_value = &htmlspecialchars($attr_value, ENT_QUOTES);
$attributes .= " $attr_name="$attr_value"";
}
}
если (is_numeric ($ ключ)) {
#echo "Мой текущий ключ ($key) — числовой. Мой родительский ключ — '$prior_key'<br>";
$ключ = $предыдущий_ключ;
}еще{
#вы не можете использовать цифровые клавиши на двух уровнях подряд, так что это нормально
#echo "Проверка наличия числового ключа в данных.";
if(is_array($value) и array_key_exists(0, $value)){
# echo "Да! Вызываю себя как результат числового массива.<br>";
$numeric_array = правда;
$xml_serialized_string .= XML_serialize($value, $level, $key);
}
#echo "<br>";
}
если(!$numeric_array){
$xml_serialized_string .= str_repeat("t", $level) "<$key$attributes>";
если (is_array ($ значение)) {
$xml_serialized_string .= "rn" . XML_serialize($value, $level+1);
}еще{
$inline = правда;
$xml_serialized_string .= htmlspecialchars($value);
}
$xml_serialized_string .= (!$inline ? str_repeat("t", $level) : "") . "</$key>rn";
}
}еще{
#echo "Пропуск записи атрибута для ключа $key<bR>";
}
}
если ($уровень == 0){
$xml_serialized_string = "<?xml version="1.0" ?>rn" $xml_serialized_string;
вернуть $xml_serialized_string;
}еще{
вернуть $xml_serialized_string;
}
}
класс XML {
var $parser #ссылка на парсер XML
var $document #вся структура XML, созданная на данный момент
var $current; #указатель на текущий элемент – что это такое?
var $parent #указатель на текущего родителя — родительский элемент будет массивом
var $parents #массив самого последнего родителя на каждом уровне;
вар $last_opened_tag;
функция XML($data=null){
$this->parser = xml_parser_create();
xml_parser_set_option ($this->parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, «открыть», «закрыть»);
xml_set_character_data_handler($this->parser, "данные");
# Register_shutdown_function(array($this, 'destruct'));
}
функция уничтожить(){
xml_parser_free($this->parser);
}
анализ функции ($ данные) {
$this->document = массив();
$this->parent = $this->document;
$this->parents = array();
$this->last_opened_tag = NULL;
xml_parse($this->parser, $data);
вернуть $this->документ;
}
функция open($parser, $tag, $attributes){
#echo "Открывающий тег $tag<br>n";
$this->data = "";
$this->last_opened_tag = $tag; #tag — строка
if(array_key_exists($tag, $this->parent)){
#echo "На текущем уровне ($level)<br>n" уже существует экземпляр '$tag';
if(is_array($this->parent[$tag]) и array_key_exists(0, $this->parent[$tag])){ #if ключи числовые
#нужно убедиться, что они числовые (учитывайте атрибуты)
$key = count_numeric_items($this->parent[$tag]);
#echo "Есть экземпляры $key: ключи числовые.<br>n";
}еще{
#echo "Существует только один экземпляр. Все перемещается<br>n";
$temp = $this->parent[$tag];
unset($this->parent[$tag]);
$this->parent[$tag][0] = $temp;
if(array_key_exists("$tag attr", $this->parent)){
#измените и атрибуты, если они существуют
$temp = $this->parent["$tag attr"];
unset($this->parent["$tag attr"]);
$this->parent[$tag]["0 attr"] = $temp;
}
$ключ = 1;
}
$this->parent = $this->parent[$tag];
}еще{
$ключ = $тег;
}
если ($ атрибуты) {
$this->parent["$key attr"] = $attributes;
}
$this->parent[$key] = массив();
$this->parent = $this->parent[$key];
array_unshift($this->parents, $this->parent);
}
данные функции ($ парсер, $ данные) {
#echo "Данные - это '", htmlspecialchars($data), "'<br>n";
if($this->last_opened_tag!= NULL){
$this->data .= $data;
}
}
функция close($parser, $tag){
#echo "Закрыть тег $tag<br>n";
if($this->last_opened_tag == $tag){
$this->parent = $this->data;
$this->last_opened_tag = NULL;
}
array_shift($this->родители);
$this->parent = $this->parents[0];
}
}
функция & XML_unserialize($xml){
$xml_parser = новый XML();
$data = $xml_parser->parse($xml);
$xml_parser->destruct();
вернуть $данные;
}
функция & XMLRPC_parse($request){
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_parse', "<p>Получен следующий необработанный запрос:</p>" . XMLRPC_show($request, 'print_r', true));
}
$data = &XML_unserialize($request);
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_parse', "<p>Возврат следующего проанализированного запроса:</p>" . XMLRPC_show($data, 'print_r', true));
}
вернуть $данные;
}
функция & XMLRPC_prepare($data, $type = NULL){
если (is_array ($ данные)) {
$num_elements = счетчик ($ данные);
if((array_key_exists(0, $data) или !$num_elements) и $type != 'struct'){ #это массив
if(!$num_elements){ #если массив пустпустой
$returnvalue = array('array' => array('data' => NULL));
}еще{
$returnvalue['array']['data']['value'] = array();
$temp = $returnvalue['array']['data']['value'];
$count = count_numeric_items($data);
for($n=0; $n<$count; $n++){
$тип = NULL;
if(array_key_exists("$n type", $data)){
$type = $data["$n тип"];
}
$temp[$n] = XMLRPC_prepare($data[$n], $type);
}
}
}else{ #это структура
if(!$num_elements){ #if структура пустапусто
$returnvalue = array('struct' => NULL);
}еще{
$returnvalue['struct']['member'] = array();
$temp = $returnvalue['struct']['member'];
while(list($key, $value) = каждый($data)){
if(substr($key, -5) != 'type'){ #if это не спецификатор типа
$тип = NULL;
if(array_key_exists("$тип ключа", $data)){
$type = $data["$тип ключа"];
}
$temp[] = array('name' => $key, 'value' => XMLRPC_prepare($value, $type));
}
}
}
}
}else{ #это скаляр
если(!$тип){
если (is_int ($ данные)) {
$returnvalue['int'] = $data;
вернуть $возвратное значение;
}elseif(is_float($data)){
$returnvalue['double'] = $data;
вернуть $возвратное значение;
}elseif(is_bool($data)){
$returnvalue['boolean'] = ($data? 1:0);
вернуть $возвратное значение;
}elseif(preg_match('/^d{8}Td{2}:d{2}:d{2}$/', $data, $matches)){ #это дата
$returnvalue['dateTime.iso8601'] = $data;
вернуть $возвратное значение;
}elseif(is_string($data)){
$returnvalue['string'] = htmlspecialchars($data);
вернуть $возвратное значение;
}
}еще{
$returnvalue[$type] = htmlspecialchars($data);
}
}
вернуть $возвратное значение;
}
функция & XMLRPC_adjustValue($current_node){
если (is_array($current_node)){
if(isset($current_node['array'])){
if(!is_array($current_node['array']['data'])){
#Если элементов нет, возвращаем пустой массив
вернуть массив();
}еще{
#echo "Избавление от массива -> данные -> значение<br>n";
$temp = $current_node['array']['data']['value'];
if(is_array($temp) и array_key_exists(0, $temp)){
$count = count($temp);
for($n=0;$n<$count;$n++){
$temp2[$n] = &XMLRPC_adjustValue($temp[$n]);
}
$temp = $temp2;
}еще{
$temp2 = &XMLRPC_adjustValue($temp);
$temp = массив($temp2);
#Я выполняю временное назначение, потому что оно позволяет избежать копирования,
# так как я могу поместить ссылку в массив
Эталонная модель #PHP немного глупа, и я не могу просто сказать:
# $temp = array(&XMLRPC_adjustValue($temp));
}
}
}elseif(isset($current_node['struct'])){
if(!is_array($current_node['struct'])){
#Если элементов нет, возвращаем пустой массив
вернуть массив();
}еще{
#echo "Избавление от struct ->member<br>n";
$temp = $current_node['struct']['member'];
if(is_array($temp) и array_key_exists(0, $temp)){
$count = count($temp);
for($n=0;$n<$count;$n++){
#echo "Передается имя {$temp[$n][name]}. Значение: " . show($temp[$n][value], var_dump, true) "<br>n";
$temp2[$temp[$n]['name']] = &XMLRPC_adjustValue($temp[$n]['value']);
#echo "adjustValue(): После присвоения значение равно " . show($temp2[$temp[$n]['name']], var_dump, true) "<br>n";
}
}еще{
#echo "Передача имени $temp[name]<br>n";
$temp2[$temp['name']] = &XMLRPC_adjustValue($temp['value']);
}
$temp = $temp2;
}
}еще{
$types = array('string', 'int', 'i4', 'double', 'dateTime.iso8601', 'base64', 'boolean');
$fell_through = правда;
foreach($types как $type){
если(array_key_exists($type, $current_node)){
#echo "Избавление от '$type'<br>n";
$temp = $current_node[$type];
#echo "adjustValue(): Текущему узлу присвоен тип $type<br>n";
$fell_through = ложь;
перерыв;
}
}
если ($ провалился) {
$тип = 'строка';
#echo "Провалился! Тип: $type<br>n";
}
переключатель ($type){
случай «int»: случай «i4»: $temp = (int)$temp Break;
случай 'строка': $temp = (строка)$temp перерыв;
случай «двойной»: $temp = (double)$temp Break;
случай 'логический': $temp = (bool)$temp Break;
}
}
}еще{
$temp = (строка)$current_node;
}
вернуть $temp;
}
функция XMLRPC_getParams($request){
if(!is_array($request['methodCall']['params'])){
#Если параметров нет, возвращаем пустой массив
вернуть массив();
}еще{
#echo "Избавление от вызова метода -> params -> param<br>n";
$temp = $request['methodCall']['params']['param'];
if(is_array($temp) и array_key_exists(0, $temp)){
$count = count($temp);
for($n = 0; $n <$count; $n++){
#echo "Сериализация параметра $n<br>";
$temp2[$n] = &XMLRPC_adjustValue($temp[$n]['value']);
}
}еще{
$temp2[0] = &XMLRPC_adjustValue($temp['value']);
}
$temp = $temp2;
вернуть $temp;
}
}
функция XMLRPC_getMethodName($methodCall){
#возвращает имя метода
return $methodCall['methodCall']['methodName'];
}
функция XMLRPC_request($site, $location, $methodName, $params = NULL, $user_agent = NULL){
$site = взорваться(':', $site);
if(isset($site[1]) и is_numeric($site[1])){
$порт = $сайт[1];
}еще{
$порт = 80;
}
$сайт = $сайт[0];
$data["methodCall"]["имя_метода"] = $имя_метода;
$param_count = count($params);
если(!$param_count){
$data["methodCall"]["params"] = NULL;
}еще{
for($n = 0; $n<$param_count; $n++){
$data["methodCall"]["params"]["param"][$n]["value"] = $params[$n];
}
}
$данные = XML_serialize($данные);
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Получен следующий список параметров для отправки:</p>" . XMLRPC_show($params, 'print_r', true));
}
$conn = fsockopen ($site, $port #открыть соединение);
if(!$conn){ #если соединение не удалось открыть
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Ошибка подключения: не удалось установить соединение с $site.</p>");
}
return array(false, array('faultCode'=>10532, 'faultString'=>"Ошибка подключения: не удалось установить соединение с $site."));
}еще{
$заголовки =
«POST $location HTTP/1.0rn» .
«Хост: $sitern» .
«Соединение: закрытьrn» .
($user_agent ? "Агент пользователя: $user_agentrn" : '') .
«Тип контента: text/xmlrn» .
"Длина контента: " . strlen($data) "rnrn";
fputs($conn, "$headers");
fputs($conn, $data);
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Отправлен следующий запрос:</p>nn" . XMLRPC_show($headers . $data, 'print_r', true));
}
#socket_set_blocking ($conn, false);
$ответ = "";
while(!feof($conn)){
$response .= fgets($conn, 1024);
}
fclose($conn);
#удалить заголовки ответа
$data = XML_unserialize(substr($response, strpos($response, "rnrn")+4));
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Получен следующий ответ:</p>nn" . XMLRPC_show($response, 'print_r', true) . "<p>Который был сериализован в следующие данные:< /p>nn". XMLRPC_show($data, 'print_r', true));
}
if(isset($data['methodResponse']['fault'])){
$return = array(false, XMLRPC_adjustValue($data['methodResponse']['fault']['value']));
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Возврат:</p>nn" . XMLRPC_show($return, 'var_dump', true));
}
вернуть $возврат;
}еще{
$return = array(true, XMLRPC_adjustValue($data['methodResponse']['params']['param']['value']));
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Возврат:</p>nn" . XMLRPC_show($return, 'var_dump', true));
}
вернуть $возврат;
}
}
}
функция XMLRPC_response($return_value, $server = NULL){
$data["methodResponse"]["params"]["param"]["value"] = $return_value;
$return = XML_serialize($data);
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_response', "<p>Получены следующие данные для возврата:</p>nn" . XMLRPC_show($return_value, 'print_r', true));
}
заголовок("Соединение: закрыть");
header("Content-Length: " . strlen($return));
заголовок("Тип контента: текст/xml");
header("Дата: " . date("r"));
если($сервер){
заголовок("Сервер: $server");
}
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_response', "<p>Отправлен следующий ответ:</p>nn" . XMLRPC_show($return, 'print_r', true));
}
эхо $возврат;
}
функция XMLRPC_error($faultCode, $faultString, $server = NULL){
$array["methodResponse"]["fault"]["value"]["struct"]["member"] = array();
$temp = $array["methodResponse"]["fault"]["value"]["struct"]["member"];
$temp[0]["имя"] = "код неисправности";
$temp[0]["значение"]["int"] = $faultCode;
$temp[1]["имя"] = "faultString";
$temp[1]["значение"]["строка"] = $faultString;
$return = XML_serialize($array);
заголовок("Соединение: закрыть");
header("Content-Length: " . strlen($return));
заголовок("Тип контента: текст/xml");
header("Дата: " . date("r"));
если($сервер){
заголовок("Сервер: $server");
}
если(определено('XMLRPC_DEBUG') и XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_error', "<p>Отправлен следующий ответ об ошибке:</p>nn" . XMLRPC_show($return, 'print_r', true));
}
эхо $возврат;
}
функция XMLRPC_convert_timestamp_to_iso8601($timestamp){
#берёт временную метку unix и преобразует её в формат iso8601, необходимый для XMLRPC
# пример даты и времени iso8601: "20010822T03:14:33"
дата возврата("YmdTH:i:s", $timestamp);
}
функция XMLRPC_convert_iso8601_to_timestamp($iso8601){
вернуть strtotime($iso8601);
}
функция count_numeric_items($array){
return is_array($array)? count(array_filter(array_keys($array), 'is_numeric')) : 0;
}
функция XMLRPC_debug($function_name, $debug_message){
$GLOBALS['XMLRPC_DEBUG_INFO'][] = массив($имя_функции, $debug_message);
}
функция XMLRPC_debug_print(){
if($GLOBALS['XMLRPC_DEBUG_INFO']){
echo "<table border="1" width="100%">n";
foreach($GLOBALS['XMLRPC_DEBUG_INFO'] как $debug){
echo "<tr><th style="vertical-align: top">$debug[0]</th><td>$debug[1]</td></tr>n";
}
эхо "</table>n";
unset($GLOBALS['XMLRPC_DEBUG_INFO']);
}еще{
echo "<p>Информации об отладке пока нет.</p>";
}
}
функция XMLRPC_show($data, $func = "print_r", $return_str = false){
ob_start();
$функ($данные);
$output = ob_get_contents();
ob_end_clean();
если ($ return_str) {
return "<pre>" . htmlspecialchars($output) "</pre>n";
}еще{
echo "<pre>", htmlspecialchars($output), "</pre>n";
}
}
?>
Пример серверной программы, server.php
<?
включить «xml-rpc.inc.php»;
//Определяем методы, которые можно вызывать удаленно
$xmlrpc_methods=массив();
$xmlrpc_methods['insertRecords']='insertRecords';
//Получаем имя метода и параметры, переданные пользователем
$xmlrpc_request = XMLRPC_parse($HTTP_RAW_POST_DATA);
$methodName = XMLRPC_getMethodName($xmlrpc_request);
$params = XMLRPC_getParams($xmlrpc_request);
if (!isset($xmlrpc_methods[$methodName])){
XMLRPC_error('1',"Вызванный вами метод не существует");
}еще {
$xmlrpc_methods[$имя_метода]($params);
}
функция InsertRecords($params){
если (пустой($params)){
XMLRPC_error('2',"Ошибка параметра");
}
XMLRPC_response(XMLRPC_prepare('http://www.emtit.com'));
}
?>
Пример метода вызова сервера клиентом PHP
<?php
include_once 'xml-rpc.inc';
$params=массив(2,3);
$result=XMLRPC_request("127.0.0.1","/services/server.php","insertRecords",$params);//Файл сервера помещается в папку сервисов
print_r ($ результат);
?>