PHP tutorial: come realizzare una biblioteca con sistema di login e motore di ricerca | Aulab

GUIDE PER ASPIRANTI PROGRAMMATORI

PHP tutorial: come realizzare una biblioteca con sistema di login e motore di ricerca

imparerai a sviluppare un’applicazione web completa utilizzando PHP e MySQL, seguendo un approccio pratico e strutturato. Partirai dalla configurazione dell’ambiente di sviluppo con Docker, per poi progettare un database relazionale efficiente. Scoprirai come organizzare il progetto in modo modulare, creare interfacce utente responsive con HTML, CSS e Bootstrap, e implementare funzionalità chiave come la registrazione e il login degli utenti, la gestione dei libri (inserimento, modifica, eliminazione), la ricerca con filtri dinamici e la protezione del sito con tecniche di sicurezza essenziali. Al termine del percorso, avrai acquisito le competenze per creare e pubblicare una web app PHP moderna e funzionale!

Immagine di copertina

Vuoi avviare una nuova carriera o fare un upgrade?

Trova il corso Digital & Tech più adatto a te nel nostro catalogo!

1

Introduzione al tutorial php

1.1

Panoramica del progetto in php

Benvenuto in questo tutorial introduttivo alla programmazione con PHP! Inizieremo il nostro percorso con un progetto pratico e concreto: una biblioteca online sviluppata interamente in PHP, che include funzionalità di login utente, una dashboard privata, un motore di ricerca per i libri e la gestione semplificata tramite Docker. Il progetto è stato pensato per essere intuitivo e modulare, così da permetterti di esplorare ogni aspetto della programmazione web con il linguaggio PHP e MySQL, partendo dalle basi e arrivando a costruire un'applicazione funzionante e personalizzabile. Ogni file ha un ruolo ben definito, facilitando la comprensione della logica sottostante e rendendo il codice facilmente estendibile per future migliorie o personalizzazioni. Inoltre, il progetto utilizza una struttura coerente e moderna, che simula scenari reali di sviluppo, e fornisce un primo assaggio del flusso di lavoro tipico di un’applicazione web. Potrai studiare come è organizzato il codice, capire come viene strutturata l'interazione con il database, e osservare da vicino come vengono gestite funzionalità comuni come l'autenticazione o la ricerca. Questo approccio ti permetterà di comprendere non solo il funzionamento del codice, ma anche la logica dietro la progettazione dell'applicazione. Potrai, inoltre, personalizzarlo gradualmente, introducendo nuove sezioni o adattandolo a contesti differenti come una libreria scolastica, un archivio digitale o un gestionale interno.   Funzionalità principali del progetto. Tra le funzionalità principali:   Registrazione e autenticazione utente con verifica delle credenziali Ricerca nel catalogo dei libri con filtro per parole chiave Interfaccia responsive e user-friendly costruita con HTML e CSS Accesso semplificato tramite Docker Compose senza dover installare nulla manualmente Gestione completa dei dati tramite MySQL e visualizzazione via phpMyAdmin Codice ben documentato e commentato, in italiano, per facilitare l'apprendimento Estendibilità del sistema, con suggerimenti per introdurre nuove funzionalità (categorie, recensioni, prestiti) Uso di script SQL per la generazione automatica delle tabelle iniziali Navigazione semplice tra le pagine principali dell'applicazione
1.2

Obiettivi del tutorial php

Lo scopo di questo tutorial è fornirti una guida pratica, accessibile e step-by-step per comprendere i fondamenti dello sviluppo web con il linguaggio PHP. L’idea è accompagnarti in un percorso in cui non solo scrivi codice, ma lo comprendi davvero. Ogni sezione del progetto è costruita per mostrarti un concetto alla volta, così da permetterti di assimilare facilmente nuove conoscenze.   Cosa imparerai in questo tutorial php? Imparerai a: Installare e configurare un ambiente PHP moderno usando Docker Utilizzare Docker Compose per gestire più servizi contemporaneamente (web server, database, interfaccia amministrativa) Scrivere script PHP per l'autenticazione e la gestione dati con controlli di sicurezza base Interagire in modo sicuro con un database MySQL usando PDO o MySQLi Creare una semplice ma efficace interfaccia utente con HTML e CSS, arricchita da Javascript Strutturare il tuo progetto in modo modulare, mantenendo ordine e leggibilità nel codice Rispettare le best practice in termini di sicurezza, validazione input e gestione degli errori Prepararti per estendere e adattare il progetto a nuovi casi d’uso o complessità crescenti Utilizzare strumenti moderni per debug, test e analisi del codice (es. console di browser, log PHP)   Alla fine del percorso, avrai realizzato una web app completa, utile come base solida da cui partire per i tuoi progetti. Inoltre, avrai acquisito strumenti e mentalità utili per affrontare altri tutorial più avanzati o iniziare lo sviluppo di applicazioni reali per clienti o portfolio. Scopriamo insieme, nel prossimo capitolo, quali sono i requisiti di base per poter seguire questo tutorial php.
1.3

Requisiti tecnici e conoscenze di base

Per seguire questo tutorial php ti serviranno alcune competenze di base. Non è necessario essere esperti, ma è utile avere familiarità con: PHP: sintassi, variabili, condizioni, cicli, funzioni di base, include e require MySQL: creazione e gestione di tabelle, inserimento e lettura dati, chiavi primarie HTML/CSS: struttura di una pagina, gestione dei form, stilizzazione base, semantica HTML JavaScript: opzionale ma utile per migliorare l’interattività lato client, es. conferme o validazioni Docker: conoscenze minime (installazione, comandi base come docker-compose up e down) Editor di codice (es. Visual Studio Code): per scrivere e leggere il codice comodamente, con estensioni utili (PHP Intelephense, formatter, ecc.) Terminale/Console: per eseguire comandi nel progetto, avviare i container, monitorare output e debug   Se hai bisogno di rispolverare le basi di alcuni di questi linguaggi, la buona notizia è che puoi sempre consultare la nostra guida all’html e css,, guida php, guida javascript e guida SQL per rinfrescarti le idee. Non ti preoccupare se non conosci tutto in partenza: ogni parte verrà spiegata in maniera graduale, con esempi chiari, e sarai guidato passo dopo passo. L’obiettivo è farti sentire a tuo agio nel muovere i primi passi nel mondo dello sviluppo web con il linguaggio PHP, anche se parti da zero. Pronto a cominciare? 

2

Preparazione dell'ambiente di sviluppo con Docker

2.1

Che cos'è Docker e perché usarlo al posto di un server locale

Prima di iniziare a scrivere codice, è fondamentale configurare correttamente l’ambiente di sviluppo. Un ambiente ben strutturato ti permette di lavorare in modo più efficiente, riducendo errori dovuti a differenze tra il tuo computer e il server di produzione. In questa sezione vedremo cos'è Docker e perchè usarlo.   Che cos'è Docker? Docker è una piattaforma che consente di creare, distribuire ed eseguire applicazioni all’interno di contenitori (containers). Questi contenitori sono ambienti leggeri, autosufficienti, che contengono tutto ciò che serve per far funzionare un'app: codice, librerie, configurazioni. Nel nostro caso, useremo Docker per: Eseguire un server Apache con PHP per ospitare l'app Avviare un database MySQL pronto all'uso Avere accesso a phpMyAdmin per la gestione visiva del database Automatizzare la configurazione iniziale tramite docker-compose.yml   Questa struttura ti permette di iniziare subito a sviluppare, senza dover configurare manualmente i singoli componenti. Docker è ampiamente usato anche in ambito professionale, quindi imparare ad utilizzarlo fin da subito ti tornerà molto utile in futuro.   Perché usare Docker al posto di un server locale Tradizionalmente, per sviluppare in PHP era necessario installare un server locale come XAMPP, WAMP o MAMP, che includevano PHP, MySQL e Apache. Tuttavia, oggi si preferisce sempre di più un approccio moderno e portabile: per questo è preferibile utilizzare Docker. Docker consente di eseguire applicazioni all’interno di contenitori isolati, con tutti i servizi necessari preconfigurati. Questo approccio garantisce: Maggiore uniformità tra ambienti (locale, test, produzione) Facile condivisione del progetto con altri sviluppatori Zero conflitti tra versioni di PHP, MySQL e altri strumenti Avvio e reset del progetto con un solo comando Maggiore controllo e scalabilità dell’ambiente Completamente reversibile e riutilizzabile su più progetti   Utilizzando Docker, puoi evitare la classica confusione causata da installazioni manuali e incompatibilità tra librerie, semplificando la vita anche se sei alle prime armi. Vediamo insieme, nel prossimo capitolo, come installare e configurare Docker!
2.2

