Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🐘 PHP – Installation, Syntaxe & Écosystùme

Guide complet IDEO‑Lab pour maütriser PHP, du script simple à l'architecture FPM moderne.

1.1

Vue d'ensemble

Qu'est-ce que PHP ? CÎté serveur, LAMP.

Server-side Web Interprété
1.2

Architecture Web

mod_php (Apache) vs PHP-FPM (Nginx).

LAMP PHP-FPM Nginx
1.3

Installation

Linux (PPA), WAMP/XAMPP, Docker (reco).

apt WAMP Docker
2.1

Syntaxe & Variables

Balises <?php, $variable, echo, commentaires.

$variable echo ;
2.2

Types & Opérateurs

string, int, bool. == vs ===, ?? (null).

string int ===
2.3

Structures de ContrĂŽle

if/else, switch, for, while, foreach.

if foreach loops
3.1

Fonctions & Scope

function(), return, scope, closures, fléchées.

function return Closures
3.2

Tableaux (Arrays)

Indexés, Associatifs (clé=>valeur).

array Associatif []
3.3

Fonctions d'Arrays

array_map, filter, reduce, implode, explode.

array_map array_filter
4.1

Superglobals (Formulaires)

$_GET, $_POST, $_SERVER.

$_GET $_POST $_SERVER
4.2

Sessions & Cookies

$_SESSION, session_start(), setcookie().

$_SESSION Cookies
4.3

Fichiers & Uploads

file_get_contents, $_FILES, move_uploaded_file.

$_FILES json_encode
5.1

POO : Classes & Objets

class, new, $this, __construct, public/private.

class $this new
5.2

POO : Héritage & Interfaces

extends, implements, abstract, final.

extends implements
5.3

POO : Avancé

namespace, use, traits, méthodes magiques.

namespace use trait
6.1

Composer (Dépendances)

Gestionnaire de paquets, autoloading (PSR-4).

Composer autoload PSR-4
6.2

Base de Données (PDO)

Connexion (DSN), try/catch, DBeaver.

PDO DSN try/catch
6.3

RequĂȘtes (PDO)

RequĂȘtes prĂ©parĂ©es (prepare, execute), fetch.

prepare execute fetch
7.1

Sécurité

Injections SQL, XSS, password_hash().

SQL Injection XSS password_hash
7.2

Déploiement

Configuration Apache & Nginx+FPM.

Apache Nginx PHP-FPM
8.1

Cheat-sheet PHP

Syntaxe fréquente & fonctions clés.

cheat syntax
1.1 Vue d'ensemble PHP
Le langage du Web CÎté Serveur

PHP (acronyme récursif pour "PHP: Hypertext Preprocessor") est un langage de script **cÎté serveur**, open-source, principalement conçu pour le développement web.

"CÎté serveur" signifie que le code est exécuté sur le serveur web (ex: Apache, Nginx) *avant* que la page ne soit envoyée au navigateur. Le navigateur ne reçoit que le résultat (HTML, CSS, JSON).

Cas d'usage
  • Sites web dynamiques : La grande majoritĂ© des CMS (WordPress, Joomla, Drupal) tournent sur PHP.
  • Applications Web : Frameworks modernes (Symfony, Laravel).
  • APIs RESTful : GĂ©nĂ©ration de JSON pour les frontends (React, Vue).
  • Scripts CLI : TĂąches planifiĂ©es (cron), outils en ligne de commande.
Flux d'une requĂȘte PHP
1. Client (Navigateur)
    │
    │ (Demande 'index.php')
    ▌
2. Serveur Web (Nginx)
    │
    │ (Passe la requĂȘte Ă ...)
    ▌
3. Interpréteur PHP
    │
    │ (ExĂ©cute 'index.php', se connecte Ă  MySQL/Postgres)
    │ (GĂ©nĂšre une page HTML)
    ▌
4. Serveur Web (Nginx)
    │
    │ (Renvoie la page HTML gĂ©nĂ©rĂ©e)
    ▌
5. Client (Navigateur)
    │
    │ (Affiche le HTML)
Positionnement : PHP vs Node.js vs Python

PHP est souvent comparé à d'autres langages de backend.

CritĂšrePHP (avec Apache/FPM)Node.js (avec Express)Python (avec Django/Flask)
ParadigmeSynchrone (bloquant), multi-processus/thread.Asynchrone (non-bloquant), "Event Loop".Synchrone (bloquant), multi-processus (WSGI).
ExĂ©cution"Share nothing". Chaque requĂȘte est un nouveau monde.Serveur "long-running" (stateful).Serveur "long-running" (stateful).
FacilitĂ© (HĂ©bergement)ExtrĂȘme. N'importe quel hĂ©bergement mutualisĂ©.Complexe. NĂ©cessite un serveur (VPS, PaaS).Complexe. NĂ©cessite un serveur (VPS, PaaS).
Cas d'usageSites de contenu, CMS, applications métiers.APIs temps-réel, WebSockets, microservices.Applications complexes, Data Science, IA.
ÉcosystùmePackagist (Composer)NPMPyPI (pip)

En résumé : PHP excelle par sa simplicité de déploiement et son écosystÚme mature (WordPress...). Il est synchrone, ce qui le rend plus simple à déboguer que Node.js pour des tùches web classiques.

1.2 Architecture Web (mod_php vs FPM)
LAMP (Linux, Apache, MySQL, PHP)

C'est l'architecture historique. PHP s'exĂ©cute comme un **module** (mod_php) Ă  l'intĂ©rieur mĂȘme du processus Apache.

