Apprendre PHP pour débutants (résumé par Luc Makwani ) COMADEV RDC

 Résumé sur PHP par COMADEV RDC 

Dispensé par Luc Makwani 

Blog : https://nazateprod.blogspot.com


Lien de la plateforme pour en savoir plus : https://www.w3schools.com

1. Qu’est-ce que PHP ? - Le tout premier script

Idée clé

PHP est un langage de script côté serveur : le code s’exécute sur le serveur web et renvoie du HTML au navigateur.

<?php

// premier script :

echo "Bonjour, monde !";

?>

Quiz

1. Où s’exécute le code PHP ?

2. Quel mot-clé affiche du texte ?

Réponses

1. Sur le serveur (côté serveur).

2. echo.

 

2. Installer et lancer PHP localement

Idée clé

Windows/Mac/Linux : installez [XAMPP] ou [MAMP] qui embarquent Apache + PHP + MySQL.

Les fichiers .php vont dans le dossier htdocs (XAMPP) ou Sites.

Démarrez Apache puis ouvrez http://localhost/nomDuFichier.php.

Quiz

1. Quel logiciel lance le serveur web local ?

2. Quelle URL utilisez-vous pour tester ?

Réponses

1. Apache (via XAMPP/MAMP).

2. http://localhost/….

 

3. Syntaxe de base : balises, commentaires, variables

Idée clé

Tout code PHP est placé entre <?php ... ?>.

Commentaires : // (ligne) ou /* ... */ (bloc).

Variables : toujours préfixées par $.

<?php

$age = 25;             // variable entière

$nom = "Luc";          /* variable chaîne */

echo "$nom a $age ans.";

?>

Quiz

1. Quel symbole précède une variable ?

2. Comment écrire un commentaire sur une ligne ?

Réponses

1. $.

2. // commentaire.

 

4. Types et conversions simples

Idée clé

Types principaux : entier (int), nombre à virgule (float), booléen (bool), chaîne (string), tableau (array), objet (object), null (null). Conversion automatique, mais on peut forcer : (int)$str.

<?php

$prix = "19.99";          // string

$total = (float)$prix * 3;

var_dump($total);         // float(59.97)

?>

Quiz

1. Comment forcer $prix à devenir un nombre ?

2. Quel type retourne var_dump(true) ?

Réponses

1. (float)$prix ou (double)$prix.

2. bool(true).

 

5. Opérateurs essentiels

Catégorie Exemple Résultat

Arithmétique 3 ** 2 9

Affectation $x += 5 ajoute 5

Comparaison $a == $b égalité (valeur)

Identique $a === $b valeur et type

