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

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)