You are on page 1of 8

Implementando servicios web con PHP

En la actualidad el término servicios web (web services) forma parte esencial dentro del
mundo del desarrollo de software, ya se ha escrito mucho sobre que son y cuales tecnologías
usan, por lo tanto la razón de ser de este artículo es realizar una implementación real de
servicios web con una tecnología tan importante como lo es el PHP, hablando un poco
también de los fundamentos teóricos pero sin ahondar demasiado en el tema.

Para lograr la implementación de servicios web en PHP se usó las tecnologías XML-RPC y SOAP
sobre las cuales se implementaron servidores y clientes consumidores de servicios web.

Servicios Web

Los servicios Web han venido a revolucionar el mundo de la programación, nos ofrecen una
infinidad de ventajas y nos ayudan a mejorar la forma de procesar información. Pero, ¿qué es
un servicio Web?, pues bien, es computación distribuida utilizando estándares abiertos como
XML y HTTP para llamar o invocar funciones de otras aplicaciones independientes sea cual sea
el sistema operativo o plataforma en que se ejecutan.

Ahora bien, podemos realizar un servicio Web sencillo en nuestra computadora, pero
posiblemente éste no cumplirá con estándares de comunicación, es por eso que debemos de
entender que para realizar una correcta función de nuestros servicios Web es necesario
estandarizarlos por medio de protocolos. Existen dos tendencias en particular que es XML-RPC
y SOAP. Estos dos protocolos son lenguajes de mensajería basada en XML, estandarizados por
el consorcio W3C.

XML-RPC

XML-RPC es el protocolo de llamada de procedimientos remotos (RPC: Remote Procedure
Calling), el cual trabaja sobre internet. Un mensaje de XML-RPC es una petición del HTTP-
POST [1]. El cuerpo del mismo está en XML, un procedimiento es ejecutado en el servidor y el
valor que devuelve está en formato XML. Un ejemplo de una petición [6] sería el siguiente:

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
<methodName>ejemplo.buscaIsbn</methodName>
<params>
<param>
<value><i4>1</i4></value>
</param>
</params>
</methodCall>

Un ejemplo de respuesta [6] sería entonces:

HTTP/1.1 200 OK
Connection: close
Content-Length: 158
Content-Type: text/xml
Date: Fri, 17 Jul 1998 19:55:08 GMT
Server: UserLand Frontier/5.1.2-WinNT

<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>PHP</string></value>
</param>
</params>
</methodResponse>

SOAP

SOAP (Simple Object Access Protocol, Protocolo de acceso a objetos simple)[3] es un
protocolo basado en XML que consiste de tres partes: la primera define cuál es el mensaje y
cómo procesarlo, la segunda es un sistema de reglas de codificación para expresar tipos de
datos definidos y una tercera parte para representar respuestas de llamadas por parte de
procedimientos remotos.

La diferencia básica entre los dos protocolos anteriores es su complejidad. XML-RPC está
diseñado para ser sencillo, mientras que SOAP está hecho con la idea de ofrecer un soporte
completo de todo tipo de servicio web.

Por otro lado, también es conveniente describir qué es WSDL. Pues bien, WSDL es un formato
XML que describe los servicios de red como un conjunto de puntos finales que procesan
mensajes contenedores de información orientada tanto a documentos como a procedimientos.
Las operaciones y los mensajes se describen de manera abstracta y después se enlazan a un
protocolo de red y a un formato de mensaje concreto para definir un punto final de red.

Desarrollo de un servidor XML-RPC

Como usaremos el framework XML-RPC [2] desarrollado por Edd Dumbill para desarrollar
nuestros servicios web basados en XML-RPC.

Dicho framework cuenta con la clase xmlrpc_server para construir nuestros servidores, la cual
se ha desarrollado lo más simple posible. El constructor básicamente hace todo el trabajo,
veamos un pequeño ejemplo:

<?php
function foo($parametros)
{
/* Instrucciones php */
}
$servidor=new xmlrpc_server(array("ejemplo.miFuncion"=>array("function"=>"foo")));
?>

Es todo lo que necesitamos hacer en un servidor. El único argumento que requiera la clase es
un arreglo asociativo de los nombres de los métodos a los nombres de las funciones que se van
a exponer, las cuales son responsables de regresar un objeto xmlrpcresp, el cual es serializado
de regreso.

xmlrpcresp.- Esta clase se usa para proveer las respuestas a las peticiones XML-RPC. Un
método en el servidor construirá el xmlrpcresp y regresará su valor. Este valor es el que se
regresa al invocar el método send de la clase xmlrpc_client. Existen dos formas de crear esta
clase:

<?php
$res = new xmlrpcresp($valor_xmlrpc);
$res = new xmlrpcresp(0, $NoError, $err);
?>

La primera instancia se usa cuando la ejecución ocurrió sin excepciones, $valor_xmlrpc es un
valor xmlrpcval con el resultado de la ejecución del método.

El segundo constructor se usa en caso de falla, $NoError y $err son valores para indicarnos lo
que estuvo mal. Los métodos más comunes de esta clase son:

faultCode:

<?php $codigo=$res->faultCode(); ?>

Regresa el código del error. Un valor de 0 indica éxito, cualquier otro valor indica falla.

faultString:

<?php $error=$res->faultString(); ?>

Regresa la descripción del error.

value:

<?php $valor_xmlrpc=$res->value(); ?>

Regresa un objeto xmlrpcval que contiene el valor regresado por el servidor. Si el faultCode
no es 0 entonces el valor regresado por este método no debe ser usado (puede que no sea un
objeto incluso).

Ahora que ya conocemos el funcionamiento de las clases que crean el servidor y forman las
respuestas vamos a crear nuestro servidor XML-RPC que contendrá el servicio web de buscar el
título de un libro enviando su ISBN con el que hemos trabajado.

<?php
//Ejemplo de un servidor XML-RPC en PHP
//Recibe un ISBN y regresa el Título //del libro.
include("xmlrpc.inc");
include("xmlrpcs.inc");
function BuscaIsbn($NoIsbn) {
global $NoError;
$err="";
// Obtenemos el parametro
$ParIsbn=$NoIsbn->getParam(0);
// Vemos si es del tipo correcto
if (isset($ParIsbn) && ($ParIsbn->scalartyp()=="int"))
{ // Obtenemos el valor numerico
$isbn=$ParIsbn->scalarval();
// Buscamos el libro
switch($isbn)
{
case 1: $titulo="PHP";
break;
case 2: $titulo="XML_RPC";
break;
case 3: $titulo="Sitios web";
break;
case 4: $titulo="Linux";
break;
default:$NoError=1;
$err="No hay libro ". "con el ISBN '". $isbn . "'";
}
} else // No es entero
{$err="Se requiere un número";}
// Creamos la respuesta
if ($err) // Si hay error
{ return new xmlrpcresp(0, $NoError, $err); }
else // Si no hay error
{ return new xmlrpcresp(new xmlrpcval($titulo)); }
}
//Creamos el servidor
$s=new xmlrpc_server(array("libros.buscaIsbn" =>array("function" => "BuscaIsbn")));
?>

Ya contamos con nuestro servidor XML-RPC y nuestro servicio web listo para ser usado.

Desarrollo de un cliente XML-RPC

El siguiente paso es conocer las clases que podemos usar para crear un cliente XML-RPC para
que consuma servicios web XML-RPC, demos un vistazo rápido a las clases principales.

xmlrpc_client.- Esta es la clase básica para un cliente XML-RPC, la forma de usarla es la
siguiente:

<?php $cliente = new xmlrpc_client($ruta_servidor,$nombre_servidor,$puerto_servidor);
?>

El puerto es opcional si se omite usa por defecto el 80 para HTTP y el 443 para HTTPS. Los
métodos más comunes de esta clase son:

send:

<?php $respuesta = $cliente->send($mensaje_xmlrpc,$tiempo_limite,$metodo_servidor);
?>
Donde $mensaje_xmlrpc es una instancia de xmlrpcmsg. $tiempo_limite es opcional y será 0
su valor si es omitido lo cual indica que censará siempre. El parámetro $metodo_servidor
también es opcional si se omite será por defecto "http", el otro valor permitido es "https" que
es una conexión SSL_HTTP. Si el valor de repuesta es 0, significa que ocurrió un error de
entrada / salida, se puede conocer los valores del error en $cliente->errno y en $client-
>errstring.

setDebug:

<?php $cliente->setDebug($valor); ?>

Donde $valor es 0 o 1 dependiendo si deseamos que el cliente imprima la información de
depuración en el navegador. Por defecto no imprime la información (0).

xmlrpcmsg.- Esta clase provee una representación para una petición a un servidor XML-RPC.
Un cliente envía un xmlrpcmsg al servidor y recibe un xmlrpcresp.

<?php $msg = new xmlrpcmsg($nombre_metodo,$arreglo_parametros); ?>

Donde $nombre_metodo es una cadena que indica el nombre del método que se desea invocar
y $arreglo_parámetros es un arreglo simple de objetos xmlrpcval. El método más común de
esta clase es:

xmlrpcval.- Esta clase es la que permite la creación y encapsulamiento de los valores para
XML-RPC (hace el trabajo sucio). Cuenta con diferentes constructores:

<?php $valor=new xmlrpcval(); ?>

Crea un valor vacío, que debe ser alterado usando los métodos addScalar, addArray o
addStruct antes de ser usado.

<?php $valor=new xmlrpcval($cadena_texto); ?>

Crea una cadena de texto sencilla.

<?php $valor=new xmlrpcval(
$valor_escalar,"int"|"boolean"|"string"|"double"|"dateTime.iso860"|"base64"); ?>

Es usado para crear un valor escalar. El segundo parámetro debe ser el nombre de un tipo
XML-RPC.

Ejemplos:

<?php $entero=new xmlrpcval(123,"int"); ?>
<?php $cadena=new xmlrpcval("Hola","string"); ?>
<?php $boleano=new xmlrpcval(1,"boolean"); ?>

<?php $valor=new xmlrpcval($arreglo,"array"|"struct"); ?>
Se usa para crear valores complejos XML-RPC. EL primer argumento es un arreglo simple en el
caso de usar "array" o un arreglo asocativo en el caso de "struct". Los elementos del arreglo
deben ser objetos xmlrpcval.

Ejemplos:

<?php $arreglo=new xmlrpcval( array(new xmlrpcval("Abi"), new
xmlrpcval("Pedro")), "array"); ?>

<?php $estructura=new xmlrpcval( array("nombre"=>new xmlrpcval("Abi"),
"edad"=>new xmlrpcval( 23,"int")),"struct"); ?>

Con estas clases son suficientes para poder desarrollar nuestro cliente XML-RPC, que esta de
la siguiente manera:

<?php
include("xmlrpc.inc");
if ($HTTP_POST_VARS["txtIsbn"]!="")
{ $f=new xmlrpcmsg('libros.buscaIsbn',array(new xmlrpcval($HTTP_POST_VARS["txtIsbn"],
"int")));
print "<pre>".htmlentities($f->serialize())."</pre>\n";
$c=new xmlrpc_client("/servidor.php", "localhost", 80);
$c->setDebug(0);
$r=$c->send($f);
if (!$r)
{ die("Falló SEND"); }
$v=$r->value();
if (!$r->faultCode())
{ print "Título del libro ".$HTTP_POST_VARS["txtIsbn"]." es ".$v-
>scalarval()."<BR>"; }
else
{ print "Falla: ";
print "Número de error: " .$r->faultCode()." Descripción del error '".$r-
>faultString()."'<BR>";}
}
?>