Logique && `

Quiz

1. Quelle différence entre == et === ?

2. Quel opérateur élève 3 au carré ?

Réponses

1. === compare valeur et type.

2. **.

 

6. Contrôle de flux : if, else, switch

<?php

$note = 14;

if ($note >= 10) {

    echo "Réussi";

} elseif ($note >= 8) {

    echo "Rattrapage";

} else {

    echo "Échoué";

}


$jour = 3;

switch ($jour) {

    case 1: echo "Lundi"; break;

    case 3: echo "Mercredi"; break;

    default: echo "Autre";

}

?>

Quiz

1. Quel mot-clé termine un bloc switch ?

2. Quelle structure choisir pour plusieurs conditions numériques fixes ?

Réponses

1. break (souvent).

2. switch.

 

7. Boucles : while, for, foreach

<?php

for ($i = 1; $i <= 3; $i++) {

    echo $i;

}


$fruits = ["pomme", "banane"];

foreach ($fruits as $f) {

    echo $f;

}

?>

Quiz

1. Quelle boucle parcourt facilement un tableau ?

2. Dans for, quelle partie s’exécute après chaque itération ?

Réponses

1. foreach.

2. L’incrément ($i++).

 

8. Fonctions

<?php

function carre(int $n): int {

    return $n * $n;

}

echo carre(4); // 16

?>

Quiz

1. Comment déclarer une fonction ?

2. À quoi sert : int après la parenthèse ?

Réponses

1. Avec function nom() {}.

2. À indiquer le type de retour (PHP 7+).

 

9. Tableaux (arrays)

<?php

// indexé

$nums = [10, 20];

// associatif

$personne = ["nom" => "Luc", "age" => 30];

// multidimensionnel

$notes = [

    "Math" => [12, 15],

    "Info" => [18, 20]

];

echo $personne["nom"];        // Luc

?>

Quiz

1. Comment accéder à la 2ᵉ note d’Info ?

2. Quelle fonction compte les éléments d’un tableau ?

Réponses

1. $notes["Info"][1] (index 0-based).

2. count($notes).

 

10. Variables superglobales (formulaires & URL)

Superglobale Usage rapide

$_GET données envoyées via URL

$_POST données de formulaire

$_SERVER infos serveur/entête

$_SESSION stockage par session

$_COOKIE stockage côté client

<?php

// url : exemple.php?nom=Luc

echo $_GET['nom'];

?>

Quiz

1. Quelle superglobale contient l’IP du client (REMOTE_ADDR) ?

2. Formulaire méthode POST : où lire les champs ?

Réponses

1. $_SERVER.

2. Dans $_POST.

 

11. Traiter un formulaire basique

HTML (form.html)

<form action="traitement.php" method="post">

  <input type="text" name="nom">

  <button>Envoyer</button>

</form>

PHP (traitement.php)

<?php

$nom = htmlspecialchars($_POST['nom'] ?? '');

echo "Bonjour $nom";

?>

Quiz

1. Pourquoi utiliser htmlspecialchars ?

2. Quelle méthode de formulaire masque les données dans l’URL ?

Réponses

1. Prévenir les attaques XSS.

2. POST.

 

12. Lire & écrire dans un fichier

<?php

file_put_contents("demo.txt", "Ligne 1\n", FILE_APPEND);

$contenu = file_get_contents("demo.txt");

echo nl2br($contenu);

?>

Quiz

1. Quel drapeau ajoute du texte sans écraser ?

2. Quelle fonction lit un fichier en chaîne ?

Réponses

1. FILE_APPEND.

2. file_get_contents.

 

13. Programmation orientée objet (OOP) en 60 s

<?php

class Compte {

    public float $solde = 0;

    public function deposer(float $mnt) {

        $this->solde += $mnt;

    }

}

$monCompte = new Compte();

$monCompte->deposer(50);

echo $monCompte->solde; // 50

?>

Quiz

1. Comment appelle-t-on une variable d’objet ?

2. Que signifie $this ?

Réponses

1. Propriété.

2. L’instance courante de la classe.

 

14. Gérer les erreurs

<?php

try {

    $x = 10 / 0;

} catch (DivisionByZeroError $e) {

    echo "Erreur : " . $e->getMessage();

}

?>

Quiz

1. Quel bloc entoure le code à risque ?

2. Quelle fonction définit le niveau d’affichage d’erreurs ?

Réponses

1. try { … }.

2. error_reporting() ou ini_set('display_errors',...).

 

15. Se connecter à MySQL en toute sécurité (PDO)

<?php

$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8", "user", "pass");

$sql = "SELECT * FROM users WHERE email = ?";

$stmt = $pdo->prepare($sql);

$stmt->execute([$_POST['email']]);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

?>

Quiz

1. Pourquoi utiliser prepare() ?

2. Quelle constante retourne un tableau associatif ?

Réponses

1. Pour éviter les injections SQL (requêtes préparées).

2. PDO::FETCH_ASSOC.

 

16. Premiers réflexes sécurité

Échapper toute sortie HTML : htmlspecialchars.

Valider / filtrer les entrées : filter_input.

Préparer vos requêtes SQL.

CSRF : tokens cachés dans les formulaires.

Sessions : session_start(); avant tout accès.

Quiz

1. Quelle fonction filtre une adresse e-mail ?

2. Où place-t-on session_start() ?

Réponses

1. filter_var($email, FILTER_VALIDATE_EMAIL).

2. Tout en haut du script, avant tout HTML.

 

17. Et après ?

Plongez dans la documentation officielle (php.net).

Testez les katas sur codewars.com ou exercism.org.

Explorez un micro-framework (Slim) puis Laravel.

Si vous visez WordPress, étudiez son API (hooks, thèmes, plugins).

Quiz final

1. Quelle ressource en ligne répertorie toutes les fonctions PHP ?

2. Quel framework MVC populaire repose sur PHP ?

Réponses

1. Le manuel officiel sur php.net.

2. Laravel.

 

Exercice complet : « Ajouter un contact »

(tout tient dans trois fichiers, fonctionne sous XAMPP/MAMP, MySQL ≥ 8.0 et Bootstrap 5.3.7)

 

1. Pré-requis (rapide)

Outil Pourquoi Où le trouver

XAMPP / MAMP Lance Apache + PHP + MySQL localement apachefriends.org / mamp.info

phpMyAdmin Créer vos bases/tables via l’interface graphique déjà inclus dans XAMPP/MAMP

Bootstrap 5.3.7 Mise en page réactive sans CSS « from scratch » CDN : https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css 

Navigateur Tester http://localhost/projet/index.php

 

2. Base de données à 2 champs

-- À exécuter dans phpMyAdmin (onglet SQL)

CREATE DATABASE tutoriel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE tutoriel;


CREATE TABLE contacts (

  id   INT PRIMARY KEY AUTO_INCREMENT,

  nom  VARCHAR(100) NOT NULL,

  email VARCHAR(150) NOT NULL UNIQUE

);

Le mot-clé AUTO_INCREMENT crée un identifiant unique automatiquement. 

 

3. Architecture du mini-projet

/projet

│ config.php       ← Connexion PDO

│ index.php        ← Formulaire Bootstrap

└ insert.php       ← Traitement + insertion

 

4. Fichier config.php

<?php

// ➜ adaptez login / mot de passe

$dsn  = 'mysql:host=localhost;dbname=tutoriel;charset=utf8mb4';

$user = 'root';

$pass = '';


try {

    $pdo = new PDO($dsn, $user, $pass, [

        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,

        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

    ]);

} catch (PDOException $e) {

    exit('Erreur de connexion : ' . $e->getMessage());

}

?>

Fonctionnalités clés

PDO fournit une interface unique pour MySQL, PostgreSQL, etc.

ATTR_ERRMODE = EXCEPTION déclenche une exception plutôt qu’un simple warning.

UTF-8 est forcé au niveau DSN pour éviter les soucis d’accents.

(voir la doc officielle de PDO::prepare pour le reste des bonnes pratiques) 

 

5. Fichier index.php – le formulaire Bootstrap

<?php require 'config.php'; ?>

<!doctype html>

<html lang="fr">

<head>

  <meta charset="utf-8">

  <title>Ajouter un contact</title>

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body class="container py-4">

  <h1 class="mb-4">Nouveau contact</h1>


  <form action="insert.php" method="post" class="row g-3 needs-validation" novalidate>

      <div class="col-md-6">

          <label for="nom" class="form-label">Nom</label>

          <input type="text" name="nom" id="nom" class="form-control" required>

          <div class="invalid-feedback">Nom obligatoire</div>

      </div>


      <div class="col-md-6">

          <label for="email" class="form-label">E-mail</label>

          <input type="email" name="email" id="email" class="form-control" required>

          <div class="invalid-feedback">E-mail valide requis</div>

      </div>


      <div class="col-12">

          <button class="btn btn-primary">Enregistrer</button>

      </div>

  </form>


  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js"></script>

  <!-- validation côté client Bootstrap -->

  <script>

  (() => {

      const forms = document.querySelectorAll('.needs-validation');

      Array.from(forms).forEach(form => {

          form.addEventListener('submit', e => {

              if (!form.checkValidity()) { e.preventDefault(); e.stopPropagation(); }

              form.classList.add('was-validated');

          }, false);

      });

  })();

  </script>

</body>

</html>

Les balises <form> / <input> sont standardisées par le W3C ; voir MDN pour le détail des attributs. 

 

6. Fichier insert.php – traitement sécurisé

<?php

require 'config.php';


$nom   = trim($_POST['nom']   ?? '');

$email = trim($_POST['email'] ?? '');


if ($nom === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {

    exit('Données invalides.');

}


$sql = "INSERT INTO contacts (nom, email) VALUES (?, ?)";

$stmt = $pdo->prepare($sql);      // requête préparée → protège des injections SQL

$stmt->execute([$nom, $email]);   // lie les paramètres et exécute


header('Location: index.php?ok=1');

exit;

?>

Fonctionnalités expliquées

Ligne Rôle

filter_var Valide côté serveur que l’e-mail est conforme RFC

prepare + execute Séparent la requête du contenu utilisateur ⇒ sécurité anti-injection SQL 

Redirection HTTP Empêche le double envoi si l’utilisateur recharge la page

 

7. Points essentiels pour un·e débutant·e

1. Affichage des erreurs

2. ini_set('display_errors', 1);

3. error_reporting(E_ALL);

Activez-les en local mais désactivez-les en production.

4. Structure MVC plus tard – Séparez la logique (PHP), la présentation (HTML/Bootstrap) et la base de données.

5. Composer :

6. composer init       # crée composer.json

7. composer require phpmailer/phpmailer

Gère les dépendances automatiquement.

8. Sécurité minimale

o htmlspecialchars() sur toute sortie issue d’un utilisateur.

o Jeton CSRF caché dans chaque formulaire.

o HTTPS obligatoire en production.

9. Charsets

o Base, tables et connexion en utf8mb4.

o Toujours préciser charset=utf8mb4 dans votre DSN.

10. Débogage PDO

11. $stmt->debugDumpParams();   // affiche la requête réelle + les valeurs liées

12. ``` 5

