Consumir Webservices SOAP desde PHP

Para consumir servicios webs desde PHP no necesitamos más que una instalación básica de PHP que ya viene con la clase SoapClient que está para salvarnos la vida.

¿Qué es un webservice SOAP?

Primero hay que saber que los servicios web pasan por una comprobación de datos a través de XML mediante archivos WSDL. Todo servidor SOAP tiene un WSDL que es la definición del servicio web. Dentro de un servicio web hay definidos objetos y funciones. Lo normal es que tengamos que utilizar estas funciones enviando estos objetos y recibiéndolos como respuesta. Cada llamada (Request) tiene una respuesta (Response) asociada.

Como ya he comentado en el artículo “Como usar webservices (SOAP) de forma correcta” una herramienta muy buena es SoapUI para hacer llamadas de prueba y verificar como han de ser las llamadas.

Conectarse al servicio

El primer paso es conectarse al servicio y ver que tiene dentro, para esto es necesario crear una clase SoapClient.

<?php

$cliente = new SoapClient("http://www.webservicex.net/globalweather.asmx?wsdl");

//obtener las funciones a las que puedo llamar
$funciones = $cliente->__getFunctions();

echo "<h2>Funciones del servicio</h2>";
foreach ($funciones as $funcion) {
	echo $funcion . "<br />";
}

//obtener los tipos de datos involucrados
echo "<h2>Tipos en el servicio</h2>";
$tipos = $cliente->__getTypes();

foreach ($tipos as $tipo) {
	echo $tipo . "<br />";
}

//veremos algo así en la pantalla del navegador:
/*

Funciones del servicio

GetWeatherResponse GetWeather(GetWeather $parameters)
GetCitiesByCountryResponse GetCitiesByCountry(GetCitiesByCountry $parameters)
GetWeatherResponse GetWeather(GetWeather $parameters)
GetCitiesByCountryResponse GetCitiesByCountry(GetCitiesByCountry $parameters)

Tipos en el servicio

struct GetWeather { string CityName; string CountryName; }
struct GetWeatherResponse { string GetWeatherResult; }
struct GetCitiesByCountry { string CountryName; }
struct GetCitiesByCountryResponse { string GetCitiesByCountryResult; }

*/

Reconociendo la información

Para muchos webservices veremos que las funciones están repetidas, esto es porque están definida para las 2 versiones de SOAP (1.1 y 1.2). De la primer función podemos deducir que se llama GetWeather, que recibe un parámetro de tipo GetWeather y devuelve un objeto de tipo GetWeatherResponse (Es muy común que el tipo de la respuesta de una función se llame igual a la función concatenando “Response” detrás).

Llamando a la función

Supongamos que queremos llamar a la función GetWeather, entonces necesitamos definir el objeto GetWeather para pasarlo por parámetro.

<?php

//crear clase para los parametros necesarios.

class GetWeather {
    public $CityName;
    public $CountryName;
    public function __construct($cityName, $countryName){
        $this->CityName = $cityName;
        $this->CountryName = $countryName;
    }
}

//inicio cliente SOAP
$cliente = new SoapClient("http://www.webservicex.net/globalweather.asmx?wsdl");

//hago la llamada pasando por parámetro un objeto como el que se define arriba
$respuesta = $cliente->GetWeather( new GetWeather('Barcelona','Spain') );

var_dump($respuesta); // se imprime por pantalla la respuesta que será un Array asociativo con la estructura definida como GetWeatherResponse

Más adelante haré otro artículo relacionado con Headers, muchas veces se han de enviar encabezados específicos en un webservice y no es tan directo como los parámetros.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInShare on StumbleUpon
Pablo Oneto

Soy un desarrollador de software web especializado en PHP.