Come installare e configurare Docker

Per installare Docker sul tuo sistema, il modo più semplice e sicuro è seguire la guida ufficiale fornita direttamente da Docker. Una volta aperta la guida ufficiale, seleziona il tuo sistema operativo (Windows, macOS o una distribuzione Linux) per visualizzare le istruzioni dettagliate. La guida copre tutto, dall’installazione del software ai passaggi per verificarne il corretto funzionamento. Una volta completata l’installazione, potrai iniziare a usare Docker per creare, gestire ed eseguire i tuoi container in modo semplice ed efficiente.   Per verificare se Docker è installato sul tuo sistema, apri il terminale (o il prompt dei comandi su Windows) e digita il comando docker --version. Se Docker è installato correttamente, vedrai stampata la versione attualmente installata. In alternativa, puoi usare anche docker info per ottenere informazioni più dettagliate sullo stato del demone Docker. Se ricevi un errore o il comando non viene riconosciuto, significa che Docker non è installato o non è configurato correttamente. Curioso di scoprire come avviare il progetto? Continua nel capitolo successivo! 
2.3

Avvio rapido del progetto

Ora che hai installato Docker e compreso il suo funzionamento, è il momento di partire. Vediamo come avviare il progetto seguendo pochi semplici passi.  Scarica il progetto dal repository su Github Apri un terminale nella cartella del progetto dove si trova il file docker-compose.yml. Lancia il seguente comando: docker-compose up Dopo qualche secondo l'applicazione sarà disponibile all’indirizzo http://localhost:8080 phpMyAdmin sarà accessibile su http://localhost:8081 Utente: root Password: password   Per spegnere l'ambiente, puoi usare: docker-compose down Questo comando fermerà tutti i contenitori e libererà le risorse.  A questo punto, non ci resta che creare il nostro database.   Creazione del database per la biblioteca. Nel file db.sql incluso nel progetto trovi già uno script pronto all’uso per creare le tabelle necessarie. Quando Docker esegue il servizio MySQL, se configurato correttamente, carica automaticamente questo script iniziale, impostando la struttura del database fin dal primo avvio. Le tabelle fondamentali previste sono: utenti: per la gestione degli utenti registrati, con campi per username, password e privilegi libri: con i dati relativi ai libri disponibili nella biblioteca: titolo, autore, genere, anno, ecc.   Puoi espandere questo schema introducendo nuove tabelle come categorie, recensioni, prestiti o preferiti, per arricchire le funzionalità dell’applicazione. Inoltre, con phpMyAdmin puoi ispezionare i dati, fare query manuali, esportare backup e modificare i contenuti con un’interfaccia grafica molto intuitiva. Nel prossimo capitolo entreremo nel dettaglio della struttura dei file e del funzionamento dell’applicazione, partendo dalla pagina principale index.php.

3

Progetta il database della biblioteca

3.1

La struttura del database

Un'applicazione web dinamica come la nostra biblioteca online ha bisogno di un database ben progettato per poter funzionare correttamente. Il database è il cuore dell'app: memorizza utenti, libri e tutte le informazioni fondamentali per il funzionamento del sistema. Una struttura chiara e ben definita fin dall’inizio facilita lo sviluppo, evita errori in fase di implementazione e rende più semplice eventuali estensioni future del progetto. Analizziamo insieme la struttura del nostro database.   Tabella utenti. Questa tabella è dedicata alla gestione degli utenti registrati al sistema. Oltre a contenere le credenziali, potrebbe in futuro essere estesa per includere informazioni anagrafiche, preferenze o cronologia delle attività. I principali campi sono: id (INT, AUTO_INCREMENT, PRIMARY KEY): identificativo numerico unico per ogni utente username (VARCHAR): nome utente univoco scelto in fase di registrazione password (VARCHAR): stringa cifrata con algoritmo hash (es. bcrypt) ruolo (VARCHAR): definisce il tipo di utente, ad esempio 'admin' o 'utente' email (VARCHAR): campo aggiuntivo possibile, utile per contatti o reset password   Questa tabella rappresenta il primo livello di sicurezza e accesso alla piattaforma. È fondamentale proteggerla con tecniche come la cifratura sicura delle password e il controllo degli accessi.   Tabella libri. Si tratta della tabella centrale per l'applicazione: contiene tutti i dettagli dei libri che popolano la nostra biblioteca. Può essere usata sia per mostrare l’elenco completo, sia per ricerche avanzate tramite parole chiave o filtri. id (INT, AUTO_INCREMENT, PRIMARY KEY): ID numerico univoco del libro titolo (VARCHAR): titolo completo del libro autore (VARCHAR): nome dell'autore genere (VARCHAR): categoria letteraria anno (INT): anno di pubblicazione descrizione (TEXT): campo opzionale per approfondimenti, sinossi o note copertina_url (VARCHAR): campo aggiuntivo per immagine del libro (opzionale)   L'aggiunta di una descrizione estesa o dell'immagine può migliorare l'esperienza utente nel frontend, soprattutto in fase di visualizzazione o consultazione.  Il database fornito contiene le informazioni base per poter iniziare a gestire la tua biblioteca di libri: prova in autonomia ad aggiungere campi aggiuntivi così da fare esperienza con la modifica di tabelle del database!   Altre tabelle opzionali (idee per estensioni future). Anche se non sono implementate in questa versione del progetto, le tabelle a seguire sono utili se desideri metterti alla prova e sviluppare una versione più completa o professionale del sistema: categorie: contiene i generi o le macro-categorie dei libri, con possibilità di filtro prestiti: registra i prestiti effettuati dagli utenti, con date di inizio e scadenza recensioni: per memorizzare opinioni, valutazioni o commenti sui libri preferiti: permette agli utenti di salvare i libri preferiti per un accesso rapido Ogni tabella aggiuntiva introduce nuove funzionalità e richiede l’aggiunta di relazioni logiche che permettono di collegare i dati in modo coerente.
3.2

Le relazioni tra le tabelle

I database relazionali si basano su relazioni logiche che permettono di collegare tra loro tabelle diverse. Questo si realizza tramite chiavi esterne (foreign keys) che stabiliscono riferimenti tra le righe di due o più tabelle.   Per esempio:   Una relazione uno-a-molti (1:N) si verifica quando un utente può avere più prestiti. In questo caso la tabella prestiti avrà un campo utente_id che punta al campo id della tabella utenti. Una relazione molti-a-molti (N:N) esiste quando un libro può appartenere a più categorie e ogni categoria può contenere più libri. Per gestire questo si utilizza una tabella ponte come libro_categoria, che contiene le colonne libro_id e categoria_id.  Anche se il progetto di questo tutorial php non implementa direttamente queste relazioni, comprenderne l’utilità è essenziale per strutturare database scalabili, efficienti e facilmente interrogabili.   Queste relazioni, infatti, permettono di:   Evitare duplicazioni di dati (es. ripetizione di nomi di categorie) Costruire query più complesse e potenti Mantenere l'integrità dei dati nel tempo Nel prossimo capitolo vedremo un esempio concreto di script SQL per creare le tabelle fondamentali del nostro progetto, senza ancora entrare nel dettaglio delle relazioni avanzate.
3.3