13.

 

8. Bibliothèques & ressources conseillées

Domaine Lib / Ressource Pourquoi

PHP PHP Manual (php.net) Référence exhaustive officielle 

Carbon (dates), PHPMailer (e-mails), Guzzle (HTTP) Outils courants, installables via Composer

MySQL MySQL 8.4 Reference Manual Syntaxe SQL, indexation, transactions 

mysqlsh (shell JSON, import/export) Administration moderne

HTML / DOM MDN Web Docs (HTML & Forms) Tutoriels, accessibilité, compatibilité 

Bootstrap getbootstrap.com docs (v5.3.x) Composants, utilitaires, JS toast, etc. 

Outils bonus VS Code + extensions PHP IntelliSense, PHP Debug Autocomplétion et pas-à-pas

 

🔧 1. STRUCTURE DU PROJET

/projet-crud/

├── config.php           ← connexion PDO

├── index.php            ← liste des contacts

├── ajouter.php          ← formulaire d’ajout

├── inserer.php          ← traitement ajout

├── modifier.php         ← formulaire prérempli

├── mettre_a_jour.php    ← traitement mise à jour

└── supprimer.php        ← suppression d’un contact

 

🛢️ 2. BASE DE DONNÉES

CREATE DATABASE tutoriel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;


USE tutoriel;


