A biblioteca XML-RPC encontrada na Internet é muito útil para desenvolver pequenas interfaces de comunicação externa. Salve este código como xml-rpc.inc.php
<?php.
/*
A biblioteca XML-RPC encontrada na Internet é muito útil para desenvolver pequenas interfaces de comunicação externa.
*/
função & XML_serialize($dados, $nível = 0, $prior_key = NULL){
#assume um hash, as chaves são os nomes das variáveis
$xml_serialized_string = "";
while(lista($chave, $valor) = cada($dados)){
$inline = falso;
$numeric_array = falso;
$atributos = "";
#echo "Minha chave atual é '$key', chamada com a chave anterior '$prior_key'<br>";
if(!strstr($key, " attr")){ #se não for um atributo
if(array_key_exists("$chave atr", $data)){
while(list($attr_name, $attr_value) = each($data["$key attr"])){
#echo "Encontrado atributo $attribute_name com valor $attribute_value<br>";
$attr_value = &htmlspecialchars($attr_value, ENT_QUOTES);
$atributos .= " $attr_name="$attr_value"";
}
}
if(is_numeric($chave)){
#echo "Minha chave atual ($key) é numérica. Minha chave pai é '$prior_key'<br>";
$chave = $prior_key;
}outro{
#você não pode ter teclas numéricas em dois níveis seguidos, então está tudo bem
#echo "Verificando se existe uma chave numérica nos dados.";
if(is_array($valor) e array_key_exists(0, $valor)){
# echo "Sim! Chamando a mim mesmo como resultado de um array numérico.<br>";
$numeric_array = verdadeiro;
$xml_serialized_string .= XML_serialize($valor, $nível, $chave);
}
#echo "<br>";
}
if(!$numeric_array){
$xml_serialized_string .= str_repeat("t", $level) "<$key$atributos>";
if(is_array($valor)){
$xml_serialized_string .= "rn" .XML_serialize($valor, $nível+1);
}outro{
$inline = verdadeiro;
$xml_serialized_string .= htmlspecialchars($valor);
}
$xml_serialized_string .= (!$inline ? str_repeat("t", $level) : "") .
}
}outro{
#echo "Ignorando registro de atributo para chave $key<bR>";
}
}
if($nível == 0){
$xml_serialized_string = "<?xml version="1.0" ?>rn" .
retornar $xml_serialized_string;
}outro{
retornar $xml_serialized_string;
}
}
classeXML {
var $parser; #uma referência ao analisador XML
var $document; #toda a estrutura XML construída até agora
var $current; #um ponteiro para o item atual - o que é isso
var $parent; #um ponteiro para o pai atual - o pai será um array
var $parents; #um array do pai mais recente em cada nível
var $last_opened_tag;
função XML($dados=nulo){
$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, "abrir", "fechar");
xml_set_character_data_handler($this->parser, "dados");
#register_shutdown_function(array($this, 'destruir'));
}
função destruir(){
xml_parser_free($this->parser);
}
função analisar($dados){
$this->document = array();
$this->parent = $this->document;
$this->pais = array();
$this->last_opened_tag = NULO;
xml_parse($this->analisador, $dados);
return $este->documento;
}
função aberta($parser, $tag, $atributos){
#echo "Tag de abertura $tag<br>n";
$this->dados = "";
$this->last_opened_tag = $tag; #tag é uma string
if(array_key_exists($tag, $this->pai)){
#echo "Já existe uma instância de '$tag' no nível atual ($level)<br>n";
if(is_array($this->parent[$tag]) and array_key_exists(0, $this->parent[$tag])){ #se as chaves forem numéricas
#precisa ter certeza de que eles são numéricos (considere atributos)
$key = count_numeric_items($this->parent[$tag]);
#echo "Existem instâncias de $key: as chaves são numéricas.<br>n";
}outro{
#echo "Há apenas uma instância. Mudando tudo<br>n";
$temp = $this->pai[$tag];
unset($this->parent[$tag]);
$this->pai[$tag][0] = $temp;
if(array_key_exists("$tag attr", $this->parent)){
#mude os atributos também, se eles existirem
$temp = $this->parent["$tag attr"];
unset($this->parent["$tag attr"]);
$this->parent[$tag]["0 attr"] = $temp;
}
$chave = 1;
}
$this->parent = $this->parent[$tag];
}outro{
$chave = $tag;
}
if($atributos){
$this->parent["$key attr"] = $attributes;
}
$this->parent[$key] = array();
$this->parent = $this->parent[$key];
array_unshift($this->parents, $this->parent);
}
dados da função($parser, $dados){
#echo "Os dados são '", htmlspecialchars($data), "'<br>n";
if($this->last_opened_tag != NULL){
$este->dados .= $dados;
}
}
função fechar($parser, $tag){
#echo "Fechar tag $tag<br>n";
if($this->last_opened_tag == $tag){
$this->parent = $this->dados;
$this->last_opened_tag = NULO;
}
array_shift($this->pais);
$this->parent = $this->parents[0];
}
}
função & XML_unserialize($xml){
$xml_parser = novo XML();
$dados = $xml_parser->parse($xml);
$xml_parser->destruir();
retornar $dados;
}
função & XMLRPC_parse($request){
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_parse', "<p>Recebida a seguinte solicitação bruta:</p>" . XMLRPC_show($request, 'print_r', true));
}
$dados = &XML_unserialize($request);
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_parse', "<p>Retornando a seguinte solicitação analisada:</p>" . XMLRPC_show($data, 'print_r', true));
}
retornar $dados;
}
função & XMLRPC_prepare($dados, $tipo = NULL){
if(is_array($dados)){
$num_elements = contagem($dados);
if((array_key_exists(0, $data) ou !$num_elements) e $type != 'struct'){ #é um array
if(!$num_elements){ #se o array estiver vaziovazio
$returnvalue = array('array' => array('dados' => NULL));
}outro{
$returnvalue['array']['dados']['valor'] = array();
$temp = $returnvalue['array']['dados']['valor'];
$contagem = contagem_numeric_items($dados);
for($n=0; $n<$contar; $n++){
$tipo = NULO;
if(array_key_exists("$n tipo", $dados)){
$tipo = $dados["$n tipo"];
}
$temp[$n] = XMLRPC_prepare($data[$n], $type);
}
}
}else{ #é uma estrutura
if(!$num_elements){ #se a estrutura estiver vazia
$returnvalue = array('struct' => NULL);
}outro{
$returnvalue['struct']['member'] = array();
$temp = $returnvalue['struct']['membro'];
while(lista($chave, $valor) = cada($dados)){
if(substr($key, -5) != 'type'){ #se não for um especificador de tipo
$tipo = NULO;
if(array_key_exists("$tipo de chave", $dados)){
$type = $data["$tipo de chave"];
}
$temp[] = array('nome' => $chave, 'valor' => XMLRPC_prepare($valor, $tipo));
}
}
}
}
}else{ #é um escalar
if(!$tipo){
if(is_int($dados)){
$returnvalue['int'] = $dados;
retornar $valor de retorno;
}elseif(is_float($dados)){
$returnvalue['duplo'] = $dados;
retornar $valor de retorno;
}elseif(is_bool($dados)){
$returnvalue['boolean'] = ($dados? 1: 0);
retornar $valor de retorno;
}elseif(preg_match('/^d{8}Td{2}:d{2}:d{2}$/', $data, $matches)){ #é uma data
$returnvalue['dateTime.iso8601'] = $dados;
retornar $valor de retorno;
}elseif(is_string($dados)){
$returnvalue['string'] = htmlspecialchars($dados);
retornar $valor de retorno;
}
}outro{
$returnvalue[$type] = htmlspecialchars($data);
}
}
retornar $valor de retorno;
}
função & XMLRPC_adjustValue($current_node){
if(is_array($current_node)){
if(isset($current_node['array'])){
if(!is_array($current_node['array']['dados'])){
#Se não houver elementos, retorne um array vazio e vazio
retornar matriz();
}outro{
#echo "Livrando-se do array -> dados -> valor<br>n";
$temp = $current_node['array']['dados']['valor'];
if(is_array($temp) e array_key_exists(0, $temp)){
$contagem = contagem($temp);
for($n=0;$n<$contar;$n++){
$temp2[$n] = &XMLRPC_adjustValue($temp[$n]);
}
$temp = $temp2;
}outro{
$temp2 = &XMLRPC_adjustValue($temp);
$temp = array($temp2);
#Eu faço o trabalho temporário porque evita copiar,
# já que posso colocar uma referência no array
O modelo de referência do #PHP é um pouco bobo, e não posso simplesmente dizer:
# $temp = array(&XMLRPC_adjustValue($temp));
}
}
}elseif(isset($current_node['struct'])){
if(!is_array($current_node['struct'])){
#Se não houver membros, retorne um array vazio e vazio
retornar matriz();
}outro{
#echo "Livrando-se de struct -> member<br>n";
$temp = $current_node['struct']['membro'];
if(is_array($temp) e array_key_exists(0, $temp)){
$contagem = contagem($temp);
for($n=0;$n<$contar;$n++){
#echo "Passando o nome {$temp[$n][name]}. O valor é: " . show($temp[$n][value], var_dump, true) "<br>n";
$temp2[$temp[$n]['nome']] = &XMLRPC_adjustValue($temp[$n]['valor']);
#echo "adjustValue(): Após a atribuição, o valor é " . show($temp2[$temp[$n]['name']], var_dump, true) "<br>n";
}
}outro{
#echo "Passando nome $temp[nome]<br>n";
$temp2[$temp['nome']] = &XMLRPC_adjustValue($temp['valor']);
}
$temp = $temp2;
}
}outro{
$types = array('string', 'int', 'i4', 'double', 'dateTime.iso8601', 'base64', 'boolean');
$fell_through = verdadeiro;
foreach($tipos como $tipo){
if(array_key_exists($type, $current_node)){
#echo "Livrando-se de '$type'<br>n";
$temp = $current_node[$type];
#echo "adjustValue(): O nó atual está definido com um tipo de $type<br>n";
$fell_through = falso;
quebrar;
}
}
if($fell_through){
$tipo = 'string';
#echo "Caiu! O tipo é $type<br>n";
}
switch ($tipo){
caso 'int': caso 'i4': $temp = (int)$temp break;
case 'string': $temp = (string)$temp break;
caso 'duplo': $temp = (duplo)$temp break;
case 'booleano': $temp = (bool)$temp break;
}
}
}outro{
$temp = (string)$current_node;
}
retornar $temp;
}
função XMLRPC_getParams($request){
if(!is_array($request['methodCall']['params'])){
#Se não houver parâmetros, retorne um array vazio e vazio
retornar matriz();
}outro{
#echo "Livrando-se de methodCall -> params -> param<br>n";
$temp = $request['methodCall']['params']['param'];
if(is_array($temp) e array_key_exists(0, $temp)){
$contagem = contagem($temp);
for($n = 0; $n < $contagem; $n++){
#echo "Parâmetro de serialização $n<br>";
$temp2[$n] = &XMLRPC_adjustValue($temp[$n]['valor']);
}
}outro{
$temp2[0] = &XMLRPC_adjustValue($temp['valor']);
}
$temp = $temp2;
retornar $temp;
}
}
função XMLRPC_getMethodName($methodCall){
#retorna o nome do método
return $methodCall['methodCall']['methodName'];
}
function XMLRPC_request($site, $location, $methodName, $params = NULL, $user_agent = NULL){
$site = explodir(':', $site);
if(isset($site[1]) e is_numeric($site[1])){
$porta = $site[1];
}outro{
$porta = 80;
}
$site = $site[0];
$data["methodCall"]["nomeMetodo"] = $NomeMetodo;
$param_count = contagem($params);
if(!$param_count){
$data["methodCall"]["params"] = NULL;
}outro{
for($n = 0; $n<$param_count; $n++){
$data["methodCall"]["params"]["param"][$n]["value"] = $params[$n];
}
}
$dados = XML_serialize($dados);
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Recebida a seguinte lista de parâmetros para enviar:</p>" . XMLRPC_show($params, 'print_r', true));
}
$conn = fsockopen ($site, $port); #abre a conexão
if(!$conn){ #se a conexão não foi aberta com sucesso
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Falha na conexão: Não foi possível fazer a conexão com $site.</p>");
}
return array(false, array('faultCode'=>10532, 'faultString'=>"Falha na conexão: não foi possível estabelecer a conexão com $site."));
}outro{
$cabeçalhos =
"POST $localização HTTP/1.0rn" .
"Hospedeiro: $sitern" .
"Conexão: fecharrn" .
($user_agent ? "User-Agent: $user_agentrn" : '') .
"Tipo de conteúdo: text/xmlrn" .
"Comprimento do conteúdo: " . strlen($data) "rnrn";
fputs($conn, "$cabeçalhos");
fputs($conn, $dados);
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Enviada a seguinte solicitação:</p>nn" . XMLRPC_show($headers . $data, 'print_r', true));
}
#socket_set_blocking ($conn, falso);
$resposta = "";
while(!feof($conn)){
$resposta .= fgets($conn, 1024);
}
fclose($conn);
#strip cabeçalhos fora da resposta
$dados = XML_unserialize(substr($response, strpos($response, "rnrn")+4));
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Recebeu a seguinte resposta:</p>nn" . XMLRPC_show($response, 'print_r', true) . "<p>Que foi serializado nos seguintes dados:< /p>nn" .XMLRPC_show($data, 'print_r', true));
}
if(isset($data['methodResponse']['fault'])){
$return = array(false, XMLRPC_adjustValue($data['methodResponse']['fault']['value']));
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Retornando:</p>nn" . XMLRPC_show($return, 'var_dump', true));
}
retornar $ retorno;
}outro{
$return = array(true, XMLRPC_adjustValue($data['methodResponse']['params']['param']['value']));
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_request', "<p>Retornando:</p>nn" . XMLRPC_show($return, 'var_dump', true));
}
retornar $ retorno;
}
}
}
função XMLRPC_response($return_value, $servidor = NULL){
$data["methodResponse"]["params"]["param"]["valor"] = $return_value;
$return = XML_serialize($dados);
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_response', "<p>Recebemos os seguintes dados para retornar:</p>nn" . XMLRPC_show($return_value, 'print_r', true));
}
header("Conexão: fechar");
header("Comprimento do conteúdo: ". strlen($return));
header("Tipo de conteúdo: texto/xml");
header("Data: ".data("r"));
if($servidor){
header("Servidor: $servidor");
}
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_response', "<p>Enviada a seguinte resposta:</p>nn" . XMLRPC_show($return, 'print_r', true));
}
eco $ retorno;
}
função XMLRPC_error($faultCode, $faultString, $servidor = NULL){
$array["methodResponse"]["fault"]["value"]["struct"]["member"] = array();
$temp = $array["methodResponse"]["fault"]["value"]["struct"]["membro"];
$temp[0]["nome"] = "faultCode";
$temp[0]["value"]["int"] = $faultCode;
$temp[1]["nome"] = "faultString";
$temp[1]["valor"]["string"] = $faultString;
$return=XML_serialize($array);
header("Conexão: fechar");
header("Comprimento do conteúdo: ". strlen($return));
header("Tipo de conteúdo: texto/xml");
header("Data: ".data("r"));
if($servidor){
header("Servidor: $servidor");
}
if(definido('XMLRPC_DEBUG') e XMLRPC_DEBUG){
XMLRPC_debug('XMLRPC_error', "<p>Enviada a seguinte resposta de erro:</p>nn" . XMLRPC_show($return, 'print_r', true));
}
eco $ retorno;
}
função XMLRPC_convert_timestamp_to_iso8601($timestamp){
#pega um carimbo de data/hora unix e o converte para iso8601 exigido pelo XMLRPC
#um exemplo de data e hora iso8601 é "20010822T03:14:33"
return date("YmdTH:i:s", $timestamp);
}
função XMLRPC_convert_iso8601_to_timestamp($iso8601){
retornar strtotime($iso8601);
}
função contagem_numeric_items($array){
retornar is_array($array) ?count(array_filter(array_keys($array), 'is_numeric')) : 0;
}
função XMLRPC_debug($nome_função, $debug_message){
$GLOBALS['XMLRPC_DEBUG_INFO'][] = array($nome_função, $debug_message);
}
função XMLRPC_debug_print(){
if($GLOBALS['XMLRPC_DEBUG_INFO']){
echo "<borda da tabela="1" largura="100%">n";
foreach($GLOBALS['XMLRPC_DEBUG_INFO'] como $debug){
echo "<tr><th style="vertical-align: top">$debug[0]</th><td>$debug[1]</td></tr>n";
}
echo "</table>n";
não definido($GLOBALS['XMLRPC_DEBUG_INFO']);
}outro{
echo "<p>Nenhuma informação de depuração disponível ainda.</p>";
}
}
função XMLRPC_show($dados, $func = "print_r", $return_str = false){
ob_start();
$func($dados);
$saída = ob_get_contents();
ob_end_clean();
if($return_str){
return "<pre>" htmlspecialchars($output) "</pre>n";
}outro{
echo "<pre>", htmlspecialchars($output), "</pre>n";
}
}
?>
Exemplo de programa de servidor, server.php
<?
inclua 'xml-rpc.inc.php';
//Define métodos que podem ser chamados remotamente
$xmlrpc_methods=array();
$xmlrpc_methods['insertRecords']='insertRecords';
//Obtém o nome do método e os parâmetros passados pelo usuário
$xmlrpc_request = XMLRPC_parse($HTTP_RAW_POST_DATA);
$nomeMetodo = XMLRPC_getMethodName($xmlrpc_request);
$params = XMLRPC_getParams($xmlrpc_request);
if (!isset($xmlrpc_methods[$methodName])){
XMLRPC_error('1',"O método que você chamou não existe");
}outro {
$xmlrpc_methods[$nomedometodo]($params);
}
function insertRecords($params){
if (emptyempty($params)){
XMLRPC_error('2',"Erro de parâmetro");
}
XMLRPC_response(XMLRPC_prepare('http://www.emtit.com'));
}
?>
Exemplo de cliente PHP chamando método servidor
<?php
include_once 'xml-rpc.inc';
$params=matriz(2,3);
$result=XMLRPC_request("127.0.0.1","/services/server.php","insertRecords",$params);//O arquivo do servidor é colocado na pasta de serviços
print_r($resultado);
?>