Esempio di script SQL per creare le tabelle principali

Il file db.sql incluso nel progetto contiene lo script necessario per inizializzare il database. Questo script viene eseguito automaticamente all’avvio dell’ambiente Docker. Ecco un esempio concreto semplificato:   CREATE DATABASE IF NOT EXISTS biblioteca; USE biblioteca; CREATE TABLE IF NOT EXISTS utenti ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, password VARCHAR(255) NOT NULL, ruolo VARCHAR(20) DEFAULT 'utente' ); CREATE TABLE IF NOT EXISTS libri ( id INT AUTO_INCREMENT PRIMARY KEY, titolo VARCHAR(100) NOT NULL, autore VARCHAR(100) NOT NULL, genere VARCHAR(50), anno INT, descrizione TEXT ); INSERT INTO utenti (username, password, ruolo) VALUES ('admin', 'admin', 'admin'); Questo script sql: Crea il database biblioteca se non esiste già Definisce la struttura di base per le due tabelle essenziali Inserisce un utente predefinito per accedere subito all’applicazione   Lo script è facilmente estendibile: puoi aggiungere ulteriori tabelle, vincoli, indici e relazioni man mano che il tuo progetto cresce. È buona pratica documentare ogni modifica con commenti nel file SQL per mantenere tracciabilità e chiarezza. Nel prossimo capitolo inizieremo a esplorare la struttura dei file PHP e vedremo come questi interagiscono con il database per dare vita all'applicazione.

4

Configura il progetto PHP

4.1

La struttura del progetto PHP

Dopo aver progettato e creato il database, è fondamentale strutturare in modo ordinato i file PHP del nostro progetto. Una buona organizzazione del codice rende più semplice comprenderne il funzionamento, correggere eventuali errori e sviluppare nuove funzionalità in futuro. La struttura che abbiamo adottato in questo progetto è pensata per essere chiara e intuitiva, anche per chi si avvicina per la prima volta alla programmazione web. Ogni file ha una funzione precisa: alcuni gestiscono l'interfaccia utente, altri si occupano dell'autenticazione, altri ancora si connettono al database e visualizzano i dati. Inoltre, lo stile grafico è mantenuto separato dal codice applicativo, secondo le buone pratiche di sviluppo. Ecco la struttura base dei file e delle cartelle inclusi nel progetto:   / (root del progetto) ├── index.php // Pagina iniziale pubblica ├── login.php // Login degli utenti registrati ├── register.php // Registrazione nuovi utenti ├── dashboard.php // Area riservata visibile dopo il login ├── libri.php // Elenco dei libri presenti nel database ├── logout.php // Script di logout utente ├── auth.php // Verifica autenticazione per pagine protette ├── db.php // Connessione al database MySQL ├── db.sql // Script SQL con struttura e dati iniziali ├── README.md // Informazioni generali sul progetto ├── docker-compose.yml // Configurazione dell'ambiente Docker └── assets/ └── style.css // Foglio di stile CSS per l'interfaccia grafica Questa organizzazione segue una logica modulare e scalabile: Ogni funzionalità dell'applicazione ha un proprio file (ad esempio, login.php si occupa esclusivamente del login) La connessione al database è centralizzata in un unico file (db.php), così da poterla richiamare facilmente dove necessario La gestione della sessione utente è separata (auth.php), rendendo più semplice la protezione delle aree riservate Il file style.css, situato nella cartella assets/, permette di mantenere separati contenuto e presentazione   Organizzare i file in questo modo ti consente di avere il controllo su ogni parte del progetto. Se vuoi aggiungere nuove pagine o funzionalità, ad esempio un sistema di recensioni o una pagina per l'aggiunta di nuovi libri, ti basterà creare un nuovo file e integrarlo nel flusso esistente.
4.2

File di configurazione del database

Uno dei file più importanti del progetto è db.php, che si occupa di connettere l'applicazione al database MySQL. Senza questo collegamento, non potremmo salvare o leggere alcuna informazione, come le credenziali degli utenti o l'elenco dei libri presenti nella biblioteca. Ecco il contenuto del file db.php:   <?php $host = 'db'; $db = 'biblioteca'; $user = 'root'; $pass = 'password'; $charset = 'utf8mb4'; $dsn = "mysql:host=$host;dbname=$db;charset=$charset"; try { $pdo = new PDO($dsn, $user, $pass); } catch (\PDOException $e) { echo 'Errore di connessione: ' . $e->getMessage(); exit; } ?> Analizziamo insieme cosa fanno le singole righe: Vengono definite le variabili $host, $db, $user, $pass, e $charset per configurare l'accesso al database. Il nome host db corrisponde al nome del servizio MySQL definito nel file docker-compose.yml Viene costruita la stringa DSN (Data Source Name), che serve a PDO per sapere dove e come connettersi Il blocco try-catch tenta di stabilire la connessione e, in caso di errore, stampa un messaggio utile per il debugging Se la connessione riesce, viene creato l'oggetto $pdo, che useremo in tutto il progetto per eseguire query e operazioni sul database Usare PDO è una scelta vantaggiosa rispetto ad altre estensioni PHP più datate (come mysqli) perché offre una maggiore flessibilità e sicurezza, soprattutto grazie al supporto per le query preparate che prevengono attacchi di tipo SQL Injection.   Perché usare db.php in tutti i file? Usare il file db.php in tutti i file è un approccio modulare che ha diversi benefici: Centralizzazione: tutte le impostazioni di connessione sono in un solo file Semplicità di aggiornamento: se cambiano host, nome del database o credenziali, non devi modificare ogni singolo file PHP Codice più pulito: i file principali si concentrano sulla logica applicativa e non sulla connessione Riutilizzabilità: ti basterà includere db.php con un semplice: require 'db.php'; per avere accesso all'oggetto $pdo in qualsiasi pagina che richieda accesso al database. Questa tecnica è largamente utilizzata in progetti reali proprio per la sua efficacia e manutenibilità nel tempo. Ti invitiamo a esplorare e comprendere bene questo file, perché costituisce la base di ogni operazione dati della tua applicazione. Nel prossimo capitolo ci dedicheremo all'interfaccia utente: esploreremo come è costruita graficamente la nostra applicazione, partendo dai form HTML, analizzando il file style.css, e introducendo alcune buone pratiche di UI design per un frontend ordinato e accessibile.

5

Cura l’interfaccia utente (UI)

5.1

Styling di base con HTML e CSS

