webservicesPHP

il sistema più piccolo possibile per avere un servizio attivo

Precisazione importante

In un sistema in produzione (serebbe a dire in uno che funziona on-line per utenti reali) la scelta migliore è usare una libreria che aiuta a gestire webservices e ne esistono per diversi linguaggi! Qui creiamo come esempio un file unico senza dipendenze (sarebbe a dire librerie di scaricate da qualche parte su internet) per capire come funziona il gioco.

Il servizio che andiamo a scrivere usa HTTP (cosa che succede usualmente) e quindi tutte le strutture che ci mette a disposizione, non serve inventarsi un meccanismo per specificare come rappresentiamo i dati: ci sono gli header. Non serve di pensare a come comunicare se le cose sono andate bene o male: ci sono già i codici di riposta di HTTP, per sapere cosa fare basta leggere l'azione (es: GET o DELETE) che ci è stata richiesta via HTTP. Quello che ci accingiamo a fare è semplicemente "mettere insieme i pezzi".

PHP

Scegliamo di utilizzare questo linguaggio che ci permette di scrivere programmi (o script che dir si voglia) lato server che girano su server HTTP (come quello di Apache), ovviamente è possibile fare un lavoro analogo con molti altri diversi.

Cosa vuoi?

Per sapere quale è l'azione richiesta dal client non c'è una funzione specifica ma un elemento della superglobal $_SERVER: $_SERVER['REQUEST_METHOD'] che potrebbe ad esempio essere "GET".

Di quale risorsa stiamo parlando

Di nuovo la superglobal $_SERVER e in particolare il suo elemento REQUEST_URI.

Informazioni per svolgere l'azione?

Per sapere invece quali sono i dati di input possiamo usare le due superglobal $_GET o $_POST a seconda del metodo usato per la richiesta.

In quale formato?

A voler essere proprio precisi potremmo anche rispondere al client in base alle sue esigenze cioè ad esempio alla lingua o al formato della risposta... ovviamente se possibile.

Poniamo ad esempio di essere in grado di rispondere sia in XML che in JSON come posso sapere quale è il formato che il mio client vorrebbe avere? Guardando l'header Accept di HTTP, PHP ci mette a disposizone una funzione per questo: getallheaders() che ritorna un array di headers. In pratica:

$intestazioni = getallheaders();
if( strpos($intestazioni['Accept'],"application/json") === false ){
    echo "JSON non ti va bene\n";
}else{
    echo "JSON ti va bene\n";
}

Come è andata

L'esigenza successiva è quella di comunicare come è andata l'operazione richiesta (se ci viene richiesto di cancellare qualcosa non è detto che vogliamo farlo!): http_response_code() serve a questo scopo, http_response_code(200) comunicherà ad esempio che la richiesta si è conclusa con successo.

Come ti sto rispondendo

HTTP nella sua intestazione ci consente di specificare il tipo di messaggio che stiamo inviando al client e PHP mette a disposizione una funzione per impostare un header qualsiasi: header(). Nello specifico visto che rappresenteremo i dati utilizzando JSON sarà header('Content-type: application/json').

Esempio

<?php
http_response_code(200);
header('Content-type: application/json');
echo "azione richiesta:${_SERVER['REQUEST_METHOD']}\n";
echo "risorsa:".$_SERVER['REQUEST_URI']."\n";
echo "senza parametri:".parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH)."\n";
echo "valore del parametro nome:".$_GET['nome']."\n";

$intestazioni = getallheaders();
echo "vorresti la risposta nel formato:".$intestazioni['Accept']."\n";

if( strpos($intestazioni['Accept'],"json") > 0 ){
    echo "JSON ti va bene\n";
}else{
    echo "JSON non ti va bene\n";
}
if( strpos($intestazioni['Accept'],"xml") > 0 ){
    echo "XML ti va bene\n";
}else{
    echo "XML non ti va bene\n";
}

L'esempio sopra ha un errore... quale?

"${" non ha sensoha senso, serve a scrivere variabili più complicate nelle stringhe application/jsonsi, è sbagliato o si mette text/plain o si cambia il testo della risposta (quello negli echo) "REQUEST_URI" non è una chiave di $_SERVERlo è, l'indirizzo della risorsa richiesta

Configurazioni fini

In caso si voglia usare (e si, si vuole!) le normali URL (es: servizio/identificativo)per specificare il servizio non bisogna cambiare lo script PHP... basta istruire il web server.

Nel caso di Apache httpd possiamo configurarlo per trasformare una URL servizio/identificativo in servizio.php?p1=identificativo inserendo la configurazione sotto nel file .htaccess o nel file di configurazione al livello di sistema.

RewriteEngine  on
# RewriteRule cosa_vai_cercando come_devo_riscriverlo flag
# flag: https://httpd.apache.org/docs/2.4/rewrite/flags.html
# [L] sta per "ultima regola" (ovviamente se combacia)
# tutte le robe che sono un elemento di servizio e finiscono per qualche_numero
RewriteRule "^servizio/([0-9]+)$" "servizio.php?p1=$1" [L]

nota: il parametro p1 se presente nell'URL originale (prima di fare rewrite) viene comunque passato allo script

[2024-01-03] è possibile che Apache httpd e in particolare la negoziazione dei contenuti dai errore nel mapping. Può essere di aiuto la configurazione sotto come riportato in post su serverfault.

AddType application/x-httpd-php .php