Web Services - SOAP - API

De wikiserver
La revisió el 13:32, 1 abr 2020 per Jnoguera (Discussió | contribucions) (API LARAVEL PASSPORT)
(dif) ← Versió més antiga | Versió actual (dif) | Versió més nova → (dif)
Dreceres ràpides: navegació, cerca

Què són els Serveis Web?

Els serveis web són aplicacions client i servidor que es comuniquen sobre (WWW) Protocol de transferència d'hipertext de la World Wide Web (HTTP). Segons el descrit pel World Wide Web Consortium (W3C), serveis web proporcionen un mitjà estàndard d'interoperabilitat entre aplicacions de programari que s'executen en una varietat de plataformes i marcs. Els serveis web es caracteritzen per la seva gran interoperabilitat i extensibilitat, així com les seves descripcions processable per màquina, gràcies a la utilització de XML. Els serveis web es poden combinar d'una manera precisa per aconseguir operacions complexes.

Tipus de Serveis Web

En el pla conceptual, un servei és un component de programari que es proporciona de la xarxa.

A nivell tècnic, els serveis web es poden implementar de diverses maneres. Els dos tipus de serveis web analitzats en aquesta secció es poden distingir com a Big Web Services i serveis web RESTful.

Big Web Services En Java EE 6, JAX-WS proporciona la funcionalitat de Big Web Services. Serveis web Grans utilitzen missatges XML que segueixen el protocol d'accés a objectes estàndard (SOAP), un llenguatge XML que defineix una arquitectura de missatges i formats de missatges. Aquests sistemes sovint contenen una descripció llegible per les màquines de les operacions que ofereix el servei, escrit en la Web Services Description Language (WSDL), un llenguatge XML per a definir sintàcticament interfícies.

El format del missatge SOAP i WSDL llenguatge de definició d'interfície han guanyat l'adopció generalitzada. Moltes de les eines de desenvolupament, com NetBeans IDE, poden reduir la complexitat del desenvolupament d'aplicacions de serveis web.

Soap-message.png

Serveis Web REST En Java EE 6, JAX-RS proporciona la funcionalitat per a la Transferència d'estat representacional ​​(REST Web Services). REST és molt adequat per a escenaris bàsics. Serveis web RESTful sovint estan millor integrats amb HTTP que els serveis basats en SOAP ja que no requereixen de missatges XML o definicions servei API WSDL.

Projecte Jersey és la implementació de referència de l'especificació JAX-RS. Jersei implementa suport per a les anotacions definides en l'especificació JAX-RS, el que facilita als desenvolupadors crear serveis web RESTful amb Java i la màquina virtual de Java (JVM).

SOAP Web Services

Simple Object Access Protocol (SOAP)és un protocol estàndard per l'intercanvi de missatges XML. La comunicació entre el client i el servei succeeix utilitzant missatges XML.

Què és el WSDL?

WSDL: Web Service Description Language. És un arxiu XML que descriu els detalls tècnics de com s'implementa un servei web, més específicament la URI, port, nom dels mètodes, els paràmetres i els tipus de dades. Llegint el WSDL poden veure:

  • Ports / EndPoint - URL del servei web
  • Format del missatge d'entrada
  • Format del missatge de sortida
  • Protocol de seguretat que s'ha de seguir
  • El protocol de servei web utilitzat

Exemple:

<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2-hudson-740-. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2-hudson-740-. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws/" name="Hola">
    <wsp:Policy wsu:Id="HolaPortBindingPolicy" />
    <types>
        <xsd:schema>
            <xsd:import namespace="http://ws/" schemaLocation="http://localhost:8084/webServiceProject/Hola?xsd=1" />
        </xsd:schema>
    </types>
    <message name="hello">
        <part name="parameters" element="tns:hello" />
    </message>
    <message name="helloResponse">
        <part name="parameters" element="tns:helloResponse" />
    </message>
    <message name="adeu">
        <part name="parameters" element="tns:adeu" />
    </message>
    <message name="adeuResponse">
        <part name="parameters" element="tns:adeuResponse" />
    </message>
    <portType name="Hola">
        <operation name="hello">
            <input wsam:Action="http://ws/Hola/helloRequest" message="tns:hello" />
            <output wsam:Action="http://ws/Hola/helloResponse" message="tns:helloResponse" />
        </operation>
        <operation name="adeu">
            <input wsam:Action="http://ws/Hola/adeuRequest" message="tns:adeu" />
            <output wsam:Action="http://ws/Hola/adeuResponse" message="tns:adeuResponse" />
        </operation>
    </portType>
    <binding name="HolaPortBinding" type="tns:Hola">
        <wsp:PolicyReference URI="#HolaPortBindingPolicy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
        <operation name="hello">
            <soap:operation soapAction="" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
        </operation>
        <operation name="adeu">
            <soap:operation soapAction="" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
        </operation>
    </binding>
    <service name="Hola">
        <port name="HolaPort" binding="tns:HolaPortBinding">
            <soap:address location="http://localhost:8084/webServiceProject/Hola" />
        </port>
    </service>
</definitions>

Existeixen dues maneres per accedir a un servei web:

  • 'El proveïdor de serveis web coneix al client:El proveïdor de serveis web proporcionarà el WSDL al client i el client podrà accedir als serveis web.
  • El proveïdor de serveis registri la WSDL com a UDDI. UUID (Universal Description, Discover and Integration). Els WSDL es poden convertir a un UDDI i així, poden estar disponibles mitjançant un directori de serveis per a la seva utilització.

SOAP Message