CREATE TABLE contacts (

  id INT AUTO_INCREMENT PRIMARY KEY,

  nom VARCHAR(100) NOT NULL,

  email VARCHAR(150) NOT NULL UNIQUE

);

 

⚙️ 3. config.php

<?php

$dsn = 'mysql:host=localhost;dbname=tutoriel;charset=utf8mb4';

$user = 'root'; // ton utilisateur

$pass = '';     // ton mot de passe


try {

    $pdo = new PDO($dsn, $user, $pass, [

        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC

    ]);

} catch (PDOException $e) {

    exit("Erreur de connexion : " . $e->getMessage());

}

?>

 

📄 4. index.php – Liste des contacts

<?php require 'config.php'; ?>

<!DOCTYPE html>

<html lang="fr">

<head>

    <meta charset="UTF-8">

    <title>Liste des contacts</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body class="container py-5">

    <h1 class="mb-4">📋 Liste des contacts</h1>


    <a href="ajouter.php" class="btn btn-success mb-3">➕ Ajouter un contact</a>


    <table class="table table-bordered table-striped">

        <thead class="table-dark">

            <tr><th>ID</th><th>Nom</th><th>Email</th><th>Actions</th></tr>

        </thead>

        <tbody>

            <?php

            $stmt = $pdo->query("SELECT * FROM contacts ORDER BY id DESC");

            foreach ($stmt as $row) {

                echo "<tr>

                        <td>{$row['id']}</td>

                        <td>{$row['nom']}</td>

                        <td>{$row['email']}</td>

                        <td>

                            <a href='modifier.php?id={$row['id']}' class='btn btn-sm btn-warning'>✏️</a>

                            <a href='supprimer.php?id={$row['id']}' class='btn btn-sm btn-danger' onclick='return confirm(\"Supprimer ce contact ?\")'>🗑️</a>

                        </td>

                      </tr>";

            }

            ?>

        </tbody>

    </table>

</body>

</html>

 

🆕 5. ajouter.php – Formulaire d’ajout

<!DOCTYPE html>

<html lang="fr">