[Image d'une architecture LAMP]
+--------------------------------------+
| SERVEUR APACHE (Processus 1)         |
|                                      |
| +----------------------------------+ |
| | Module PHP (Interpréteur chargé) | |
| +----------------------------------+ |
|                                      |
| (Traite la requĂȘte .php)             |
+--------------------------------------+
+--------------------------------------+
| SERVEUR APACHE (Processus 2)         |
| +----------------------------------+ |
| | Module PHP (Interpréteur chargé) | |
| +----------------------------------+ |
+--------------------------------------+
  • Avantage : ExtrĂȘmement simple Ă  configurer (apt install libapache2-mod-php).
  • Avantage : Pas de configuration de socket/port.
  • InconvĂ©nient : Lourd. Chaque processus Apache charge tout l'interprĂ©teur PHP, mĂȘme pour servir une image CSS/JS.
  • InconvĂ©nient : Moins sĂ©curisĂ© (le code PHP s'exĂ©cute avec l'utilisateur Apache www-data).
LEMP / Nginx + PHP-FPM (Recommandé)

C'est l'architecture moderne et performante. Nginx (trÚs rapide pour les fichiers statiques) et PHP-FPM (FastCGI Process Manager) sont deux services **séparés**.

[Image d'une architecture Nginx FPM]
+--------------------------------------+
| SERVEUR NGINX (Non-bloquant)         |
| (Sert CSS, JS, Images...)            |
|                                      |
| (RequĂȘte .php ?) ------------------+ |
+--------------------------------------+
                                     | (FastCGI)
                                     | (via Socket ou TCP 9000)
                                     ▌
+--------------------------------------+
| SERVICE PHP-FPM (Process Manager)    |
|                                      |
| (Pool de workers PHP)                |
|  [Worker 1] [Worker 2] [Worker 3]    |
+--------------------------------------+
  • Avantage : Nginx gĂšre les statiques (rapide), FPM gĂšre le PHP (dĂ©diĂ©).
  • Avantage : FPM gĂšre un "pool" de workers, bien plus efficace en mĂ©moire.
  • Avantage : SĂ©curisĂ©. FPM peut tourner avec un utilisateur diffĂ©rent de Nginx.
1.3 Installation (Linux, Windows, Docker)
Installation (Ubuntu 22.04+ / Debian 11+)

Recommandé : Utiliser le PPA ondrej/php pour avoir les versions les plus récentes (ex: PHP 8.3).

# 1. Ajouter le PPA
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update

# 2. Installer PHP-FPM et les extensions courantes
# (Installe PHP 8.3 au 01/11/2025)
sudo apt-get install -y php-fpm php-cli php-mysql php-pgsql php-sqlite3 \
                          php-curl php-gd php-xml php-zip php-mbstring

# 3. Vérifier
php -v
# PHP 8.3.x (cli) ...
Installation Nginx + FPM
# 1. Installer Nginx
sudo apt-get install -y nginx

# 2. Configurer Nginx pour FPM
# (Voir section 7.2)

# 3. Démarrer les services
sudo systemctl enable --now nginx
sudo systemctl enable --now php8.3-fpm
Windows (WAMP / XAMPP)

Pour le développement Windows, XAMPP est la solution la plus simple. Elle installe une stack complÚte (Apache, MariaDB, PHP, PhpMyAdmin).

  1. Allez sur apachefriends.org
  2. Téléchargez et lancez l'installeur XAMPP.
  3. Lancez le "XAMPP Control Panel".
  4. Cliquez "Start" sur Apache et "Start" sur MySQL.
  5. Placez vos fichiers PHP dans C:\xampp\htdocs\
  6. Ouvrez votre navigateur sur http://localhost/
Docker (Environnement de Dev Moderne)

Utiliser Docker Compose est la meilleure façon de reproduire un environnement de production (Nginx, FPM, DB séparés).

docker-compose.yml (Exemple)
version: "3.8"
services:
  # 1. Le serveur Web
  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf

  # 2. Le service PHP
  php:
    image: php:8.3-fpm-alpine
    volumes:
      - ./src:/var/www/html

  # 3. La BDD
  db:
    image: mariadb:10.11
    environment:
      MARIADB_ROOT_PASSWORD: root_secret
    volumes:
      - db-data:/var/lib/mysql

volumes:
  db-data:

Placez vos fichiers PHP dans ./src/ et votre nginx.conf (cf 7.2) puis lancez docker compose up -d. Accédez via http://localhost:8080.

2.1 Syntaxe & Variables
Balises PHP

Le code PHP est exécuté à l'intérieur de balises. Tout ce qui est à l'extérieur est envoyé tel quel (HTML).

<h1>Titre HTML</h1>

<?php
// Ceci est un commentaire PHP
echo "<p>Ceci est généré par PHP.</p>";
?>

<!-- Balise courte (echo) -->
<p>Utilisateur : <?= $nom_utilisateur; ?></p>
<!-- <?= ... ?> est un raccourci pour <?php echo ... ?> -->

Chaque instruction PHP doit se terminer par un point-virgule ;.

Variables

Les variables commencent par $. Elles sont sensibles à la casse ($nom != $NOM) et typées dynamiquement.

$nom = "Alice"; // String
$age = 30;       // Integer
$prix = 19.99;   // Float
$est_admin = true; // Boolean
Affichage (echo & print)

echo est (marginalement) plus rapide et peut prendre plusieurs arguments.

echo "Bonjour";
echo "Bonjour", " ", "le monde"; // Affiche "Bonjour le monde"

print "Bonjour"; // (Retourne 1)

// Concaténation avec '.'
echo "Utilisateur: " . $nom . " (Age: " . $age . ")";

// Interpolation (guillemets doubles)
echo "Utilisateur: $nom (Age: $age)";
// (Ne marche pas avec des guillemets simples '')
Débogage (var_dump)

Pour afficher le type et la valeur d'une variable.

var_dump($nom);
// string(5) "Alice"

var_dump($age);
// int(30)
2.2 Types de Données & Opérateurs
Types de Données (Typage Dynamique)
TypeExemple
string"Bonjour", 'Bonjour'
integer10, -5
float10.5, -0.1
booleantrue, false
array[1, "deux"], ["cle" => "val"]
objectnew MaClasse()
nullnull (Variable sans valeur)
Type Juggling (Conversion auto)

PHP convertit les types automatiquement. C'est pratique mais dangereux.

$a = "10"; // String
$b = 5;    // Integer

$c = $a + $b;
var_dump($c); // int(15) (PHP a converti $a en int)

// Casting (Conversion manuelle)
$d = (int) $a;
$e = (string) $b;
Comparaison : == vs === (Crucial)

C'est la source d'erreur n°1 des débutants.

== (ÉgalitĂ© - Valeur seule)

Compare les valeurs *aprĂšs* "type juggling".

"10" == 10     // true (string "10" est converti en int 10)
0 == false     // true (0 est "falsy")
0 == null      // true
"" == null     // true
=== (Identique - Valeur ET Type)

Recommandé. Compare les valeurs ET les types. Pas de conversion.

"10" === 10    // false (string vs int)
0 === false    // false (int vs bool)
0 === null     // false
!= (Différent) vs !== (Non-identique)
"10" != 10     // false
"10" !== 10    // true
Opérateurs (Sélection)
TypeOpérateursExemple
Arithmétique+, -, *, /, % (modulo)10 % 3 (donne 1)
Assignation=, +=, -=, .= (concat)$a += 5; ($a = $a + 5)
Logique&& (ET), || (OU), ! (NON)if ($a && $b)
Incrément$a++, ++$a, $a--, --$a
Null Coalesce??$nom = $_GET['nom'] ?? 'Visiteur';
(Raccourci pour isset($_GET['nom']) ? $_GET['nom'] : 'Visiteur')
Ternaire(cond) ? Vrai : Faux$statut = ($age > 18) ? 'Majeur' : 'Mineur';
2.3 Structures de ContrĂŽle
Conditions (if, else, switch)
// if / elseif / else
if ($age > 18) {
    echo "Majeur";
} elseif ($age == 18) {
    echo "Juste 18";
} else {
    echo "Mineur";
}

// switch
switch ($role) {
    case 'admin':
        echo "AccĂšs total";
        break;
    case 'editeur':
        echo "AccÚs édition";
        break;
    default:
        echo "AccĂšs visiteur";
}

// Syntaxe alternative (Templates)
<?php if ($connecte): ?>
    <h1>Bienvenue</h1>
<?php else: ?>
    <h1>Connexion</h1>
<?php endif; ?>
Boucles (for, while, foreach)
// for
for ($i = 0; $i < 10; $i++) {
    echo $i;
}

// while
$j = 0;
while ($j < 10) {
    echo $j;
    $j++;
}

// foreach (La plus utile)
$couleurs = ["rouge", "vert", "bleu"];
foreach ($couleurs as $couleur) {
    echo $couleur;
}

// foreach (avec clés)
$user = ["nom" => "Alice", "age" => 30];
foreach ($user as $cle => $valeur) {
    echo "$cle : $valeur\n";
}

// break & continue
foreach ($couleurs as $couleur) {
    if ($couleur == "vert") {
        continue; // Saute "vert"
    }
    if ($couleur == "bleu") {
        break; // ArrĂȘte la boucle
    }
    echo $couleur; // Affiche "rouge"
}
3.1 Fonctions & Scope
Définition & Appel
// Définition
function saluer($nom) {
    echo "Bonjour, $nom !";
}

// Appel
saluer("Alice");
ParamĂštres & Retour
function additionner($a, $b) {
    $resultat = $a + $b;
    return $resultat;
}

$somme = additionner(10, 5); // $somme vaut 15
PHP 7+ : Typage Strict (Recommandé)

Permet de forcer les types des arguments et du retour. Aide à prévenir les bugs.

// Active le mode strict (en haut du fichier)
declare(strict_types=1);

function additionner_strict(int $a, float $b): int {
    return (int)($a + $b);
}

$somme = additionner_strict(10, 5.5);
// $somme vaut 15 (int)

// additionner_strict("10", 5.5); // Erreur (TypeError)
Scope (Portée des variables)

Les fonctions ont un scope isolé. Elles n'ont pas accÚs aux variables extérieures, sauf si on les passe en paramÚtre.

$nom = "Alice"; // Scope global

function saluer() {
    echo $nom; // Erreur: Undefined variable $nom
}

function saluer_ok($nom_local) {
    echo $nom_local; // OK
}
saluer_ok($nom);
Mot-clĂ© global (À Ă©viter)
$nom = "Alice";
function saluer_global() {
    global $nom; // Importe $nom
    echo $nom;
}
// (Ceci est considéré comme une mauvaise pratique)
Fonctions Anonymes (Closures)

Une fonction stockée dans une variable. TrÚs utilisée pour les callbacks (ex: array_map).

$nombres = [1, 2, 3];

$double = function($n) {
    return $n * 2;
};

$nombres_doubles = array_map($double, $nombres);
// [2, 4, 6]

// Utilisation du 'use' (Closure)
$facteur = 10;
$multiplier = function($n) use ($facteur) {
    return $n * $facteur; // $facteur est importé du scope parent
};
$nombres_x10 = array_map($multiplier, $nombres);
// [10, 20, 30]
Fonctions Fléchées (Arrow Functions) (PHP 7.4+)

Une syntaxe plus courte pour les closures simples, qui capture automatiquement le scope.

$facteur = 10;
$nombres = [1, 2, 3];

// 'fn' capture $facteur automatiquement
$nombres_x10 = array_map(fn($n) => $n * $facteur, $nombres);
3.2 Tableaux (Arrays)
Le "couteau suisse" de PHP

En PHP, "Array" est une structure de données ordonnée (dictionnaire, liste, map) tout-en-un.

1. Tableaux Indexés (Listes)

(Index 0, 1, 2...)

// Syntaxe moderne (depuis PHP 5.4)
$fruits = ["pomme", "banane", "orange"];

// Syntaxe ancienne
$fruits_old = array("pomme", "banane", "orange");

// AccĂšs
echo $fruits[1]; // "banane"

// Ajout
$fruits[] = "fraise";

// Nombre d'éléments
echo count($fruits); // 4
2. Tableaux Associatifs (Maps / Dictionnaires)

(Clés personnalisées)

$utilisateur = [
    "nom" => "Alice",
    "age" => 30,
    "est_admin" => true
];

// AccĂšs
echo $utilisateur["nom"]; // "Alice"

// Ajout / Modification
$utilisateur["email"] = "alice@mail.com";
$utilisateur["age"] = 31;
Boucle foreach (Indispensable)
// Indexé
foreach ($fruits as $fruit) {
    echo $fruit;
}

// Associatif
foreach ($utilisateur as $cle => $valeur) {
    echo "$cle : $valeur\n";
}
3.3 Fonctions d'Arrays (Les plus utiles)
Manipulation de listes
$nombres = [1, 2, 3, 4, 5];

// Appliquer une fonction à chaque élément
$carres = array_map(fn($n) => $n * $n, $nombres);
// [1, 4, 9, 16, 25]

// Filtrer les éléments
$pairs = array_filter($nombres, fn($n) => $n % 2 == 0);
// [2, 4] (Préserve les clés)
// (Utiliser array_values() pour ré-indexer à 0)

// Réduire à une seule valeur
$somme = array_reduce($nombres, fn($carry, $item) => $carry + $item, 0);
// 15
Recherche & Extraction
$utilisateur = ["nom" => "Alice", "age" => 30];
$fruits = ["pomme", "banane"];

// Vérifier si une clé existe
isset($utilisateur["age"]); // true
array_key_exists("age", $utilisateur); // true

// Vérifier si une valeur existe
in_array("pomme", $fruits); // true

// Obtenir toutes les clés
$cles = array_keys($utilisateur); // ["nom", "age"]

// Obtenir toutes les valeurs
$valeurs = array_values($utilisateur); // ["Alice", 30]

// Transformer un Array en String
$csv = implode(", ", $fruits); // "pomme, banane"

// Transformer un String en Array
$tags = explode(",", "php,js,css"); // ["php", "js", "css"]
4.1 Superglobals & Gestion de Formulaires

Les "Superglobals" sont des variables array prédéfinies, accessibles depuis n'importe quel scope.

HTML (form.html)
<!-- Méthode GET (données dans l'URL) -->
<form action="recherche.php" method="GET">
    <input type="text" name="q">
    <button type="submit">Rechercher</button>
</form>
<!-- URL: /recherche.php?q=monter -->

<!-- MĂ©thode POST (donnĂ©es dans le corps de la requĂȘte) -->
<form action="login.php" method="POST">
    <input type="text" name="username">
    <input type="password" name="password">
    <button type="submit">Connexion</button>
</form>
PHP (recherche.php)
<?php
// Utiliser '??' (null coalesce) pour éviter les erreurs
$terme = $_GET['q'] ?? '';

echo "Résultats pour : " . htmlspecialchars($terme);
?>
PHP (login.php)
<?php
// Vérifier la méthode (bonne pratique)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';
    
    // (Logique de validation...)
    echo "Bonjour $username";
    
} else {
    echo "Veuillez soumettre le formulaire.";
}
?>
$_SERVER (Infos Serveur & RequĂȘte)

Un tableau contenant des informations sur le serveur et la requĂȘte.

CléExempleDescription
REQUEST_METHOD'GET' ou 'POST'La méthode HTTP utilisée.
REQUEST_URI'/page.php?id=10'L'URL complĂšte aprĂšs le nom d'hĂŽte.
SCRIPT_NAME'/page.php'Le chemin du script actuel.
DOCUMENT_ROOT'/var/www/html'La racine du site.
HTTP_HOST'ideolab.com'Le nom d'hĂŽte (Host header).
REMOTE_ADDR'123.45.67.89'L'adresse IP du client.
$_ENV & .env

$_ENV contient les variables d'environnement du systĂšme.

Pratique moderne : Ne pas stocker les secrets (ex: BDD) dans le code. Utiliser un fichier .env Ă  la racine (exclu de Git).

# .env
DB_HOST=localhost
DB_USER=mon_user
DB_PASS=mon_pass_secret

Puis utiliser Composer (cf 6.1) pour installer une librairie qui charge ce fichier :

composer require vlucas/phpdotenv
<?php
require 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// La variable est maintenant dispo
$db_host = $_ENV['DB_HOST'];
?>
4.2 Sessions & Cookies
$_COOKIE

Stocke des données **cÎté client** (navigateur). PHP lit la superglobale $_COOKIE.

Pour *crĂ©er* un cookie, on utilise setcookie(). Attention : setcookie() doit ĂȘtre appelĂ©e *avant* tout echo ou HTML.

<?php
// setcookie(nom, valeur, expiration, chemin)
$expiration = time() + (3600 * 24 * 30); // 30 jours
setcookie("langue", "fr", $expiration, "/");

// Lire le cookie (Ă  la prochaine requĂȘte)
$lang = $_COOKIE['langue'] ?? 'en';
?>
$_SESSION

HTTP est "stateless". Les sessions permettent de mémoriser des données (ex: "qui est connecté") entre les pages.

Fonctionnement :

  1. session_start() : PHP crée un ID de session unique (ex: abc123).
  2. PHP envoie cet ID au client via un Cookie (ex: PHPSESSID=abc123).
  3. PHP stocke les données ($_SESSION['user_id'] = 10;) sur le **serveur** (ex: /tmp/sess_abc123).
  4. À la page suivante, session_start() lit le cookie PHPSESSID, trouve le fichier sess_abc123, et remplit $_SESSION.

Exemple (login.php)
<?php
session_start(); // TOUJOURS en premier

// (AprÚs vérification du POST...)
if ($user_valide) {
    $_SESSION['user_id'] = $user['id'];
    $_SESSION['username'] = $user['nom'];
    header('Location: dashboard.php'); // Redirection
    exit;
}
?>
Exemple (dashboard.php)
<?php
session_start();

if (!isset($_SESSION['user_id'])) {
    die("AccÚs refusé");
}

echo "Bienvenue, " . htmlspecialchars($_SESSION['username']);
?>
4.3 Gestion des Fichiers & Uploads
Lecture & Écriture (Simple)
// Lire un fichier
$contenu = file_get_contents("mon_fichier.txt");

// Écrire/Écraser un fichier
file_put_contents("log.txt", "Nouveau log\n");

// Ajouter Ă  un fichier
file_put_contents("log.txt", "Autre log\n", FILE_APPEND);

// Vérifier l'existence
if (file_exists("config.ini")) { ... }

// Supprimer
unlink("fichier_temp.tmp");
Gestion de chemins
// Constantes magiques
$chemin_script = __FILE__; // Chemin complet du script actuel
$dossier_script = __DIR__; // Dossier du script actuel

// Joindre des chemins (propre)
$config_path = $dossier_script . DIRECTORY_SEPARATOR . 'config.ini';
$config = file_get_contents($config_path);
JSON (JavaScript Object Notation)

Le format standard pour les APIs et les configs.

// Array PHP
$user = ["nom" => "Alice", "age" => 30];

// 1. Array PHP -> String JSON
$json_string = json_encode($user, JSON_PRETTY_PRINT);
/*
{
    "nom": "Alice",
    "age": 30
}
*/
file_put_contents("user.json", $json_string);

// 2. String JSON -> Array PHP
$json_lu = file_get_contents("user.json");
$user_array = json_decode($json_lu, true); // 'true' = array associatif

echo $user_array['nom']; // "Alice"
Uploads ($_FILES)
HTML (upload.html)
<!-- 'enctype' est obligatoire pour les fichiers -->
<form action="upload.php" method="POST" enctype="multipart/form-data">
    <label>Avatar:</label>
    <input type="file" name="avatar_file">
    <button type="submit">Envoyer</button>
</form>
PHP (upload.php)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['avatar_file'])) {

    $file = $_FILES['avatar_file'];

    // 1. Vérifier les erreurs
    if ($file['error'] !== UPLOAD_ERR_OK) {
        die("Erreur d'upload (Code: " . $file['error'] . ")");
    }
    
    // 2. Infos du fichier
    $nom_original = $file['name'];
    $type_mime = $file['type'];
    $taille = $file['size'];
    $chemin_temporaire = $file['tmp_name']; // (ex: /tmp/phpAbc12)
    
    // 3. (Valider type, taille...)
    
    // 4. Déplacer le fichier
    $dossier_uploads = __DIR__ . '/uploads/';
    $nouveau_chemin = $dossier_uploads . basename($nom_original);
    
    if (move_uploaded_file($chemin_temporaire, $nouveau_chemin)) {
        echo "Fichier uploadé !";
    } else {
        echo "Échec du dĂ©placement.";
    }
}
?>
5.1 POO : Classes, Objets & Propriétés
Classe (Le Plan) & Objet (La Maison)