SOAP està basat en XML i, per això, està considerat llegible per alguns éssers humans, però està basat en un esquema XSD específic que se li ha d'afegir. Veiem un petit missatge SOAP treient tota la informació i agafant només les etiquetes que fan que sigui un missatge SOAP:

<?xml version="1.0"?>
<soap:Envelope
 xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
 soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
 <soap:Header>
  ...
 </soap:Header>
 <soap:Body>
  ...
  <soap:Fault>
   ...
  </soap:Fault>
 </soap:Body>
</soap:Envelope>

Sembla només un altre arxiu XML però, el que fa que sigui un missatge SOAP és l'element root anomenat Envelope que té l'espai de noms soap a http://www.w3.org/2001/12/soap-envelope. L'atribut soap:encodingStyle determina el tipus de dades que s'utilitza en el fitxer per que SOAP no té una codificació per defecte.

L'element soap:Envelope és obligatori però l'elemenmt següent soap:Header és opcional i normalment conté informació rellevant a l'autenticació i la sessió. El protocol SOAP no ofereix autenticació però ofereix als desenvolupadors aquesta etiqueta per a incloure-ho.

El següent element es tracta de soap:Body que és obligatori. Conté el missatge RPC (Remote Procedure Call) on s'inclou els mètodes i si és un missatge de resposta, també el valor retornat pel mètode. L'etiqueta soap:Fault és opcional. Si està present al missatge conté els erros i el missatges dels errors.

Donem un cop d'ull a un missatge SOAP de petició:

<?xml version="1.0"?>
<soap:Envelope
 xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
 soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
 <soap:Body xmlns:m="http://www.yourwebroot.com/stock">
  <m:GetStockPrice>
   <m:StockName>IBM</m:StockName>
  </m:GetStockPrice>
 </soap:Body>
</soap:Envelope>

El missatge anterior és una petició per obtenir el preu d'estoc d'una empresa en concret. Dintre de l'etiqueta soap:Body veuràs l'element GetStockPrice que No correspon a SOAP, si no, que aquest element fa referència a un mètode particular de l'aplicació de servidor que es cridarà al rebre aquest missatge. L'element StockName també és específic de l'aplicació servidora i correspon a un paràmetre de la funció anterior.

El missatge de resposta és molt semblant:

<?xml version="1.0"?>
<soap:Envelope
 xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
 soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
 <soap:Body xmlns:m="http://www.yourwebroot.com/stock">
  <m:GetStockPriceResponse>
   <m:Price>183.08</m:Price>
  </m:GetStockPriceResponse>
 </soap:Body>
</soap:Envelope>

Dintre de l'element soap:Body veuràs l'element GetStockPriceRespomse que conté l'element Price amb la dada de resposta. Ambdós elements son específics de l'aplicació de servidor.

Client Java Swing d'un servei Web

Es farà una implementació d'un servei web client utilitzant JAVA SWING. Segueix aquests passos:

  • Crea un nou projecte de tipus Java Application.

Wsclient-java1.png

  • Crea un formulari SWING per afegir els camps elements necessaris (buttons, labels, text fields, etc)

Wsclient-java2.png

Wsclient-java3.png

  • Una vegada tinguis el formulari, afegeix la funcionalitat de web-service client

Wsclient-java4.png

  • Omple el camp wsdl a l'hora de configurar el client. Deixa en blanc el camp package:

Wsclient-java5.png

  • Una vegada generat, ja es pot utilitzar el client del WS des del formulari Swing. Per tal d'utilitzar-lo, genera el codi necessari insertant-lo des del netbeans:

Wsclient-java6.png

Wsclient-java7.png

Wsclient-java8.png

  • Podem veure el codi generat. Él nom de la funció generada correspon al nom del servei web:

Wsclient-java9.png

  • Ja podem utilitzar la crida al servei web associant-la al click d'un botó. El resultat de la execució del servei web es mostrarà en un Dialog.

Wsclient-java10.png

  • Resultat de l'execució:

Wsclient-java11.png

Wsclient-java12.png

https://www.youtube.com/watch?v=BeY1bQzMeAk

Accedir a un servei Web des de un client php

Per accedir a un servei web, és molt fàcil, només s'ha de donar el WSDL a la classe SoapClient de PHP. L'objecte generat conté tots els serveis webs que estan implementat en el WSDL. Per passar els paràmetres, es fa servir un Array associatiu on la clau és el nom del paràmetre configurat en el WS i el valor és el que es vol enviar al servei web. Exemple:

$client = new SoapClient("http://192.168.56.1:8084/webServiceProject/Hola?wsdl");

$result = $client->hello(array("name"=>"alex"));

echo $result->return;

Per accedir al resultat del WebService, hem de veure en el WSDL el nom del camp corresponent al resultat del WS i així podrem accedir al valor.

Es pot crear un formulari amb php i en el controlador, fer la crida al servei Web corresponent.

Resultat execució codi anterior (Es recorda que es necessari una màquina virtual amb php + apache2):

Wsclient-php1.png

NuSOAP server

És molt senzill crear un servei web utilitzant la llibreria NuSOAP de PHP. Pots descarregar-la des d'aquest | enllaç. Baixa't-ho i descomprimeix-lo en el directori principal de l'aplicació. Per utilitzar-ho només has d'incloure la llibreria nusoap.php en el codi de l'aplicació.

Veiem un exemple d'utilització de la llibreria nusoap per crear un servei web.

<?php
require_once "nusoap.php";

function getProd($category) {
    if ($category == "books") {
        return join(",", array(
            "The WordPress Anthology",
            "PHP Master: Write Cutting Edge Code",
            "Build Your Own Website the Right Way"));
	}
	else {
            return "No products listed under that category";
	}
}

