Cómo consumir un WebService SOAP con PHP

Qué son los WebServices

Los WebServices son un mecanismo muy útil para integrar aplicaciones a través del protocolo HTTP, y de ese modo, aprovechar las capacidades de terceros dentro de nuestras propias aplicaciones.

Un ejemplo muy común es de las pasarelas de pago, como ser PayPal o MercadoPago.

Se basan siempre en la existencia de dos procesos:

  • El cliente (Consumidor)
  • El servidor (Productor)

A nivel técnico existen dos operaciones que pueden realizarse a través de WebServices:

  1. Consumirlos
  2. Exponerlos

Uno de los protocolos que pueden utilizar los WebServices es SOAP (Otro muy común es REST).

Consumirlos usando PHP es bastante simple, para ello se utiliza la clase SoapClient.

Cómo obtener la localización del visitante usando su IP

Para este ejemplo usaremos el WebService de cdyne.com para obtener información geográfica en base a la IP buscada.

<?php

$url = "http://ws.cdyne.com/ip2geo/ip2geo.asmx?wsdl";

try {
 $client = new SoapClient($url, [ "trace" => 1 ] );
 $result = $client->ResolveIP( [ "ipAddress" => $argv[1], "licenseKey" => "0" ] );

 print_r($result);
} catch ( SoapFault $e ) {
 echo $e->getMessage();
}


echo PHP_EOL;

En este caso, este script debería ser corrido desde CLI.

Por ejemplo, si lo guardás como «ws.php», al ejecutar php ws.php 210.45.151.101 obtendrás la salida:

stdClass Object
(
 [ResolveIPResult] => stdClass Object
 (
 [City] => Huainan
 [StateProvince] => 01
 [Country] => China
 [Organization] => 
 [Latitude] => 32.6264
 [Longitude] => 116.9969
 [AreaCode] => 0
 [TimeZone] => 
 [HasDaylightSavings] => 
 [Certainty] => 90
 [RegionName] => 
 [CountryCode] => CN
 )
)

Como podrás observar, la respuesta del método ResolveIP es un objeto de tipo StdClass.

StdClass es una clase genérica de PHP (Algo medio raro y, casi diría que un abuso de la naturaleza interpretada del lenguaje). Esta clase no tiene métodos ni propiedades definidas, pero sirve como una especie de contenedor al que se le puede asignar arbitrariamente todo lo que uno quiera (En rigor de verdad, esto puede hacerse con cualquier clase de PHP, sólo que es preferible no hacerlo).

Básicamente, al construir el cliente a partir de la definición de un WSDL están disponibles todos los servicios expuestos como métodos propios (como si estuviesen accesibles en forma local, a pesar de que la verdadera llamada es remota).

Es interesante notar esto, si ves la línea $result = $client->ResolveIP( [ "ipAddress" => $argv[1], "licenseKey" => "0" ] ); podrás notar que se está invocando al método ResolveIP sobre un objeto de clase SoapClient.

La clase SoapClient es una clase estándar de PHP, mientras que el método ResolveIP sólo tiene sentido dentro de este WebService. Si te estás preguntando cómo puede una clase estándar reconocer métodos desconocidos te diría que deberías darle una mirada al tema de los métodos mágicos de PHP (O tomar el curso de PHP Orientado a Objetos).

Como te imaginarás, si existe la clase SoapClient… debe existir la clase SoapServer (Tema de otro post).

En el curso de PHP WebServices estudiamos este tema en mayor profundidad, mientras tanto, si te quedó alguna duda podés dejarla en un comentario.

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

