08 tecweb1920 rest - diunitogoy/materiale/1920/08_tecweb1920_rest.pdf · un'applicazione che...
TRANSCRIPT
aa 2019/2020
1
RESTful servicescon PHP
Goy ‐ a.a. 2019/2020 1Tecnologie Web: approcci avanzati
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati 2
REST API: Riferimenti bibliografici ‐ I
• How To Create A Simple REST API in PHP? Step By Step Guide!www.codeofaninja.com/2017/02/create‐simple‐rest‐api‐in‐php.html
• E. Zimuel, Sviluppare in PHP 7, Tecniche Nuove, 2017capitolo 9 (Sviluppo di web API)
• ...
• AJAX CRUD Tutorial Using jQuery, JSON and PHP – Step by Step Guide! www.codeofaninja.com/2015/06/php‐crud‐with‐ajax‐and‐oop.html
aa 2019/2020
2
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati 3
REST API: Riferimenti bibliografici ‐ IIInoltre (cose utili che NON vediamo)...
• REST API Authentication Example in PHP – JWT Tutorialwww.codeofaninja.com/2018/09/rest‐api‐authentication‐example‐php‐jwt‐tutorial.html
• Suggerimenti da Zimuel (2017):– P. Sturgeon. Build APIs You Won't Hate. 2015– L. Richardson, S. Ruby, M. Amundsen. RESTful Web APIs. O'Reilly
Media, 2013– L. Mitchell. PHP Web Services. O'Reilly Media, 2013– S. Parastatidis, J. Webber, I. Robinson. REST in Practice. O'Reilly
Media, 2010
• ...
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Aggregare servizi: mashup ‐ IMashup [https://it.wikipedia.org/wiki/Mash-up_(informatica)]:
In informatica un mash‐up è un sito o un'applicazione web di tipo ibrido, cioè tale da includere dinamicamente informazioni o contenuti provenienti da più fonti. Un es. potrebbe essere un programma che, acquisendo da un sito web una lista di appartamenti, ne mostra l'ubicazione utilizzando il servizio Google Maps per evidenziare il luogo in cui gli stessi appartamenti sono localizzati.Mash‐up (letteralmente: "poltiglia"), in termini informatici, indica un'applicazione che usa contenuti [e servizi!] da più sorgenti per creare un servizio completamente nuovo. Il contenuto dei mash‐up è normalmente preso da terzi via API, tramite feed (es. RSS e Atom) o JavaScript.
4
aa 2019/2020
3
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Aggregare servizi: mashup ‐ II
La definizione delle modalità di invocazione dei servizi può seguire approcci diversi, più o meno standardizzati:
1. Open API
2. servizi RESTful
3. SOAP Web Services
5
meno formale (meno standard)
più formale (più standard)
Per farvi un'idea dei servizi disponibili...www.programmableweb.com/apis/directory
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Microservizi ‐ I
"La tendenza, in questi ultimi anni, è quella di creare dei microservizi tramite un linguaggio di backend come PHP per l'utilizzo con applicazioni client per il web (Javascript) o per il mobile, tramite lo sviluppo di applicazioni native o ibride. PHP 7 può essere la soluzione ideale per lo sviluppo si questi microservizi" [Zimuel 2017, p. 242]
6
microservizio1 microservizio2 microservizio3 microservizio...
aa 2019/2020
4
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: intro ‐ I• servizi RESTful = servizi la cui interfaccia di accesso è basata sul
paradigma REST (REpresentational State Transfer)
• REST = insieme di principi "architetturali" per la progettazione e realizzazione di interfacce di accesso ai servizi (non è né uno standard, né una tecnologia, né un linguaggio, ...) non è necessario introdurre nuovi protocolli o linguaggi:interfaccia RESTful = utilizza, sostanzialmente, URL e HTTP !!
• obiettivo: offrire la possibilità di interagire con il servizio indipendentemente dal linguaggio di programmazione possibilità di far interagire in modo "trasparente" applicazioni eterogenee
7
ServiceConsumerService
ConsumerServiceConsumer
messaggio di richiesta
messaggio di risposta
ServiceProvider
interfaccia
(REST o
SOAP/
WSD
L)
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: intro ‐ II
[da: www.programmableweb.com/api/twitter]
EsempioInvocazione del servizio: https://api.twitter.com/1.1/search/tweets.json?q=%40BigData
NB: l'invocazione del servizio (search/tweets) è un URL con parametri (metodo GET di HTTP)
8
aa 2019/2020
5
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: intro ‐ IIIEsempio di risultato (NB: è un oggetto JSON){ "statuses": [
{ ..."created_at": "Mon Sep 24 03:35:21 +0000 2012","id_str": "250075927172759552","entities": { ...
"hashtags": [{ "text": "BigData, ... }
],},"in_reply_to_user_id_str": null,"contributors": null,"text": "...","metadata": {
"iso_language_code": "en","result_type": "recent"
},"retweet_count": 0,..."user": { ...
"name": "Sean Cummings","profile_image_url": "...","created_at": "Mon Apr 26 06:01:55 +0000 2010","location": "LA, CA", ...
}, ...}, ...]}
9
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
JSON ‐ I
Cos'è JSON (JavaScript Object Notation)?[www.json.org; www.html.it/articoli/introduzione-a-json-1/]
• è un formato testuale molto usato per lo scambio di dati in applicazioni client‐server
• è basato su due strutture:– coppie nome‐valore– liste ordinate di valori (array)
• Esempio: JSON è utilizzato nelle API di Google Maps, x es per creare una mappa:map = new google.maps.Map(document.getElementById("map"),options);
options = {zoom: 14,center: new google.maps.LatLng(45.06...,7.68...),mapTypeId: google.maps.MapTypeId.ROADMAP
};
10
JSON "object"
aa 2019/2020
6
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
JSON ‐ IIEsempio (oggetto studente):{
"nome":"Paolo","cognome":"Rossi","matricola":123456,"emails":["[email protected]","[email protected]"],"indirizzo":
{"via":"Roma","num":1,"cap":00100
}"esami":[
{"codice":"INF123","voto":"30L"
}{"codice":"SPS456","voto":"28"
}]
}11
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
JSON ‐ III
E' possibile manipolare oggetti JSON con Javascript:
JSON.stringify(<JSON object>); stringa
JSON.parse(<string>); oggetto JSON
Un oggetto JSON è un oggetto Javascript…studente.nome Paolo
studente.cognome Rossi
studente.matricola 123456
studente.emails lista (array) di 2 elementi di tipo stringa
studente.indirizzo.via Roma
studente.indirizzo.num 1
studente.indirizzo.cap 00100
studente.esami lista (array) di 2 oggetti: la scorro e, per ogni oggetto,chiedo codice e voto…
12
aa 2019/2020
7
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: intro ‐ IVPrincipi architetturali del paradigma REST:[www.html.it/pag/19595/introduzione-ai-web-service/ lezioni 1 - 4]
1. Identificazione delle risorse: "risorsa" = qualsiasi elemento oggetto di elaborazione (es: un cliente, un libro, un prodotto)Ogni risorsa deve essere identificata univocamente attraverso un URI; x es: http://www.myapp.com/clienti/1234
2. Utilizzo esplicito dei metodi HTTP: utilizzare i metodi (le operazioni) definiti nel protocollo HTTP per interagire con il servizio: GET, POST, PUT/PATCH, DELETE
rende uniforme l'invocazione di operazioni sulle risorse13
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: intro ‐ V3. Risorse autodescrittive (content negotiation):
il formato dei dati (MIME type) desiderato può essere indicato nella richiesta (x es: Accept: application/json)il formato inviato è indicato nella risposta(x es: Content-Type: application/json; charset=UTF-8)
4. Collegamenti tra risorse: tutto quello che un client deve sapere su una risorsa, e sulle risorse ad essa correlate, deve essere contenuto nella risposta stessa (HTTP response) o accessibile tramite link (rif. principio 1)
5. Comunicazione senza stato (stateless):HTTP è stateless (= una richiesta non ha alcuna relazione con le richieste precedenti/successive) lo stesso principio vale per la comunicazione con servizi RESTful una risposta REST dipende solo dalle info contenute nella richiesta !!
NOTA sulla sicurezza: gli accessi a una web API dovrebbero essere sempre controllati per prevenire attacchi (es. Denial Of Service) o usi non autorizzati (... validate sempre gli input!!!)
14
aa 2019/2020
8
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: progettazione ‐ I
Progettare il servizio:
1. Funzionalità (chi può fare cosa)
2. Dati (input/output)
3. API endpoints (richieste/risposte)
4. Corrispondenza con i metodi HTTP
5. Route protection
6. URL styling
Case study: backoffice edicola fumetti (usati) online
15
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: progettazione ‐ II
1. Funzionalità (chi può fare cosa) [*] inserire un nuovo prodotto admin cancellare un prodotto admin aggiornare le info su un prodotto admin leggere la lista dei prodotti everyone leggere le info su un prodotto everyone cercare un prodotto everyone
2. Dati (input/output)
formato: JSON
[*] il processo di autenticazione non lo vediamo :‐(16
aa 2019/2020
9
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Servizi RESTful: progettazione ‐ III
3. API endpoints (richieste/risposte) inserimento in: dati prod; out: messaggio cancellazione in: id prod; out: messaggio aggiornamento in: dati prod; out: messaggio lettura lista in: ‐‐ ; out: lista prodotti lettura singolo prodotto in: id prod; out: info prod ricerca in: stringa; out: lista prodotti
4. Corrispondenza con i metodi HTTP inserimento POST cancellazione DELETE aggiornamento PUT (o PATCH) lettura lista GET lettura singolo prodotto GET ricerca GET
17
replace a resource
update parts of a resource
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Postman ‐ IPer testare le API REST (prima di costruire un client) possiamo usare Postman (https://www.getpostman.com/downloads/)
scaricatelo e installatelo!
18
aa 2019/2020
10
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: database ‐ IDatabase fumettiTabella categorie (struttura)
Tabella prodotti (struttura)
19RIF fumetti.sql
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: database ‐ IITabella categorie (dati)
Tabella prodotti (dati)
20
aa 2019/2020
11
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: file system ‐ Iapi/
config/Database.php (classe x gestire la connessione al DB)
objects/Product.php (classe che rappresenta le proprietà deiprodotti e gestisce le richieste di operazioni su di essi)
product/create.phpdelete.phpread.phpread_one.phpupdate.phpsearch.php
app_client/esClientRest.htmljquery-3.4.1.js
21
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: READ ‐ IImplementiamo le funzionalità previste...
leggere la lista dei prodotti accesso everyone; metodo GETdati in ‐‐ ; out: lista prodotti
metodo read() in Product.php:– invia al DB una query che seleziona tutti i record della tabella
prodotti– restituisce la lista (tabella) dei prodotti
read.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– crea un'istanza di Product e invoca il metodo read()
– legge il risultato (recordset) e lo codifica in JSON
– restituisce il JSON (con la lista dei prodotti)22
aa 2019/2020
12
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: READ ‐ II
Inviamo al servizio una richiesta di lettura dei prodotti:
• avviate Postman (NB ci mette una vita...!)
• impostate il metodo GET
• inserite l'URL: http://localhost/esempiTW/REST/api/product/read.php
• cliccate su Send
23
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: CREATE ‐ Iinserire (creare) un nuovo prodotto accesso admin; metodo POSTdati in: dati prod; out: messaggiometodo create() in Product.php:
– invia al DB una query che crea un nuovo record (in prodotti)– restituisce un messaggio (ok/problemi...)
create.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– stabilisce i metodi consentitiheader("Access-Control-Allow-Methods: POST");
– legge i dati nella richiesta (POST)
$data = json_decode(file_get_contents("php://input"));
– crea un'istanza di Product e invoca il metodo create()– restituisce un messaggio (ok/ko)
24
(2)(1)
aa 2019/2020
13
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Note ‐ I(1)json_encode($products); restituisce una stringa che contiene l'oggetto JSON corrispondente al parametro (per es. $products), che può essere di qualunque tipo
json_decode($json_string); "decodifica" l'ogg. JSON, rappr. come stringa, passato come param.
(2)
25
http://php.net/manual/en/function.file-get-contents.php
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Note ‐ II
26
*
http
s://s
tack
over
flow
.com
/que
stio
ns/8
8935
74/p
hp-p
hp-in
put-
vs-p
ost
aa 2019/2020
14
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Note ‐ III
27
http
s://s
tack
over
flow
.com
/que
stio
ns/8
8935
74/p
hp-p
hp-in
put-
vs-p
ost
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: CREATE ‐ II
Inviamo al servizio una richiesta di inserimento nuovo prodotto:
• avviate Postman
• impostate il metodo POST
• inserite l'URL: http://localhost/esempiTW/REST/api/product/create.php
• cliccate su Body, poi su raw e inserite i dati:{
"nome":"La valle del terrore","prezzo":"25","descrizione":"Una storia disegnata da Magnus","cat_id":1,"creato":"2019-02-20 00:00:00"
}
• cliccate su Send
28
aa 2019/2020
15
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: CREATE ‐ IIIRichiesta
Risposta
29
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: READ_ONE ‐ Ileggere le info su un prodotto accesso everyone; metodo GETdati in: id prod; out: info prodmetodo readOne() in Product.php:
– invia al DB una query che cerca il prodotto con quell'id– restituisce il record trovato (o un messaggio di errore)
read_one.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– stabilisce i metodi consentitiheader("Access-Control-Allow-Methods: GET");
– legge l'id nella richiesta (GET) $_GET['id']– crea un'istanza di Product e invoca il metodo readOne()– legge il risultato (recordset) e lo codifica in JSON– restituisce il JSON (con le info sul prodotto)
30
saltato slide 30‐34
aa 2019/2020
16
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: READ_ONE ‐ II
Inviamo al servizio una richiesta delle info su un prodotto:
• avviate Postman
• impostate il metodo GET
• inserite l'URL: http://localhost/esempiTW/REST/api/product/read_one.php?id=11 (NB attenzione che sia un id esistente!)
• cliccate su Send
31
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: UPDATE ‐ Iaggiornare i dati su un prodotto accesso admin; metodo PUTdati in: dati prod; out: messaggiometodo update() in Product.php:
– invia al DB una query che aggiorna il record (id in input)– restituisce un messaggio (ok/problemi...)
update.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– stabilisce i metodi consentitiheader("Access-Control-Allow-Methods:POST,PUT,PATCH");
– legge i dati nella richiesta (PUT)$data = json_decode(file_get_contents("php://input"));
– crea un'istanza di Product e invoca il metodo update()– restituisce un messaggio (ok/ko)
32
aa 2019/2020
17
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: UPDATE ‐ II
Inviamo al servizio una richiesta di inserimento nuovo prodotto:• avviate Postman• impostate il metodo PUT• inserite l'URL:
http://localhost/esempiTW/REST/api/product/update.php• cliccate su Body, poi su raw e inserite i dati:
{"id":"11","nome":"La valle del terrore","prezzo":"50","descrizione":"Una storia disegnata da Magnus","cat_id":1,"creato":"2019-02-20 00:00:00"
}
• cliccate su Send
NB se specificate un id inesistente, l'operazione sembra andarea buon fine ugualmente... occorrerebbe un controllopreliminare sull'id!!!
33
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: UPDATE ‐ IIIRichiesta
Risposta
34
aa 2019/2020
18
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: DELETE ‐ Icancellare un prodotto accesso admin; metodo DELETEdati in: id prod; out: messaggio
metodo delete() in Product.php:– invia al DB una query che cancella il prodotto con quell'id– restituisce un messaggio (ok/problemi...)
delete.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– stabilisce i metodi consentitiheader("Access-Control-Allow-Methods: DELETE");
– legge l'id nella richiesta (DELETE)$data = json_decode(file_get_contents("php://input"));
– crea un'istanza di Product e invoca il metodo delete()– restituisce un messaggio (ok/ko)
35
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: DELETE ‐ II
Inviamo al servizio una richiesta delle info su un prodotto:
• avviate Postman
• impostate il metodo DELETE
• inserite l'URL: http://localhost/esempiTW/REST/api/product/delete.php
• cliccate su Body, poi su raw e inserite i dati:{
"id":"11"}
• cliccate su Send
36
aa 2019/2020
19
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: SEARCH ‐ Icercare un prodotto accesso everyone; metodoGETdati in: stringa; out: lista prodotti
metodo search() in Product.php:– invia al DB una query che cerca i prodotti con quella stringa
nel nome o nella descrizione o nel nome della categoria– restituisce la lista (tabella) dei prodotti trovati
search.php:– stabilisce i permessi di lettura del file
header("Access-Control-Allow-Origin: *") // anyone
– definisce il formato della rispostaheader("Content-Type: application/json; charset=UTF-8");
– legge la stringa nella richiesta (GET) $_GET['s']– crea un'istanza di Product e invoca il metodo search()– legge il risultato (recordset) e lo codifica in JSON– restituisce il JSON (con la lista dei prodotti)
37
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: SEARCH ‐ II
Inviamo al servizio una richiesta di ricerca (data una stringa):
• avviate Postman
• impostate il metodo GET
• inserite l'URL: http://localhost/esempiTW/REST/api/product/search.php?s=Topolino
• cliccate su Send
38
aa 2019/2020
20
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Case Study: SEARCH ‐ IIIRichiesta
Risposta
39
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (semplice) ‐ ICreiamo un'app (client) che utilizza i servizi REST creati
40
aa 2019/2020
21
Client app (semplice) ‐ IIesClientRest.html<a href="err.php" id="read">leggi tutti i prodotti</a><div id="products"> </div>
$("#read").on("click", function() {$.ajax({url:"http://localhost/.../product/read.php",type:"GET",success:function(response) {html_list = "<ul>";for (i = 0; i < response.records.length; i++){html_list += "<li>"+JSON.stringify(response.records[i])+"</li>";}
html_list += "</ul>";$("#products").html(html_list);
},error: ...
});return false;
});
41
ATTENZIONE! necessario per far funzionare on click: senza, partela request legata all'attributo href e la chiamata ajax non funziona!
quando l'utente clicca sull'elem. con id="read" ...
quando arriva la risposta del server, eseguiamo la callback: costruiamo una lista (<ul></ul>) scorrendo l'oggetto JSONresponse (lista di prodotti) e la mettiamo nell'elem. con id="products"; la funz. html(html_list) inserisce la stringacontenuta in html_list nell'elem. con id="products"
inviamo una richiesta (asincrona) al server
Tecnologie Web: approcci avanzati
Client app (semplice) ‐ III$("#read-one").on("click", function(){
$.ajax({url:"http://localhost/.../product/read_one.php?id=4",type:"GET",success:function(response){
$("#products").html("<pre>"+JSON.stringify(response)+"</pre>");
},error: ...
});return false;
});
$("#create").on("click", function(){$.ajax({
url:"http://localhost/.../product/create.php",type:"POST", contentType:'application/json',data:JSON.stringify({"nome":"La valle del terrore", "prezzo":"25","descrizione":"Una storia disegnata da Magnus", "cat_id":1, "creato":"2019-02-20"}),success:function(response){...},
error: ...});return false;
});42Goy ‐ a.a. 2019/2020
in questo caso, la risposta del server (response) è un oggetto JSON che rappresenta un prodotto: lo mettiamo direttamente nell'elem. con id="products"
content‐type dei dati della request
dati della request
aa 2019/2020
22
Tecnologie Web: approcci avanzati
Client app (semplice) ‐ IV$("#update").on("click", function(){
$.ajax({url:"http://localhost/.../product/update.php",type:"PUT",... analoga alla create (ma nei dati serve anche l'id!!) ...
$("#delete").on("click", function(){$.ajax({
url:"http://localhost/.../product/delete.php",type:"DELETE", contentType:'application/json',data:JSON.stringify({"id":"11"}),... analoga alla create ...
$("#search").on("click", function(){$.ajax({
url:"http://localhost/.../product/search.php?s=Topolino",... analoga alla read ...
43Goy ‐ a.a. 2019/2020
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Note conclusive ‐ IPrepared Statements and Bound Parameters[https://www.w3schools.com/php/php_mysql_prepared_statements.asp]
• Prepared statements basically work like this:– Prepare: An SQL statement template is created and sent to the
database. Certain values are left unspecified, called parameters ("?"). Ex: INSERT INTO MyGuests VALUES(?, ?, ?)
– The database parses, compiles, and performs query optimization on the SQL statement template, and stores the result without executing it
– Execute: At a later time, the application binds the values to the parameters, and the database executes the statement.
• Prepared statements have three main advantages:
– they reduce parsing time as the preparation on the query is done only once (although the statement is executed multiple times)
– bound parameters minimize bandwidth to the server as you need send only the parameters each time, and not the whole query
– they are very useful against SQL injections, because parameter values are transmitted later, need not be escaped, and ‐ if the statement template is not derived from external input ‐ SQL injection cannot occur
44
aa 2019/2020
23
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Note conclusive ‐ IIEsempio$db = new PDO("mysql:dbname=fumetti;host=localhost","root","");$this->price = ...;$query = "UPDATE prodotti SET prezzo=:price";$stmt = $conn->prepare($query);$stmt->bindParam(':price', $this->price);$stmt->execute();
$this->id = ...;$query = "SELECT * FROM prodotti WHERE id = ?";$stmt = $conn->prepare($query);$stmt->bindParam(1, $this->id);$stmt->execute();
Varie [php.net/manual]$row = $stmt->fetch(PDO::FETCH_ASSOC);$this->name = $row['nome']; ...• it fetches the next row from a result set• parameter = fetch_style (controls how the next row is returned and must be
one of the PDO::FETCH_* constants)• PDO::FETCH_ASSOC: returns an array indexed by column name
45
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
NEW CASE STUDY: backoffice edicola fumetti (usati) online• esClientRest.html è a dir poco grezza... miglioratela!
• Innanzi tutto occorre creare una UI per acquisire i dati (x es. utilizzando dei form HTML)
• Sicuramente occorre migliorare la visualizzazione dei risultati ottenuti
• Poi si possono apportare altre varie migliorie... x es:– nella update, se l'utente specifica un id inesistente, l'operazione
sembra andare a buon fine ugualmente... occorrerebbe un controllo preliminare sull'id
– ...
PUT ALL TOGETHER & TRY YOURSELF!
46cartella api e app_client + fumetti.sql
aa 2019/2020
24
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ I
Creiamo un'altra app (client) che utilizza i servizi REST, un po' piùcomplessa… (basata sul Tutorial:www.codeofaninja.com/2015/06/php‐crud‐with‐ajax‐and‐oop.html)
47
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ IIStruttura sul File System:app/
index.html (single‐page app!)assets/css/style.css
js/ (librerie javascript)bootbox.min.jsjquery‐3.4.1.js
products/create‐product.jsdelete‐product .jsproducts.jsread‐one‐product.jsread‐products.jssearch‐product.jsupdate‐product.js
app.js
48
aa 2019/2020
25
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ IIIindex.html:<head>• importa il CSS di Bootstrap
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384..." crossorigin="anonymous">
• importa il nostro CSS<link href="app/assets/css/style.css" rel="stylesheet">
<body>• importa la libreria jQuery
<script src="app/assets/js/jquery-3.4.1.js"></script>
• importa la libreria Bootstrap<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384... " crossorigin="anonymous"></script>
• importa la libreria BootBox<script src="app/assets/js/bootbox.min.js"></script>
49
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ IV
• importa il file app.js<script src="app/app.js"></script>
• crea un elemento HTML con id=app<div id="app"></div>
• importa i file app/products/products.jsread‐products.jscreate‐product.jsread‐one‐product.jsupdate‐product.jsdelete‐product.jssearch‐product.js
50
aa 2019/2020
26
modifica (o restituisce) il contenuto di un elemento; NB:• <el>contenuto</el>• restituisce il contenuto del primo el.
che corrisponde al selettore; modificail contenuto di tutti gli el. che corrisp.
al selettore
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ Vapp.js:• crea la struttura HTML della home page
$(document).ready(function(){var app_html = "<div class='container'>";app_html += "<div class='page-header'>";app_html += "<h1 id='page-title'>Read Products</h1>";app_html += "</div>";app_html += "<!– content here -->";app_html += "<div id='page-content'></div>";app_html += "</div>";
// inject to 'app' element// (in index.html)$("#app").html(app_html);
});
• definisce la funzione changePageTitlefunction changePageTitle(page_title){
$('#page-title').text(page_title); // page titledocument.title=page_title; // window title
}51
= (ma solo testo, no tag HTML)
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ VI• definisce la funzione serializeObject, per creare un
oggetto JSON a partire dai dati del form (verràusata per gestire la creazione e l'aggiornamento di un prodotto)// function to make form values to json format$.fn.serializeObject = function() {
var o = {};var a = this.serializeArray();$.each(a, function() {if (o[this.name] !== undefined) {if (!o[this.name].push) {o[this.name] = [o[this.name]];
}o[this.name].push(this.value || '');
} else {o[this.name] = this.value || '';
}});return o;
};
52
$.fn = alias di jQuery.prototypeLe funzione definite su $.fn sonoereditate da tutti glioggetti jQuery usato x estenderejQuery con nuovefunzioni ; es:$.fn.myFun = function(){…}$("#el").myFun()
la keyword this è una variabilepredefinita che siriferisce all'oggetto a cui appartiene; se usata all'interno di una funzione, siriferisce all'oggetto"possessore" di quellafunzione
serializeObject verrà invocata su unogg. che contiene i dati inviatiattraverso un form e restituirà un oggetto JSON che rappresenta tali dati
aa 2019/2020
27
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ VIIproducts.js:• definisce la funzione readProductsTemplate che crea la struttura
HTML della pagina di presentaz. dei prodotti (verrà usata per visualizzare i prodotti, x es. in risposta a una search)function readProductsTemplate(data, keywords){var read_products_html=`<form id='…' action='#' method='post'><div class='…'><input type='text' value='`+keywords+`'… />...`;
// loop through returned list of data$.each(data.records, function(key, val){// creating new table row per recordread_products_html+=`<tr><td>` + val.name + `</td>...`;
});read_products_html+=`</table>`;// inject to 'page-content' of our app$("#page-content").html(read_products_html);
}53
data = ris. dellarichiesta (es. search) = lista(array) di prodottikeywords = parole cercate – vedisearch‐product.js (e read‐products.js)
scorre data ed esegue la funzionesu ogni elementokey = indice (chiave) dell'el. correnteval = valore dell'el. corrente
consente
glia‐cap
o (e
le variabiliinterpolate:
`Ciao ${n}!`
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ VIIIread-products.js:• definisce la funzione showProducts (che usa la
readProductsTemplate per visualizzare i prodotti)function showProducts(){
// get list of products from the API$.getJSON("http://localhost…/read.php", function(data){readProductsTemplate(data, "");changePageTitle("Read Products");
});}
• visualizza i prodotti al caricamento della pagina e al click sulpulsante Read ProductsshowProducts();$(document).on('click', '.read-products-button', function(){
showProducts();});
54
equivale a: $.ajax({dataType: 'json',url: http://localhost…/read.php, type: 'GET',success: function(data){…} });
// data = JSON-encoded data from the server
aa 2019/2020
28
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ IXcreate-product.js:• al click sul pulsante Create Product, inserisce il form HTML
nell'elemento con id= page‐content (+ invoca la funzionechangeTitle)$("#page-content").html(create_product_html);changePageTitle("Create Product");
• al click sul pulsante Submit, invia i dati del form al server$(document).on('submit', '#create-product-form', function(){var form_data = JSON.stringify($(this).serializeObject());$.ajax({
url: "http://localhost…/create.php",type : "POST",contentType : 'application/json',data : form_data,success : function(result) {
showProducts();},error: ...
});return false;
});
55
legge i dati del form ($(this)) e li strasformain un oggetto JSON (in formato stringa)…
… lo invia al server e poi visualizza nuovamente la lista dei prodotti
NB: $(this) è un riferimento all'elem. del DOM che ha generato l'evento: nel caso di submit contiene i dati inviati con il form
!!
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ Xread-one-product.js:• al click sul pulsante Read accanto a un prodotto, legge l'id di quel
prodotto, chiede al server i dati e li visualizza nell'elemento con id= page‐content (+ invoca la funzione changeTitle)$(document).on('click', '.read-one-...button', function(){
var id = $(this).attr('data-id');$.getJSON("http://localhost…/read_one.php?id=" + id,
function(data){var read_one_product_html=`...`;$("#page-content").html(read_one_product_html);changePageTitle("Create Product");
});});
56
HTML pulsante Read:<button class='…' data-id='product-id'>$(this) = il pulsante Readattr('data-id') = il valore dell'attributo data‐id
aa 2019/2020
29
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ XIupdate-product.js:• al click sul pulsante Edit accanto a un prodotto, legge l'id di quel
prodotto, chiede al server i dati e li inserisce nel form HTML, cheviene visualizzato nell'elemento con id= page‐content (+ invoca la funzione changeTitle)
$(document).on('click', '.update-...button', function(){var id = $(this).attr('data-id');$.getJSON("http://localhost…/read_one.php?id=" + id,
function(data){var name = data.name;var price = data.price;var description = data.description;var category_id = data.category_id;var category_name = data.category_name;
var update_product_html=`… <input value=\"` + name + `\" type='text' …/> …`;$("#page-content").html(update_product_html);changePageTitle("Update Product");
});});
57
variabili usate per inserire i valori nei campi del form
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ XIIdelete-product.js:• al click sul pulsante Delete accanto a un prodotto, legge l'id di quel
prodotto, chiede conferma all'utente e invia al server una richiestadi cancellazione (dopo la quale mostra nuovamente l'elenco deiprodotti)$(document).on('click', '.delete-...button', function(){
var id = $(this).attr('data-id');bootbox.confirm({message:"<h4>Are you sure?</h4>",buttons:{confirm:{label:'<span class="…"></span>Yes',className: 'btn-danger'},
cancel:{label:'<span class="…"></span>No',className: 'btn-primary'}
},callback: [vedi prox slide]
});});
58
usiamo la libreriaBootbox.js per mostrare una dialog box (per confermarela cancellazione)
<button class='…' data-id='13'>$(this)= pulsante Readattr('data-id')= ilvalore dell'attributodata‐id (cioè l'id del prodotto corrispondente)
aa 2019/2020
30
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ XIII...bootbox.confirm({
message: ...buttons: ...callback: function (result){if(result==true){$.ajax({url: "http://localhost…/delete.php",type: "POST",dataType : 'json',data: JSON.stringify({id:product_id}),success: function(result){showProducts();
},error: function(xhr, resp, text) {console.log(xhr, resp, text);
}});
}}
});
59
funzione di callback della finestra di dialogo: gestisce la risposta dell'utente; il parametro result vale true o false (a seconda di quale pulsante è stato cliccato)
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
Client app (più complessa) ‐ XIVsearch-product.js:• quando l'utente scrive una o più keyword nel campo di ricerca e
avvia la ricerca, legge le keyword, chiede al server effettuare la ricerca, passandogli le keywords e usa la readProductsTemplateper visualizzare i risultati (+ invoca la funzione changeTitle)$(document).on('submit', '#search-product-form', function(){
var keywords = $(this).find(":input[name='keywords']").val();
$.getJSON("http://="…/search.php?s=" + keywords, function(data){
readProductsTemplate(data, keywords);changePageTitle("Search products: " + keywords);
});return false;
});
60
<form id='search-product-form' action='#' method='post'><input type='text' value='`+keywords+`' name='keywords' … />
el.find(sel) prende i discendenti di el "di tipo" selin questo caso, prende gli elementi (i dati) contenuti in $(this) [= dati del form] che abbiano name='keywords'
metto nella var keywords il valore del campo del form con name='keywords' (cioè le keywords scritte dall'utente!), infatti:
aa 2019/2020
31
Goy ‐ a.a. 2019/2020 Tecnologie Web: approcci avanzati
NEW CASE STUDY (versione 2):
backoffice edicola fumetti (usati) online
• La UI è in inglese... trasformatela in italiano :‐)
• Per inserire un nuovo prodotto (e per aggiornarne le info) bisogna sapere l'id della categoria:– create un servizio REST che vi restituisce l'elenco delle categorie
– usatelo per costruire un menu (select) in cui è possibile scegliere la categoria
PUT ALL TOGETHER & TRY YOURSELF!
61cartella api e app_client_Bootstrap + fumetti.sql