$server = new soap_server();
$server->register("getProd");
$server->service($HTTP_RAW_POST_DATA);

Primer s'inclou el fitxer nusoap.php per poder accedir a la llibreria NuSOAP. Després es defineix la funció getProd() i s'instancia un objecte de la classe soap_server. Immediatament després s'utilitza el mètode register per afegir la funció getProd al servidor sopa i poder accedir a ella des de un client. És a dir, convertim la funció getProd en un servei web.

Segurament, en un escenari real, la funció getProd hauria de cercar en una Base de Dades la informació que s'ha d'enviar a l'usuari. Ara mateix, no volem complicar el codi en coses externes a SOAP.

Es poden registrar funcions addicionals en el servidor per per donar més funcionalitats a l'aplicació. El procés seria idèntic del descrit anteriorment.

NuSOAP Client

Crearem una pàgina php que utilitzarà el servei web anterior:

<?php
require_once "nusoap.php";
$client = new nusoap_client("http://localhost/nusoap/productlist.php");

$error = $client->getError();
if ($error) {
    echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
}

$result = $client->call("getProd", array("category" => "books"));

if ($client->fault) {
    echo "<h2>Fault</h2><pre>";
    print_r($result);
    echo "</pre>";
}
else {
    $error = $client->getError();
    if ($error) {
        echo "<h2>Error</h2><pre>" . $error . "</pre>";
    }
    else {
        echo "<h2>Books</h2><pre>";
        echo $result;
        echo "</pre>";
    }
}

Com va passar en el servidor, primer s'ha d'incloure la llibreria nusoap.php amb la directiva required_once. Seguidament, es crea un nova instància d'un client soap amb la classe: nusoap_client. El constructor necessita la localització del servidor soap al que s'ha de connectar. És a dir, del fitxer on es troba la creació del soap_server amb les funcions registrades.

La funció getError comprova si el client SOAP s'ha creat correctament i si no ha estat així, mostra un missatge d'error.

El mètode call() genera i envia un missatge SOAP de tipus petició (Request) a la funció o el mètode definit com a primer paràmetre. El segon paràmetre de la funció call() és un array associatiu del paràmetres que necessita el mètode servidor.

La propietat fault i el mètode getError() son utilitzat per comprovar i mostrar cualsevol error produït en la comunicació.

Creació d'un arxiu WSDL

Escriure un fitxer WSDL a mà pot ser de bojos. Una utilitat molt interessant de nusoap és que pot crear un fitxer WSDL automàticament. Veurem un exemple modificant una mica l'exemple anterior:

<?php
require_once "nusoap.php";

function getProd($category) {
    if ($category == "books") {
        return join(",", array(
            "The WordPress Anthology",
            "PHP Master: Write Cutting Edge Code",
            "Build Your Own Website the Right Way"));
    }
    else {
        return "No products listed under that category";
    }
}

$server = new soap_server();
$server->configureWSDL("productlist", "urn:productlist");

$server->register("getProd",
    array("category" => "xsd:string"),
    array("return" => "xsd:string"),
    "urn:productlist",
    "urn:productlist#getProd",
    "rpc",
    "encoded",
    "Get a listing of products by category");

$server->service($HTTP_RAW_POST_DATA);

/*if ( !isset( $HTTP_RAW_POST_DATA ) )
 $HTTP_RAW_POST_DATA =file_get_contents( 'php://input' );
$server->service($HTTP_RAW_POST_DATA);*/

Bàsicament és el mateix codi amb quatre canvis. El primer canvi que s'ha afegit és la crida a la funció configureWSDL(). Aquest mètode prepara al servidor per a que pugui generar un fitxer WSDL dels nostres serveis registrats. El primer paràmetre d'aquesta funció, és el nom del servei i el segon correspon a l'espai de noms del servei.

El segon canvi afegeix informació addicional al mètode register. Veiem-ho:

  • getProd: correspon al nom de la funció
  • array("category"=>"xsd:string") correspon a la descripció dels paràmetres que necessita la funció getProd, veieu que cada paràmetre té associat un tipus de dades.
  • array("return"=>"xsd:string") correspon al valor de retorn de la funció getProd. S'ha d'especificar el tipus de dades a retornar.
  • urn:productlist defineix l'espai de noms
  • urn:productlist#getProd defineix l'acció SOAP
  • rpc defineix el tipus de crida. Aquesta pot ser rpc o document
  • encoded definexi el valor de l'atribut use. Pot ser encoded o literal
  • L'últim paràmetre és un string de documentació que descriu el mètode getProd.

Per veure el fitxer wsdl només hem d'afegir a la url ?wsdl al final. Exemple: http://yourwebroot/productlist.php?wsdl Una vegada vegis el WSDL ja es pots copiar en un fitxer i depositar-lo en el directori web.

Al tenir el WSDL generat en un fitxer en el servidor web podem aprofitar-lo per crear un client soap que el llegeixi. Per fer-ho només s'ha de canviar aquesta línia del client soap:

$client = new nusoap_client("http://localhost/nusoap/productlist.php");

per aquesta altre:

$client = new nusoap_client("products.wsdl", true);

Veieu que ara es crea el client SOAP utilitzant el fitxer products.wsdl que es troba en el mateix directory del servidor que l'aplicació client. El següent paràmetre és un booleà que indica que accepti aquest fitxer WSDL.

Pràctica Web Services

Ejemplo de consumir un Web Service SOAP de la universidad de Alicante desde el cliente.

La dirección que expone este Web Services es la siguiente: https://cvnet.cpd.ua.es/servicioweb/publicos/pub_gestdocente.asmx?wsdl, como puedes ver al final muestra un archivo WSDL, que es donde expone las interfaces que van a ser consumidas.