<head>

    <meta charset="UTF-8">

    <title>Ajouter un contact</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body class="container py-5">

    <h2>➕ Nouveau contact</h2>

    <form action="inserer.php" method="post">

        <div class="mb-3">

            <label>Nom</label>

            <input type="text" name="nom" class="form-control" required>

        </div>

        <div class="mb-3">

            <label>Email</label>

            <input type="email" name="email" class="form-control" required>

        </div>

        <button class="btn btn-primary">Enregistrer</button>

    </form>

</body>

</html>

 

✅ 6. inserer.php – Insertion

<?php

require 'config.php';


$nom = trim($_POST['nom']);

$email = trim($_POST['email']);


if ($nom && filter_var($email, FILTER_VALIDATE_EMAIL)) {

    $sql = "INSERT INTO contacts (nom, email) VALUES (?, ?)";

    $stmt = $pdo->prepare($sql);

    $stmt->execute([$nom, $email]);

}


header("Location: index.php");

exit;

 

✏️ 7. modifier.php – Formulaire de modification

<?php

require 'config.php';

$id = $_GET['id'];

$stmt = $pdo->prepare("SELECT * FROM contacts WHERE id = ?");

$stmt->execute([$id]);

$contact = $stmt->fetch();


if (!$contact) exit("Contact introuvable !");

?>

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title>Modifier contact</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body class="container py-5">

    <h2>✏️ Modifier contact</h2>

    <form action="mettre_a_jour.php" method="post">

        <input type="hidden" name="id" value="<?= $contact['id'] ?>">

        <div class="mb-3">

            <label>Nom</label>

            <input type="text" name="nom" class="form-control" value="<?= htmlspecialchars($contact['nom']) ?>" required>

        </div>

        <div class="mb-3">

            <label>Email</label>

            <input type="email" name="email" class="form-control" value="<?= htmlspecialchars($contact['email']) ?>" required>

        </div>

        <button class="btn btn-primary">Mettre à jour</button>

    </form>

</body>

</html>

 

🔁 8. mettre_a_jour.php – Traitement de mise à jour

<?php

require 'config.php';


$id    = $_POST['id'];

$nom   = trim($_POST['nom']);

$email = trim($_POST['email']);


if ($id && $nom && filter_var($email, FILTER_VALIDATE_EMAIL)) {

    $sql = "UPDATE contacts SET nom = ?, email = ? WHERE id = ?";

    $stmt = $pdo->prepare($sql);

    $stmt->execute([$nom, $email, $id]);

}


header("Location: index.php");

exit;

 

❌ 9. supprimer.php – Suppression

<?php

require 'config.php';


$id = $_GET['id'] ?? null;

if ($id) {

    $stmt = $pdo->prepare("DELETE FROM contacts WHERE id = ?");

    $stmt->execute([$id]);

}


header("Location: index.php");

exit;

 

📚 À Apprendre pour approfondir

MySQL

MySQL Officiel

Types de données : INT, VARCHAR, TEXT, DATE, ENUM, etc.

Index, clés primaires et étrangères

Fonctions utiles : NOW(), CONCAT(), LEFT(), LIKE, GROUP BY, JOIN

PHP

Documentation PHP Officielle

Fonctions de manipulation de chaînes (strtoupper, substr, str_replace)

Sessions ($_SESSION)

Fichiers (fopen, file_put_contents, move_uploaded_file)

Sécurité : htmlspecialchars, password_hash, filter_var

HTML + Bootstrap

Bootstrap 5

MDN HTML

Formulaires : input, textarea, select, required, type=email

Classes utiles Bootstrap : container, form-control, btn, table, alert

 

1. Nouvelle arborescence

/projet-crud/

│ config.php

│ auth.php                 ← helpers session + protection

│ login.php                ← formulaire de connexion

│ register.php             ← inscription

│ logout.php

│ index.php                ← liste + recherche + pagination (protégé)

│ ajouter.php  inserer.php

│ modifier.php mettre_a_jour.php

└ supprimer.php

 

2. Schéma MySQL (ajout de la table users)

CREATE TABLE users (

  id INT AUTO_INCREMENT PRIMARY KEY,

  nom VARCHAR(100) NOT NULL,

  email VARCHAR(150) NOT NULL UNIQUE,

  password_hash VARCHAR(255) NOT NULL,

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);

Le mot de passe est stocké chiffré avec password_hash 

 

3. auth.php – sessions et garde-barrière

<?php

if (session_status() === PHP_SESSION_NONE) {

    session_start();                              // lance / reprend la session

}