Une classe est un "plan" pour créer des objets. Un objet est une "instance" de cette classe.

<?php
// 1. Définition de la classe (le plan)
class Utilisateur {
    
    // Propriétés (les données)
    public $nom;
    public $email;
    
    // Méthodes (les actions)
    public function saluer() {
        echo "Bonjour, je suis " . $this->nom;
    }
}

// 2. Création d'objets (les instances)
$user1 = new Utilisateur();
$user1->nom = "Alice"; // AccĂšs public
$user1->email = "alice@mail.com";

$user2 = new Utilisateur();
$user2->nom = "Bob";

// 3. Appel de méthodes
$user1->saluer(); // "Bonjour, je suis Alice"
$user2->saluer(); // "Bonjour, je suis Bob"
?>
$this (L'objet lui-mĂȘme)

À l'intĂ©rieur d'une mĂ©thode, $this fait rĂ©fĂ©rence Ă  l'instance actuelle de l'objet ($user1 ou $user2).

__construct (Constructeur)

Cette méthode magique est appelée automatiquement lors du new. Parfait pour initialiser l'objet.

class Utilisateur {
    public $nom;
    public $email;
    
    // 1. Le constructeur
    public function __construct(string $nom_init, string $email_init) {
        $this->nom = $nom_init;
        $this->email = $email_init;
        echo "Utilisateur créé !";
    }
    
    public function saluer() {
        // $this fait référence à l'objet courant
        echo "Bonjour, " . $this->nom;
    }
}

$user1 = new Utilisateur("Alice", "alice@mail.com");
$user1->saluer();
PHP 8+ : Promotion des Propriétés

Syntaxe raccourcie (trĂšs pratique) :

class Utilisateur {
    // PHP crée $nom et $email automatiquement
    public function __construct(
        public string $nom,
        public string $email
    ) {
        // (Corps vide)
    }
}
Visibilité (Encapsulation)

Permet de contrÎler l'accÚs aux propriétés/méthodes.

  • public : Accessible partout (par l'objet, par les classes enfants, et de l'extĂ©rieur).
  • protected : Accessible par la classe et ses classes enfants (HĂ©ritage).
  • private : Accessible *uniquement* par la classe elle-mĂȘme.
class CompteBancaire {
    private float $solde; // Privé !
    
    public function __construct(float $depot_initial) {
        $this->solde = $depot_initial;
    }
    
    // "Getter" public
    public function getSolde(): float {
        return $this->solde;
    }
    
    // "Setter" public
    public function deposer(float $montant) {
        if ($montant > 0) {
            $this->solde += $montant;
        }
    }
}
$compte = new CompteBancaire(100);
// $compte->solde = -500; // Erreur Fatale ! (private)
$compte->deposer(50);
echo $compte->getSolde(); // 150
static

Lié à la Classe, pas à l'objet. On utilise self:: (ou static::).

class MathUtil {
    public static float $pi = 3.14;
    
    public static function addition(int $a, int $b): int {
        return $a + $b;
    }
}
// Pas de 'new'
echo MathUtil::$pi;
echo MathUtil::addition(5, 10);
5.2 POO : Héritage & Interfaces
Héritage (extends)

Permet à une classe "enfant" d'hériter des propriétés/méthodes (public, protected) d'une classe "parent".

// Classe Parent
class Animal {
    public function __construct(protected string $nom) {}
    
    public function manger() {
        echo "{$this->nom} mange.";
    }
}

// Classe Enfant
class Chien extends Animal {
    // Hérite de $nom et manger()
    
    public function aboyer() {
        echo "{$this->nom} aboie : Wouaf !";
    }
    
    // Surcharge (Override)
    public function manger() {
        echo "{$this->nom} mange ses croquettes.";
    }
}

$medor = new Chien("Médor");
$medor->manger(); // "Médor mange ses croquettes."
$medor->aboyer(); // "Médor aboie : Wouaf !"
Interfaces (implements)

Une Interface est un "contrat". Elle définit les méthodes qu'une classe **doit** implémenter, mais pas *comment*.

// Le Contrat
interface Forme {
    public function calculerAire(): float;
}

interface Colorable {
    public function setCouleur(string $c);
}

// Implémentation (oblige à définir calculerAire() et setCouleur())
class Carre implements Forme, Colorable {
    private $cote;
    private $couleur;
    
    public function __construct($cote) { $this->cote = $cote; }
    
    public function calculerAire(): float {
        return $this->cote * $this->cote;
    }
    
    public function setCouleur(string $c) {
        $this->couleur = $c;
    }
}

class Cercle implements Forme {
    private $rayon;
    
    public function __construct($rayon) { $this->rayon = $rayon; }
    
    public function calculerAire(): float {
        return pi() * ($this->rayon ** 2);
    }
}
Classes Abstraites (abstract)

Un mĂ©lange entre une classe et une interface. Elle ne peut pas ĂȘtre instanciĂ©e (pas de new). Elle peut contenir des mĂ©thodes implĂ©mentĂ©es (normales) ET des mĂ©thodes abstraites (non-implĂ©mentĂ©es).

// Classe abstraite (ne peut pas faire 'new Vehicule')
abstract class Vehicule {
    protected $vitesse = 0;
    
    // Méthode implémentée
    public function rouler() {
        $this->vitesse = 50;
    }
    
    // Méthode abstraite (Contrat pour les enfants)
    abstract public function getNombreRoues(): int;
}

class Voiture extends Vehicule {
    // Doit implémenter la méthode abstraite
    public function getNombreRoues(): int {
        return 4;
    }
}

class Moto extends Vehicule {
    public function getNombreRoues(): int {
        return 2;
    }
}

$v = new Voiture();
$v->rouler();
echo $v->getNombreRoues(); // 4
5.3 POO : Namespaces & Traits
ProblĂšme : Collisions de Noms

Que faire si vous avez deux classes Utilisateur (une pour le CRM, une pour le Forum) ?

Solution : Namespaces (Espaces de noms)

Similaire aux dossiers. Ils permettent d'organiser le code et d'éviter les collisions.

// Fichier: src/CRM/Utilisateur.php
namespace App\CRM;

class Utilisateur {
    public function __construct() { echo "User CRM"; }
}

// Fichier: src/Forum/Utilisateur.php
namespace App\Forum;

class Utilisateur {
    public function __construct() { echo "User Forum"; }
}

// Fichier: index.php
namespace App;

// Importer les classes
use App\CRM\Utilisateur as CrmUser;
use App\Forum\Utilisateur as ForumUser;

$user1 = new CrmUser();   // "User CRM"
$user2 = new ForumUser(); // "User Forum"

// Ou utiliser le FQCN (Fully Qualified Class Name)
$user3 = new \App\CRM\Utilisateur();

C'est la base de Composer et de PSR-4 (cf 6.1).

Traits (Réutilisation horizontale)

PHP n'autorise pas l'héritage multiple. Un "Trait" est un "copier-coller" de méthodes que vous pouvez "use" dans une classe.

// 1. Le Trait (un ensemble de méthodes)
trait LoggerTrait {
    public function log(string $message) {
        echo "LOG: $message";
    }
}

// 2. Les Classes
class Article {
    use LoggerTrait; // "Copie" les méthodes
    
    public function save() {
        $this->log("Article sauvegardé");
    }
}
class Commentaire {
    use LoggerTrait;
    
    public function post() {
        $this->log("Commentaire posté");
    }
}

$article = new Article();
$article->save(); // "LOG: Article sauvegardé"
Méthodes Magiques

Méthodes spéciales (commençant par __) appelées automatiquement par PHP.

MéthodeDéclencheur
__construct()new MaClasse()
__destruct()Juste avant que l'objet ne soit détruit.
__toString()echo $objet; (Doit retourner un string).
__get($nom)Lire une propriété privée/inconnue (ex: $obj->nom).
__set($nom, $val)Écrire sur une propriĂ©tĂ© privĂ©e/inconnue (ex: $obj->nom = 'Val').
__call($nom, $args)Appeler une méthode privée/inconnue (ex: $obj->maMethode()).
6.1 Composer (Gestionnaire de dépendances)
Le "npm" ou "pip" de PHP

Composer est l'outil indispensable du PHP moderne. Il gĂšre :

  1. Les Dépendances : (Librairies externes, ex: un logger, un client HTTP). Il les télécharge depuis Packagist.org.
  2. L'Autoloading : (Le chargement automatique des classes).
Installation (Globale)
# (Voir getcomposer.org)
# Télécharge 'composer.phar' et le déplace
sudo mv composer.phar /usr/local/bin/composer
Flux de travail
1. `composer init` (Crée composer.json)
2. `composer require monolog/monolog` (Ajoute une dépendance)
   (Crée `composer.lock` et `vendor/`)
3. `require 'vendor/autoload.php';` (Dans votre code)
4. (Coder...)
5. `composer install` (En déploiement, pour installer depuis `composer.lock`)
composer.json (Le Fichier de Config)

Définit les dépendances du projet.

{
    "name": "ideo-lab/mon-projet",
    "description": "Un projet d'exemple",
    "type": "project",
    "require": {
        "php": ">=8.1",
        "monolog/monolog": "^3.0",
        "guzzlehttp/guzzle": "^7.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
Commandes
# Initialiser un projet
composer init

# Ajouter une dépendance de prod
composer require monolog/monolog

# Ajouter une dépendance de dev
composer require --dev phpunit/phpunit

# Installer les dépendances (d'aprÚs composer.lock)
composer install

# Mettre à jour les dépendances (d'aprÚs composer.json)
composer update
Autoloading (PSR-4)

Fini les require_once ! Composer génÚre un "autoloader".

GrĂące Ă  la section autoload du composer.json :

"autoload": {
    "psr-4": {
        "App\\": "src/"
    }
}

Composer sait que App\CRM\Utilisateur se trouve dans src/CRM/Utilisateur.php.

index.php (Le Point d'Entrée)
<?php
// 1. Inclure l'autoloader (LA SEULE INCLUSION NÉCESSAIRE)
require_once __DIR__ . '/vendor/autoload.php';

// 2. Utiliser les classes (locales ou vendor)
use App\CRM\Utilisateur;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// 3. Composer charge les fichiers automatiquement
$log = new Logger('ideolab');
$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));

$user = new Utilisateur();

$log->warning('Un utilisateur a été créé.');
?>
6.2 Base de Données : PDO (Connexion)
PDO (PHP Data Objects)

C'est l'extension moderne et sĂ©curisĂ©e pour parler Ă  une BDD. C'est une couche d'abstraction (le code est le mĂȘme pour MySQL, PgSQL, SQLite).

Ne **jamais** utiliser les anciennes fonctions mysql_* (obsolĂštes et dangereuses).

Le DSN (Data Source Name)

Une chaßne de caractÚres qui décrit la connexion.

// DSN pour MySQL / MariaDB
$dsn_mysql = 'mysql:host=localhost;dbname=ideo_lab_crm;charset=utf8mb4';

// DSN pour PostgreSQL
$dsn_pgsql = 'pgsql:host=localhost;port=5432;dbname=ideo_lab_crm';

// DSN pour SQLite (fichier)
$dsn_sqlite = 'sqlite:/path/to/db.sqlite';
Connexion (try/catch)

La connexion doit **toujours** ĂȘtre dans un bloc try/catch pour gĂ©rer les Ă©checs.

<?php
$dsn = 'mysql:host=localhost;dbname=testdb';
$user = 'dbuser';
$pass = 'dbpass';

// Options (recommandées)
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Lance des exceptions
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Retourne des arrays associatifs
    PDO::ATTR_EMULATE_PREPARES   => false, // Utilise de vraies requĂȘtes prĂ©parĂ©es
];

try {
    
    // $pdo est l'objet de connexion
    $pdo = new PDO($dsn, $user, $pass, $options);
    
    echo "Connexion réussie !";
    
} catch (\PDOException $e) {
    // Attrape l'erreur
    echo "Erreur de connexion : " . $e->getMessage();
    exit; // ArrĂȘter le script
}
?>
6.3 PDO : RequĂȘtes PrĂ©parĂ©es (SĂ©curitĂ©)
La Faille (Injection SQL)

Ne **JAMAIS** insĂ©rer de variables ($_GET, $_POST) directement dans une requĂȘte.

// $id_user vient de l'URL (ex: 105)
$id_user = $_GET['id'];

// REQUÊTE NON SÉCURISÉE (DANGEREUSE)
$stmt = $pdo->query("SELECT * FROM users WHERE id = $id_user");
$user = $stmt->fetch();

L'attaque : Un pirate appelle l'URL /page.php?id=105 OR 1=1

La requĂȘte devient :

SELECT * FROM users WHERE id = 105 OR 1=1

... ce qui retourne TOUS les utilisateurs de la base.

Solution : RequĂȘtes PrĂ©parĂ©es (prepare & execute)

On envoie la "structure" (? ou :placeholder) et les "données" (variables) séparément. Le SGBD les assemble de maniÚre sécurisée.

1. Placeholders (?)
$id_user = $_GET['id'];
$statut = 'actif';

// 1. Préparer
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND statut = ?");

// 2. Exécuter (envoie les données)
$stmt->execute([ $id_user, $statut ]);

$user = $stmt->fetch();
2. Placeholders nommés (:nom) (Recommandé)
$id_user = $_GET['id'];
$statut = 'actif';

$sql = "SELECT * FROM users WHERE id = :id_param AND statut = :statut_param";
$stmt = $pdo->prepare($sql);

$stmt->execute([
    ':id_param' => $id_user,
    ':statut_param' => $statut
]);
$user = $stmt->fetch();
Lire les résultats (SELECT)
$stmt = $pdo->prepare("SELECT * FROM users WHERE statut = ?");
$stmt->execute(['actif']);

// 1. fetch() - Pour 1 seul résultat
$user = $stmt->fetch(); // Retourne un array ou 'false'
if ($user) {
    echo $user['nom'];
}

// 2. fetchAll() - Pour plusieurs résultats
$users = $stmt->fetchAll(); // Retourne un array de arrays
foreach ($users as $user) {
    echo $user['nom'];
}
INSERT, UPDATE, DELETE
$sql = "INSERT INTO users (nom, email) VALUES (:nom, :email)";
$pdo->prepare($sql)->execute([
    ':nom' => 'Nouveau User',
    ':email' => 'new@mail.com'
]);

// Récupérer le dernier ID inséré
$last_id = $pdo->lastInsertId();

// Obtenir le nombre de lignes affectées (UPDATE/DELETE)
$sql = "UPDATE users SET nom = ? WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute(['Nom Modifié', 10]);
$nb_lignes = $stmt->rowCount();
7.1 Sécurité (Top 3)
Faille : Injection SQL

Risque : Un attaquant lit ou modifie votre BDD.

Exemple faillible :

$id = $_GET['id'];
$pdo->query("SELECT * FROM users WHERE id = $id");

Solution : RequĂȘtes PrĂ©parĂ©es (cf 6.3)

$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
Faille : XSS (Cross-Site Scripting)

Risque : Un attaquant injecte du JavaScript (<script>) dans votre page, qui s'exécute chez vos visiteurs (ex: vol de cookies de session).

Exemple faillible : (L'utilisateur met <script>alert(1);</script> dans son nom)

$nom = $_POST['nom']; // Vient de l'utilisateur
// (Sauvegarde en BDD...)
// (Plus tard...)
$nom_bdd = $user['nom'];
echo "<h1>Bienvenue, " . $nom_bdd . "</h1>";
// Le navigateur exécute le script !

Solution : Échapper le HTML à l'affichage (htmlspecialchars)

// Échapper TOUJOURS les donnĂ©es utilisateur avant de les 'echo'
echo "<h1>Bienvenue, " . htmlspecialchars($nom_bdd) . "</h1>";
// Résultat HTML: <h1>Bienvenue, &lt;script&gt;...</h1>
// (Le navigateur affiche le texte, n'exécute pas le script)
Faille : Stockage de Mots de Passe

Risque : Si votre BDD fuite, tous les mots de passe sont en clair (ou facilement réversibles si md5/sha1).

Exemple faillible :

// NE JAMAIS FAIRE ÇA
$pass_md5 = md5($_POST['password']);
$pdo->query("INSERT INTO users (pass) VALUES ('$pass_md5')");

Solution : password_hash & password_verify

Utilise des algorithmes de hachage modernes (ex: bcrypt) avec "sel" (salt) automatique.

// 1. Inscription (Stocker le hash)
$pass_clair = $_POST['password'];
$hash = password_hash($pass_clair, PASSWORD_BCRYPT);
// $hash = "$2y$10$..." (long string de 60+ chars)
$stmt = $pdo->prepare("INSERT INTO users (pass_hash) VALUES (?)");
$stmt->execute([$hash]);

// 2. Connexion (Vérifier le hash)
$pass_clair_login = $_POST['password'];
$hash_bdd = $user['pass_hash'];

if (password_verify($pass_clair_login, $hash_bdd)) {
    // Mot de passe correct !
    $_SESSION['user_id'] = $user['id'];
} else {
    // Mot de passe incorrect
}
7.2 Déploiement (Apache & Nginx)
Apache (mod_php) & .htaccess

Souvent utilisé en hébergement mutualisé. Le .htaccess permet de configurer la "réécriture d'URL" (URL Rewriting) pour avoir de belles URLs (Front Controller).

# Fichier: /var/www/html/.htaccess
# (Assure que 'mod_rewrite' est activé)
RewriteEngine On

# Si le fichier ou dossier n'existe pas...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# ... tout rediriger vers 'index.php'
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

Toutes les requĂȘtes (/contact, /produit/123) sont envoyĂ©es Ă  index.php, qui peut ensuite router la demande (Pattern "Front Controller").

Nginx + FPM (Production)

La configuration Nginx (/etc/nginx/sites-available/default) doit savoir quels fichiers envoyer Ă  FPM.

server {
    listen 80;
    server_name ideolab.com;
    root /var/www/html/public; # Racine (souvent 'public')

    # Fichier d'index
    index index.php index.html;
    
    # "Front Controller" (belles URLs)
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # C'est la partie clé :
    # Envoyer les scripts .php Ă  FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        
        # Socket UNIX (plus rapide)
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        
        # (Alternative: TCP)
        # fastcgi_pass 127.0.0.1:9000;
    }
    
    # Interdire l'accÚs aux .htaccess (sécurité)
    location ~ /\.ht {
        deny all;
    }
}
8.1 Cheat-sheet PHP
Syntaxe & Variables
<?php ... ?>
<?= $variable ?> // (echo)

$var = "valeur";
$var = 10;
$var = true;
$var = null;

// Concaténation
$str = "a" . "b";
$str .= "c";

// Interpolation
echo "Val: $var";

// Constantes
define("MA_CONSTANTE", 123);
const MA_CONST_2 = 456;

// Debug
var_dump($var);
print_r($array);
Fonctions (Top 10)
// Vérification
isset($var); // Existe et n'est pas null
empty($var); // (0, "", "0", [], null)

// String
$len = strlen($str);
$pos = strpos($str, "mot");
$str = str_replace("a", "b", $str);
$str = substr($str, 0, 10); // (début, longueur)
$str = strtolower($str);
$str = strtoupper($str);
$str = trim($str); // Retire espaces début/fin

// Array
$count = count($array);
$str = implode(", ", $array);
$array = explode(", ", $str);
in_array("val", $array);
array_push($array, "val");

// Fichier / JSON
$data = file_get_contents("file.txt");
file_put_contents("file.txt", $data);
$json = json_encode($array_or_obj);
$data = json_decode($json, true); // true = array

// Sécurité
$safe_html = htmlspecialchars($input);
$hash = password_hash($pass, PASSWORD_BCRYPT);
$ok = password_verify($pass, $hash);