<?php
    header('Content-Type: text/html; charset=ISO-8859-1'); 
    require_once('lib/nusoap.php');
    //Parámetros
    $slengua = "C";
    $scurso = "2011-12";
    $scoddep = "B142";
    $scodest = "";
    
    //url del webservice
    $wsdl="https://cvnet.cpd.ua.es/servicioweb/publicos/pub_gestdocente.asmx?wsdl";
    
    //instanciando un nuevo objeto cliente para consumir el webservice
    $client=new nusoap_client($wsdl,'wsdl');
    //pasando los parámetros a un array
    $param=array('plengua'=>$slengua, 'pcurso' => $scurso, 'pcoddep' => $scoddep, 'pcodest' => $scodest);
    //llamando al método y pasándole el array con los parámetros
    $resultado = $client->call('wsasidepto', $param);
   
    //si ocurre algún error al consumir el Web Service
    if ($client->fault) { // si
        $error = $client->getError();
    if ($error) { // Hubo algun error
            //echo 'Error:' . $error;
            //echo 'Error2:' . $error->faultactor;
            //echo 'Error3:' . $error->faultdetail;faultstring
            echo 'Error:  ' . $client->faultstring;
        }
        
        die();
    }
    
    echo "<pre>";
    //print_r($resultado);
	$result=$resultado['wsasideptoResult']['ClaseAsiDepto'];
	
	for($i=0;$i<=count($result);$i++){
		echo $result[$i]['codasi']."<br>";
		echo $result[$i]['nomasi']."<br>";
		echo $result[$i]['enlaceasi']."<br>";
		echo $result[$i]['codest']."<br>";
		echo $result[$i]['nomest']."<br>";
		echo "<br>"."<br>";		
	}	
    echo "</pre>";
 
 
?>

Ejemplo de consumir un Web Service SOAP desde servidor externo (Obtener Ip) https://ws.cdyne.com/ip2geo/ip2geo.asmx

require_once "./nusoap.php";
    $url = "http://ws.cdyne.com/ip2geo/ip2geo.asmx?wsdl";
    try {
     $client = new SoapClient($url, 'wsdl' );
     $param=array('ipAddress'=>"210.45.151.101", 'licenseKey' => "0");
     $result = $client->call('ResolveIP', $param);
     print_r($result);
    } catch ( SoapFault $e ) {
     echo $e->getMessage();
    }
    echo PHP_EOL;

FICHERO TXT EN EL SERVIDOR

melon,
melocoton,
banana,
frambuesa


RECUPERA FICHERO MOSTRANDO DATOS

<?php

$curl = curl_init("http://localhost/frutas.txt");   //Inicia una nueva sesión cURL

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);   //Define opciones para nuestra sesion cURL,  si se quiere que el contenido que devuelve la página se almacene en una variable, se puede utilizar la opción CURLOPT_RETURNTRANSFER

$respuesta = curl_exec($curl);   //Ejecuta la sesión cURL que se le pasa como parámetro.
 
$info = curl_getinfo($curl);   //Obtiene información de la última transferencia

echo $respuesta;
echo $info;

if($info['http_code'] == 200){


	$datos = explode (",", $respuesta);

	echo "<h1>Frutas en mi tienda</h1>";

	foreach ($datos as $key => $value) {
		echo $key."->".$value . "<br>";
	}
}

/*  //ejemplo cargar una web en el php
       $cliente = curl_init();
	curl_setopt($cliente, CURLOPT_URL, "https://www.google.com/search?q=lamerce");
	curl_exec($cliente);
	curl_close($cliente);
*/


?>

FICHERO SERVER.PHP

<?php
require_once "./nusoap/lib/nusoap.php";
      
   
   function getInfo() {
      
       return "Info de los libros";
      
    }


    function getProd($categoria) {
        if ($categoria == "libros") {
            return join(",", array(
                "El señor de los anillos",
                "Los límites de la Fundación",
                "The Rails Way"));
        }
        else {
            return "No hay productos de esta categoria";
        }
    }
      
    $server = new soap_server();
    $server->configureWSDL("producto", "urn:producto");
      
    $server->register("getProd",
        array("categoria" => "xsd:string"),  //parametro de entrada
        array("return" => "xsd:string"),     //parametro de salida
        "urn:producto",                      //namespace
        "urn:producto#getProd",              //accion
        "rpc",                               //estilo
        "encoded",
        "Nos da una lista de productos de cada categoría");



    $server->register("getInfo",
        array(""),
        array("return" => "xsd:string"),
        "urn:producto",
        "urn:producto#getInfo",
        "rpc",
        "encoded",
        "Nos da Info ");
      
      if(!isset($HTTP_RAW_POST_DATA)){   ///Datos POST sin tratar , En general, se debería utilizar php://input en lugar de $HTTP_RAW_POST_DATA.

    $HTTP_RAW_POST_DATA = file_get_contents("php://input");
}

 $server->service($HTTP_RAW_POST_DATA);
   
?>

FICHERO CLIENTE.PHP

<?php
require_once "./nusoap/lib/nusoap.php";

$cliente = new nusoap_client("http://localhost/webservice/server.php");
//$cliente = new nusoap_client("http://localhost/webservice/server.php?wsdl", 'wsdl');
//$cliente = new nusoap_client("./server.php?wsdl", true);

      
    $error = $cliente->getError();
    if ($error) {
        echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
    }
      
    $result = $cliente->call("getProd", array("categoria" => "libros"));

    $result1 = $cliente->call("getInfo");
      
    if ($cliente->fault) {
        echo "<h2>Fault</h2><pre>";
        print_r($result);
        echo "</pre>";
    }
    else {
        $error = $cliente->getError();
        if ($error) {
            echo "<h2>Error</h2><pre>" . $error . "</pre>";
        }
        else {
            echo "<h2>Libros</h2><pre>";
            echo $result;
            echo $result1;
            echo "</pre>";
        }
    }