28 Comments

  1. Josué Aguirre

    Saludos Pablo, me puedes ayudar con lo siguiente por favor:

    Estoy trabajando en un cliente php pero al ejecutar el codigo me marca un error, he trabajado en varios web services y nunca he tenido este inconveniente, creo que es la forma en que envío los parámetros, he probado de varias formas y no lo consigo.

    Pobré el web service con SoapUi y no me da ningún error. Le probe con soapclient y con nu soap.

    Te dejo el código a ver si me puedes hechar una mano. Gracias de antemano.

    ‘2’,
    ‘Branch’ => ‘Quito’,
    ‘ClientWeight’ => ‘3’,
    ‘Comments’ => ‘Testing WebService’,
    ‘Company’ => ’10’,
    ‘ContentSdtl’ => ‘Testing Contents’,
    ‘CustomerId’ => ‘01346’,
    ‘DeclaredValue’ => ‘100’,

    ‘DeliveryAddress’ => array(
    ‘AddressLine1’ => ‘Sangurima 22-13’,
    ‘AddressLine2’ => ‘Luis Pauta’,
    ‘City’ => ‘Cuenca’,
    ‘Country’ => ‘Ecu’,
    ‘Name’ => ‘Josué Aguirre’,
    ‘Phone’ => ‘0995474970’,
    ‘State’ => ‘Azuay’,
    ‘ZipCode’ => ‘0’,
    ),

    ‘ElectronicWeight’ => ‘5’,
    ‘GUIANumber’ => ”,
    ‘Height’ => ’10’,
    ‘Idtrx’ => ’75’,
    ‘Length’ => ’10’,
    ‘Password’ => ‘TEST’,
    ‘PickUpConsignee’ => ‘52307’,
    ‘PickupRequestDate’ => ’05/20/2016′,
    ‘Pieces’ => ‘1’,
    ‘Service’ => ‘CRG’,
    ‘UnitDimension’ => ‘CM’,
    ‘Username’ => ‘WEBSERVICE’,
    ‘Warehouseid’ => ‘QUITO’,
    ‘Warehouseidloc’ => ”,
    ‘WeightUnit’ => ‘KG’,
    ‘Width’ => ’10’,
    );

    /*try
    {
    $WS = new SoapClient($WebService);
    $result = $WS->CreateWayBill($parametros);
    $code = $result->WayBillResponse->ReturnCode;
    }
    catch(SoapFault $exception)
    {
    echo $exception->getMessage();
    }*/

    $WS = new nusoap_client($WebService, ‘wsdl’);

    $WS->soap_defencoding = ‘UTF-8’;

    $err = $WS->getError();
    if($err) echo ‘{“error_connect”:”‘ .$err.'”}’;

    $result = $WS->call(“CreateWayBill”, $parametros);

    if ($WS->fault)
    {
    echo ‘Fallo: ‘;
    print_r($result);
    }
    else
    {
    $err = $WS->getError();
    if($err)
    {
    echo ‘Error: ‘.$err ;
    }
    else
    {
    echo ‘Resultado: ‘;
    print_r ($result);
    }
    }
    ?>

    1. Pablo Oneto
      Pablo Oneto

      Para poder hacer esto, seguramente necesites generar los headers necesarios… pronto hare un artículo hablando de ello, pero mira esto: $auth = array(
      ‘UserName’=>’USERNAME’,
      ‘Password’=>’PASSWORD’,
      );
      $header = new SoapHeader(‘NAMESPACE’,’Auth’,$auth,false);
      $client->__setSoapHeaders($header);
      Fuente:
      http://php.net/manual/es/class.soapheader.php#107889

    1. Pablo Oneto
      Pablo Oneto

      En el ejemplo del artículo, $response es un objeto con la respuesta, totalmente utilizable. En la variable habrá cualquier cosa, dependiendo de lo especificado en el caso del WebService que tengas que integrar. Por ejemplo, el objeto de la respuesta tendrá propiedades de este estilo: $response->temperature = 28, $response->humidity = 92, $response->sunrise = 7:02 que podrás utilizar sin problemas.

  2. CESAR B M

    Hola Pablo gracias tu articulo es muy bueno, yo particularmente no soy muy bueno (por ahora) en php y he podido utilizar a algunos de los servicios a los que me quiero conectar, te quería preguntar en el caso de que el método del webServ solicite un parámetro y retorne múltiples(mas de 3) valores de retorno como seria la declaración

    1. CESAR B M

      Listo! tenia que poner el nombre de la variable como se llama en el web service y solo para retroalimentar:

      class CONSULTAPEDIDO {
      public $SFOLIO;
      public function __construct($Sfolio){
      $this->SFOLIO = $Sfolio;//este campo era el necesario si le cambio de nombre no funciona
      }
      }
      //inicio cliente SOAP
      $cliente = new SoapClient(“yourwhebservices”);
      $folio=’314095′;
      //hago la llamada pasando por parámetro un objeto como el que se define arriba
      $respuesta = $cliente->CONSULTAPEDIDO(new CONSULTAPEDIDO($folio));

      var_dump($respuesta); // se imprime por pantalla la respuesta que será un Array asociativo con la estructura definida como GetWeatherResponse

  3. Jose Hernández

    Hola Pablo, que buenos tutoriales tienes, pero he buscado un caso como este que estoy haciendo y no logro resolver:

    Estoy consumiendo un web service por php pero necesito que la respuesta me diga: “True VISA” y no como aparece en la última línea que está encerrado en un objeto. Me podrías ayudar con este caso? Te lo agradeceré mucho!

    $url = “https://secure.ftipgw.com/ArgoFire/validate.asmx?WSDL”;
    $cliente = new SoapClient($url);
    $debito_credito = $cliente->IsDebitCard(array(‘CardNumber’=>’4435894871662287’));
    $b = $debito_credito->IsDebitCardResult;

    print_r($b);

    stdClass Object ( [any] => TrueVISA )

    1. Pablo Oneto
      Pablo Oneto

      La respuesta depende enteramente del servidor al que haces la petición… por lo que veo, tendrías que utilizar el objeto $b y retornar $b->any

  4. xflores77

    Hola Pablo, este tutorial esta muy bueno. Gracias.
    Tengo una consulta yo tengo un problema consumiendo un web service nose si me puedes ayudar.
    el queryString busca un record donde el valor de cynetyNumber = 1
    Se puede mandar params en esta forma?

    $params = array(‘queryString’ ->’cynetyNumber’ = 1 , ‘entity name ->’company’);
    $response = $client->$function($params);

    gracias

    1. Pablo Oneto
      Pablo Oneto

      Esto depende del server, te recomendaría hacer una clase con stdClass como esto:

      $queryString = new stdClass;
      $queryString->cynetyNumber = 1;
      $queryString->entityName = “company”;
      $response = $client->function($queryString);

      pero depende del dato que espere el servidor siempre, si espera una clase o si espera un array.

  5. Jamesson Parra

    Dada la experiencia broda. Gracias a tu articulo de no usar “nusoap” me ayudo, mejor respuesta y estabilidad al ser nativo de PHP 5 >… Pero tengo una duda, como se accede a las funciones de un XML que tiene la función dentro de una clase. EJEMPLO: nameFunction.ExecuteResponse Execute(nameFunction.Execute $parameters)

    1. Pablo Oneto
      Pablo Oneto

      No he tenido este problema, pero esto seguro que la forma de llamar a la función la obtendrás con __getFunctions:

      $cliente = new SoapClient("www.servicio.com?wsdl");
      $funciones = $cliente->__getFunctions();
  6. Jamesson Parra

    Lo he logrado, pero para esto ( y no te va a gustar por ser una recomendación que haces de no usarlo) he llamado a la libreria nusoap. usando lo siguiente:

    require_once (__DIR__ .”/lib/nusoap.php”);

    $tagAccion = ”.$tuValor.”;

    $client = new nusoap_client(“www.nameServicio.aspx?wsdl”,true);
    $personaWS = $client->send($client->serializeEnvelope($tagAccion,””,array(),’document’, ‘literal’));

    Ahora, si me dices como puedo transformar esas lineas con el SOAP nativo de PHP 5. con gusto me vuelo el nusoap.php

    UN gran abrazo, espero sirva de ayuda para otra persona.

      1. Jamesson Parra

        $tagAccion = ‘[nameFunction.Execute xmlns=”esquemaWS”][parameter]$value[/parameter][/nameFunction.Execute]’;

        Reemplazar corchetes por llaves angulares, ya que no se muestra en los comentarios.
        Perdonen el intento saludos!

  7. Pablo Oneto
    Pablo Oneto

    Hola Jamesson, si quieres puedes enviarme por correo el ejemplo concreto (las urls y el método al que quieres llamar) porque no puedo ver lo que necesitas exactamente, me gustaría ayudarte. pablooneto (arroba) gmail.com

      1. veronica trejo

        Hola Pablo, lo que pasa es que con el ejemplo, para consumir el servicio, enviaba los parámetros vacíos, pero ya pude enviar la información haciéndolo con una clase, ahora tengo otra duda, tu podrías orientarme de como pasar la información por html?
        Si gustas, te envío como quedo mi cliente para no enviar parámetros vacíos.

        Muchísimas gracias.

        Saludos!

    1. Pablo Oneto
      Pablo Oneto

      Veo que te refieres al servicio web del ejemplo, en la variable $respuesta tendrás lo que responde el webservice, en el ejemplo hice un var_dump para ver que era lo que tenía dentro. No entiendo a que te refieres con pasar la información por HTML.

  8. Victor Ayala

    Buenos días Pablo, en el caso de mi dirección url de webservice tengo esta ruta $cliente = new SoapClient(“https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl”);

    y cuando ejecuto la operación me genera este error:

    Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn’t load from ‘https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl’ : failed to load external entity “https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl” in /storage/ssd3/996/1818996/public_html/index.php:4 Stack trace: #0 /storage/ssd3/996/1818996/public_html/index.php(4): SoapClient->SoapClient(‘https://reading…’) #1 {main} thrown in /storage/ssd3/996/1818996/public_html/index.php on line 4

    1. Pablo Oneto
      Pablo Oneto

      Al acceder a la URL veo un WSDL que parece correcto. Creo un cliente y hago getFunctions y va todo bien, seguro estás colocando la URL correctamente?

      <?php
      $cliente = new SoapClient("https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl");
      
      var_dump($cliente->__getFunctions());
      1. Víctor Ayala

        Si, he seguido las instrucciones tal como lo sugiere sin tener aún éxito, el sitio donde estoy realizando pruebas es 000webhost.com, ya verifiqué que estuviera habilitado el soap client tanto cliente como servidor, puede ser que haya alguna configuración adicional que desconozco.

        ¿Alguna otra idea antes de probar localmente? Muchas gracias, quedo atento.

        1. Pablo Oneto
          Pablo Oneto

          puedes intentar utilizando http://phptester.net/ para probar un pequeño pedazo de código (elige la versión de PHP que utilices, lo normal sería 5.5 pero debería ser 7.. a ver si se actualizan los hostings) así descartas cualquier cosa de configuración. Pega mi código y verás que funciona.

          he probado esto y la respuesta es “corecta”

          <?php
          $cliente = new SoapClient("https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl");
          
          $parameters = new stdClass;
          $parameters->processId = 23;
          $parameters->userData = new stdClass;
          $parameters->userData->UserName = "test";
          $parameters->userData->Password = "123";
          
          $response = $cliente->GetProcessResult($parameters);
          
          var_dump($response);
          

          Da un fatal, pero es lo que devuelve el servicio web.

          Este otro servicio parece ir mejor…

          <?php
          $cliente = new SoapClient("https://readingreportservice.xm.com.co/ReadingReportService.svc?wsdl");
          
          $parameters = new stdClass;
          $parameters->userData = new stdClass;
          $parameters->userData->UserName = "test";
          $parameters->userData->Password = "123";
          
          $response = $cliente->GetBorderStatus($parameters);
          
          var_dump($response);
          

          De todas formas puede que ambos vayan bien y por no proveer un user/pass correctos no estar funcionando… tendrás que revisar la documentación de los servicios

Deja un comentario