function is_logged_in(): bool {

    return isset($_SESSION['user_id']);

}


function require_login(): void {

    if (!is_logged_in()) {

        header('Location: login.php');

        exit;

    }

}

?>

session_start() crée ou reprend la session en toute sécurité ; toutes les pages protégées l’appellent. 

 

4. register.php – inscription

<?php

require 'config.php';

require 'auth.php';


if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $nom     = trim($_POST['nom']   ?? '');

    $email   = trim($_POST['email'] ?? '');

    $pass    = $_POST['password']   ?? '';


    if ($nom && filter_var($email, FILTER_VALIDATE_EMAIL) && strlen($pass) >= 6) {

        $hash = password_hash($pass, PASSWORD_DEFAULT);

        $stmt = $pdo->prepare('INSERT INTO users (nom,email,password_hash) VALUES (?,?,?)');

        $stmt->execute([$nom, $email, $hash]);

        header('Location: login.php?inscrit=1');

        exit;

    }

}

?>

<!doctype html><html lang="fr"><head>

<meta charset="utf-8"><title>Inscription</title>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head><body class="container py-5">

<h2>Créer un compte</h2>

<form method="post" class="col-md-6">

    <div class="mb-3"><label>Nom</label><input class="form-control" name="nom" required></div>

    <div class="mb-3"><label>E-mail</label><input class="form-control" type="email" name="email" required></div>

    <div class="mb-3"><label>Mot de passe (≥ 6 car.)</label><input class="form-control" type="password" name="password" required></div>

    <button class="btn btn-primary">S’inscrire</button>

    <a href="login.php" class="btn btn-link">Déjà inscrit ?</a>

</form>

</body></html>

 

5. login.php / logout.php

login.php

<?php

require 'config.php';

require 'auth.php';


if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $email = trim($_POST['email'] ?? '');

    $pass  = $_POST['password']   ?? '';


    $stmt = $pdo->prepare('SELECT id,password_hash FROM users WHERE email = ?');

    $stmt->execute([$email]);

    $user = $stmt->fetch();


    if ($user && password_verify($pass, $user['password_hash'])) {   // vérifie le hash

        $_SESSION['user_id'] = $user['id'];

        header('Location: index.php');

        exit;

    }

    $erreur = 'Identifiants invalides';

}

?>

<!doctype html><html lang="fr"><head>

<meta charset="utf-8"><title>Connexion</title>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head><body class="container py-5">

<h2>Se connecter</h2>

<?php if (!empty($erreur)) echo "<div class='alert alert-danger'>$erreur</div>"; ?>

<form method="post" class="col-md-6">

    <div class="mb-3"><label>E-mail</label><input class="form-control" type="email" name="email" required></div>

    <div class="mb-3"><label>Mot de passe</label><input class="form-control" type="password" name="password" required></div>

    <button class="btn btn-primary">Connexion</button>

    <a href="register.php" class="btn btn-link">Créer un compte</a>

</form>

</body></html>

logout.php

<?php

require 'auth.php';

session_destroy();

header('Location: login.php');

exit;

 

6. index.php – recherche + pagination (protégé)

<?php

require 'config.php';

require 'auth.php';

require_login();                      // ▶︎ redirige vers login si non connecté


$limit = 5;                           // 5-lignes par page

$page  = max(1, (int)($_GET['p'] ?? 1));

$offset = ($page - 1) * $limit;


$search = trim($_GET['q'] ?? '');

$params = [];

$where  = '';


if ($search !== '') {

    $where  = 'WHERE nom LIKE ? OR email LIKE ?';

    $like   = "%$search%";

    $params = [$like, $like];

}


/* total pour pagination */

$stmt = $pdo->prepare("SELECT COUNT(*) FROM contacts $where");

$stmt->execute($params);

$total = (int)$stmt->fetchColumn();

$pages = (int)ceil($total / $limit);


/* données à afficher */

$sql = "SELECT * FROM contacts $where ORDER BY id DESC LIMIT $limit OFFSET $offset";

$stmt = $pdo->prepare($sql);

$stmt->execute($params);

$contacts = $stmt->fetchAll();

?>

<!doctype html><html lang="fr"><head>

<meta charset="utf-8"><title>Contacts</title>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

</head><body class="container py-5">


