Etiqueta: WebServices

  • Cómo enviar XML a un WebService con PHP

    Cómo enviar XML a un WebService con PHP

    Para empezar, debemos responder una pregunta escencial: ¿se trata de un WebService de tipo SOAP o uno de tipo REST?

    ¡La forma de enviarlo en uno u otro caso será muy diferente!

    Otra historia es cómo recibir XML a través de WebServices desarrollados usando PHP… tema para otro post 🙂

    Cómo enviar XML a un WebService SOAP con PHP

    Como siempre, para el caso de que se trate de un webservice de tipo SOAP, usaremos la clase SOAPClient

    Tomemos como ejemplo este Servicio Web que tiene un solo método disponible (CustomerSearch), el cual recibe XML y devuelve XML.

    Tenemos dos alternativas para generar el XML que queremos enviar:

    1. Escribirlo explícitamente (o «a mano»)
    2. Usar la clase SimpleXMLElement

    Si aún estás en dudas, no dudes más: usa la clase, te ahorrará una gran cantidad de dolores de cabeza.

    Con lo que la llamada se vería algo así como:

    <?php
    
    $url = 'https://secure.softwarekey.com/solo/webservices/XmlCustomerService.asmx?WSDL';
    $client = new SoapClient($url);
    
    $xmlr = new SimpleXMLElement("<CustomerSearch></CustomerSearch>");
    $xmlr->addChild('AuthorID', 1);
    $xmlr->addChild('UserID', 'mchojrin');
    $xmlr->addChild('UserPassword', '1234');
    $xmlr->addChild('Email', 'mauro.chojrin@leewayweb.com');
    
    $params = new stdClass();
    $params->xml = $xmlr->asXML(); // OJO: La propiedad xml es particular de este WebService, debes reemplazarla por el nombre del parámetro que espera recibir el servicio al que buscas conectarte
    
    $result = $client->CustomerSearchS($params);
    
    print_r($result);
    
    echo PHP_EOL;

    Si ejecutas este código te encontrarás con algo como:

    stdClass Object
    (
        [CustomerSearchSResult] => stdClass Object
            (
                [any] => <Customers xmlns=""><ResultCode>-1</ResultCode><ErrorMessage>Invalid Login</ErrorMessage></Customers>         
            ) 
    ) 

    Lo que seguramente te interese es lo que está dentro de la clave any, con lo cual, para obtenerlo podrías usar echo $result->CustomerSearchSResult->any; en lugar de print_r($result);. Aunque probablemente lo que quieras no sea mostrar el resultado explícitamente, si no procesarlo de alguna manera… ¿qué mejor que recurrir nuevamente a SimpleXMLElement?

    <?php
    
    $url = 'https://secure.softwarekey.com/solo/webservices/XmlCustomerService.asmx?WSDL';
    $client = new SoapClient($url);
    
    $xmlr = new SimpleXMLElement("<CustomerSearch></CustomerSearch>");
    $xmlr->addChild('AuthorID', 1);
    $xmlr->addChild('UserID', 'mchojrin');
    $xmlr->addChild('UserPassword', '1234');
    $xmlr->addChild('Email', 'mauro.chojrin@leewayweb.com');
    
    $params = new stdClass();
    $params->xml = $xmlr->asXML();
    
    $result = new SimpleXMLElement($client->CustomerSearchS($params)->CustomerSearchSResult->any);
    
    $r = current($result->xpath('/Customers/ResultCode'));
    
    if ( $r == '-1' ) {
            echo 'Fallo: '.$result->xpath('/Customers/ErrorMessage')[0];
    } else {
            echo 'Exito!';
    }
    
    echo PHP_EOL;

    Cómo enviar XML a un WebService REST con PHP

    En el caso de tratarse de un Servicio Web basado en REST todo es más fácil.

    Puedes usar cURL:

    <?php
    
    $server = 'http://www.leewayweb.com/miaplicacion';
    $headers = [
        "Content-type: text/xml",
        "Content-length: " . strlen($requestXML), "Connection: close",
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $server);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 100);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $requestXML);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $data = curl_exec($ch);
    
    if (curl_errno($ch)) {
        print curl_error($ch);
        echo "Algo fallo";
    } else {
        curl_close($ch);
    }

    O bien algo un poco más elaborado como Guzzle:

    <?php
    
    use GuzzleHttp\Client;
    use GuzzleHttp\Psr7\Request;
    
    $client = new Client();
    $request = new Request(
        'POST',
        $uri,
        [
            'Content-Type' => 'text/xml; charset=UTF8'
        ],
        $xml
    );
    
    echo $response->getBody();
    

    (Para que funcione este ejemplo hay que tener instalada la librería o incluirla, por ejemplo, usando composer.).

  • Cómo exponer un WebService REST con PHP

    Cómo exponer un WebService REST con PHP

    ¿Qué es un WebService?

    Ya en el artículo sobre cliente REST di una pequeña definición de un WebService, por si no lo leíste te lo cuento:

    Un WebService es una pequeña aplicación web diseñada para interactuar con otras aplicaciones (en lugar de hacerlo con personas).

    Las dos aplicaciones que se comunican toman el rol de:

    1. Servidor: quien expone el servicio
    2. Cliente: quien lo consume

    ¿Qué es REST?

    REST es un protocolo de intercambio de información basado en HTTP.

    ¿Cómo se implementa en PHP?

    Los servicios web basados en REST suelen ser mucho más fáciles de crear (y consumir) que los basados en SOAP.

    De hecho, cualquier aplicación PHP que hayas hecho podría ser un WebService REST! (Bueno… tal vez no uno muy útil, pero eso es otro tema :)).

    Te muestro un ejemplo super simple:

    <?php
    
    echo json_encode( [ 'Hola' ] );
    

    No está mal, ¿cierto?

    En este caso lo que vemos es una aplicación que, al ser invocada usando curl http://localhost:8080/rest_server.php (Asumiendo que está montada sobre el servidor local) nos dará esta salida:

    ["Hola"]

    El cliente que haya realizado dicha invocación deberá saber qué tipo de contenido le estamos enviando (¡y actuar en consecuencia!).

    Podés probarlo iniciando el servidor de esta forma:

    php -S localhost:8080 &

    (El & para que el proceso se ejecute en background y puedas seguir).

    En caso de que se hubiese producido un error (Por ejemplo, que el recurso buscado no se encontrara disponible), deberíamos usar la función http_response_code para enviar un aviso al cliente:

    http_response_code( 404 );

    Por último, una buena práctica es también hacer explícito el tipo de contenido que vamos a enviar al cliente:

    header('Content-type: application/json');

    De esta forma el cliente tiene algo más de información y puede tomar mejores decisiones.

    En definitiva, si podés elegir, te recomiendo usar siempre servicios web basados en REST. Otro consejo es que tengas a mano los códigos de error HTTP (No es necesario saberlos todos de memoria, pero ayuda :)).

    ¿Qué ejemplos se te ocurren ahora que sabés armar servicios REST?

  • Cómo exponer un WebService SOAP con PHP

    Cómo exponer un WebService SOAP con PHP

    ¿Qué es un WebService?

    Ya en el artículo sobre cliente SOAP di una pequeña definición de un WebService (Una más exhaustiva está en el curso de WebServices con PHP), por si no lo leíste te lo cuento:

    Un WebService es una pequeña aplicación web diseñada para interactuar con otras aplicaciones (en lugar de hacerlo con personas).

    Las dos aplicaciones que se comunican toman el rol de:

    1. Servidor: quien expone el servicio
    2. Cliente: quien lo consume

    ¿Qué es SOAP?

    SOAP es un protocolo de intercambio de información basado en XML.

    ¿Cómo se implementa en PHP?

    Ahora que estamos claros con las definiciones veamos un ejemplo:

    server.php:

    <?php
    
    class MiClase
    {
     public function saludar()
     {
     return 'Hola ' . func_get_args()[0] . PHP_EOL;
     }
    }
    
    try {
     $server = new SoapServer(
     null,
     [
     'uri'=> 'http://localhost:8080/soap_server.php',
     ]
     );
    
     $server->setClass('MiClase');
     $server->handle();
    } catch (SOAPFault $f) {
     print $f->faultstring;
    }

    cliente.php

    <?php
    
    $client = new SoapClient(null, array(
          'location' => "http://localhost:8080/server.php",
          'uri'      => "http://localhost:8080/server.php",
          'trace'    => 1 ));
    
    try {
    	echo $return = $client->__soapCall("saludar", ["mundo!" ] );
    } catch ( SOAPFault $e ) {
    	echo $e->getMessage().PHP_EOL;
    }
    

    Para que todo esto tenga sentido, primero necesitamos tener un webserver levantado en localhost:8080. Para hacerlo simple, usemos el servidor incorporado al intérprete de PHP:

    php -S localhost:8080 &

    Y entonces, al ejecutar php soap_client.php veremos:

    Hola mundo!

    Si en lugar de publicar este script (server.php) en nuestro localhost lo subiéramos a un servidor accesible públicamente, cualquier aplicación conectarse a este servicio e invocar nuestro método saludar.

    Puedes utilizar un archivo WSDL para darle más robustez al servicio (y hacerlo descubrible también), pero por el momento tienes todo lo necesario para permitir a otras aplicaciones interactuar con la tuya a través de un WebService SOAP.

    ¡Feliz integración! 🙂

  • Cómo consumir un WebService REST con PHP

    Cómo consumir un WebService REST con PHP

    La conexión de tus aplicaciones php con WebServices REST te permitirá ampliar tus capacidades apoyándote en servicios de grandes compañías.

    Los detalles específicos dependen de las definiciones que haya realizado el productor del servicio pero, para no encontrarte con sorpresas, es buena idea tener claras las bases.

    Repasemos los conceptos comunes a todo Servicio Web REST.

    Qué es un webservice

    Un webservice (o servicio web) es una forma de integrar aplicaciones web.

    Básicamente se trata de un servidor que expone parte de su funcionalidad para que sus clientes (que generalmente son otros servidores de diferentes aplicaciones) puedan utilizarlas.

    Las principales ventajas de usar web services son:

    1. La posibilidad de valernos de la capacidad instalada (¡y mantenida!) por terceros
    2. La facilidad para extender la funcionalidad de nuestra aplicación (Basta con realizar las llamadas al servicio web que deseamos)

    La principal desventaja de usar este enfoque es que dependemos de servicios de terceros que, salvo en casos muy puntuales, no podemos controlar.

    Ejemplos de webservices:

    1. Autenticación de usuarios vía Facebook, Google, Twitter, etc…
    2. Generación de mapas en tiempo real
    3. Consulta de cotizaciones de acciones

    Qué es RESTful

    RESTful es un modelo arquitectónico de software que plantea una suerte de volver a las fuentes.

    Su filosofía se basa en el poder del protocolo HTTP (Subyacente en toda aplicación web), el cual incluye los conceptos de verbo (GET, POST, DELETE, PUT), recurso, código de errores (404, 500, etc…) y demás elementos que, en teoría al menos, deberían alcanzar para modelar cualquier tipo de interacción cliente-servidor.

    Es muy común que en una aplicación RESTful los objetos o entidades del modelo de datos sean expuestos casi directamente, teniendo una URL específica para cada uno de ellos.

    Por ejemplo, en una aplicación diseñada para una institución educativa sería esperable encontrarse con una URL de tipo:

    http://miescuela.com/alumnos

    Al realizar una petición de tipo GET a esta URL se esperará recibir información de los alumnos de esa institución.

    A su vez, una URL del tipo:

    http://miescuela.com/alumnos/14

    Debería darme información del alumno cuyo id es 14.

    Existe mucha controversia respecto de qué es una API RESTful y qué no lo es…

    Sin entrar en mayor detalle, la idea es que, para consumir un servicio web basado en REST sólo se requiere conocer su URL (De nuevo, esto es en teoría… en la práctica se utilizan varias formas de modificación del pedido, como ser el envío de headers y demás).

    Siendo que se trata de un servicio RESTful, la comunicación entre cliente y servidor es sencilla (A diferencia de lo que es un WebService SOAP), se trata simplemente de enviar un pedido HTTP y procesar su respuesta.

    Cómo realizar peticiones REST con PHP

    Existen varias opciones disponibles, veamos las más comúnmente utilizadas:

    cURL

    La librería cURL permite realizar peticiones a servidores remotos.

    Si bien funciona, es un método de bastante bajo nivel, con sus pros y sus contras.

    Volviendo al ejemplo que te comentaba antes, una forma de hacer la llamada sería esta:

    <?php
    $ch = curl_init();
    
    curl_setopt($ch, CURLOPT_URL, "http://miescuela.com/alumnos");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $res = curl_exec($ch);
    
    curl_close($ch);

    En la variable $res quedará la respuesta del webservice (Asumiendo por supuesto que no haya habido ningún problema de conexión, transferencia, etc…).

    file_get_contents

    Una opción alternativa (y generalmente más conveniente) es el uso de la función file_get_contents.

    Esta función recibe como parámetro el nombre del archivo que se quiere leer y devuelve todo su contenido como un string.

    Si bien el uso normal de la función es la lectura de archivos locales, php en realidad entiende a los archivos como flujos. Por lo tanto, si está todo bien configurado, una URL puede usarse como nombre de un flujo.

    De este modo nos ahorramos muchas de las complicaciones propias de tratar con una interface de más bajo nivel (y, obviamente, perdemos cierto control, pero generalmente no es necesario hilar tan fino).

    El ejemplo sería:

    <?php
    $res = file_get_contents("http://miescuela.com/alumnos");

    Cómo se procesan los resultados

    Los resultados se procesan de acuerdo al formato de la respuesta.

    Usualmente los Servicios Web devuelven XML o JSON (Existen otras posibilidades, claro, pero estas son las más comunes).

    En el caso de tratarse de un XML, lo mejor es usar la biblioteca SimpleXML, si se trata de json, con json_decode será suficiente.

    Si se trata de otro formato habrá que estudiar el caso puntual, pero en última instancia, siempre se trata de procesar un string…

    Ejemplo de consumor de un WebService REST con PHP

    MercadoLibre tiene una API RESTful que permite interactuar con el sitio de forma simple.

    Veamos un ejemplo de una llamada de acceso público: la que nos da información básica de un usuario.

    La URL que se utiliza es https://api.mercadolibre.com/users/USERID/

    Por ejemplo https://api.mercadolibre.com/users/226384143/ retorna:

    {
      "id": 226384143,
      "nickname": "TETE9928972",
      "registration_date": "2016-08-25T11:36:00.000-04:00",
      "country_id": "AR",
      "address": {
        "city": "Palermo",
        "state": "AR-C"
      },
      "user_type": "normal",
      "tags": [
        "normal",
        "test_user",
        "user_info_verified"
      ],
      "logo": null,
      "points": 100,
      "site_id": "MLA",
      "permalink": "http://perfil.mercadolibre.com.ar/TETE9928972",
      "seller_reputation": {
        "level_id": null,
        "power_seller_status": null,
        "transactions": {
          "canceled": 0,
          "completed": 0,
          "period": "historic",
          "ratings": {
            "negative": 0,
            "neutral": 0,
            "positive": 0
          },
          "total": 0
        }
      },
      "buyer_reputation": {
        "tags": []
      },
      "status": {
        "site_status": "active"
      }
    }

    Un string JSON.

    El código completo para obtener esta información con php es:

    <?php
    
    echo file_get_contents('https://api.mercadolibre.com/users/226384143/');

    Claro que si quisiéramos hacer algo con esta información sería más conveniente hacer algo como:

    <?php
    
    $data = json_decode( file_get_contents('https://api.mercadolibre.com/users/226384143/'), true );
    
    echo $data['nickname'];

    ¡Listo! Ya estás en condiciones de integrar cualquier WebService RESTful en tu aplicación.

    Más información sobre WebServices con PHP

    Como te decía al comienzo, otro protocolo muy utilizado a la hora de conectar aplicaciones a través de Servicios Web es SOAP. Este protocolo es bastante más complejo que RESTful, principalmente porque se basa en intercambios de XML con un formato bastante particular.

    Puedes intentar leer e interpretar estos XML por tus propios medios aunque lo más recomendable es utilizar las herramientas que PHP ofrece para ello.

    De hecho, si te enfrentas a WebServices de basados en SOAP php tiene un soporte nativo muy completo.

  • Cómo consumir un WebService SOAP con PHP

    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.

  • Cómo obtener la cotización del día de una acción con PHP

    Todo lo que voy a mostrarte acá se basa en la API de Yahoo Finance.

    Lo primero que tenés que hacer es instalar composer.

    Segundo, inicializar el proyecto:

    php composer.phar init

    Tercero: agregar la dependencia del paquete https://github.com/scheb/yahoo-finance-api:

    php composer.phar require scheb/yahoo-finance-api

    Y después podés usar un código como este:

    #!/usr/bin/php
    <?php
    
    require __DIR__ . '/vendor/autoload.php';
    
    $client = new \Scheb\YahooFinanceApi\ApiClient();
    
    $d = new DateTime($argv[2]);
    
    echo "Buscando ".$argv[1]." en fecha: ".$d->format('d/m/y').PHP_EOL;
    try {
      $data = $client->getHistoricalData($argv[1], $d, $d);
    
      echo $data['query']['results']['quote']['Close'].PHP_EOL;
    } catch ( Exception $e ) {
      echo $e->getMessage().PHP_EOL;
    }
    

    En este ejemplo, lo que tenés es una utilidad de línea de comandos que recibe dos parámetros:

    1. El ticker (Símbolo del papel en cuestión, por ejemplo TS para la acción de Tenaris)
    2. La fecha.

    La llamada sería así:

    php get_stock_price.php TS Yesterday

    y el resultado será algo como:

    Buscando TS en fecha: 15/12/16
    34.220001