Fin dalle prime pagine, il progetto offre una grafica semplice ma efficace, costruita con linguaggio HTML semantico e uno stile CSS minimalista. Il foglio di stile del nostro progetto tutorial php si trova nel file assets/style.css, dove vengono definiti i colori, il layout di base, la tipografia e l'aspetto responsive. Ogni sezione dell'applicazione eredita queste regole, rendendo l'interfaccia omogenea e intuitiva anche per chi non ha una forte esperienza con il web design. (Ma, se vuoi approfondire, puoi consultare la nostra guida al web design per programmatori!)  L'obiettivo è offrire un'interfaccia pulita, leggibile e coerente su tutte le pagine. Tra le regole principali troviamo: Stile uniforme per i titoli (gli headings: h1, h2, h3) con colori e spaziatura consistenti Margini e padding ottimizzati per garantire una buona leggibilità su tutti i dispositivi Layout responsive che si adatta anche a schermi di piccole dimensioni Classi CSS per gestire contenitori, card, box di testo e form   Inoltre, alcune regole CSS sono pensate per migliorare la user experience con dettagli visivi come angoli arrotondati, ombre leggere, e spaziature che separano chiaramente le sezioni. Questo approccio "mobile-first" garantisce una buona esperienza utente fin dall'inizio, anche senza framework esterni. Il design di base creato è sufficiente per avviare il progetto, ma vale la pena precisare che esiste un mondo oltre questo stile semplice. Con l'integrazione di un framework come Bootstrap, possiamo arricchire l'interfaccia utente, rendendola più moderna e interattiva. Nel prossimo capitolo esploreremo come Bootstrap può semplificare l'aggiunta di componenti avanzati, migliorando l'esperienza visiva e la responsività dell'applicazione.
5.2

Introduzione al un framework CSS Bootstrap

Abbiamo visto come uno stile CSS personalizzato possa già offrire una buona base visiva per l’applicazione, ma per rendere l'interfaccia più moderna e facilitare l'aggiunta di componenti reattivi, è possibile integrare un framework CSS come Bootstrap. Attenzione: nel progetto fornito nel nostro tutorial php non è incluso Bootstrap: tutto lo stile è realizzato a mano tramite style.css per permetterti di apprendere meglio i concetti base del linguaggio CSS. Se desideri estendere il progetto e utilizzare Bootstrap, puoi farlo molto facilmente. Basta includere il link al CDN di Bootstrap nell'<head> dei tuoi file PHP:   <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> E da quel momento potrai usare classi pronte come container, row, col, btn, form-control ecc. per ottenere una UI più ricca, responsive e coerente. Bootstrap include anche una vasta gamma di componenti pre-stilizzati come navbar, alert, card, tab e badge, utili per progetti più articolati.   Esempio: un form con Bootstrap. <form class="container mt-4"> <div class="mb-3"> <label for="username" class="form-label">Username</label> <input type="text" class="form-control" id="username"> </div> <div class="mb-3"> <label for="password" class="form-label">Password</label> <input type="password" class="form-control" id="password"> </div> <button type="submit" class="btn btn-primary">Login</button> </form> Questo codice è un esempio di come grazie a Bootstrap possiamo produrre un'interfaccia moderna, mobile-friendly e coerente, senza dover scrivere stili personalizzati da zero. In pochi minuti potrai trasformare una pagina semplice in una vera interfaccia professionale. Se vuoi rimanere su uno stile essenziale, puoi continuare a usare style.css e aggiungere solo gli elementi di Bootstrap che ti servono. (PS. Se vuoi approfondire la conoscenza di Bootstrap, dai un'occhiata alla nostra guida Boostrap in italiano!)
5.3

Responsive: ottimizzazione per dispositivi mobili

Come sicuramente saprai, il responsive design è un approccio allo sviluppo web che ha l’obiettivo di garantire una corretta visualizzazione e usabilità dell’interfaccia su qualsiasi tipo di dispositivo, dal desktop al tablet fino allo smartphone. In pratica, un sito responsive adatta automaticamente il layout, le dimensioni del testo e la disposizione degli elementi in base alla dimensione dello schermo, migliorando l’esperienza dell’utente senza richiedere zoom o scroll orizzontale. Questo è particolarmente importante oggi, dato che una grande parte della navigazione avviene da dispositivi mobili. Il progetto per il nostro tutorial php include alcune regole CSS per adattare l'interfaccia anche ai dispositivi mobili. Queste regole sono visibili nella parte finale di style.css e si attivano tramite media queries come questa:   @media (max-width: 576px) { body { padding: 0.5em; } h1 { font-size: 1.5em; } .form-container, .card, .dashboard-links { margin-top: 1em; box-shadow: none; border-radius: 0; } .btn { width: 100%; } } Grazie a queste regole: I testi si adattano a schermi piccoli mantenendo leggibilità I pulsanti diventano più grandi e facilmente cliccabili Le card e i contenitori si riducono in modo ordinato per evitare scroll orizzontale   Questo rende l'interfaccia utilizzabile anche su smartphone e tablet, elemento essenziale oggi per qualunque applicazione web. Ricorda che puoi testare il comportamento responsive ridimensionando la finestra del browser o utilizzando gli strumenti per sviluppatori del browser stesso. Nel prossimo capitolo ci occuperemo del sistema di autenticazione: vedremo come sono gestiti la registrazione degli utenti, il login, e il logout, e come proteggere le pagine riservate.

6

Realizza il sistema di autenticazione

6.1

Registrazione degli utenti

La registrazione degli utenti è il primo passo per abilitare l'accesso protetto all'applicazione. Nel nostro progetto, questa funzionalità è gestita dal file register.php, che presenta un form all'utente e, una volta inviati i dati, li valida e li salva nel database.   Form di registrazione utente. Il form HTML è semplice e chiaro, progettato per raccogliere username e password. Ecco un esempio di struttura che troverai nel file:   <h1>Registrazione</h1> <form method="post"> <label for="username">Username:</label> <input type="text" id="username" name="username" required><br> <label for="password">Password:</label> <input type="password" id="password" name="password" required><br> <button type="submit">Registrati</button> </form> Il form utilizza l'attributo required per garantire che i campi non vengano lasciati vuoti, migliorando l'esperienza utente e riducendo gli errori di inserimento.   Validazione dei dati (PHP + lato client con JS). Una volta inviato il form, il file register.php utilizza il linguaggio PHP per validare i dati sul server. Viene controllato: Che i campi non siano vuoti (ulteriore verifica rispetto a quella del browser) Che l'username non sia già presente nel database Che la password venga convertita in hash prima del salvataggio   Esempio di controllo e inserimento nel file register.php:   if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST["username"]; $password = password_hash($_POST["password"], PASSWORD_DEFAULT); require 'db.php'; $stmt = $pdo->prepare("SELECT * FROM utenti WHERE username = ?"); $stmt->execute([$username]); if ($stmt->rowCount() > 0) { echo "Username già registrato."; } else { $stmt = $pdo->prepare("INSERT INTO utenti (username, password) VALUES (?, ?)"); $stmt->execute([$username, $password]); echo "Registrazione completata con successo."; } } Questa logica protegge il sistema da duplicazioni di username e garantisce la sicurezza delle credenziali grazie all'uso della funzione password_hash, che cripta la password prima di salvarla nel database. Sul lato client (vale a dire considerando ciò che avviene sul dispositivo dell'utente, ovvero nel browser), il form HTML può essere arricchito con l’utilizzo del linguaggio JavaScript per fornire feedback in tempo reale, ad esempio per mostrare se le password rispettano determinati criteri (lunghezza minima, presenza di numeri o simboli). Tuttavia, nel progetto fornito nel nostro tutorial php, tale validazione lato client non è presente: può essere aggiunta in seguito come miglioramento, per permetterti di metterti alla prova in autonomia.   Salvataggio dell’utente nel database. Una volta superati tutti i controlli, i dati dell'utente vengono salvati nella tabella utenti del database biblioteca. Questa tabella è stata definita nel file db.sql e include i campi id, username, password e ruolo. Per default, ogni nuovo utente ha ruolo "utente", ma è possibile estendere questa logica per distinguere anche utenti amministratori. Grazie a questa struttura, il sistema di registrazione è sicuro, funzionante e pronto per essere utilizzato da qualsiasi visitatore dell'applicazione.
6.2

Login degli utenti

