đ PHP â Installation, Syntaxe & ĂcosystĂšme
Guide complet IDEOâLab pour maĂźtriser PHP, du script simple Ă l'architecture FPM moderne.
Vue d'ensemble
Qu'est-ce que PHP ? CÎté serveur, LAMP.
Server-side Web InterprétéArchitecture Web
mod_php (Apache) vs PHP-FPM (Nginx).
LAMP PHP-FPM NginxInstallation
Linux (PPA), WAMP/XAMPP, Docker (reco).
apt WAMP DockerSyntaxe & Variables
Balises <?php, $variable, echo, commentaires.
Types & Opérateurs
string, int, bool. == vs ===, ?? (null).
Structures de ContrĂŽle
if/else, switch, for, while, foreach.
Fonctions & Scope
function(), return, scope, closures, fléchées.
Tableaux (Arrays)
Indexés, Associatifs (clé=>valeur).
array Associatif []Fonctions d'Arrays
array_map, filter, reduce, implode, explode.
Superglobals (Formulaires)
$_GET, $_POST, $_SERVER.
Sessions & Cookies
$_SESSION, session_start(), setcookie().
Fichiers & Uploads
file_get_contents, $_FILES, move_uploaded_file.
POO : Classes & Objets
class, new, $this, __construct, public/private.
POO : Héritage & Interfaces
extends, implements, abstract, final.
POO : Avancé
namespace, use, traits, méthodes magiques.
Composer (Dépendances)
Gestionnaire de paquets, autoloading (PSR-4).
Composer autoload PSR-4Base de Données (PDO)
Connexion (DSN), try/catch, DBeaver.
RequĂȘtes (PDO)
RequĂȘtes prĂ©parĂ©es (prepare, execute), fetch.
Sécurité
Injections SQL, XSS, password_hash().
Déploiement
Configuration Apache & Nginx+FPM.
Apache Nginx PHP-FPMCheat-sheet PHP
Syntaxe fréquente & fonctions clés.
cheat syntaxLe 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Ăšre | PHP (avec Apache/FPM) | Node.js (avec Express) | Python (avec Django/Flask) |
|---|---|---|---|
| Paradigme | Synchrone (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'usage | Sites de contenu, CMS, applications métiers. | APIs temps-réel, WebSockets, microservices. | Applications complexes, Data Science, IA. |
| ĂcosystĂšme | Packagist (Composer) | NPM | PyPI (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.
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.
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).
- Allez sur apachefriends.org
- Téléchargez et lancez l'installeur XAMPP.
- Lancez le "XAMPP Control Panel".
- Cliquez "Start" sur Apache et "Start" sur MySQL.
- Placez vos fichiers PHP dans
C:\xampp\htdocs\ - 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.
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)
Types de Données (Typage Dynamique)
| Type | Exemple |
|---|---|
| string | "Bonjour", 'Bonjour' |
| integer | 10, -5 |
| float | 10.5, -0.1 |
| boolean | true, false |
| array | [1, "deux"], ["cle" => "val"] |
| object | new MaClasse() |
| null | null (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)
| Type | Opérateurs | Exemple |
|---|---|---|
| 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'; |
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"
}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 15PHP 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);
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); // 42. 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";
}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"]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é | Exemple | Description |
|---|---|---|
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']; ?>
$_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 :
session_start(): PHP crée un ID de session unique (ex:abc123).- PHP envoie cet ID au client via un Cookie (ex:
PHPSESSID=abc123). - PHP stocke les données (
$_SESSION['user_id'] = 10;) sur le **serveur** (ex:/tmp/sess_abc123). - Ă la page suivante,
session_start()lit le cookiePHPSESSID, trouve le fichiersess_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']);
?>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.";
}
}
?>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(); // 150static
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);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(); // 4ProblĂš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éthode | Dé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()). |
Le "npm" ou "pip" de PHP
Composer est l'outil indispensable du PHP moderne. Il gĂšre :
- Les Dépendances : (Librairies externes, ex: un logger, un client HTTP). Il les télécharge depuis Packagist.org.
- 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éé.');
?>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
}
?>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();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, <script>...</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
}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;
}
}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);