In questa lezione impari a
- usare array, cicli e funzioni per elaborare dati
- validare un form lato server e difenderlo dall'XSS
- leggere e modificare un database con mysqli e query preparate
- realizzare CRUD, ricerca con paginazione, login e transazioni
- collaudare un'applicazione con una lista di prove, come fa chi la corregge
Dopo la palestra SQL della lezione 17, questa è la palestra PHP. Le esercitazioni sono in due blocchi:
- A – PHP da solo (1–3): si possono fare dopo la lezione 9;
- B – PHP con MySQL (4–8): si fanno dopo le lezioni 10–14 e usano gli stessi database delle esercitazioni SQL. Se non hai ancora fatto l'esercitazione SQL corrispondente, falla prima, oppure chiedi al docente il file
.sqldel database.
Ogni esercitazione va in una cartella sua dentro htdocs di XAMPP (per esempio htdocs/videoteca/) e si apre con http://localhost/videoteca/. Nel blocco B parti dal kit della biblioteca della lezione 12: db.php, funzioni.php (con h(), messaggio(), vai() e il token CSRF), header.php, footer.php e stile.css si riusano quasi senza modifiche: basta cambiare il nome del database in config.php.
Come controllarti. In PHP non c'è una tabella di risultati da confrontare: ogni esercitazione ha una lista di prove da fare. Sono le stesse che farà il docente quando corregge: se tutte danno il risultato atteso, il lavoro è giusto. Le soluzioni complete le ha il docente.
Esercitazione 1 – La pagella
⭐ Facile · array associativi, foreach, funzioni sugli array, match
Scrivi una pagina index.php che mostra la pagella di uno studente. I voti sono in un array associativo scritto nel codice:
$studente = 'Giulia Rossi';
$voti = [
'Italiano' => 7,
'Matematica' => 5.5,
'Inglese' => 8,
'Informatica' => 9,
'Sistemi' => 6,
'Storia' => 5,
];
Cosa deve fare la pagina
- Una tabella con materia e voto; le righe con voto sotto il 6 sono in rosso.
- La media, con due decimali e la virgola, e il giudizio: sotto 6 insufficiente, da 6 a 7 sufficiente, da 7 a 8 discreto, da 8 a 9 buono, da 9 in su ottimo (usa
match). - Il voto più alto e quello più basso, con la materia (suggerimento:
max,minearray_search). - Il numero delle insufficienze e l'elenco delle materie.
Le prove da fare
- La media è 6,75 e il giudizio sufficiente.
- Voto più alto: 9 in Informatica; più basso: 5 in Storia.
- Insufficienze: 2 (Matematica, Storia), e sono le due righe rosse.
- Il voto di Matematica si legge 5,5, non 5.5.
- Cambia un voto nell'array (per esempio Storia a 7): tutti i risultati devono aggiornarsi da soli, senza toccare altro codice.
Esercitazione 2 – Il modulo di iscrizione
⭐ Facile · form POST, validazione lato server, XSS
La scuola organizza corsi pomeridiani. Scrivi una pagina con un form di iscrizione: nome e cognome, email, età, corso (un menu a tendina con Python per principianti, Siti web con HTML e CSS, Robotica con Arduino) e una casella "Accetto l'informativa sulla privacy".
Cosa deve fare la pagina
- Controllare i dati lato server: nome obbligatorio (massimo 60 caratteri), email valida, età intera tra 14 e 99, un corso tra quelli previsti, privacy accettata.
- Se ci sono errori, ripresentare il form con ogni errore accanto al suo campo e con i valori già scritti.
- Se è tutto giusto, mostrare un riepilogo dell'iscrizione al posto del form.
- Ogni dato scritto dall'utente va stampato con
htmlspecialchars.
Le prove da fare
- Invia il form vuoto: compaiono 5 errori, uno per campo.
- Scrivi l'email
pippoed età12: due errori, e il nome e il corso scelti restano nel form. - Scrivi come nome
<b>Ciao</b>: deve comparire scritto così, non in grassetto. - Con gli strumenti per sviluppatori del browser cambia il
valuedi un'opzione del corso inhackere invia: il server deve rifiutarlo. - Togli
novalidateo i controlli HTML (required,type="email"): i controlli devono funzionare lo stesso, perché quelli veri sono in PHP. - Dati corretti: compare il riepilogo con il nome completo del corso.
Esercitazione 3 – Funzioni utili
⭐ Facile · funzioni con tipi, include, cicli, stringhe
Scrivi un file funzioni.php con quattro funzioni, e una pagina index.php che lo include con require e le prova.
tabellina(int $n, int $fino = 10): arrayrestituisce un array[1 => n, 2 => 2n, …]. La pagina mostra la tabellina del numero scritto in un piccolo form GET (?n=7), con 7 se manca o non è valido.celsius_in_fahrenheit(float $c): float, arrotondata a un decimale: °F = °C × 9/5 + 32.bisestile(int $anno): bool: un anno è bisestile se è divisibile per 4 ma non per 100, oppure se è divisibile per 400.isbn13_valido(string $isbn): bool: un codice ISBN di 13 cifre è valido se, moltiplicando le cifre alternativamente per 1 e per 3 (la prima per 1), la somma è un multiplo di 10. I trattini vanno ignorati.
Le prove da fare
?n=7→ l'ultima riga è 7 × 10 = 70;?n=abc→ tabellina del 7.- Temperature: −40 → −40, 0 → 32, 37 → 98,6, 100 → 212.
- 1900 non bisestile, 2000 bisestile, 2024 bisestile, 2026 no.
9788804668237valido,978-88-04-66823-7valido,9788804668238non valido,12345non valido.
Esercitazione 4 – La videoteca sul web
⭐⭐ Medio · mysqli, query preparate, parametri GET, 404
Usa il database es_videoteca dell'esercitazione SQL 2.
Le pagine
index.php: l'elenco di tutti i film in ordine di titolo, con anno e regista. Ogni titolo è un link alla sua scheda.film.php?id=…: la scheda del film (titolo, anno, genere, regista con nazionalità, durata in minuti e in ore e minuti) e l'elenco degli altri film dello stesso regista, anch'essi con il link.
L'id arriva dall'indirizzo: controllalo con filter_input e usa una query preparata. Se il film non esiste, la pagina risponde con il codice 404 e il messaggio Film non trovato.
Le prove da fare
- L'elenco mostra 8 film.
- La scheda di Interstellar dice 169 minuti (2 h 49 min) e propone Inception e Oppenheimer come altri film di Nolan.
- La scheda di C'è ancora domani mostra l'apostrofo e la è correttamente.
- La scheda di Il mio vicino Totoro propone La città incantata; quella di C'è ancora domani dice che non ci sono altri film.
film.php?id=999,film.php?id=abcefilm.phpsenza id → Film non trovato. Negli strumenti per sviluppatori (scheda Rete) il codice è 404.film.php?id=1 OR 1=1→ Film non trovato, non il primo film.
Esercitazione 5 – La rubrica: CRUD completo
⭐⭐ Medio · INSERT, UPDATE, DELETE, un form per due usi, errori del database
Usa il database es_rubrica dell'esercitazione SQL 1.
Le pagine
index.php: l'elenco dei contatti in ordine di cognome, con i link Modifica ed Elimina e il link Nuovo contatto.modifica.php: lo stesso form per inserire (senza id) e modificare (modifica.php?id=3, con i campi già compilati). Nome, cognome e telefono sono obbligatori; il telefono contiene solo cifre e spazi (da 6 a 15 caratteri); email e data di nascita, se scritte, devono essere valide. I campi facoltativi vuoti si salvano comeNULL.elimina.php?id=…: chiede conferma; la cancellazione avviene solo con un form POST protetto dal token CSRF.
Dopo ogni salvataggio si torna all'elenco con un messaggio (schema Post/Redirect/Get).
Le prove da fare
- Salva un contatto con tutti i campi vuoti e telefono
abc: compaiono gli errori, nessun inserimento. - Inserisci un contatto con il telefono di Marco Rossi (
3331234567): la pagina mostra numero già in rubrica accanto al telefono, non un errore di PHP. (Suggerimento: cattura lamysqli_sql_exceptione controlla chegetCode()valga 1062.) - Inserisci un contatto corretto: torni all'elenco, i contatti diventano 7, compare il messaggio. Ricarica la pagina con F5: non si crea un doppione.
- Modifica il contatto appena creato: il form è già compilato e la modifica si vede nell'elenco.
- Apri il link Elimina: deve solo chiedere conferma. Il contatto sparisce solo dopo aver premuto il pulsante.
modifica.php?id=999→ messaggio Contatto non trovato.- In phpMyAdmin controlla che un contatto senza email abbia email
NULL, non vuota.
Esercitazione 6 – Le iscrizioni in palestra
⭐⭐ Medio · JOIN e COUNT da PHP, controlli prima dell'INSERT, transazioni
Usa il database es_palestra dell'esercitazione SQL 3. Nell'esercitazione SQL hai visto che il database non può impedire di superare i posti di un corso: ora il controllo lo fa PHP.
Le pagine
index.php: i corsi con giorno, ora, iscritti su posti e posti liberi (in verde), oppure Completo (in rosso). Il nome del corso porta alla pagina del corso.corso.php?id=…: gli iscritti al corso, in ordine di cognome, con la data di iscrizione.iscrivi.php: un form con due menu a tendina (iscritto e corso). Prima di inserire, PHP controlla che la persona non sia già iscritta e che il corso non sia completo; altrimenti mostra un messaggio chiaro. La data di iscrizione è quella di oggi.
Per i più bravi: metti il controllo e l'INSERT in una transazione, leggendo il corso con SELECT … FOR UPDATE. Così due segreterie che iscrivono contemporaneamente non possono prendere entrambe l'ultimo posto.
Le prove da fare
- Nell'elenco Spinning risulta Completo (3 / 3) e Boxe ha 0 / 6 iscritti.
- Iscrivi Marta Fontana a Spinning → il corso è completo.
- Iscrivi Anna Neri a Yoga → già iscritta.
- Iscrivi Simone Greco a Boxe → messaggio di conferma, e Boxe passa a 1 / 6 con 5 posti liberi.
- La pagina di Spinning elenca Costa, Galli, Ricci in quest'ordine.
- Iscrivi due volte di seguito la stessa persona allo stesso corso: la seconda volta deve comparire il messaggio, non un errore di chiave primaria.
Esercitazione 7 – L'officina: ricerca e paginazione
⭐⭐⭐ Impegnativo · LIKE con parametri, COUNT, LIMIT e OFFSET, http_build_query
Usa il database es_officina dell'esercitazione SQL 4.
Scrivi index.php: l'elenco di tutti gli interventi (data, targa e modello dell'auto, cliente, descrizione, costo), dal più recente, 3 per pagina, con un campo di ricerca che filtra per targa o cognome del cliente (anche scritti in parte o in minuscolo). Sopra la tabella: quanti interventi sono stati trovati e il loro costo totale. Sotto: Precedente, Pagina X di Y, Successiva. I link delle pagine devono conservare la ricerca.
Le prove da fare
- Senza ricerca: 7 interventi, totale 1.979,00 €, Pagina 1 di 3.
- Pagina 3: un solo intervento, il tagliando del 15/01/2026.
- Cerca
esposito: 3 interventi, totale 695,00 €, una sola pagina. - Cerca
ij789: 2 interventi (la Golf di Laura Conti). - Cerca
' OR 1=1 --: 0 interventi, nessun errore. - Cerca
<script>: il testo compare nel campo di ricerca così com'è, senza effetti. - Scrivi a mano
?pagina=99: ti porta all'ultima pagina;?pagina=-1o?pagina=abcalla prima. - Cerca una lettera che dia più di 3 risultati e passa alla pagina 2: la ricerca resta nel campo e nell'indirizzo.
Esercitazione 8 – La pizzeria: login e ordini
⭐⭐⭐ Impegnativo · registrazione, password_hash, sessioni, CSRF, transazioni
Usa il database es_pizzeria dell'esercitazione SQL 6. Per il login i clienti hanno bisogno di email e password: aggiungi le colonne con questa istruzione (in phpMyAdmin, scheda SQL):
ALTER TABLE clienti
ADD email VARCHAR(80) UNIQUE,
ADD password_hash VARCHAR(255);
I clienti già presenti restano senza email e senza password: non potranno accedere finché non si registrano.
Le pagine
index.php: il listino delle pizze, visibile a tutti.registrati.php: nome, cognome, indirizzo di consegna, email e password (almeno 8 caratteri). La password si salva solo conpassword_hash; un'email già usata va segnalata con un messaggio.login.phpelogout.php: accesso conpassword_verifyesession_regenerate_id; il messaggio di errore è lo stesso sia per l'email sbagliata sia per la password sbagliata.ordina.php(solo per chi ha fatto il login): il listino con una casella di quantità (da 0 a 20) per ogni pizza. L'ordine e le sue righe si salvano in una transazione: una riga inordinie una riga indettagli_ordineper ogni pizza con quantità maggiore di zero.ordini.php(solo per chi ha fatto il login): gli ordini del cliente collegato, con data, pizze, totale e stato (Consegnato / In preparazione).
Tutti i form POST hanno il token CSRF.
Le prove da fare
- Apri
ordina.phpsenza login: torni al login con un messaggio. - Registrati con una password di 5 caratteri: rifiutata. Poi registrati correttamente; riprova con la stessa email: esiste già.
- In phpMyAdmin la colonna
password_hashcontiene una stringa che inizia con$2y$, non la password. - Login con password sbagliata e con un'email inesistente: stesso messaggio.
- Invia un ordine con tutte le quantità a 0: scegli almeno una pizza.
- Ordina 2 Margherite e 1 Diavola: in I miei ordini compare un ordine da 19,50 €, In preparazione. Nel database ci sono 1 riga nuova in
ordinie 2 indettagli_ordine. - Il nuovo cliente vede solo il suo ordine, non quelli di Luca Moretti o degli altri.
- Dopo Esci,
ordini.phpnon è più accessibile.
Quando le esercitazioni del blocco B ti vengono bene, sei pronto per il progetto finale.