18 comentarios

  1. Tengo una duda, como se le puede fijar el outgoing ws-security desde php? necesito acceder a una ruta que requiere unas firmas de seguridad especifica, si puedes compartir una documentación o darme algún consejo lo agradezco mucho, porque estuve revisando en la documentación a ver si tenia que enviarlo en la array de options, pero allí no aparecé nada

  2. Hola soy nuevo en esto de consumir soap tengo una duda que no logro resolver al hacer mi peticion por algunos metodos si la informacion biene de esta forma

    hola
    mundo

    no tengo problemas para convertirlos a un arreglo y trabajarlo, quedandome algo asi:

    object(stdClass)#2 (1) { [«xResult»]=> object(stdClass)#3 (2) { [«x1»]=> string(4) «hola» [«x2»]=> string(5) «mundo» } }

    array(2) {
    [«x1»]=>
    string(4) «hola»
    [«x2»]=>
    string(5) «mundo»
    }

    pero otros métodos me regresan la información de esta forma

    hola
    mundo

    y no logro acceder a los campos que ocupo, pues me los regresa como si fuera una sola cadena y no puedo separarlos como quiero, cualquier comentario lo agradecería mucho

  3. Hola mchojrin,

    Uso la función
    $client = new SoapClient(«rutinas/some.wsdl», array(‘login’=> «xxxxxx»,’password’=> «xxxxxx»));
    $hoy=date(‘d-m-Y’);
    $res=$client->ubicaciones( array(‘StartDate’=> $hoy,’EndDate’=> $hoy,’count’=>’MEXICO’));

    Hasta aquí tengo respuesta, el detalle es que faltan algunos campos, esto lo se porque al consultar desde SOAPUI esos campos si los veo, la única diferencia es que el archivo wsdl que importo a PHP camio la linea a false o de lo contrario lanza un error
    Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Unknown required WSDL extension

    También uso curl_init de esta manera los campos en cuestión si aparecen, pero tengo el problema de lidiar con la respuesta XML, tiene algún POST sobre la respuesta XML?

    1. Habría que ver por qué da error al importar el WSDL… ¿será que el archivo está mal formado? Tal vez podrías descargarlo y analizarlo con alguna herramienta tipo http://www.wsdl-analyzer.com/

      Para ver temas de XML puedes consultar https://academy.leewayweb.com/como-recorrer-un-archivo-xml-usando-php/

      Aunque te recomiendo intentar arreglar el problema de SOAP… intentar interpretar un XML de un webservice puede ser una tarea realmente compleja…

    1. Hola Miguel!

      Gracias por tu pregunta 🙂

      Por lo qe veo que comentas me inclino a pensar que hay un problema con las URLs. Tal vez tengas un archivo .htaccess o similar mal configurado? En todo caso, prueba ingresar a la URL http://miurl.co.co/carpetadondesealojaelws/wsprueba.wsdl.asmx (Es decir, sin el ?wsdl) a ver qué sucede.

      Si ni así puedes entrar es casi seguro que sea lo que te comento, si no es eso habría que mirar más en profundidad.

      Suerte!

  4. una consulta, a mi me retorna al hacer tal cual como haces el $result en forma de cadena, toda la respuesta, del servicio SOAP como podria acceder a cada uno de los campos o en todo caso como podria devolver el $result en forma de std class como en tu caso para acceder a cada uno de los campos, saludos

  5. Hola muchas gracias por la explicacion, tengo una duda como se podria obtener el valor por ejemplo de [City] => Huainan este ultimo Huainan, estoy trabajando con un ejemplo similar pero no este caso

    saludos

    1. Hola Daniel:

      Gracias por tu pregunta. Muy acertada por cierto :).

      Voy a modificar el artículo para que quede más claro, mientras tanto, la forma de acceder a la campo City sería:

      echo $result->ResolveIPResult->City;

      Esto funciona así porque $result es un objeto de clase StdClass (La clase «genérica» de PHP), si te fijas la salida del print_r notarás que tiene una propiedad que se llamana ResolveIPResult (también de clase StdClass) que tiene una propiedad City, en este caso Huainan.

      Puedes leer más sobre StdClass en el sitio de php.net: http://php.net/manual/es/reserved.classes.php.

      ¿Me expliqué correctamente?

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.