?>

Exercici Web Service SOAP

  • Crea un servei web que permeti Sumar, Restar, Multiplicar i Dividir.
  • Busca un servei web a internet que utilitzi SOAP. site: wsdl
  • Crea un servei web que façi dos consultes a una base de dades que tingui informació.
  • Crea una aplicació client en Swing que utilitzi el servei web anterior
  • Crea una aplicació client en PHP que també utilitzi aquest servei.

API PHP

curl o file_gets_contents()

Para recuperar datos de una API, pueden usarse dos formas con curl o file_gets_contents()

¿Cúal es mejor?

En pocas palabras:

file_get_contents()

Es un simple destornillador. Ideal para simples solicitudes GET donde el encabezado, método de solicitud HTTP, tiempo de espera, cookies, redirecciones y otras cosas más complejas no importan.

También se pueden usar para peticiones POST, pero habría que crear un contexto para ello (Ver esta contribución en el Manual de PHP).

Es menos seguro que cURL y por eso viene desactivado por defecto en muchos entornos PHP.

cURL

Es mucho más potente y para usos más avanzados.

cURL es probablemente la librería de HTTP más ampliamente utilizada en el mundo de la programación. Originalmente fue codificado utilizando lenguaje C, y luego fue portado a muchos otros lenguajes.

cURL puede manejar manipulaciones HTTP complicadas de manera elegante, como solicitudes HTTP asíncronas, informes de progreso, etc.

El único problema de cURL es que requiere algún tiempo, varias horas al menos, para familiarizarse con sus funciones y estilo de codificación.

Pero al ser una librería tan usada, la documentación y ejemplos de código en la red son abundantes.

Como ejemplo, sólo basta con ver la amplia documentación para cURL en el Manual de PHP (enlace de más arriba).

¿Cuál es más rápido?

Todas las pruebas que he leído hasta ahora indican que cURL es más rápido.

El siguiente gráfico es el producto de una prueba entre diferentes métodos, publicada por Philip Norton en Quickest Way To Download A Web Page With PHP

https://es.stackoverflow.com/questions/81565/diferencias-entre-file-get-contents-y-curl

Antes hay que asegurarse que curl está instalado en nuestro server apache.

sudo apt-get install curl-php

sudo service apache2 restart

Instalar POSTMAN para hacer las pruebas

wget https://dl.pstmn.io/download/latest/linux64 -O postman.tar.gz
sudo tar -xzf postman.tar.gz -C /opt
rm postman.tar.gz
sudo ln -s /opt/Postman/Postman /usr/bin/postman



SERVIDOR

<?php 
  // La base de datos se llama blog, la tabla "posts" y sus atributos (title, status, content, user_id)
	$connection=mysqli_connect('localhost','root','','blog');

	$request_method=$_SERVER["REQUEST_METHOD"];
	switch($request_method)
	{
		case 'GET':
			// Retrive Products
			if(!empty($_GET["id"]))
			{
				$product_id=intval($_GET["id"]);  //transforma en número entero
				get_products($product_id);
			}
			else
			{
				get_products();
			}
			break;

		case 'POST':
			insert_product();
			break;

		case 'PUT':
			// Update Product
			$product_id=intval($_GET["id"]);
			update_product($product_id);
			break;

		case 'DELETE':
			// Delete Product
			$product_id=intval($_GET["id"]);
			delete_product($product_id);
			break;

		default:
			// Invalid Request Method
			header("HTTP/1.0 405 Method Not Allowed");
			break;
	}

	function insert_product()
	{
		global $connection;
		$title=$_POST["title"];
		$status=$_POST["status"];
		$content=$_POST["content"];
		$user_id=$_POST["user_id"];
		
		$query = "INSERT INTO posts (title, status, content,user_id) VALUES ('$title', '$status', '$content', '$user_id')";


		if(mysqli_query($connection, $query))
		{
			$response=array(
				'status' => 1,
				'status_message' =>'Product Added Successfully.'
			);
		}
		else
		{
			$response=array(
				'status' => 0,
				'status_message' =>'Product Addition Failed.'
			);
		}
		header('Content-Type: application/json');
		echo json_encode($response);
	}

	function get_products($product_id=0)
	{
		global $connection;
		$query="SELECT * FROM posts";
		if($id != 0)
		{
			$query.=" WHERE id=".$id." LIMIT 1";
		}
		$response=array();
		$result=mysqli_query($connection, $query);
		while($row=mysqli_fetch_array($result))
		{
			$response[]=$row;
		}
		header('Content-Type: application/json');
		echo json_encode($response);
	}

	function delete_product($product_id)
	{
		global $connection;
		echo "entra";
		$query="DELETE FROM posts WHERE id=".$product_id;
		if(mysqli_query($connection, $query))
		{
			$response=array(
				'status' => 1,
				'status_message' =>'Product Deleted Successfully.'
			);
		}
		else
		{
			$response=array(
				'status' => 0,
				'status_message' =>'Product Deletion Failed.'
			);
		}
		header('Content-Type: application/json');
		echo json_encode($response);
	}

	function update_product($product_id)
	{
		//(title, status, content, user_id)
		global $connection;
		parse_str(file_get_contents("php://input"),$post_vars);  //php://input es un flujo de sólo lectura que permite leer datos del cuerpo solicitado, por tanto $post_vars recibirá todos los datos(título, status,content,user_id).

		$title=$post_vars["title"];
		$status=$post_vars["status"];
		$content=$post_vars["content"];
		$user_id=$post_vars["user_id"];
		$query="UPDATE posts SET title='{$title}', status='{$status}', content='{$content}', user_id='{$user_id}' WHERE id=".$product_id;
		if(mysqli_query($connection, $query))
		{
			$response=array(
				'status' => 1,
				'status_message' =>'Product Updated Successfully.'
			);
		}
		else
		{
			$response=array(
				'status' => 0,
				'status_message' =>'Product Updation Failed.'
			);
		}
		header('Content-Type: application/json');
		echo json_encode($response);
	}

	// Close database connection
	mysqli_close($connection);