Una volta registrati, gli utenti devono poter accedere all'area riservata dell'applicazione. Questo avviene tramite il file login.php, che gestisce il form di login, la verifica delle credenziali e la creazione della sessione PHP.   Creazione del form di login. Il form di login è molto simile a quello di registrazione, ma con uno scopo diverso: confrontare i dati inseriti con quelli presenti nel database.   <h1>Login</h1> <form method="post"> <label for="username">Username:</label> <input type="text" id="username" name="username" required><br> <label for="password">Password:</label> <input type="password" id="password" name="password" required><br> <button type="submit">Accedi</button> </form> Validazione delle credenziali. Nel file login.php, dopo l'invio del form, i dati vengono verificati rispetto a quelli salvati nel database. In particolare, viene controllato se l'username esiste e se la password corrisponde tramite password_verify.   if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST["username"]; $password = $_POST["password"]; require 'db.php'; $stmt = $pdo->prepare("SELECT * FROM utenti WHERE username = ?"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { session_start(); $_SESSION['user'] = $user['username']; $_SESSION['ruolo'] = $user['ruolo']; header("Location: dashboard.php"); exit; } else { echo "Credenziali non valide."; } } Creazione di una sessione PHP. Quando le credenziali sono corrette, viene creata una sessione PHP tramite session_start(). Le informazioni dell'utente (es. username e ruolo) vengono salvate in variabili di sessione, utili per controllare l'accesso alle altre pagine del sito. Grazie a questo meccanismo, possiamo: Verificare se un utente ha effettuato l'accesso Personalizzare l'interfaccia in base al ruolo Proteggere aree riservate come dashboard.php o libri.php
6.3

Logout degli utenti

Il logout è una parte fondamentale di ogni sistema di autenticazione: consente all’utente di uscire dalla sessione in modo sicuro e impedisce accessi non autorizzati alle pagine riservate dopo il logout. Nel nostro progetto, questa funzionalità è gestita nel file logout.php. Il codice è molto semplice, ma efficace:   <?php session_start(); session_destroy(); header("Location: index.php"); exit; ?> Analizziamo insieme il codice. Distruzione della sessione. La funzione session_destroy() elimina tutte le variabili di sessione memorizzate, assicurando che l’utente venga disconnesso completamente dal sistema. Prima di distruggere la sessione, è necessario avviarla con session_start(). Questa operazione invalida tutte le informazioni dell’utente precedentemente salvate, come $_SESSION['user'] o $_SESSION['ruolo'], impedendo l’accesso alle sezioni protette senza nuova autenticazione.   Reindirizzamento dell’utente. Dopo aver distrutto la sessione, l’utente viene automaticamente reindirizzato alla home page (index.php) grazie al comando header("Location: index.php");. In questo modo, si garantisce un flusso di navigazione coerente e si evita che l’utente resti su una pagina riservata dopo il logout. Questo script può essere collegato a un link o pulsante visibile nella dashboard o in un menu di navigazione, ad esempio:   <a href="logout.php">Logout</a> Nel prossimo paragrafo vedremo come proteggere le pagine riservate utilizzando il file auth.php, che verifica la presenza della sessione prima di permettere l’accesso.

7

Gestione della biblioteca

7.1

Aggiunta di libri nella biblioteca

Una delle funzionalità centrali del progetto di creazione di una biblioteca online è, ovviamente, la possibilità di inserire nuovi libri all'interno del catalogo digitale. Questo passaggio rappresenta l'inizio del ciclo di vita dei dati all'interno dell'applicazione e costituisce la prima lettera della sigla CRUD: Create. L'operazione è gestita direttamente nella pagina libri.php, dove si trova un form HTML pensato per facilitare l'inserimento manuale da parte dell'utente.   Questa sezione è particolarmente utile non solo per gli amministratori del sistema, ma anche come esercizio per comprendere a fondo il meccanismo che collega un'interfaccia utente a un database relazionale. L'inserimento di nuovi record permette di popolare il sistema e verificarne la reattività.   Form per inserire nuovi libri. Il form si trova nella parte iniziale della pagina e raccoglie tutti i campi essenziali per descrivere un libro: titolo, autore, genere, anno di pubblicazione e descrizione. Ogni campo è accompagnato da un'etichetta e da un input specifico, pensato per rendere l'esperienza di compilazione il più fluida possibile. La struttura è semplice, intuitiva e si adatta a diverse risoluzioni di schermo, mantenendo la compatibilità con dispositivi mobili.   <form method="post"> <input type="text" name="titolo" placeholder="Titolo" required> <input type="text" name="autore" placeholder="Autore" required> <input type="number" name="anno" placeholder="Anno"> <button type="submit" name="submit">Aggiungi libro</button> </form> I campi titolo e autore sono contrassegnati con l'attributo required, che attiva una prima forma di validazione lato client, impedendo l'invio del form se non vengono compilati. Questo riduce il carico sul server e migliora la user experience.   Ogni campo ha un significato preciso: titolo: il nome del libro, fondamentale per l'identificazione e la ricerca. autore: la persona che ha scritto il libro. anno: l'anno di pubblicazione, utile per ordinare o filtrare.   Questa struttura è facilmente estendibile: in futuro potrai aggiungere campi per l'ISBN, la casa editrice, la disponibilità o la posizione in scaffale, senza dover modificare radicalmente il codice.   Validazione e salvataggio nel database. Una volta inviato il form, i dati vengono elaborati nella stessa pagina libri.php attraverso un controllo PHP. All'inizio del file, il codice intercetta la richiesta e procede con la memorizzazione nel database:   if (isset($_POST['submit'])) { $titolo = $_POST['titolo']; $autore = $_POST['autore']; $genere = $_POST['genere']; $anno = $_POST['anno']; $descrizione = $_POST['descrizione']; $stmt = $pdo->prepare("INSERT INTO libri (titolo, autore, genere, anno, descrizione) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$titolo, $autore, $genere, $anno, $descrizione]); echo "<p>Libro aggiunto con successo.</p>"; } Il controllo isset($_POST['submit']) assicura che il codice venga eseguito solo in seguito all'invio del form, evitando elaborazioni indesiderate all'apertura della pagina. I dati vengono raccolti tramite la superglobale $_POST e poi inseriti nel database usando una query preparata con PDO.   L'utilizzo di prepare() con execute() garantisce sicurezza contro le SQL Injection, poiché i dati inseriti dall'utente non vengono concatenati direttamente alla query SQL, ma gestiti come parametri isolati. Questo è un punto fondamentale di buona pratica in ogni applicazione web che interagisce con un database.   Il messaggio "Libro aggiunto con successo" viene poi mostrato a schermo per confermare l'avvenuta operazione, migliorando la comunicazione con l'utente.   Questo tipo di logica è estremamente importante da apprendere, poiché rappresenta la base per molte delle interazioni tra linguaggio PHP e MySQL. E da qui in avanti, è possibile estendere il sistema con altre funzionalità più complesse: controlli più avanzati sul formato dei dati (es. anno solo numerico, campo descrizione con limite di lunghezza), gestione di errori con messaggi specifici, inserimento di contenuti multilingua o validazione lato server tramite espressioni regolari.   Con questa prima operazione CRUD, la biblioteca digitale inizia a prendere vita. Ogni libro inserito viene memorizzato in modo persistente e può essere richiamato, aggiornato o cancellato in qualsiasi momento.
7.2

Visualizzazione dei libri della biblioteca