Listo ya hemos implementado nuestro servidor y nuestro cliente XML-RPC, pero no es la única
forma de consumir o crear servicios, veamos otra forma de crear y consumir servicios web.

Desarrollo de clientes SOAP con PHP

La mayoría de los servicios web que encontramos en la actualidad se basan en los estándares
SOAP y WSDL [5] analizados anteriormente.

La implementación de SOAP sobre PHP que vamos a utilizar se llama NuSOAP [4] que es
desarrollado por la empresa NuSphere y que fue liberado bajo licencia LPGL.

Veamos el siguiente script en PHP que usa SOAP para consumir un servicio web que regresa el
típico mensaje de "Hola Mundo":

<?php
// Manejo de la forma para ver si ya se envió
if (!(string)$_POST["boton"] == "") {
// Incluimos las clases de SOAP
require("nusoap.php");
// crea el cliente
$cliente = new soapclient("http://www.pecesama.net/ws/server.php?wsdl",
"wsdl");
$proxy = $cliente->getProxy();
// llamada al metodo (BuscaIsbn)
$resultado = $proxy->BuscaIsbn((string)$_POST["isbn"]);
// Revisa errores
if (!$cliente->getError()) {
// muestra resultados
print "El titulo del libro con ISBN ".(string)$_POST["isbn"]." es:
".$resultado;
}
// Error
else {
echo "<h1>Error: ".$cliente->getError()."</h1>";
}
}
?>
<!-- Forma de busqueda -->
<form name="datos" action="#" method="POST">
ISBN: <input type="text" name="isbn">
<input name="boton" type="submit" value="Buscar">
</form>

De esta sencilla manera podemos consumir servicios web basados en SOAP, solo enviándole la
dirección del WSDL que como vimos es la descripción del servicio web creando una clase proxy
por medio de la cual llamamos el método.

De esta manera logramos consumir con nuestro lenguaje favorito (PHP) tantos y tantos
servicios web que existen en la actualidad basados en SOAP y WSDL de una manera sencilla y
rápida.

Desarrollo de servidores SOAP con PHP

Solo nos falta desarrollar un servidor de servicios web con SOAP y PHP, para esto seguiremos
usando NuSOAP y nuevamente usaremos el ejemplo de buscar el título del libro mediante su
ISBN:

<?php
// Incluimos las clases de SOAP
require("nusoap.php");
// Creamos el objeto del servidor
$servidor=new soap_server();
// Registramos la función que queremos exponer como servicio web
$servidor->register("buscaIsbn");
// Generación del WSDL
$servidor->debug_flag=false;
$servidor->configureWSDL("ISBN", "http://www.pecesama.net/ws");
$servidor->wsdl->schemaTargetNamespace = "http://www.pecesama.net/ws";
/*// Agregamos un tipo de dato complejo
$servidor->wsdl->addComplexType(
"datosLibro",
"complexType",
"struct",
"all",
"",
array(
"titulo" => array("name"=>"titulo", "type"=>"xsd:string"))
);*/
// Registramos el método
$servidor->register("BuscaIsbn", array("titulo" => "xsd:string"),
array("return"=>"xsd:string"), http://www.pecesama.net/ws");

function BuscaIsbn($isbn)
{
if (isset($isbn))
{
switch($isbn) /*No usaremos base de datos*/
{
case 111: $titulo="Taller de PHP";
break;
case 222: $titulo="PHP y XML_RPC";
break;
case 333: $titulo="Creando sitios web con PHP";
break;
case 444: $titulo="PHP para principiantes";
break;
default: return new soap_fault("Client", "", "El libro no existe.", "");
}
}
else
{
// No hay isbn
return new soap_fault("Client", "", "No envio ISBN.", "");
}
return $titulo;
}
// Enviar el resultado como una respuesta SOAP por HTTP
$servidor->service($HTTP_RAW_POST_DATA);
exit();
?>