CLIENTE

// GET 

$url = 'http://localhost/api/server.php?id=1';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response_json = curl_exec($ch);
curl_close($ch);
$response=json_decode($response_json, true);
 print_r($response);

//DELETE

$url = 'http://localhost/api/server.php?id=2';
$ch = curl_init($url);  //// abrimos la sesión cURL
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');  // definimos la URL a la que hacemos la petición
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  // recibimos la respuesta y la guardamos en una variable
$response_json = curl_exec($ch);
curl_close($ch);  // recibimos la respuesta y la guardamos en una variable
$response=json_decode($response_json, true);
print_r($response);


//PUT
$data=array(
		'title' =>'Nuevo',
		'status' => "enviado",
		'content' => "10",		
		'user_id' =>'2'
);
$url = 'http://localhost/api/server.php?id=3';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response_json = curl_exec($ch);
print_r($response_json);
curl_close($ch);
$response=json_decode($response_json, true);

//POST 
$data=array(
		'title' =>'Television',
		'status' => "1000",
		'content' => "10",
		'user_id' =>'2'
);
$url = 'http://localhost/api/server.php';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true); // indicamos el tipo de petición: POST
// definimos cada uno de los parámetros
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);  //curl_setopt($ch, CURLOPT_POSTFIELDS, "title=value1&status=value2&content=value3&user_id=5");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);// recibimos la respuesta y la guardamos en una variable

$response_json = curl_exec($ch);
// cerramos la sesión cURL
curl_close($ch);
print_r($response_json);  //mostramos datos
$response=json_decode($response_json, true);


También se pueden hacer llamadas al servidor mediante el terminal..

//POST
curl -d "title=value1&status=value2&content=value3&user_id=5" http://localhost/api1/server.php

curl --data "title=value1&status=value2&content=value3&user_id=value4" http://localhost/api1/server.php

//DELETE
curl -X "DELETE" http://localhost/api1/server.php?id=1

//GET
 curl --data "title=value1&si -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost/api1/server.php?id=1


http://frikibloggeo.blogspot.com/2017/01/crear-un-web-service-api-rest-con-php-y.html


EXERCICIS

  • Familiarizarse con cURL y crear una API con una base de datos y probar el funcionamiento de POSTMAN
  • Encontrar como hacer un GET por consola del cURL, también probar cómo ejecutar en el terminal del servidor estos comandos.

https://www.apptha.com/blog/how-to-build-a-rest-api-using-php/


https://www.tmb.cat/es/sobre-tmb/herramientas-para-desarrolladores/datos-tiempo-real




https://www.youtube.com/watch?v=BeY1bQzMeAk

Exercici Web Service SOAP

  • Crea un servei web que permeti Sumar, Restar, Multiplicar i Dividir.
  • Busca un servei web a internet que utilitzi SOAP.
  • Crea un servei web que façi dos consultes a una base de dades que tingui informació.
  • Crea una aplicació client en Swing que utilitzi el servei web anterior
  • Crea una aplicació client en PHP que també utilitzi aquest servei.

XML

En aquest apartat es veurà com utilitzar XML per guardar dades des de un servidor PHP. Exemple de XML:

Fitxer aules.xml:
<aules>   
    <aula>
        <nom>205</nom>
        <subxarxa>172.16.205.0</subxarxa>
        <mascara>24</mascara>
        <estatinicial>denega</estatinicial>
        <estatactual>filtra</estatactual>
    </aula>
    <aula>
        <nom>206</nom>
        <subxarxa>172.16.206.0</subxarxa>
        <mascara>24</mascara>
        <estatinicial>denega</estatinicial>
        <estatactual>denega</estatactual>
    </aula>
</aules>

Per representar aquest fitxer com a un arbre i poder-lo recòrrer s'utilitza la llibreria DOMDocument de PHP.

Creació del Arbre XML

Per crear una representació del fitxer anterior, primer s'ha de crear l'objecte DOMDocument i a continuació llegir el fitxer:

$file = "files/aules.xml";
$xmldom = new DOMDocument();
$xmldom->load($file);

Obtenir un element del arbre

Es pot utilitzar la funció getElementsByTagName. Exemple:

$aules = $xmldom->getElementsByTagName("aula");

Recòrrer tots els elemens

Podem recòrrer tots els element amb un foreach:

$aules = $xmldom->getElementsByTagName("aula");
foreach ($aules as $aula) {
    $name = $aula->getElementsByTagName("nom")->item(0)->nodeValue;
    $net = $aula->getElementsByTagName("subxarxa")->item(0)->nodeValue;
    $mask = $aula->getElementsByTagName("mascara")->item(0)->nodeValue;
}

Afegir un nou element

Per afegir un nou elment s'ha de crear un node nou i afegir tos els fills que es necessiti per crear el XML correcte. Exemple:

$auladom = $xmldom->createElement("aula");
//creamos el nodo NOM con su valor $classroomname
$aulanomdom = $xmldom->createElement("nom");
$domnode = $xmldom->createTextNode(strtolower($classroomName));
$aulanomdom->appendChild($domnode);
$auladom->appendChild($aulanomdom);

//creamos el nodo NETWORK con su valor $network
$aulanetwork = $xmldom->createElement(XARXA_AULA_XML);
$domnode = $xmldom->createTextNode(strtolower($network));
$aulanetwork->appendChild($domnode);
$auladom->appendChild($aulanetwork);

//creamos el nodo MASK con su valor $mask
$aulamask = $xmldom->createElement(MASK_AULA_XML);
$domnode = $xmldom->createTextNode(strtolower($mask));
$aulamask->appendChild($domnode);
$auladom->appendChild($aulamask);

//creamos el nodo initial status con su valor $initialstatus
$aulastatus = $xmldom->createElement(INIT_AULA_XML);
$domnode = $xmldom->createTextNode(strtolower($initialstatus));
$aulastatus->appendChild($domnode);
$auladom->appendChild($aulastatus);

//creamos el nodo current status con su valor $initialstatus
$aulacurrentstatus = $xmldom->createElement(CURRENT_AULA_XML);
$domnode = $xmldom->createTextNode(strtolower($initialstatus));
$aulacurrentstatus->appendChild($domnode);
$auladom->appendChild($aulacurrentstatus);

//afegim el node aula a la llista de nodes
$root = $xmldom->documentElement;
$root->appendChild($auladom);

//guardem        
$xmldom->save($filename);

Finalment, s'ha de guardar el dom resultant al fitxer per mantenir correctament els canvis. Es fa amb la funció save.

Esborrar un element

Per esborrar un element, primer s'ha de cercar, després dir-li al pare que ens volem eliminar. Però també hem d'esborrar els fills!.

//funció que esborra un node i els seus fills
    function deleteNode($node) {
        deleteChildren($node);
        $parent = $node->parentNode;
        $oldnode = $parent->removeChild($node);
    }

//funció que esborra els fills d'un node
    function deleteChildren($node) {
        while (isset($node->firstChild)) {
            deleteChildren($node->firstChild);
            $node->removeChild($node->firstChild);
        }
    } 
    
//funció que cerca al XML un node amb el nom=$classroomname    
    function delete($classroomName){
         $aules = $xmldom->getElementsByTagName("aula");
          foreach ($aules as $aula) {
            $name = $aula->getElementsByTagName("nom")->item(0)->nodeValue;
            if (strcmp(strtolower($name), strtolower($classroomName)) == 0){
                deleteNode($aula);
                $xmldom->save($this->filename);   
            }
        }
    }

Finalment, s'ha de guardar el dom resultant al fitxer per mantenir correctament els canvis. Es fa amb la funció save.

Modificar un valor

Per modificar un valor, primer es cerca i després es mira quin dels atributs es vol modificar:

function setNewClassroomAttr($classroomName, $attr, $value)
    {
        $aules = $xmldom->getElementsByTagName("aula");
        foreach ($aules as $aula) {
            $name = $aula->getElementsByTagName("nom")->item(0)->nodeValue;
            if (strcmp(strtolower($name), strtolower($classroomName)) == 0){
                $aula->getElementsByTagName($attr)->item(0)->nodeValue = strtolower($value);
                $this->xmldom->save($this->filename);   
            }
        }
        
    }

Finalment, s'ha de guardar el dom resultant al fitxer per mantenir correctament els canvis. Es fa amb la funció save.

Podeu trobar més informació a http://www.php.net/manual/en/class.domdocument.php

Mashups

Una remescla, també coneguda pel terme anglès mashup, és una aplicació web híbrida que utilitza contingut d'altres aplicacions web per a crear un nou contingut complet, consumint serveis directament sempre a través del protocol http.

El contingut d'un mashup normalment prové de llocs web de tercers a través d'una interfície pública o utilitzant una API. Altres mètodes que constitueixen l'origen de les seves dades inclouen: sindicació web (RSS o Atom), screen scraping, etc.

Els mashup estan revolucionant el desenvolupament web de la mateixa manera que els weblogs han revolucionat la publicació en línia. Permeten que qualsevol combini, de forma innovadora, dades que existeixen en diferents pàgines web. Requereixen pocs coneixements tècnics, les API existents són senzilles i potents i els mashup són relativament fàcils de dissenyar. Els creadors de mashups són generalment gent innovadora que vol combinar de formes noves i creatives dades disponibles públicament.

API de Google Maps

A continuació trobareu un llistat amb les funcions més interesant de la API de Googlem maps que podeu utilitzar per realitzar mashups.

Primer heu d'afegir la llibreria de google Maps:

<script src="http://maps.googleapis.com/maps/api/js"></script>

Després heu de un contenidor per al mapa.

<div id="googleMap" style="width:500px;height:380px;"></div>


Una vegada teniu el contenidor heu de crear el mapa. Per crea-lo necessiteu informar a l'API de google maps unes quantes propietats:

  • center: Indica on ha de centrar el mapa. S'ha de donar les coordenades de latitud i longitud.
  • zoom: Indica el nivel de ZOOM del mapa. Zomm = 0 mostra la terra sencera.
  • mapTypeId: Indica el tipus de Mapa a mostrar. Existeixen els següents tipus de mapa: ROADMAP, SATELLITE, HYBRID, TERRAIN.

Exemple de les propietats:

var mapProp = {
  center:new google.maps.LatLng(51.508742, -0.120850),
  zoom: 7,
  mapTypeId: google.maps.MapTypeId.ROADMAP
};

Una vegada s'ha definit les propietats ja es pot crear el mapa i un listener:

var map=new google.maps.Map(document.getElementById("googleMap"), mapProp);
google.maps.event.addDomListener(window, 'load', initialize);

Exemple de mapa centrat a londres:

<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
  var mapProp = {
    center:new google.maps.LatLng(51.508742,-0.120850),
    zoom:5,
    mapTypeId:google.maps.MapTypeId.ROADMAP
  };
  var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>

<body>
<div id="googleMap" style="width:500px;height:380px;"></div>
</body>

</html>

Bé, ja tenim creat el mapa. Potser ens interessa afegir alguna marca dintre del mapa. Aquestes marques s'anomenen overlays i poden ser de diferents tipus:

  • Marker - Localitzacions úniques del mapa. Poden tenir icones personalitzats.
  • Polyline - Series de línies rectes en el mapa
  • Polygon - Series de línies rectes en el mapa pero la forma resultant ha d'estar tancada.
  • Circle and Rectangle
  • Info Windows - Mostra contingut dintre de popups.
  • marques personalitzades

https://www.w3schools.com/graphics/google_maps_intro.asp

Exemples:

<div id="map" style="width:100%;height:500px"></div>

<script>
function myMap() {
  var mapCanvas = document.getElementById("map");
  var myCenter = new google.maps.LatLng(51.508742,-0.120850); 
  var mapOptions = {center: myCenter, zoom: 5};
  var map = new google.maps.Map(mapCanvas,mapOptions);
  var marker = new google.maps.Marker({
    position: myCenter,
    animation: google.maps.Animation.BOUNCE
  });
  marker.setMap(map);
}
</script>

<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBu-916DdpKAjTmJNIgngS6HL_kDIKU0aU&callback=myMap"></script>
<div id="map" style="width:100%;height:500px"></div>

<script>
function myMap() {
  var mapCanvas = document.getElementById("map");
  var myCenter = new google.maps.LatLng(51.508742,-0.120850); 
  var mapOptions = {center: myCenter, zoom: 5};
  var map = new google.maps.Map(mapCanvas,mapOptions);
  var marker = new google.maps.Marker({
    position: myCenter,
    icon: "pinkball.png"
  });
  marker.setMap(map);
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBu-916DdpKAjTmJNIgngS6HL_kDIKU0aU&callback=myMap"></script>
//basic:
var marker=new google.maps.Marker({
  position:myCenter,
  });

marker.setMap(map);

//Amb animació:
var marker=new google.maps.Marker({
  position:myCenter,
  animation:google.maps.Animation.BOUNCE
  });

marker.setMap(map);

//amb una icona
var marker=new google.maps.Marker({
  position:myCenter,
  icon:'pinkball.png'
  });

marker.setMap(map);


//amb un poligon
var myTrip = [stavanger,amsterdam,london,stavanger];
var flightPath = new google.maps.Polygon({
  path:myTrip,
  strokeColor:"#0000FF",
  strokeOpacity:0.8,
  strokeWeight:2,
  fillColor:"#0000FF",
  fillOpacity:0.4
});

//amb un cercle
var myCity = new google.maps.Circle({
  center:amsterdam,
  radius:20000,
  strokeColor:"#0000FF",
  strokeOpacity:0.8,
  strokeWeight:2,
  fillColor:"#0000FF",
  fillOpacity:0.4
});

//amb una finestra d'informacio
var infowindow = new google.maps.InfoWindow({
  content:"Hello World!"
  });

infowindow.open(map,marker);

També podem afegir un listener a un marker per, per exemple, obrir un infowindow quan es faci click en ell:

var infowindow = new google.maps.InfoWindow({
  content:"Hello World!"
  });

google.maps.event.addListener(marker, 'click', function() {
  infowindow.open(map,marker);
  });

Exemple de posicionament d'un marker on l'usuari fa click i a més a més afegeix un infowindow:

google.maps.event.addListener(map, 'click', function(event) {
  placeMarker(event.latLng);
  });

function placeMarker(location) {
  var marker = new google.maps.Marker({
    position: location,
    map: map,
  });
  var infowindow = new google.maps.InfoWindow({
    content: 'Latitude: ' + location.lat() +
    '<br>Longitude: ' + location.lng()
  });
  infowindow.open(map,marker);
}

Podeu trobar la referència complerta de la API de google maps | aqui.

APIS https://github.com/toddmotto/public-apis/blob/master/README.md

Com trobar les coordenades d'una ciutat

Podeu utilitzar l'API de google per trobar les coordenades d'una ciutat. Pots fer-ho de dues maneres: Exemple1:

$address = 'india';
$details_url = "http://maps.googleapis.com/maps/api/geocode/json?address=".$address."&sensor=falsecurl_init();
curl_setopt($ch, CURLOPT_URL, $details_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = json_decode(curl_exec($ch), true);

// If Status Code is ZERO_RESULTS, OVER_QUERY_LIMIT, REQUEST_DENIED or INVALID_REQUEST
if ($response['status'] != 'OK') {
	return null;
}

//print_r($response);
//print_r($response['results'][0]['geometry']['location']);

$latLng = $response['results'][0]['geometry']['location'];

$lat = $latLng['lat'];
$lng = $latLng['lng'];

Exemple2:

$geocode_stats = file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?address=india&sensor=false");

$output_deals = json_decode($geocode_stats);

$latLng = $output_deals->results[0]->geometry->location;

$lat = $latLng->lat;
$lng = $latLng->lng;


Webgrafia


http://frikibloggeo.blogspot.com/2017/01/crear-un-web-service-api-rest-con-php-y.html

https://www.youtube.com/watch?v=BeY1bQzMeAk