Dopo aver popolato il database è fondamentale offrire un'interfaccia che permetta di consultare facilmente i libri inseriti. Vediamo come realizzare questa parte nel nostro progetto.   Tabella con elenco libri. In libri.php, subito dopo il form di inserimento, viene generata dinamicamente una tabella HTML che visualizza l'elenco dei libri, ordinati dal più recente al meno recente.   $stmt = $pdo->query("SELECT * FROM libri ORDER BY id DESC"); La query recupera tutti i dati e li passa a un ciclo foreach, che costruisce la tabella:   echo "<table border='1'>"; echo "<tr><th>Titolo</th><th>Autore</th><th>Genere</th><th>Anno</th><th>Descrizione</th><th>Azioni</th></tr>"; foreach ($stmt as $libro) { echo "<tr>"; echo "<td>" . htmlspecialchars($libro['titolo']) . "</td>"; echo "<td>" . htmlspecialchars($libro['autore']) . "</td>"; echo "<td>" . htmlspecialchars($libro['genere']) . "</td>"; echo "<td>" . htmlspecialchars($libro['anno']) . "</td>"; echo "<td>" . htmlspecialchars($libro['descrizione']) . "</td>"; echo "<td><a href='libri.php?modifica={$libro['id']}'>Modifica</a> | <a href='libri.php?elimina={$libro['id']}'>Elimina</a></td>"; echo "</tr>"; } echo "</table>"; L'uso di htmlspecialchars() è una buona pratica per evitare l'inserimento di script potenzialmente dannosi, proteggendo l'applicazione da attacchi XSS. Inoltre, l'inserimento diretto dei link di modifica ed eliminazione consente di gestire le successive operazioni Update e Delete con un semplice clic. Questa tabella diventa il cuore operativo della gestione della biblioteca, consentendo di controllare in tempo reale tutti i dati presenti e offrendo una panoramica strutturata dei contenuti.   Pagination. Nel progetto base, la visualizzazione mostra tutti i risultati in un'unica tabella. Questo va bene per un numero limitato di elementi, ma in caso di database più ampi diventa poco efficiente. L'aggiunta della pagination rappresenta, quindi, un'evoluzione naturale per ottimizzare l'interfaccia e migliorare l'esperienza utente. Una possibile implementazione consiste nel mostrare un numero fisso di libri per pagina (ad esempio 10), utilizzando i parametri LIMIT e OFFSET all'interno della query SQL:   $limit = 10; $page = isset($_GET['page']) ? (int)$_GET['page'] : 1; $offset = ($page - 1) * $limit; $stmt = $pdo->prepare("SELECT * FROM libri ORDER BY id DESC LIMIT :limit OFFSET :offset"); $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, PDO::PARAM_INT); $stmt->execute(); A questa logica si può abbinare un sistema di navigazione che consenta all'utente di muoversi tra le varie pagine, generando link del tipo:   <a href="libri.php?page=1">1</a> <a href="libri.php?page=2">2</a> Questo meccanismo migliora notevolmente la scalabilità dell'applicazione e ne prepara la struttura a gestire collezioni sempre più grandi. Introdurre la paginazione può sembrare un dettaglio, ma in realtà rappresenta un importante passo verso una gestione dei dati più efficiente, modulare e professionale, soprattutto in vista di sviluppi futuri o di una messa online dell'applicativo.
7.3

Modifica ed eliminazione dei libri della biblioteca

Nel nostro progetto della biblioteca, la gestione dei libri non si limita alla semplice visualizzazione: sono già presenti e pienamente funzionanti le funzionalità per modificare ed eliminare ogni titolo direttamente dalla tabella di riepilogo. All'interno del file libri.php, ogni riga dell'elenco include due link: uno per modificare e uno per eliminare. Queste operazioni completano il ciclo CRUD, permettendo agli utenti di aggiornare o cancellare in modo dinamico le informazioni archiviate nel database. Approfondiamo entrambe le funzionalità.   Eliminazione dei libri. L'eliminazione di un titolo specifico avviene tramite un link che invia una richiesta GET contenente l'ID del libro da cancellare. Il codice incluso in libri.php intercetta questa richiesta e la gestisce nel seguente modo:   if (isset($_GET['elimina'])) { $id = $_GET['elimina']; $stmt = $pdo->prepare("DELETE FROM libri WHERE id = ?"); $stmt->execute([$id]); echo "<p>Libro eliminato con successo.</p>"; } Questo frammento di codice verifica innanzitutto la presenza del parametro elimina nella stringa dell'URL, il che indica l'intenzione dell'utente di cancellare un libro specifico. Se tale parametro è presente, il codice estrae l'ID del libro e costruisce una query SQL che utilizza un segnaposto (?) per evitare che il valore venga concatenato direttamente nella stringa della query. In questo modo, l'interazione con il database avviene in totale sicurezza grazie all'uso della funzione prepare, che consente di prevenire vulnerabilità comuni come le SQL Injection. Una volta eseguita la query attraverso il metodo execute, il database elimina in modo permanente il record associato all'ID passato. L'operazione si conclude con un messaggio a video che informa l'utente del buon esito della cancellazione. Questo tipo di feedback è importante per migliorare la user experience e mantenere l'utente consapevole delle modifiche effettuate. Vale la pena notare che questa logica può essere facilmente estesa in futuro per includere conferme JavaScript prima della cancellazione, messaggi di avviso stilizzati con Bootstrap o addirittura una funzione di "eliminazione soft" che nasconde il libro senza rimuoverlo dal database. Il collegamento corrispondente nel ciclo foreach è simile a:   <a href="libri.php?elimina=<?= $libro['id'] ?>">Elimina</a>   Modifica dei libri. Anche la funzione di modifica è implementata nello stesso file, seguendo un approccio condizionale. Se nell'URL è presente il parametro modifica, il libro con quell'ID viene caricato e i suoi dati mostrati all'interno di un form HTML per la modifica:   if (isset($_GET['modifica'])) { $id = $_GET['modifica']; $stmt = $pdo->prepare("SELECT * FROM libri WHERE id = ?"); $stmt->execute([$id]); $libroModifica = $stmt->fetch(); } Il form è precompilato con i dati correnti del libro grazie all'utilizzo del valore value="<?= htmlspecialchars($libroModifica['campo']) ?>" per ciascun input. Questo metodo consente non solo di mostrare all'utente i dati attuali in modo chiaro, ma anche di facilitarne l'eventuale modifica senza il rischio di dover riscrivere tutto da capo. È una tecnica che migliora l'usabilità, soprattutto quando il numero di campi è elevato. L'impiego della funzione htmlspecialchars è particolarmente importante in ottica di sicurezza: evita l'esecuzione involontaria di codice HTML o JavaScript potenzialmente malevolo, proteggendo l'applicazione da attacchi di tipo XSS (Cross-Site Scripting). Inoltre, grazie a questa tecnica, il form di modifica diventa adattabile a qualsiasi dato proveniente dal database. In contesti più complessi, questa strategia può essere estesa con l'uso di funzioni PHP che generano dinamicamente l'intero set di input, rendendo il modulo scalabile e più semplice da mantenere nel tempo. Una volta modificati, i dati vengono inviati con POST, e il codice PHP li aggiorna nel database:   if (isset($_POST['update'])) { $stmt = $pdo->prepare("UPDATE libri SET titolo = ?, autore = ?, genere = ?, anno = ?, descrizione = ? WHERE id = ?"); $stmt->execute([ $_POST['titolo'], $_POST['autore'], $_POST['genere'], $_POST['anno'], $_POST['descrizione'], $_POST['id'] ]); echo "<p>Libro modificato con successo.</p>"; } L'interfaccia include anche un campo hidden con l'ID del libro da modificare. Questo campo, invisibile all'utente ma fondamentale per il funzionamento dell'applicazione, permette di mantenere il riferimento preciso all'elemento selezionato nel database. In questo modo, il sistema è in grado di distinguere esattamente quale record aggiornare anche quando vengono gestiti più elementi contemporaneamente. L'utilizzo di un campo hidden è una tecnica comune nei form dinamici e contribuisce a rendere più affidabile la logica di aggiornamento.   Completa il paradigma CRUD con modifica ed eliminazione dei libri della biblioteca. Con le funzionalità di modifica ed eliminazione, il progetto implementa in maniera completa le operazioni tipiche del paradigma CRUD:   Create: tramite il form iniziale di inserimento, che consente di aggiungere nuovi libri nel database Read: attraverso la tabella HTML generata dinamicamente, che mostra tutti i libri salvati Update: modificando i dati esistenti tramite il form precompilato Delete: rimuovendo record specifici mediante il link di eliminazione.   Questa struttura non solo è utile per una biblioteca, ma rappresenta uno standard universale per la gestione di qualsiasi insieme di dati persistenti. Le stesse tecniche, infatti, possono essere facilmente riutilizzate in applicazioni aziendali o commerciali, ad esempio per il tracciamento di ordini, la gestione di clienti e fornitori, l'organizzazione di eventi, o la pubblicazione di articoli su una piattaforma di contenuti. Apprendere questi meccanismi significa acquisire un linguaggio comune a molti settori dello sviluppo web: che si tratti di ecommerce, CRM, sistemi di prenotazione o CMS, la logica CRUD costituisce la spina dorsale di gran parte delle applicazioni moderne. Una comprensione approfondita di queste dinamiche è quindi fondamentale per strutturare soluzioni scalabili, manutenibili e coerenti con le best practice dello sviluppo back-end.