<div class="d-flex justify-content-between align-items-center mb-4">

  <h1 class="m-0">📋 Contacts</h1>

  <div>

    <a href="ajouter.php" class="btn btn-success">➕ Ajouter</a>

    <a href="logout.php" class="btn btn-outline-secondary">Déconnexion</a>

  </div>

</div>


<form class="input-group mb-3" method="get">

  <input type="text" class="form-control" placeholder="Rechercher nom ou e-mail…" name="q" value="<?= htmlspecialchars($search) ?>">

  <button class="btn btn-outline-secondary">🔍</button>

</form>


<table class="table table-bordered">

  <thead class="table-dark"><tr><th>ID</th><th>Nom</th><th>Email</th><th>Actions</th></tr></thead>

  <tbody>

  <?php foreach ($contacts as $c): ?>

    <tr>

      <td><?= $c['id'] ?></td>

      <td><?= htmlspecialchars($c['nom']) ?></td>

      <td><?= htmlspecialchars($c['email']) ?></td>

      <td>

        <a href="modifier.php?id=<?= $c['id'] ?>" class="btn btn-sm btn-warning">✏️</a>

        <a href="supprimer.php?id=<?= $c['id'] ?>"

           class="btn btn-sm btn-danger"

           onclick="return confirm('Supprimer ce contact ?')">🗑️</a>

      </td>

    </tr>

  <?php endforeach; ?>

  </tbody>

</table>


<!-- pagination Bootstrap -->

<nav aria-label="Pagination">

  <ul class="pagination">

    <?php if ($page > 1): ?>

      <li class="page-item"><a class="page-link" href="?q=<?= urlencode($search) ?>&p=<?= $page-1 ?>">«</a></li>

    <?php endif; ?>


    <?php for ($i = 1; $i <= $pages; $i++): ?>

      <li class="page-item <?= $i == $page ? 'active' : '' ?>">

        <a class="page-link" href="?q=<?= urlencode($search) ?>&p=<?= $i ?>"><?= $i ?></a>

      </li>

    <?php endfor; ?>


    <?php if ($page < $pages): ?>

      <li class="page-item"><a class="page-link" href="?q=<?= urlencode($search) ?>&p=<?= $page+1 ?>">»</a></li>

    <?php endif; ?>

  </ul>

</nav>


<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js"></script>

</body></html>

La structure suit le composant « Pagination » Bootstrap 5. 

 

7. Aides-mémoire & bonnes pratiques

Sujet Point-clés Références

Hash mot de passe password_hash, password_verify, re-hash via password_needs_rehash

Sessions Démarrer tôt, toujours régénérer l’ID après connexion (session_regenerate_id)

Recherche LIKE Utiliser ? + %val% (requête préparée) ⇒ protège contre injections (voir code)

Pagination SQL LIMIT … OFFSET … ; compter total via COUNT(*)

 




Commentaires

COMADEV Luc Makwani | Technicien IT & Web Designer

Je transforme les idées en solutions numériques

Technicien IT • Web Designer • Créateur digital

Me contacter +243 85 8184794

À propos

Luc Makwani est un professionnel du numérique basé à Kinshasa. Il accompagne les entreprises et particuliers dans leurs projets technologiques : développement web, design web, IA générative, gestion de pages réseaux sociaux et marketing digital, maintenance informatique et communication digitale.

Mes services

Développement Web

Sites modernes, WordPress, HTML, CSS, JavaScript, PHP et bases de données.

Design Digital

Création graphique, retouche photo, identité visuelle et contenus numériques.

Solutions IT

Maintenance informatique, réseaux, installation et assistance technique.

© Luc Makwani - COMADEV RDC

Wikipedia

Résultats de recherche

Pour Tout Projet Web | COMADEV RDC

Pour Tout Projet Web  | COMADEV RDC
Contactez-nous maintenant +243 858184794

Articles les plus consultés

Les signes astrologiques (zodiaques) mois, signification et éléments #nazate

Le serpent Mamba noir ( son histoire) #Nazate

Assainissement cours

Un autre regard pour l'environnement

Sueurs froides ; le résumé

Comment réussir ses études universitaires

Mauvaises actions de l'homme sur l'environnement

La Fibre optique

La solution contre le Corona Virus : ManaCovid. par les chercheurs Etienne BATANGU et Mamyssa BATANGU de la RDC. #Nazate official (version française)

Contactez nous

Nom

E-mail *

Message *