4) Sauvegarder les données
Sauvegarder les données avec SQLite

Objectifs de la séance
- Comprendre pourquoi les variables PHP disparaissent à chaque requête et comment y remédier.
- Créer et interroger une base de données SQLite depuis PHP avec PDO.
- Écrire les cinq opérations fondamentales en SQL : créer une table, insérer, lire, modifier, supprimer.
- Protéger ses requêtes contre les injections SQL avec les requêtes préparées.
- Encapsuler toute la logique d'accès aux données dans une classe
Databasedédiée. - Vérifier la persistance des données entre deux rechargements de page.
Notions théoriques
Le problème de la mémoire courte de PHP
PHP fonctionne à la requête. Quand un navigateur demande une page, PHP démarre, exécute le code, envoie le HTML, puis s'arrête. Toutes les variables créées pendant l'exécution sont détruites. À la prochaine requête, PHP repart de zéro.
C'est pour cette raison que si l'on crée un personnage dans index.php et qu'on recharge la page,
le personnage a disparu. Il n'existe aucun moyen de "garder en vie" une variable PHP d'une
requête à l'autre.
Pour persister des données entre les requêtes, il faut les stocker ailleurs : dans un fichier, dans une base de données, ou dans une session (côté serveur). Dans ce projet, on choisit une base de données SQLite.
Qu'est-ce que SQLite ?
SQLite est un moteur de base de données relationnelle. Contrairement à MySQL ou PostgreSQL,
il ne nécessite pas de serveur séparé : la base entière est stockée dans un seul fichier sur
le disque (par exemple jeu.db). C'est le choix idéal pour des projets de petite taille,
des prototypes, et des applications embarquées.
Une base de données relationnelle organise les données en tables. Une table ressemble à un tableau : elle a des colonnes (les champs) et des lignes (les enregistrements).
Le langage SQL
SQL (Structured Query Language) est le langage utilisé pour interagir avec une base de données. Les cinq instructions à connaître pour cette séance :
| Instruction | Rôle |
|---|---|
CREATE TABLE | Créer une nouvelle table |
INSERT INTO | Ajouter une ligne dans une table |
SELECT | Lire des données |
UPDATE | Modifier des données existantes |
DELETE | Supprimer des données |
PDO : l'interface PHP vers les bases de données
PDO (PHP Data Objects) est une extension PHP qui fournit une interface uniforme pour communiquer avec différents moteurs de bases de données. Que l'on utilise SQLite, MySQL ou PostgreSQL, le code PHP reste quasiment identique.
Pour ouvrir une connexion SQLite avec PDO :
$pdo = new PDO("sqlite:jeu.db");
PHP crée le fichier jeu.db s'il n'existe pas encore. Le fichier sera créé dans le
même dossier que le script PHP en cours d'exécution.
Il est recommandé d'activer le mode exception dès l'ouverture, pour que les erreurs SQL provoquent une exception PHP visible plutôt que d'échouer silencieusement :
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Exécuter une requête simple
Pour une requête qui ne renvoie pas de résultats (création de table, suppression...) :
$pdo->exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, nom TEXT)");
Les requêtes préparées
Pour les requêtes qui insèrent ou modifient des données, on ne construit jamais la requête par concaténation de chaînes.
Voici pourquoi.
Si l'on écrivait :
$nom = $_POST['nom']; // valeur venant de l'utilisateur
$pdo->exec("INSERT INTO personnage (nom) VALUES ('" . $nom . "')");
Un utilisateur malveillant pourrait saisir comme nom : '); DROP TABLE personnage; --
et la requête construite deviendrait :
INSERT INTO personnage (nom) VALUES (''); DROP TABLE personnage; --')
Ce type d'attaque s'appelle une injection SQL. Elle peut détruire des données, les exfiltrer, ou donner un accès non autorisé à la base.
La solution : les requêtes préparées. On écrit la requête avec des paramètres nommés
(préfixés par :) à la place des valeurs variables, puis on fournit les valeurs séparément.
PDO se charge de les insérer de manière sécurisée.
$stmt = $pdo->prepare("INSERT INTO personnage (nom, vie) VALUES (:nom, :vie)");
$stmt->execute([':nom' => "Lara", ':vie' => 100]);
Lire des résultats
Après un SELECT, on récupère les lignes avec fetchAll :
$stmt = $pdo->query("SELECT * FROM personnage");
$resultats = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($resultats as $ligne) {
print $ligne['nom'] . " a " . $ligne['vie'] . " PV";
}
PDO::FETCH_ASSOC renvoie chaque ligne sous forme de tableau associatif, avec les noms
de colonnes comme clés. C'est bien plus lisible que $ligne[0], $ligne[1]...
Les tableaux associatifs en PHP
Jusqu'ici on a vu des tableaux indexés numériquement : $tab[0], $tab[1]...
Un tableau associatif utilise des clés textuelles à la place des indices numériques :
$personnage = [
'nom' => "Lara",
'vie' => 100,
'type' => "guerrier"
];
print $personnage['nom']; // Lara
print $personnage['vie']; // 100
C'est le format dans lequel PDO retourne les lignes de la base de données.