8

Crea il motore di ricerca

8.1

Il form di ricerca della biblioteca

Per permettere agli utenti di trovare rapidamente i libri presenti nella biblioteca, il progetto include un semplice ma efficace motore di ricerca. Questa funzionalità è essenziale per migliorare la fruibilità del sistema, ed è pensata per consententire di filtrare i contenuti in base a criteri specifici. Il form di ricerca è incluso nella pagina dashboard.php e, una volta compilato, invia i dati al file libri.php tramite una richiesta GET. Questo tipo di comunicazione è particolarmente utile quando si desidera che l'URL rifletta i parametri della ricerca, rendendo così anche i risultati condivisibili o salvabili nei preferiti del browser. Ecco un esempio del form:   <h2>Cerca un libro</h2> <form method="get" action="libri.php"> <input type="text" name="query" placeholder="Cerca per titolo, autore o genere"> <button type="submit">Cerca</button> </form> L'elemento input consente all'utente di digitare liberamente un termine, che può corrispondere a parte del titolo, del nome dell'autore o della categoria (genere) del libro. Questa flessibilità nel campo di ricerca permette una maggiore tolleranza agli errori di digitazione e alle imprecisioni. L'interazione risulta così semplice e accessibile, indipendentemente dal dispositivo utilizzato, sia esso un desktop, un tablet o uno smartphone. Inoltre, il form è progettato per integrarsi bene nell'interfaccia della dashboard, mantenendo una coerenza grafica e funzionale con il resto dell'applicazione. Il pulsante di invio attiva una richiesta GET che incorpora il parametro query all'interno dell'URL, rendendo il sistema trasparente nel funzionamento e facilmente condivisibile. Questo è particolarmente utile in un contesto multiutente o in scenari in cui si desidera salvare la ricerca eseguita per consultazioni future. Una volta inviato, il valore del campo viene intercettato dal file libri.php, che si occupa di elaborarlo ed eseguire una query personalizzata sul database. L'intero processo avviene in pochi istanti, restituendo all'utente una lista filtrata di risultati rilevanti.   Ricerca per titolo, autore o categoria.  Nel file libri.php, il codice PHP si occupa di rilevare la presenza del parametro query nell'array $_GET e costruisce una query SQL dinamica, che include una condizione di ricerca su più colonne contemporaneamente. In questo modo, è possibile ottenere risultati anche nel caso in cui l'utente non conosca esattamente dove si trovi la parola ricercata (titolo, autore o genere), aumentando la flessibilità del sistema.   if (isset($_GET['query'])) { $query = '%' . $_GET['query'] . '%'; $stmt = $pdo->prepare("SELECT * FROM libri WHERE titolo LIKE ? OR autore LIKE ? OR genere LIKE ?"); $stmt->execute([$query, $query, $query]); } else { $stmt = $pdo->query("SELECT * FROM libri"); } La concatenazione del simbolo % prima e dopo la stringa consente di cercare corrispondenze parziali in qualsiasi punto del campo, rendendo la ricerca molto più flessibile e tollerante. Questo significa che non è necessario conoscere l'esatto inizio o fine del testo cercato: anche un frammento all'interno del titolo, del nome dell'autore o del genere sarà sufficiente a produrre risultati. Ad esempio, cercando "Dost", si potranno ottenere risultati come "Fedor Dostoevskij" oppure "I fratelli Karamazov di Dostoevskij". Questa tecnica è particolarmente utile nel contesto di una biblioteca, dove gli utenti possono avere ricordi frammentari o approssimativi di un'opera. Non sempre si ha a disposizione il titolo completo o l'autore preciso, quindi un sistema di ricerca basato su corrispondenze parziali rappresenta un enorme vantaggio in termini di accessibilità e funzionalità. Inoltre, l'approccio con LIKE e % è facilmente estendibile: è possibile aggiungere ulteriori campi di ricerca, come l'anno di pubblicazione o la descrizione, rendendo il motore ancora più ricco e articolato. L'interrogazione finale restituisce, quindi, un elenco aggiornato di risultati coerenti, filtrati secondo criteri versatili e ben adattati all'esperienza reale dell'utente.
8.2

Filtrare i risultati: query con LIKE

La clausola LIKE è una delle funzionalità più versatili e potenti messe a disposizione dal linguaggio SQL quando si tratta di implementare un motore di ricerca semplice ma efficace. Il suo funzionamento si basa sull'utilizzo di caratteri jolly, in particolare %, che permette di cercare corrispondenze parziali all'interno di un campo di testo. A differenza dell'operatore =, che richiede una corrispondenza esatta tra la stringa inserita e il valore presente nel database, LIKE consente di individuare risultati che contengono anche solo una parte del termine cercato. Questa differenza è essenziale quando si lavora con dati aperti al contributo o alla consultazione da parte di utenti finali, i quali spesso inseriscono parole incomplete, nomi parziali o termini comuni. Il carattere % può essere inserito all'inizio, alla fine o su entrambi i lati del termine di ricerca, permettendo così di controllare se un valore "inizia con", "finisce con" o "contiene" la stringa specificata.   Esempio concreto di utilizzo. Proviamo a fare un esempio concreto: se un utente digita "Pirandello", il sistema restituirà anche record come "Luigi Pirandello", oppure "Pirandello Luigi" se i campi sono invertiti. Ma non solo: digitando una parte ancora più breve, come "rand", si potranno intercettare anche variazioni o errori di battitura, riducendo notevolmente il rischio di ricerche a vuoto. Questa flessibilità rende l'applicazione più intelligente e reattiva nei confronti dell'utente, migliorando la qualità complessiva dell'interazione. Inoltre, l'approccio con LIKE si integra perfettamente con le query preparate in PHP, mantenendo un elevato livello di sicurezza contro possibili iniezioni SQL. Questo equilibrio tra usabilità e protezione è uno dei punti di forza dell'implementazione, e può essere riutilizzato anche in altri moduli dell'applicazione, come ad esempio la ricerca tra utenti, recensioni o categorie di contenuti.
8.3

Visualizzazione dei risultati

