November 13th, 2007Remoting, Web Services y PHP
Los servicios web es software accesible desde internet por otras aplicaciones:
- Son accesibles desde internet ya que son identificadas mediante URI’s.
- Pueden interacturar con otras aplicaciones ya que son descritas, definidas y descubiertas mediante artefactos XML, así pues, los mensajes entre aplicaciones están descritos mediante éste.
En la actualidad se están desarrollando muchos de estos servicios, los cuales podemos usar en nuestras propias aplicaciones. Durante este manual, veremos como crear servicios web mediante remoting, y como acceder mediante PHP a estos servicios usando las librerías nuSoap.
IMPORTANTE: Durante este tutorial, se hará uso de los conocimientos adquiridos en los tutoriales de Remoting. Además, usaremos un servidor de la Calculadora de los ejemplos anteriores… coger uno de los que el servidor recoge la configuración desde un archivo exterior. Si no tenéis tiempo o no queréis mirar los manuales, aquí está el proyecto que sigue este manual (con el servidor, la calculadora y el cliente en PHP).
Puedes escontrar el código fuente de este tutorial aquí.
1. Creando servicios web con NET/Mono Remoting
1.1. SOAP (Simple Object Access Protocol)
Mediante los manuales de Remoting hemos creado aplicaciones distribuidas cliente-servidor. Uno de los canales que los que podíamos hacer uso era el canal HTTP el cual usa SOAP (Simple Object Access Protocol, protocolo basado en XML para hacer llamadas remotas a objetos) para la comunicación entre ellos. Además, como recordaremos, el cliente necesitaba una dirección URI para acceder al servicio remoto.
En el dibujo, podemos comprobar como tanto el servidor como el cliente podrían formar parte de tecnologías diferentes. Lo único que habría que ajustar es el parser SOAP de cada uno de ellos.
En realidad, anteriormente ya habíamos creado servicios web con Remoting. De hecho, el servidor servía nuestra calculadora como un servicio web, y el cliente hacía uso de éste. Para comprobar esto, usaremos un sniffer y capturaremos los mensajes que se generan cuando el cliente llama a la operación Suma (el cliente en color azul, el servidor en color rojo):
POST /Calculadora.remota HTTP/1.1
User-Agent: Mono Remoting Client (Mono CLR 2.0.50727.42)
SOAPAction: “http://schemas.microsoft.com/clr/nsassem/Calculo.Calculadora/Calculo#Suma”
Content-Type: text/xml; charset=”utf-8″
Content-Length: 611
Expect: 100-continue
Connection: close
Host: localhost:8080
HTTP/1.0 100 Continue
Server: Mono Remoting, Mono CLR 2.0.50727.42
Content-Length: 0
X-Powered-By: Mono
Connection: close
<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:clr=”http://schemas.microsoft.com/clr/”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<SOAP-ENV:Body>
<i2:Suma id=”ref-1″
xmlns:i2=”http://schemas.microsoft.com/clr/nsassem/Calculo.Calculadora/Calculo”>
<izq xsi:type=”xsd:double”>2</izq>
<dcha xsi:type=”xsd:double”>2</dcha>
</i2:Suma>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTP/1.0 200 OK
Content-Type: text/xml; charset=”utf-8″
Server: Mono Remoting, Mono CLR 2.0.50727.42
Content-Length: 590
X-Powered-By: Mono
Connection: close<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:clr=”http://schemas.microsoft.com/clr/”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<SOAP-ENV:Body>
<i2:SumaResponse id=”ref-1″
xmlns:i2=”http://schemas.microsoft.com/clr/nsassem/Calculo.Calculadora/Calculo”>
<return xsi:type=”xsd:double”>4</return>
</i2:SumaResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Como podemos ver, el paso de mensajes está formado en SOAP. Las capturas las realicé con Wireshark (Ethereal).
1.2. WSDL (Web service description language)
Como el nombre de WSDL indica, es un lenguaje que describe los servicios web disponibles. Cuando necesitamos acceder a un servicio web, es posible que no sepamos el nombre de los métodos, los argumentos que debemos pasar a cada uno, los tipos de los que disponemos… Toda esta documentación puede ser descrita mediante WSDL y así acceder de manera correcta a los web services.
Podemos acceder al WSDL de nuestra calculadora, de los ejemplos de remoting, arrancando el servidor escribiendo la dirección seguida de “?wsdl” en un navegador, como por ejemplo:
-
http://localhost:8080/Calculadora.remota?wsdl
Y en nuestro navegador nos aparecerá la descripción de nuestra calculadora en WSDL, que cualquier cliente podría usar para documentarse:
- <definitions name=“Calculadora” targetNamespace=“http://schemas.microsoft.com/clr/nsassem/Calculo/Calculo”>
- <types/>
- <message name=“Calculadora.get_LaBaseInput”/>
- <message name=“Calculadora.get_LaBaseOutput”>
- <part name=“return” type=“xsd:double”/>
- </message>
- <message name=“Calculadora.set_LaBaseInput”>
- <part name=“value” type=“xsd:double”/>
- </message>
- <message name=“Calculadora.set_LaBaseOutput”/>
- <message name=“Calculadora.SumaInput”>
- <part name=“izq” type=“xsd:double”/>
- <part name=“dcha” type=“xsd:double”/>
- </message>
- <message name=“Calculadora.SumaOutput”>
- <part name=“return” type=“xsd:double”/>
- </message>
- …
Hemos cogido solo una parte del WSDL para describirlo ligeramente. En el ejemplo, aparecen las operaciones get y set para el atributo laBase y el método Suma. Como vemos, cada operación tiene dos partes: Input y Output que describen la entrada (los argumentos de entrada) y la salida (el resultado de la operación). La única nota a remarcar es no confundirnos con los nombres de los métodos: por ejemplo, la operación para Sumar es Suma y no SumaInput.
2. El servidor
Para el manual usaremos nuestra calculadora y el servidor recogerá la siguiente configuración:
- <configuration>
- <system.runtime.remoting>
- <application>
- <channels>
- <channel ref=“http” port=“8080″ />
- </channels>
- <service>
- <wellknown mode=“SingleCall”
- type=“Calculo.Calculadora, Calculo”
- objectUri=“Calculadora.soap” />
- </service>
- </application>
- </system.runtime.remoting>
- </configuration>
A sido tan fácil crear un servidor que comparta servicios web, que no hemos tocado nada nuevo.
3. Cliente en PHP
Ya que el servidor únicamente necesita mensajes en SOAP, podemos usar cualquier aplicación que pueda mandarle este tipo de mensajes y así poder recibir la respuesta en SOAP. Como ejemplo, en este tutorial, aprenderemos a usar PHP con una librería llamada nuSoap, que nos ayuda en las peticiones al servidor. Descargaremos las librerías de nuSoap y crearemos la siguiente estructura de archivos (para que todos lo hagamos igual y funcione):
- www (carpeta que usa Apache para las páginas web)
- lib (la carpeta lib de nuSoap)
- Cliente.php
- lib (la carpeta lib de nuSoap)
NOTA: para que el cliente en PHP funcione, tendremos que haber instalado un servidor Apache para que funcione con PHP. Hay un manual de como hacerlo (bajo [X]Ubuntu) aquí.
En el archivo Cliente.php escribiremos lo siguiente:
- <html>
- <head>
- <title>Web services con C# y PHP</title>
- </head>
- <body>
-
- <?
- // Ejemplo de nuSoap del archivo /samples/client1.php modificado para
- // nuestra calculadora. Tambien esta traducido al castellano y anyadido algunos
- // comentarios de mas :P
- // Librerias de nuSoap
- require_once(‘lib/nusoap.php’);
- // Configuracion inicial
- //$servicioRemoto = ‘http://localhost:8080/Calculadora.soap’;
- $servicioRemotoWSDL = ‘http://localhost:8080/Calculadora.soap?wsdl’;
- $proxyhost = isset($_POST['proxyhost']) ? $_POST['proxyhost'] : ”;
- $proxyport = isset($_POST['proxyport']) ? $_POST['proxyport'] : ”;
- $proxyusername = isset($_POST['proxyusername']) ? $_POST['proxyusername'] : ”;
- $proxypassword = isset($_POST['proxypassword']) ? $_POST['proxypassword'] : ”;
- // $cliente = new nusoap_client(
- // $servicioRemoto, false,
- // $proxyhost, $proxyport, $proxyusername, $proxypassword);
- // Con WSDL
- $cliente = new nusoap_client(
- $servicioRemotoWSDL, ‘wsdl’,
- $proxyhost, $proxyport, $proxyusername, $proxypassword);
- //Comprobamos errores
- $err = $cliente->getError();
- if ($err)
- {
- echo ‘<h2>Error en el constructor</h2><pre>’ . $err . ‘</pre>’;
- echo ‘<h2>Debug</h2><pre>’.
- htmlspecialchars($client->getDebug(), ENT_QUOTES) . ‘</pre>’;
- exit();
- }
- // Llamaremos al metodo Sumar, el cual tiene los parametros a y b
- // Creamos un array que representa los parametros
- $parametros = array(
- ‘izq’ => ‘8′,
- ‘dcha’ => ‘9′
- );
- // Hacemos una llamada al metodo y recogemos el resultado
- $metodo = ‘Suma’;
- $resultado = $cliente->call($metodo, $parametros,”,”);
- // Comprobamos los errores y mostramos el resultado
- if ($cliente->fault)
- {
- echo ‘<h2>Error: La peticion contiene un contenido SOAP invalido</h2>’.
- ‘<pre>’; print_r($resultado); echo ‘</pre>’;
- }
- else
- {
- $err = $cliente->getError();
- if ($err)
- {
- echo ‘<h2>Error</h2><pre>’ . $err . ‘</pre>’;
- }
- else
- {
- echo ‘<h2>Resultado</h2><pre>’; print_r($resultado); echo ‘</pre>’;
- }
- }
- ?>
-
- </body>
- </html>
Como vemos, el cliente en PHP necesita varias cosas:
- Inicializar el cliente, pudiendo especificar un proxy web intermedio. Se puede usar tanto la dirección del WSDL como la del servicio. En el código he puesto las dos, pero he comentado una (podéis cambiarlo para ver que el resultado es el mismo).
- Construir un array con los argumentos que necesita el método.
- Hacer una llamada al método remoto que necesitamos y recoger la respuesta.
- Mostrar el resultado o el posible error (por no poder establecer la conexión, por un error en los argumentos, porque el método no exista, …)
Ahora iniciaremos el servidor y accederemos mediante nuestro navegador a nuestra página en PHP para ver los resultados. Si hemos añadido trazas en nuestra calculadora, podremos ver que se ejecutan en la consola del servidor cuando el cliente en PHP hace las consultas:
- ./Servidor.exe
Constructor
Metodo: Suma
Salida en el navegador web.
Array
{
[return] => 17
[!id] => ref-1
}
Con esta introducción, podemos descubrir por nosotros mismos la funcionalidad de nuSoap, que seguro que se os han llenado la cabeza de ideas… aunque todavía nos quedan algunas cosas que tratar:
- ¿Funcionan igual las formas de compartir singleCall, singleton y CAO con PHP y nuSoap?
- Operaciones que tienen argumentos de tipo out y ref.
- ¿Como recoger otro tipo de datos que no sean los nativos?
- Servicios web que nos ofrecen otras compañías (como Google).
Podéis recoger el código fuente de este tutorial en la sección Source Code.

