Logo de islavisual
Isotipo de islavisual IslaVisual
imagen de sección

Ultima revisión 25/01/2013

Paso de Parámetros en SOAP y PHP I

Este artículo va para todos aquellos que se preguntan cómo puede hacer la comunición SOAP con tipos de datos simples y complejos. Es decir, cómo enviar-recibir parámetros mediante SOAP.

Una de las cosas que todos vemos, o solemos ver, al principio cuando nos metemos en el mundo del los Servicios Web es el XML-RPC (un protocolo de llamada a procedimiento remoto que usa XML para codificar los datos y HTTP para la transmisión de mensajes) pero, si investigáis un poco, descubriréis que muchos lenguajes no se llevan muy bien que digamos con este protocolo.

Seguidamente, uno le echa valor y se decide, por ejemplo, a implementar un Web Service en PHP y, de repente, se encuentra con otro obstáculo. PHP 5.x no es que esté demasiado "maduro" en este tema y además, como se puede comprobar fácilmente, hay escasa documentación.

Después de pelearse y conseguir nuestro primer Servicio Web, Luego uno se también suele meterse en los archivos de descripción WSDL y, normalmente, ya muchos toman la decisión de dejarlo por imposible porque, aunque parecen sencillos, pero no lo son.

Bueno. No hay que ponerse catastrofistas. Una de las grandes aportaciones que nos hace SOAP y WSDL es que tanto el servidor como el cliente, de forma automática, comprueban muchos errores y lo hace todo de forma independiente al usuario. Es por esta razón que nos encontramos tantos problemas para realizar estructuras complejas como son los array asociativos.

Si lo que queremos es crear o gestionar datos simples como cadenas, enteros o fechas, esta tecnología puede ayudarnos mucho pero, si lo que se quiere es gestionar estructuras de elementos complejas como son los arrays asociativos los dolores de cabeza aumentarán considerablemente ya que no existe casi documentación sobre ello, y por si fuera poco, la que hay, o no lo explican bien, o no es del todo veráz.

Dicho esto, recordemos que los Servicios Web se componen de 3 partes básicamente. Definición del archivo WSDL, el archivo PHP del Cliente y el archivo PHP del Servidor. El WSDL es el más importante ya que sin este nunca funcionará.

Por si no habéis tocado mucho el SOAP, primero, haremos un ejemplo con paso de parámetros simples y, a continuación, realizaremos uno con estructuras complejas.

Ejemplo 1: Paso de Parámetros Simples en SOAP

La archivo WSDL (soap.wsdl)

Como se ve a continuación, NO DECLARAMOS NINGÚN TYPES porque al sólo tener que manejar un parámetro simple de tipo string ya lo hace sóla la aplicación.

<?xml version="1.0" encoding="utf-8"?>
<!-- NOTAS IMPORTANTES -->
<!-- ***************** -->
<!-- SI SE CAMBIA EL SERVICIO WEB DE UBICACIÓN SE DEBE SUSTITUIR http://www.islavisual.com/ws POR LA URL QUE PROCEDA. -->
<!-- SI ADEMÁS SE UTILIZA UN ARCHIVO schema.xsd TAMBIÉN HAY QUE CAMBIARLO DÓNDE APAREZCA. -->
<definitions name="servicio" 
             targetNamespace='http://www.islavisual.com/ws/soap.wsdl'
             xmlns            ='http://schemas.xmlsoap.org/wsdl/'
             xmlns:http        ="http://schemas.xmlsoap.org/wsdl/http/"
             xmlns:soap        ="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:SOAP-ENC    ="http://schemas.xmlsoap.org/soap/encoding/" 
             xmlns:xsd        ='http://www.w3.org/2001/XMLSchema'>
    
    <!--    AHORA DEBEMOS DEFINIR LO QUE EN SOAP SE DENOMINA MENSAJES. ESTOS MENSAJES SE CORRESPONDEN CON EL NOMBRE DE LA
            FUNCIÓN Y SUS PARÁMETROS DE LA CLASE DEL SOAP-SERVER. 
            EL name DEL message ES EQUIVALENTE AL NOMBRE DE LA FUNCIÓN. 
            EL name DE CADA part SE CORRESPONDE CON CADA UNO DE LOS PARÁMETROS DE LA FUNCIÓN. 
            EN EL ELEMENTO part:
                SI QUEREMOS DEFINIR PARÁMETROS DE ENTRADA LO HAREMOS CON EL ATRIBUTO type EN EL MENSAJE QUE TERMINA EN Request.
                SI QUEREMOS DEFINIR PARÁMETROS DE ENTRADA LO HAREMOS CON EL ATRIBUTO type EN EL MENSAJE QUE TERMINA EN Response.-->
    
    <!-- MESSAGE estaActivo -->
    <message name='estaActivoRequest'>
        <part name='message' type='xsd:string' />
    </message>
    <message name='estaActivoResponse'>
        <part name='result' type='xsd:string' />
    </message>
    <!-- fin MESSAGE estaActivo -->
    
    <!--    DEFINICIÓN DE LAS OPERACIONES PERMITIDAS Y MENSAJES INVOLUCRADOS (PETICIÓN Y RESPUESTA, ...).
            NORMALMENTE    TANTO input COMO output TENDRÁN CORRESPONDENCIAS CON LOS MENSAJES DEFINIDOS EN LA ZONA DE MENSAJES
            ANTES DEFINIDA. -->
            
    <portType name='servicioPortType'>
        <!-- OPERACION estaActivo -->
        <operation name='estaActivo'>
            <input message='tns:estaActivoRequest' />
            <output message='tns:estaActivoResponse' />
        </operation>
        <!-- fin OPERACION estaActivo -->
    </portType>
    
    <!--    AHORA ESPECIFICAMOS LOS PROTOCOLOS DE COMUNICACIÓN USADOS. DICHO DE OTRA MANERA ES LA DEFINICIÓN DEL FORMATO DE 
            CADA MENSAJE Y DETALLES DEL PROTOCOLO DE CADA PortType.
            AQUÍ DECLARAMOS UNA OPERACIÓN, LE ASOCIAMOS LA FUNCIÓN DE LA CLASE Y, SU ENTRADA Y SALIDA -->
            
    <binding name='servicioBinding' type='tns:servicioPortType'>
        <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>
        <!-- OPERACION estaActivo -->
        <operation name='estaActivo'>
            <soap:operation soapAction='http://www.islavisual.com/ws#estaActivo' />
            <input>
                <soap:body use='literal' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' namespace='http://www.islavisual.com/ws' />
            </input>
            <output>
                <soap:body use='literal' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
            </output>
        </operation>
        <!-- fin OPERACION estaActivo -->
    </binding>
    
    <!-- AHORA REALIZAMOS LA DEFINICIÓN DEL CONJUNTO DE PUERTOS Y DIRECCIÓN DE LOS MISMOS. -->
    <service name='servicio'>
        <port binding='tns:servicioBinding' name='servicioPort'>
            <soap:address location='http://www.islavisual.com/ws/soapServer.php'/>
        </port>
    </service>
