SOAP – Server y Cliente en PHP con Nusoap.

Introducción

Antes que nada no voy a entrar en detalles del protocolo sino de como implementarlo con php, pero me consta que lo correcto es al menos aclarar, aunque sea repetitivo, que significan estas siglas.
Sin meterme mucho en el tema puedo contarles que SOAP son las siglas de siglas de Simple Object Access Protocol, el cual obviamente es un protocolo que fue creado por varios grosos (MS, IBM, Etc), y su fuente de datos es el XML con un diseño que cumple el patrón Cabecera-Desarrollo y que actualmente está auspiciado por la W3C.

Es un protocolo que se usa mucho para webservices, y por lo tanto, para hacer una petición desde un cliente se necesita una respuesta desde un servidor.

Si lo que se desea es crear un cliente, el cual hace peticiones a un SOAP servidor que no es nuestro, la tarea será más simple. Ahora, si lo que se desea es tener un cliente, ya el enfoque es otro aunque nada complicado, ya lo verán.

Lo único a tener en cuenta es que debemos contar con una directiva del php.ini indispensable para su funcionamiento, ésta es la directiva always_populate_raw_post_data la cual debe estar en ON.

Otra necesidad es poder tener algo con cual poder escribir y parsear este xml, para ellos tenemos dos opciones: una es usar las funciones que nos da php al habilitar una dll, para más información de esto pueden ver la documentación de php en php.net/soap; dos, usar nusoap, una clase hecha para esta tarea, la cual permite crear cliente, servidor.

Para ser más prácticos les mostraré un simple ejemplo de un servidor y un cliente.

Primer paso, tener nuestro servidor.

Para comenzar no podremos avanzar sin antes tener nuestra querida librería nusoap. En este ejemplo he usado la versión 0.7.2, la cual pueden descargar desde acá.

Una vez en sus máquinas, pueden descomprimir el directorio lib del zip en un directorio nuestro llamado “include” (o el nombre que más les guste). No es necesario mover los ejemplos, pero si gustan pueden darle una mirada, cosa que nunca está de más.

Para usar esta clase todo lo que debemos hacer en nuestro php es incluirla. Entonces, creamos un php que se llame server.php, y en él escribimos:

<?
require_once(‘includes/nusoap.php’);
?>

Ahora bien, necesitamos crear un objeto del tipo servidor, eso es simple, lo hacemos instanciando el método soap_server, nos quedaría algo así:

<?
require_once(‘includes/nusoap.php’);
$server = new soap_server;
?>

Bien, hasta acá venimos bárbaro, pero me olvide de comentarles que la tarea de un servidor es la de servir. Claro que este comentario es obvio!, pero para el caso no se preguntan que es lo que servirá mi servidor? Pues no más que datos es la respuesta que pensarán y es correcta. El tema es nuestros datos se servirán en base a una petición del cliente mediante funciones, tal cual cuando usamos funciones nuestras del tipo getUser( $id ).

Entonces, para procesar de manera simple una petición haremos una función en php, una simple función, por ejemplo:

function hola( $name ){
return «Hola {$name}»;
}

De más esta decir que puedo tener todas las funciones necesarias y estas estar en un archivo aparte, pero para el ejemplo es lo mismo.

Ahora bien, aquí viene lo interesante del servidor y es que registraremos en nuestro SOAP la función que acabamos de crear de la siguiente manera:

$server->register( ‘hola’ );

Solo nos resta tomar toda la petición del cliente, y esto lo haremos con la variable de php llamada $HTTP_RAW_POST_DATA la cual contiene el post en bruto. En caso de no contar con la directiva always_populate_raw_post_data en ON como dijimos, pueden intentar setearla de la siguiente manera, aunque no garantizo su funcionamiento ya que depende de otras configuaraciones del servidor web y OS:

$rawPost = strcasecmp($_SERVER[‘REQUEST_METHOD’], ‘POST’) == 0? (isset($GLOBALS[‘HTTP_RAW_POST_DATA’])? $GLOBALS[‘HTTP_RAW_POST_DATA’] : file_get_contents(«php://input»)) : NULL;

Una cosa que no esta de más es validar el dato que nos manda el cliente, para esto podemos modificar la función para crear un fault, quedando así:

function hola( $name ){
return empty( $name ) ? new soap_fault(‘Client’,»,’Ingrese un nombre válido’) : «Hola » . $name;
}

Ahora, como está todo en partes, para sintetizar quedaría así nuestro achivo que llamaremos para el ejemplo servidor.php:

<?
$rawPost = strcasecmp($_SERVER[‘REQUEST_METHOD’], ‘POST’) == 0? (isset($GLOBALS[‘HTTP_RAW_POST_DATA’])? $GLOBALS[‘HTTP_RAW_POST_DATA’] : file_get_contents(«php://input»)) : NULL;
require_once(‘includes/nusoap.php’);
$server = new soap_server;
$server->register(«hola»);
$server->service($rawPost);
function hola( $name ){
return empty( $name ) ? new soap_fault(‘Client’,»,’Ingrese un nombre válido’) : «Hola » . $name;
}
?>

Solo resta nuestro cliente para poder probarlo, que como les decía es mucho más simple.
El mismo todo lo que debe hacer es llamar a nuestro servidor haciendo llamada a la función hola y pasarle un parámetro que es lo que ésta espera.

Para ellos creamos cliente.php, incluimos nuevamente la clase nusoap, e instanciamos al método soapclient pasándole como parámetro la url de nuestro servidor. Una vez creado el objeto haremos un método call a nuestra función hola y le pasaremos los parámetros necesarios, tan simple como esto:

<?
require_once(‘includes/nusoap.php’);
$soapclient = new soapclient(‘http://estudiowas.com.ar/nusoaptest/server.php&#8217;);
echo $soapclient->call( ‘hola’ , array(‘name’ => ‘Mundo’) );
?>

Ya tenemos nuestro servidor y nuestro cliente, pueden verlo funcionando desde acá

Con el servidor podemos servir o procesar peticiones de un cliente cualquiera. Con nuestro cliente podemos llamar a un servidor y usar sus prestaciones.

Espero que este ejemplo les sea practico y puedan usarlo en grandes ideas!, acá dejo las descargas:

Nusoap 0.7.2

Ejemplo completo

Llamada al cliente

43 Responses to SOAP – Server y Cliente en PHP con Nusoap.

  1. Claudio dice:

    Me gusto la simplicidad del todo, y lo mejor es que funciona, no se como es que tengo la directiva esa funcionando, pero lo voy a llamar suerte.

    Ahora tendré que ver como autentificarme contra el servidor y que este me procese el pedido, pero supongo que teniendo esto en mis manos ya podré lograrlo más fácil. Si saben si lo hago como si fueran simples funciones como hola les agradecere a quién aporte 😉

    Gracias campeón.

  2. Helena dice:

    El ejemplo esta muy bien pero, podrías hacer un ejemplo de un servicio web que cogiera los datos de varias bases de datos distintas y los mostrara en el cliente???

  3. Nicolaspar dice:

    Helena, lo que pides es simple, deberías en el servidor tener varias conexiones (una por cada diferente base de datos), y luego funciones registradas que hagan lo que necesitas con cada conexión, de manera independiente o combinada.

    De esta manera, el cliente pedirá la llamada a la función del servidor quien le dará los datos necesarios de estas dbs.

    Saludos.

  4. Helena dice:

    Gracias, Nicolas.

  5. lucas dice:

    a mi no me funciono!! extraje los archivos y me sale este mensaje cuando compilo el server.php:

    Fatal error: Cannot redeclare class soapclient in C:\Dokumente und Einstellungen\laguero\Desktop\Lucas\nusoaptest\includes\nusoap.php on line 7240

    que paso?

  6. Nicolaspar dice:

    Lucas: tenés instalada la dll de soap en tu php; más info: http://ar2.php.net/manual/es/ref.soap.php

    No se porque usan el mismo nombre, pero podés editar tu php.ini y así desinstalar esta dll, o bien usar ésta y no nusoap.

  7. cript dice:

    Está bien la introducción, pero nusoap no permite manejo de sesiones verdad ?¿?

    Imaginémonoes que queremos hacer un webservice, en el que el primer paso sea la autentificación y si estamos autentificados ya podemos acceder a los recursos del webservice de los que obtendremos diferentes resultados dependiendo del usuario que acceda.

    ¿Cómo podríamos hacer esto?

  8. genial!

    ahora, si sabre como empezar 😀

  9. Sabigual dice:

    Gracias por la publicación, pero me dá este error tu ejemplo y ya tengo la librería activa en mi servidor.

    Fatal error: Cannot redeclare class soapclient in C:\AppServ\www\nusoaptest\includes\nusoap.php on line 7240

    Alguna idea??

  10. Sabigual dice:

    No creo que sea problema de la librería que trae PHP Version 5.2.3, ya que esta libreria le funciona a otros servidores, ha de ser algo mas, no se, yo uso el proyecto appserver que trae apache, php, mysql y este funciona bien.

    Espero si es posible arrojen mas luz al respecto de este error que no encuentro la razon por la que ni este ni ningun otro ejemplo se me ejecuta en mi servidor.

    Gracias anticipadas por la colaboración muchach@s.

  11. Yulimar dice:

    Hola. Necesito de su ayuda por favor, si alguien sabe como enviar datos estructurados a un Webservices, escribanme. La estructura es de la siguiente forma:

    string
    string
    string
    char

    string

    Gracias.

  12. elo950 dice:

    Gracias, me ha sido de mucha ayuda aunque hubiera sido mas completo si usabamos un wsdl, aun asi es el yuyorial mas simple que encontre y me sirve de base, gracias de nuevo

  13. German dice:

    Gracias por el aporte y no te molestes por los patudos que piden ayuda para sus trabajos.
    Saludos

  14. Luis dice:

    Estimados.

    Tengo un problema me conecto a un web service que esta en .net. instalado en la red local. Al invocar al metodo desde el Cliente y pasarle un parametro , funciona a la perfeccion.

    Pero si hago lo mismo a un web service que esta en la internet , no llegan los parametros que envio.

    Ocupo:
    – nusoap nusoap-0.7.3.zip
    – PHP Version 5.0.5

    y asi hago el llamado al webservice llamando al metodo ValidaXML y pasando como parametro hola:

    require_once(‘lib/nusoap.php’);
    $wsdlURL = ‘http://test.dvs.cl/WebServiceLuisRelease/WebServiceLuis.asmx?WSDL’;
    $soap = new soapclient($wsdlURL, ‘WSDL’);
    $result = $soap->call(‘ValidaXML’,’hola’);
    $data=$result[«ValidaXMLResult»];

    Tendre que configurar el php.ini o algo asi , ya que tengo comunicacion con el web service que esta en internet , pero no llegan los parametros.

  15. Sonao dice:

    Buenas, estoy intentando comunicarme con un servicio web por soap. Tengo la siguiente duda: ¿las funciones del servidor las creo yo o las crean ellos para que las llamen desde fuera?

  16. nicolaspar dice:

    Por si no quedo claro, el cliente y el server no son más que archivos PHPs en nuestro ejemplo. Entonces, si tenés acceso al ws server, o sos el que lo crea deberás si crear las funciones.
    Sino, solo podrás usar las que te hayan creado en el mismo usando solamente el ws cliente.

  17. Antonio dice:

    hola, estoy empezando a usar un servicio nusoap como cliente y éste me responde en xml, mi pregunta es ¿como puedo coger los datos de ese xml? yo se como coger los datos de un archivo en xml pero no en una respuesta de nusoap, estoy buscando por internet y no encuentro nada, espero que me puedas ayudar, gracias de antemano. Saludos

  18. Matony dice:

    El articulo esta muy bien explicado lo malo es que no puedo ver en funcionamineto el ejemplo.

    Descargue los archivos y tampoco lo puedo ver. Me sale este mensaje a alguien mas le salio esto?? como lo soluciono??

    Fatal error: Cannot redeclare class soapclient in C:\xammp\htdocs\webservice\nusoaptest\includes\nusoap.php on line 7240

  19. Enrique dice:

    A mí me sucede lo mismo que Matony, me sale el mismo error tanto para el ejemplo que en mi máquina..

    ¿Alguien sabrá por qué ocurre ésto?

  20. nicolaspar dice:

    Hola, ese error es porque tenés habilitada la extensión soap de PHP y la class nusoap usa los mismos nombres. Leete como usarla en http://www.php.net/soap o bien edita el php.ini y pon en OFF esta extensión. Saludos.

  21. isantos dice:

    que tal..
    gracias por el aporte, es un ejemplo muy sencillo y facil de hacer, ya lo eh checado… solo que necesito que me ayudes a recoger datos de una bd mysql, eh estado intentandolo pero aun no puedo hacerlo….
    Te invito a que visites y comentes mi blog | http://www.ddsmedia.net/blog

  22. atmjesus dice:

    Hola!!

    Yo lo he probado pero en vez de devolverme por pantalla «Hola Mundo», me devuelve «Array» :S

    ¿Alguna solución?

    Graciass

  23. GUiLTY dice:

    si te devuelve array mira que contesta.

    echo $soapclient->call( ‘hola’ , array(’name’ => ‘Mundo’) );

    cambialo por

    $resposta = $soapclient->call( ‘hola’ , array(’name’ => ‘Mundo’) );

    var_dump($resposta);

    un saludo!

  24. Hola me gustaria saber como puedo cachar errores en el servidor, que son generados por enviar información al bufer, o al menos es lo que parece, por que en el cliente me dice le siguiente mensaje: el formato de mensaje no es XML correcto.

    • daniel dice:

      estan los metodos fault y error del soap, la sintaxis es mas o menos asi
      $resposta = $soapclient->call( ‘hola’ , array(’name’ => ‘Mundo’) );
      if($resposta->fault){ //la falta }

      no recuerdo exactamente pero e trabajado con eso, creca el codigo de nusoap.php y busca esos metodos… son dos para la captura y manejo de errores. l ose por que e trabajado con eso , pero bueno no lo tengo a la mano ahora…

  25. daniel dice:

    Hola como puedo modificar el código que das como ejemplo para que al ir la dirección del servidor donde se encuentre el servidor.php me de una lista de los servicios que tiene para ser consumidos? por que intento hacerlo como siempre uso unos servicios con C# poniendo el URl y el nombre del archivo seguido de ?WSDL y me da es un error me dice que no es WSDL lo que esta aceptando el servicio..

    me gustaría publicar una serie de servicio y quie me muestre un listado como explique antes, alguien me puede ayudar en eso?

  26. luis cisternas dice:

    Hola amigos:
    Les cuento que tengo que conectarme a un W.S de .net , cuyo wsdl es SVC.
    Lo he realizado de la misma forma que con un asmx(el cual en otros w.s «ASMX», me funciona perfecto).
    El wsdl es asi:

    El Nombre del metodo es «Solicitudes» el cual NO RECIBE NINGUN PARAMETRO
    y el Response(Result) es «SolicitudesResponse»

    Debiese recibir esto:
    Response: Solicitudes

    0

    Esta es la forma en que trato de conectarme.
    [B]
    Forma 1:
    $wsdlURL=’http://IPSERVIDOR/DemandaWs/Demandas.svc?wsdl’;
    if($wsdlURL!=»)
    {
    $soap = new soapclient($wsdlURL,’WSDL’);
    $result = $soap->call(‘Solicitudes’,», », », false, true);
    $data=$result[«SolicitudesResponse»];
    }

    Forma 2
    $wsdlURL=’http://IPSERVIDOR/DemandaWs/Demandas.svc?wsdl’;
    if($wsdlURL!=»)
    {
    $soap = new soapclient($wsdlURL,’WSDL’);
    $result = $soap->call(‘Solicitudes’,», », », false, true);
    $data=$result[«SolicitudesResult»];
    }

    [COLOR=»Red»]Conclusion , no recibo ningun paramtero del result al colocarle un var_dump($data), recibo NULL.

    1.-¿Se conecta de la misma forma para un asmx y un SVC? , estoy utilizando la version del PHP Version 5.2.14 y require_once(‘lib/nusoap.php’) Version 0.7.2 [/COLOR]
    2.-Tendre que configurar el php.ini, he estado averguando y el wsdl svc es un wcf.
    [/B]

    Anteriormente lo he hecho con un asmx e aqui un ejemplo :

    Me conecto asi y me funciona correctamente :

    $soap = new soapclient($wsdlURL,’WSDL’);
    $param = 1;
    $result = $soap->call(‘DEL_DOC’, array(‘parameters’ => $param), », », false, true);
    $data=$result[«DEL_DOCResult»];

    Se agradece cualquier aporte amigos…………….

  27. Luis dice:

    No funciona cuando hago clic en el link, se ve facil.

  28. Walter Chalco dice:

    El problema con:
    Fatal error: Cannot redeclare class soapclient in C:\xammp\htdocs\webservice\nusoaptest\includes\nusoap.php on line 7240

    fue solusionado comentado el php.ini
    ;extension=php_soap.dll

  29. Julio dice:

    Una pregunta, quiero meter 2 funciones en un mismo servidor.php

    lo estoy haciendo así:

    $server->register(‘enviaarchivo’, // method name
    array(‘curp’ => ‘xsd:string’,’id’ => ‘xsd:string’,’tokentr’ => ‘xsd:string’), // parametros solicitados por el metodo
    array(‘return’ => ‘xsd:string’), // parametros de regreso
    ‘urn:servicioenvio’, // namespace
    ‘urn:servicioenvio#enviaarchivo’, // soapaction
    ‘rpc’, // style
    ‘encoded’, // uso
    ‘Envia archivo en sobre soap codificado base64’ // documentacion
    );

    $server->register(‘datosbruto’, // method name
    array(‘curp’ => ‘xsd:string’,’id’ => ‘xsd:string’,’tokentr’ => ‘xsd:string’), // parametros solicitados por el metodo
    array(‘return’ => ‘xsd:string’), // parametros de regreso
    ‘urn:datosbruto’, // namespace
    ‘urn:datosbruto#datosbruto’, // soapaction
    ‘rpc’, // style
    ‘encoded’, // uso
    ‘Regresa los resultados en bruto en base al layout’ // documentacion
    );

    Sin embargo en la página: http://www.validwsdl.com se pueden ver los métodos que incluye y todo; pero solo logra ver el primero, el segundo método no aparece.

    Hay algo diferente qué hacer cuando se registran 2 métodos?

    Saludos

  30. Way cool! Some extremely valid points! I appreciate you writing this write-up and also the rest of the website is very good.

  31. coka dice:

    Hola yo tengo un problema al correr tu programa que cuando ejecuto el codigo del cliente m manda una pagina en blanco que puedo hacer en este caso estuve investigando dics que es porque mi maquina es de 64bits y dicn k es por eso xk segui tods los pasos k tienes en tu pagina porfa resuelveme mi duda gracias

  32. Cristian dice:

    Hola…. Tengo un problema y no se como solucionarlo:
    Tengo un WS para validar usuario y contraseña, y otro para listar articulos… funcionan ahora bien, lo que necesito es listar los articulos solamente si el usuario y la contraseña son correctas, o sea como incluyo un WS dentro de otro para hacer que valide ??

    Espero haber sido claro…
    Muchas gracias

    • Se me ocurren dos opciones simples.
      1- En el mismo WS que valida al usuario, si es correcto, listas las noticias.
      2- Sino, un poco más complicado, generas un token en el login (lo que hacen los servicios más comunes). Luego, pasando el token correcto listarías noticias o lo que necesites. El token puede ser una combinación de md5($key.$userID), donde $key es un dato privado tuyo a modo de password. Si queres caducar el token podés correr un cron una vez por día que elimine de un tabla (o file, o lo que sea) los token creados con más de X segundos/minutos/días…

      Espero que te ayude la lógica planteada. Sino puede recurrir a cifrados más complejos usando oAuth por ejemplo, pero salvo que, por ejemplo sea una entidad bancaria, dudo que te sea necesario.

      • Cristian dice:

        Estimado Nicolas…
        No logro que funcione el login y listar los productos… o sea funcionan por separado, cuando los quiero combinar no me funciona… alguna idea de como ???

        Desde ya muchísimas gracias
        Saludos

  33. Cristian dice:

    Estimado Nicolas… muchas gracias en responder. Voy a tratar de probar esas opciones.
    te comento, soy nuevo en esto de los WS, y estoy pensando eso dado que cualquiera que acceda a la URL puedo hacer uso del mismo, o sea lo veo como débil, vulnerable, por eso lo pensé de esa forma, por ahi hay otra forma de hacerlo seguro y no lo estoy viendo: mi pensamiento es: por ejemplo tengo un ABM de articulos, el que acceda a http://direccion.com/articulos.php?wsdl tiene pleno acceso al mismo, me explico ?? por eso mismo lo pensé de esa manera, ya que todos los ejemplos son simples y no contemplan esto que estoy planteando.

    Si tienes alguna corrección a mi logica por favor te agradecería que me indiques cual y como.

    Desde ya muchísimas gracias
    Saludos

  34. Thanks in favor of sharing such a nice thinking, article is good, thats
    why i have read it completely

  35. Hector D'aleman dice:

    Hola, muchas gracias por el articulo.
    Tengo una pregunta, necesito leer una .dll de un dispositivo externo, tomar los datos que el me entrega y enviarle estos al servidor. Como puedo hacer uso de esto?, tendran algun ejemplo porfavor?
    Gracias…

Deja un comentario