Una volta eseguita la ricerca, i risultati vengono mostrati a schermo sotto forma di tabella HTML. Questa rappresentazione tabellare è pensata per garantire chiarezza visiva, permettendo di confrontare velocemente più libri grazie alla suddivisione per colonne. Le intestazioni includono titolo, autore, genere, anno e descrizione, replicando il formato dell'elenco completo dei libri per coerenza e facilità di lettura. L'interfaccia testuale viene generata dinamicamente tramite PHP, e ogni riga della tabella corrisponde a un libro diverso estratto dal database. Questo tipo di presentazione è particolarmente efficace quando si ha a che fare con dataset strutturati, come nel caso di un archivio bibliografico. Può inoltre essere arricchita con colonne aggiuntive (ad esempio editore, ISBN o disponibilità) o trasformata in una griglia più complessa con l'ausilio di framework CSS come Bootstrap.   echo "<table border='1'>"; echo "<tr><th>Titolo</th><th>Autore</th><th>Genere</th><th>Anno</th><th>Descrizione</th></tr>"; foreach ($stmt as $libro) { echo "<tr>"; echo "<td>{$libro['titolo']}</td>"; echo "<td>{$libro['autore']}</td>"; echo "<td>{$libro['genere']}</td>"; echo "<td>{$libro['anno']}</td>"; echo "<td>{$libro['descrizione']}</td>"; echo "</tr>"; } echo "</table>"; Il ciclo foreach rappresenta uno dei costrutti più versatili nel linguaggio PHP per la manipolazione di array. In questo caso, consente di scorrere in modo efficiente l'intera lista di risultati ottenuti dalla query SQL e di stampare, per ciascun record, una nuova riga nella tabella. L'approccio garantisce scalabilità: anche con un numero elevato di risultati, la logica del codice rimane semplice e pulita. Inoltre, è possibile introdurre condizioni all'interno del ciclo per variare la presentazione in base al contenuto (ad esempio evidenziare libri recenti o con descrizioni particolarmente lunghe).   Messaggi in caso di risultati vuoti. Nel caso in cui nessun libro corrisponda alla ricerca, è fondamentale fornire un messaggio chiaro all'utente. Questo aiuta a evitare fraintendimenti o l'impressione che il sistema non funzioni. Il messaggio può essere semplice e diretto, come questo:   if ($stmt->rowCount() == 0) { echo "<p>Nessun risultato trovato per la tua ricerca.</p>"; } Tuttavia, per migliorare ulteriormente l'esperienza utente, si possono prevedere messaggi personalizzati che suggeriscano alternative: proporre una nuova ricerca, mostrare i libri più recenti, oppure fornire collegamenti rapidi ad altre sezioni della biblioteca. Con queste attenzioni, anche un esito "vuoto" può trasformarsi in un momento informativo e costruttivo per l'utente.

9

Sicurezza

9.1

Protezione contro SQL Injection

Una delle vulnerabilità più diffuse in ambito PHP è l’SQL Injection, cioè la possibilità per un utente di manipolare una query SQL inserendo comandi malevoli all’interno dei campi di input. Questo tipo di attacco può causare danni considerevoli: dalla lettura non autorizzata di dati sensibili fino alla loro cancellazione o modifica. Per difendersi da questi scenari, il progetto utilizza query preparate con PDO, che separano in modo netto il codice SQL dai dati forniti dall’utente. Esempio:   $stmt = $pdo->prepare("SELECT * FROM utenti WHERE username = ?"); $stmt->execute([$username]); In questo codice, il punto interrogativo (?) rappresenta un segnaposto, noto anche come placeholder. Quando la query viene eseguita tramite il metodo execute(), il valore fornito viene associato in modo sicuro al segnaposto, senza essere interpretato come parte della struttura SQL. In altre parole, il motore di database distingue in modo chiaro tra comandi e dati, impedendo che input potenzialmente dannoso venga eseguito come codice SQL.   Separare dati e logica: la chiave per prevenire le SQL Injection. Questa separazione tra logica e contenuto è un principio fondamentale della programmazione web sicura: consente di difendersi efficacemente da tentativi di SQL Injection, anche in scenari complessi in cui l'utente inserisce caratteri speciali o stringhe strutturate con l'obiettivo di manipolare la logica della query. Nel progetto, questa strategia è applicata in maniera sistematica in tutte le sezioni che interagiscono con il database. Nei file register.php e login.php, ad esempio, viene utilizzata per controllare e verificare le credenziali utente; in libri.php è impiegata sia per l'inserimento di nuovi record che per l'aggiornamento e la cancellazione. Questo approccio uniforme non solo rende il codice più sicuro, ma migliora anche la manutenibilità e la leggibilità complessiva dell'applicazione. L'utilizzo di prepare e execute è da considerarsi oggi uno standard professionale, imprescindibile per qualsiasi progetto web che preveda interazioni SQL dinamiche. Inoltre, grazie a PDO, il codice può essere facilmente migrato verso altri tipi di database (PostgreSQL, SQLite, ecc.) senza modificare la logica applicativa. Oltre a PDO, anche l'estensione MySQLi offre il supporto per le query preparate. Tuttavia, PDO è stato scelto in questo progetto per la sua flessibilità, portabilità e per la maggiore semplicità nella gestione delle eccezioni e degli errori, soprattutto in applicazioni multipiattaforma o predisposte per una futura evoluzione.
9.2

Hash delle password

In qualsiasi progetto, la protezione solida delle credenziali degli utenti è una priorità assoluta. Il nostro progetto affronta questa esigenza implementando l’hash delle password. Questo significa che le password non vengono mai salvate in chiaro nel database: al momento della registrazione, la password viene trasformata in una stringa crittografata grazie alla funzione password_hash().   $password = password_hash($_POST['password'], PASSWORD_DEFAULT); L’hash è unidirezionale: una volta generato, non può essere decifrato o convertito nella password originale, ma solo confrontato con un altro hash per verificarne la corrispondenza. Questa caratteristica rende l’hash ideale per la protezione delle password, perché anche se un database venisse compromesso, le credenziali non risulterebbero leggibili o utilizzabili.   Come funziona? Nel flusso di autenticazione, il sistema non confronta le password in chiaro, bensì controlla che l’hash della password inserita coincida con quello memorizzato. Questo confronto avviene grazie alla funzione password_verify(), che incapsula le migliori pratiche crittografiche disponibili e gestisce anche eventuali differenze dovute all'evoluzione degli algoritmi di hashing. Inoltre, questa funzione è in grado di riconoscere automaticamente il tipo di algoritmo utilizzato (grazie al prefisso incorporato nell'hash stesso), rendendo il codice più flessibile e a prova di futuro. Utilizzare password_verify() in questo modo significa aderire agli standard più moderni e sicuri per la gestione delle credenziali, evitando metodi obsoleti come md5() o sha1(), che sono stati resi inefficaci dagli sviluppi delle tecniche di attacco. È importante sottolineare che questo meccanismo, pur semplice da implementare, costituisce una delle principali difese contro la compromissione degli account utente.   if ($user && password_verify($password, $user['password'])) { // login riuscito } Questo approccio è oggi uno standard di sicurezza. Funzioni come md5() o sha1() non sono più considerate sicure per questo scopo, perché vulnerabili agli attacchi con dizionario o rainbow table. PASSWORD_DEFAULT invece garantisce l’uso automatico dell’algoritmo migliore disponibile. È possibile, in progetti avanzati, combinare questa strategia con salting manuale, controllo di forza della password, e rehashing periodico.

10

Testa il tuo progetto PHP

Coming soon...

Sei indeciso sul percorso? 💭

Parliamone! Scrivici su Whatsapp e risponderemo a tutte le tue domande per capire quale dei nostri corsi è il più adatto alle tue esigenze.

Oppure chiamaci al 800 128 626