</definitions>

La archivo client.php

Podemos declarar las opciones de la conexión estableciendo un array bastante simple:

$options = array(
    // Opciones frecuentes
    'trace' => true,
    'exceptions' => true,
    'wsdl_cache' => WSDL_CACHE_NONE,
    'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
    'soap_version'   => SOAP_1_2,

    // Credenciales de Autentificación para peticiones SOAP.
    'login' => 'username',
    'password' => 'password',
    
    // Codificación de la conexión
    'encoding'=>'UTF-8',
    
    // URL del Proxy. No se debe poner aquí el http ó https ya que no funcionaría.
    'proxy_host' => 'www.islavisual.com', 
    'proxy_port' => 44300,
    
    // Credenciales de Autentificación para el Proxy.
    'proxy_login' => NULL,
    'proxy_password' => NULL);

Establecemos la conexión:

$client = new SoapClient("http://www.islavisual.com/ws/soap.wsdl", $options );

Hacemos la llamada a la función deseada. En este caso es una función muy simple que sólo nos devuelve el TimeStamp de Unix si recibe el valor 'Hello' y NULL si no coincide.

$client->isAlive( new SoapParam("Hello", "message"));

Y finalmente procedemos a establecer las cabeceras y la respuesta del Servidor:

header ("Content-Type:text/xml; charset=utf-8");
echo $client->__getLastResponse();

La archivo server.php

Primero podemos configurar algunas variables del Servidor aunque no es necesario:

ini_set("soap.wsdl_cache_enabled", "1");
ini_set("soap.soap.wsdl_cache_dir", "/tmp");
ini_set("soap.wsdl_cache_ttl", "86400");

Segundo declaramos la clase con las funciones a incorporar a nuestro Web Service:

class SOAPFunctions {
    private $_SOAPSERVER = NULL;
    private $_HEADERVARS = "";
    private $_params     = array();
    private $_USER         = "";
    private $_PASSWORD     = "";

    public function __construct($soapServer_resource){
        $this->_SOAPSERVER     = $soapServer_resource;
        $this->_USER        = $_SERVER['PHP_AUTH_USER'];
        $this->_PASSWORD    = $_SERVER['PHP_AUTH_PW'];
    }

    public function isAlive($message){
        if($message == "Hello") return time();
        else return NULL;
    }
}

Finalmente establecemos el Constructor de SoapServer y configuramos unas pocas propiedades:

$wsdl = "http://".$_SERVER['SERVER_NAME'].dirname($_SERVER['SCRIPT_NAME'])."/";
$soap_server  = new SoapServer($wsdl."soap.wsdl");
$soap_server->setClass("SOAPFunctions", $soap_server);
$soap_server->handle();

  • Con setClass le indicamos cuál es la clase que tiene nuestros métodos.
  • Con handle le indicamos que procese la petición SOAP y nos devuelva una respuesta.

Ahora si lo queréis probar sólo tendréis que ejecutar o llamar al client.php

Ahora pasemos al capítulo 2 en el que explicaremos como realizar el Paso de Parámetros en SOAP con Estructuras complejas como son los arrays asociativos.

Sobre el autor

Imagen de Pablo Enrique Fernández Casado
Pablo Enrique Fernández Casado

CEO de IslaVisual, Manager, Full Stack Analyst Developer y formador por cuenta ajena con más de 25 años de experiencia en el campo de la programación y más de 10 en el campo del diseño, UX, usabilidad web y accesibilidad web. También es escritor y compositor de música, además de presentar múltiples soft kills como la escucha activa, el trabajo en equipo, la creatividad, la resiliencia o la capacidad de aprendizaje, entre otras.

Especializado en proveer soluciones integrales de bajo coste y actividades de consultoría de Usabilidad, Accesibilidad y Experiencia de Usuario (UX), además de ofrecer asesoramiento en SEO, optimización de sistemas y páginas web, entre otras habilidades.