Technologies Web - GLIRT INSAT

Le Resume Ultime
du WebDev

HTML, CSS, JavaScript, PHP, Git et Symfony expliques simplement: imagine que le Web est un restaurant. HTML construit les tables, CSS les decore, JS fait bouger les serveurs, PHP cuisine cote serveur, Git garde l'historique, Symfony organise toute la cuisine.

La grande carte mentale

Ne memorise pas en vrac. Range chaque notion dans son etage, sinon ton cerveau fait un gros panier melange.

Le Web en une histoire tres simple

Navigateur --requete HTTP--> Serveur Navigateur <--reponse HTML/CSS/JS-- Serveur HTML = squelette de la page CSS = habits et couleurs JS = actions dans le navigateur PHP = logique cote serveur BD = grand cahier ou on garde les donnees Symfony = usine bien rangee pour PHP
Idee fausse a jeter HTML n'est pas un langage de programmation. Il ne calcule pas. Il decrit. Dire "je programme en HTML" dans un examen, c'est techniquement faible.

Front-end

C'est ce que l'utilisateur voit et touche: HTML, CSS, JS, formulaires, boutons, couleurs, evenements.

Navigateur DOM UI

Back-end

C'est la cuisine cachee: PHP, controleurs, sessions, base de donnees, securite, reponses serveur.

PHP Symfony HTTP

Outils

Git garde les versions. Composer installe les paquets. Doctrine parle a la base comme si c'etait des objets.

Git Composer ORM

HTML5: les briques de la maison

HTML dit au navigateur: "ceci est un titre", "ceci est une image", "ceci est un formulaire". Il ne choisit pas la beaute, il choisit le sens.

Structure minimale

<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <title>Ma page</title> </head> <body> <h1>Titre principal</h1> <p>Un paragraphe.</p> </body> </html>
Version enfant Le head, c'est l'etiquette sur la boite. Le body, c'est ce qu'il y a dans la boite.

Balises a connaitre

  • h1 a h6: titres, du plus important au plus petit.
  • p: paragraphe.
  • a href: lien vers une autre page, un endroit de la meme page, ou une ressource.
  • img src alt: image avec texte alternatif obligatoire pour l'accessibilite.
  • ul, ol, li: listes.
  • table, tr, th, td: tableau.

HTML5 semantique

Les balises semantiques donnent du sens, pas juste une forme.

BaliseImage simple
headerLe panneau d'entree.
navLa carte des chemins.
mainLe contenu principal.
sectionUn chapitre.
articleUn contenu autonome.
footerLe bas de page.

Formulaires: la boite ou l'utilisateur met des infos

<form action="/traiter.php" method="post"> <label for="email">Email</label> <input id="email" name="email" type="email" required> <button type="submit">Envoyer</button> </form>

GET

Les donnees voyagent dans l'URL. Bien pour chercher ou filtrer.

POST

Les donnees voyagent dans le corps de la requete. Bien pour inscrire, modifier, envoyer un formulaire.

Piege examen GET n'est pas "securise" juste parce que ca marche. Il affiche les donnees dans l'URL. Pour mot de passe ou inscription, pense POST.

CSS3: habiller la maison

CSS prend les briques HTML et decide leur apparence: taille, couleur, position, bordure, ombre, espace.

La cascade: qui gagne quand deux regles se battent ?

  1. Importance
    Une regle !important crie tres fort, mais n'en abuse pas.
  2. Specificite
    #id gagne souvent contre .classe, qui gagne contre une balise simple.
  3. Ordre
    Si deux regles ont la meme force, la derniere ecrite gagne.

Selecteurs a maitriser

SelecteurSignificationExemple enfant
pTous les paragraphesTous les bonbons rouges.
.noteElements avec class noteTous ceux qui portent un badge.
#menuElement avec id menuLe seul enfant appele menu.
a[href*="insat"]Liens dont href contient insatTout lien avec ce mot dedans.
p:hoverQuand la souris passe dessusLe bouton change quand tu le touches.
li:first-childPremier enfantLe premier dans la file.
Question web25 typique .paragraphe selectionne une classe. #paragraphe selectionne un id. Si le HTML a une classe et ton JS cherche un id, il ne trouve rien.

Box model

content = le jouet padding = le coussin autour du jouet border = la boite margin = l'espace avec les autres boites

Avec box-sizing: border-box, la largeur inclut le padding et la bordure. C'est plus simple.

Couleurs, fonds, bordures

  • color: couleur du texte.
  • background: fond.
  • border-radius: coins arrondis.
  • box-shadow: ombre.
  • font-family: police, avec plusieurs choix de secours.

JavaScript: faire bouger la page

JavaScript parle au navigateur. Il peut lire la page, changer les styles, reagir au clic, calculer, afficher dans la console.

Variables: petites boites avec des noms

MotRolePiege
letVariable qui peut changerExiste dans son bloc.
constReference qui ne change pasUn tableau const peut encore changer son contenu.
varAncienne variableHoisting: elle monte en haut et vaut undefined au debut.
var x = 3; function f() { console.log(x); // undefined: le var local est hisse var x = 7; console.log(x); // 7 }

Syntaxe JS de base: lire du code sans paniquer

// 1) Condition: si / sinon const age = 19; if (age >= 18) { console.log("majeur"); } else { console.log("mineur"); } // 2) Boucle: repeter const notes = [12, 15, 9]; for (let i = 0; i < notes.length; i++) { console.log(notes[i]); } // 3) Fonction: petite machine reutilisable function somme(a, b) { return a + b; } console.log(somme(2, 3)); // 5
Version enfant Une variable est une boite. Une condition est une porte: si la condition est vraie, tu passes. Une boucle est un tapis roulant: elle repete la meme action.

Conversions automatiques

console.log("2" + "3"); // "23" console.log("2" - "3"); // -1

+ avec des textes colle. - force les nombres. C'est bizarre, mais l'examen adore ce piege.

Tableaux

const tab = [11, 4, 21, 3, 31, 13, 0, 1]; tab.sort(); // tri alphabetique par defaut // [0, 1, 11, 13, 21, 3, 31, 4]

Pour trier des nombres correctement: tab.sort((a, b) => a - b).

Fonctions: declaration, expression, flechee

// Declaration: utilisable meme avant sa ligne grace au hoisting function double(x) { return x * 2; } // Expression: stockee dans une variable const triple = function (x) { return x * 3; }; // Fonction flechee: version courte const carre = (x) => x * x; console.log(double(4)); // 8 console.log(triple(4)); // 12 console.log(carre(4)); // 16
Piege prof Une fonction qui ne fait que console.log() affiche quelque chose, mais retourne undefined si elle n'a pas de return. C'est exactement le genre de detail qui casse les QCM.

Objets et classes en JS

// Objet simple: sac avec des proprietes const user = { nom: "Aymen", age: 20, saluer: function () { return "Bonjour " + this.nom; } }; console.log(user.nom); // Aymen console.log(user["age"]); // 20 console.log(user.saluer()); // Bonjour Aymen // Classe JS: moule pour fabriquer plusieurs objets class Etudiant { constructor(nom, section) { this.nom = nom; this.section = section; } presenter() { return this.nom + " est en " + this.section; } } const e1 = new Etudiant("Aymen", "GLIRT"); console.log(e1.presenter());
Detail important Dans une methode, this veut dire "l'objet actuel". Si tu perds this, c'est comme parler d'un enfant sans dire lequel.

DOM et evenements

const para = document.querySelector("p"); // le premier p seulement para.addEventListener("mouseover", function () { para.style.fontSize = "30px"; }); para.addEventListener("mouseout", function () { para.style.fontSize = "15px"; });
Debunk direct Si tu dis "ca modifie tous les paragraphes", c'est faux. querySelector("p") prend le premier. Pour tous, il faut querySelectorAll("p") puis une boucle.

PHP: la cuisine cote serveur

PHP s'execute sur le serveur. Le navigateur ne voit pas ton PHP, il recoit seulement le HTML que PHP fabrique.

Superglobales

  • $_GET: infos envoyees dans l'URL.
  • $_POST: infos envoyees dans le corps de la requete.
  • $_SESSION: infos gardeess pour un utilisateur connecte.
  • $_COOKIE: petite info gardee chez le navigateur.
  • $_FILES: fichiers envoyes par formulaire.

Sessions

session_start(); $_SESSION["nomUser"] = "Aymen"; if (isset($_SESSION["nomUser"])) { echo "Bienvenue " . $_SESSION["nomUser"]; }

Une session, c'est comme un bracelet d'entree: le serveur reconnait l'utilisateur d'une page a l'autre.

Comment une session PHP marche vraiment

Une session PHP garde des donnees sur le serveur. Le navigateur garde seulement un petit identifiant, souvent dans un cookie appele PHPSESSID. Donc le navigateur dit "je suis le ticket 123", et le serveur retrouve le bon petit tiroir de donnees.

  1. Demarrer
    session_start() lit ou cree la session. Fais-le avant d'afficher du HTML.
  2. Ecrire
    $_SESSION["nom"] = "Aymen" met une valeur dans le tiroir de cet utilisateur.
  3. Lire
    isset($_SESSION["nom"]) verifie si la valeur existe avant de l'utiliser.
  4. Proteger
    Si l'utilisateur n'est pas connecte, tu le rediriges vers login.php.
  5. Deconnecter
    Tu vides $_SESSION, tu detruis la session, puis tu supprimes le cookie si besoin.
Piege tres classique Si tu oublies session_start(), $_SESSION ne travaille pas correctement. C'est comme chercher un cahier sans ouvrir le cartable.

Mini-systeme login avec session

1. Connexion

<?php // login.php session_start(); if ($_POST["email"] === "aymen@insat.tn" && $_POST["password"] === "1234") { $_SESSION["user"] = [ "email" => $_POST["email"], "role" => "ROLE_USER" ]; header("Location: profile.php"); exit; } echo "Email ou mot de passe incorrect";

2. Page protegee

<?php // profile.php session_start(); if (!isset($_SESSION["user"])) { header("Location: login.php"); exit; } echo "Bienvenue " . $_SESSION["user"]["email"];

3. Deconnexion propre

<?php // logout.php session_start(); $_SESSION = []; if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie( session_name(), "", time() - 3600, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } session_destroy(); header("Location: login.php"); exit;
Version enfant Login met ton nom dans le cahier. La page protegee verifie si ton nom est dans le cahier. Logout arrache la page du cahier.

Sessions: erreurs a ne pas faire

ErreurPourquoi c'est fauxCorrection
Afficher du HTML avant session_start() PHP doit envoyer les headers/cookies avant le contenu. Mettre session_start() tout en haut.
Utiliser $_SESSION["x"] sans verifier Si la cle n'existe pas, tu risques warning ou logique fausse. Utiliser isset($_SESSION["x"]).
Faire header("Location: ...") sans exit Le script peut continuer apres la redirection. Ajouter exit; juste apres.
Stocker le mot de passe en session Inutile et dangereux. Stocker id, email, role; jamais le mot de passe brut.

Fonctions et references

function sommeProduit($som, &$prod, $x, $y) { $som = $x + $y; // copie: ne change pas $s dehors $prod = $x * $y; // reference: change $p dehors } $s = 0; $p = 0; sommeProduit($s, $p, -3.4, 2); // $s = 0 et $p = -6.8
Version enfant Sans &, tu donnes une photocopie. Avec &, tu donnes le vrai cahier, donc la fonction peut ecrire dedans.

PHP Objet

ConceptExplication simplePiege
ClasseLe moule a gateau.Ce n'est pas encore un objet.
ObjetLe gateau cree avec le moule.== compare les valeurs, === compare la meme instance.
StaticAppartient a la classe.$this n'existe pas dans une methode static.
AbstractClasse incomplete qui sert de base.On ne l'instancie pas directement.
InterfaceContrat de methodes.Elle impose ce qu'une classe doit fournir.
TraitMorceau de code reutilisable.Ce n'est pas une vraie relation d'heritage.

Classe PHP complete: le moule, puis l'objet

<?php class User { // Proprietes = les donnees de l'objet private string $name; private string $email; // Constructeur = appele quand on fait new User(...) public function __construct(string $name, string $email) { $this->name = $name; $this->email = $email; } // Getter = lire une propriete privee public function getName(): string { return $this->name; } // Setter = modifier une propriete privee public function setEmail(string $email): void { $this->email = $email; } public function presenter(): string { return "Je suis " . $this->name; } } $user = new User("Aymen", "aymen@insat.tn"); echo $user->getName(); echo $user->presenter();
Version enfant class User est le moule. new User(...) fabrique un vrai objet. $this veut dire "cet objet-la, celui qu'on vient de fabriquer".

Visibilite: public, private, protected

MotQui peut toucher ?Image simple
publicTout le monde.Objet pose sur la table.
privateSeulement la classe elle-meme.Journal intime ferme.
protectedLa classe et ses enfants.Cahier de famille.
class Compte { private float $solde = 0; public function deposer(float $montant): void { if ($montant > 0) { $this->solde += $montant; } } } $c = new Compte(); $c->deposer(50); // $c->solde = 999999; // interdit: solde est private
Debunk direct Mettre toutes les proprietes en public parce que "c'est plus facile" est une mauvaise habitude. Tu casses l'encapsulation: n'importe quel code peut mettre l'objet dans un etat idiot.

Static: appartient a la classe, pas a l'objet

class Compteur { public static int $nb = 0; public function __construct() { self::$nb++; } public static function combien(): int { return self::$nb; // Pas de $this ici: on n'est pas dans un objet precis. } } new Compteur(); new Compteur(); echo Compteur::combien(); // 2
Piege web25 Dans une methode static, $this n'existe pas. Utilise self:: pour la classe actuelle ou static:: pour le late static binding.

Heritage et abstract

abstract class Personne { public function __construct(protected string $nom) {} abstract public function role(): string; } class Etudiant extends Personne { public function role(): string { return "Etudiant: " . $this->nom; } } $e = new Etudiant("Aymen"); echo $e->role();

Une classe abstraite est un moule incomplet. Elle force les enfants a terminer certaines methodes.

Interface et trait

interface Payable { public function payer(float $montant): bool; } trait Horodatage { public function maintenant(): string { return date("Y-m-d H:i:s"); } } class Facture implements Payable { use Horodatage; public function payer(float $montant): bool { return $montant > 0; } }

Une interface est un contrat. Un trait est un morceau de code colle dans une classe.

Securite minimale Pour eviter l'injection SQL, utilise des requetes preparees. Ne colle jamais directement une saisie utilisateur dans une requete SQL.

Git: la machine a remonter le temps

Git garde les versions de ton projet. Si tu casses quelque chose, tu peux comprendre quand, ou, et par qui.

Le cycle vital

git status # voir ce qui a change git add fichier.html # mettre dans le panier git commit -m "message" # prendre une photo du panier git log # voir les photos git diff # voir les changements exacts

Branches

Une branche, c'est une route parallele. Tu testes une idee sans casser la route principale.

git branch feature-login git switch feature-login git merge feature-login

Depot distant

Le remote, c'est le cartable partage sur internet, souvent GitHub.

git remote -v git push git pull
Conflit Un conflit arrive quand deux personnes modifient la meme zone. Git ne devine pas le bon choix. Toi, tu dois lire et decider.

Symfony: PHP bien range

Symfony evite le code spaghetti. Il range les routes, controleurs, templates, formulaires, base de donnees et securite.

Le voyage d'une requete

  1. L'utilisateur demande une URL
    Exemple: /article/5.
  2. Le routeur cherche la bonne route
    Il lit les attributs, YAML, XML ou PHP.
  3. Le controleur agit
    Il recupere les donnees, appelle les services, prepare la reponse.
  4. Twig affiche
    Le template transforme les variables en HTML propre.
  5. Doctrine parle a la BD si besoin
    Repository pour lire, EntityManager pour ajouter/modifier/supprimer.

Routing

#[Route("/Examen/{year<\\d{2}>}/{univ?insat}")] public function exam(string $year, string $univ) { ... }

year<\\d{2}> veut exactement deux chiffres. Donc /Examen/24 marche, /Examen/2024 ne marche pas.

Controleur

#[Route("/hello", name: "hello")] public function hello(): Response { return $this->render("hello/index.html.twig", [ "name" => "GLIRT" ]); }

Le controleur est le chef de table: il recoit la demande et choisit quoi renvoyer.

Twig

SyntaxeRole
{{ variable }}Afficher une variable.
{% if condition %}Executer une instruction.
{% extends "base.html.twig" %}Heriter d'un template parent.
{% block body %}Zone remplacable par l'enfant.
{{ parent() }}Recuperer le contenu du bloc parent.
{{ path("route") }}Generer une URL interne relative.
{{ absolute_url(path("route")) }}Generer un lien complet, utile pour email.
Piege enfant/parent Dans Twig, parent() s'affiche avec {{ }}, pas avec {% %}, parce qu'il produit du contenu.

Doctrine: ORM + Unit of Work

Doctrine te laisse manipuler des objets PHP, puis il synchronise avec les tables SQL.

$user = new User(); $user->setEmail("aymen@insat.tn"); $entityManager->persist($user); // prepare $entityManager->flush(); // execute en BD

Repository

Lit la BD: find, findAll, findBy, requetes select.

EntityManager

Ecrit dans la BD: persist, remove, flush.

Transaction Doctrine Plusieurs insert/update/delete dans un flush() sont regroupes. Si une operation echoue, tout est annule. C'est pour ca que deux emails uniques identiques donnent "aucun user ajoute".

Migrations et fixtures

  • Migration: photo de l'evolution de la structure BD. Permet avancer ou revenir entre versions.
  • Fixture: donnees de depart ou de test pour remplir la BD.

Relations Doctrine

  • ManyToMany cree une table de jointure automatiquement.
  • Si la relation a ses propres champs, cree une entite intermediaire.
  • Une relation n'est pas obligee d'etre bidirectionnelle.

Formulaires Symfony

ElementRole
createForm / createFormBuilderConstruire le formulaire.
handleRequest($request)Prendre les donnees de la requete et les mettre dans l'objet.
isSubmitted()Verifier si le formulaire a ete envoye.
isValid()Lancer/verifier la validation.
mapped => falseChamp sans propriete correspondante dans l'entite.
query_builderPersonnaliser la liste d'un champ lie a une entite.
Correction importante Un formulaire Symfony n'est pas toujours associe a une entite. Il peut aussi recuperer des informations independantes.

Securite Symfony

  • User Provider: charge l'utilisateur.
  • Authenticator: verifie l'identite.
  • access_control: protege les routes par roles.
  • role_hierarchy: un role peut heriter d'autres roles.
access_control: - { path: ^/admin, roles: ROLE_ADMIN } - { path: ^/profile/delete, roles: ROLE_ADMIN } - { path: ^/profile, roles: ROLE_USER }

Symfony lit les controles d'acces de haut en bas et prend le premier qui correspond. Pour /profile/delete, c'est ROLE_ADMIN.

web25 QCM corrige

Le scan est une image OCRisee. J'ai reconstruit les questions lisibles et corrige les pieges selon les cours du workspace.

Regle de l'examen Chaque question peut avoir 0 ou plusieurs bonnes reponses. Ne cherche pas "la seule bonne case" par habitude: certaines questions ont plusieurs cases.

Corrige rapide Q1 - Q40

QReponsePourquoi, version tres simple
1CEmail unique + flush transactionnel: si le deuxieme casse, tout est annule.
2BDans Twig, le contenu parent s'affiche avec {{ parent() }}.
3A: 1Le code incremente une copie locale mais ne refait pas set dans la session.
4ALa session contient nomUser, donc on affiche le message.
5BJS cherche #paragraphe mais HTML a class="paragraphe"; rien ne change.
6AquerySelector("p") prend le premier paragraphe, pas celui qui contient para3.
7B$this dans une methode static declenche une erreur.
8DLa boucle affiche 2, 3, 4. Elle s'arrete avant 5.
9ALes operations de persistance Doctrine sont regroupees en transaction.
10AmonObjet.p cherche une propriete appelee "p", donc undefined dans la boucle.
1123 puis -1+ colle deux chaines, - convertit en nombres.
128 puis undefinedg(2,4) affiche 8, puis console.log(g(...)) affiche le retour: undefined.
13undefined puis 7var x local est hisse au debut de la fonction.
14A, B, Ca[href*="insat"] prend tout href qui contient "insat".
15Dsort() sans comparateur trie comme du texte.
16DSeul $prod est passe par reference, donc $s reste 0 et $p devient -6.8.
17A, B, C, D, ELe cours cite PHP, annotations, attributs, YAML et XML pour le routing.
18A, B, C, DUn ORM donne une couche objet, mappe les entites, abstrait la BD et fournit une API de travail.
19A, B, DLes migrations gerent l'evolution et permettent changer de version, pas faire du CRUD metier.
20A, BLes fixtures remplissent la BD avec donnees de test ou initiales.
21BPlusieurs select sont executes separement; la transaction concerne surtout le flush d'ecriture.
22C, Dyear doit avoir 2 chiffres; univ est optionnel.
23AManyToMany cree une table de jointure. Pour ajouter des champs, il faut une entite relation.
24A, BUn trait centralise du code et peut contenir methodes/proprietes; ce n'est pas un type parent.
25B/profile/delete matche la regle admin avant la regle profile user.
26DROLE_ADMIN herite des roles directs et indirects.
27A, B, COrdre des blocs peu important; include possible; un enfant ecrit dans les blocs herites.
28BUn lien d'activation email doit etre absolu, sinon le mail ne sait pas quel domaine utiliser.
29ALes flash messages vivent en session pour une duree courte.
30Bquery_builder personnalise la requete qui alimente les choix.
31Bmapped => false dit: ce champ n'a pas de propriete dans l'entite.
32B, CContraintes possibles dans le form et dans l'entite; le controleur orchestre surtout.
33B: FauxUn form peut etre lie a un objet ou juste recuperer des donnees libres.
34AhandleRequest prend les donnees de la requete et hydrate l'objet/form.
35A, CInjection SessionInterface ou via $request->getSession().
36C, DEn Symfony 6, injecte ManagerRegistry dans le constructeur ou l'action.
37BUne classe abstraite sert a imposer/partager une base, pas a etre instanciee directement.
38false, false, true, true== compare valeurs; === compare la meme instance.
39A, BPolymorphisme par heritage et interfaces.
40BLes requetes preparees protegent contre SQL Injection.

Les pieges les plus rentables a reviser

JS

  • querySelector prend le premier, querySelectorAll prend une liste.
  • #id n'est pas .class.
  • var est hisse et peut donner undefined.
  • sort() trie en texte sans comparateur numerique.

Symfony / PHP

  • flush() Doctrine = transaction d'ecriture.
  • handleRequest ne remplace pas isValid.
  • mapped => false pour champ sans entite.
  • $this interdit en contexte static.

Checklist avant l'examen

Si tu sais faire ces verifications, tu arretes de repondre au feeling. Le feeling est mauvais en QCM technique.

Quand tu lis du code

  1. Repere le langage
    JS, PHP, Twig et YAML n'ont pas les memes regles.
  2. Trace les variables
    Demande: est-ce une copie, une reference, une session, une propriete static ?
  3. Lis les selecteurs exactement
    #x, .x, x ne selectionnent pas la meme chose.
  4. Regarde ce qui est vraiment appele
    Un code defini mais jamais appele ne produit rien.
  5. Verifie les effets caches
    Transaction, hoisting, conversion automatique, ordre des access_control.

Questions flash

Difference entre HTML et CSS ?
HTML donne le sens et la structure. CSS donne l'apparence.
Difference entre Repository et EntityManager ?
Repository lit. EntityManager prepare/ecrit/supprime avec persist, remove, flush.
Pourquoi une migration n'est pas une fixture ?
Migration change la structure/version de la BD. Fixture ajoute des donnees.
Pourquoi l'email doit avoir un lien absolu ?
Dans un email, le navigateur n'est pas deja sur ton site. Il lui faut le domaine complet.
Pourquoi prepared statement ?
Pour separer la requete SQL des valeurs utilisateur et eviter l'injection SQL.

Sources utilisees dans ce workspace

Cours Web 1 HTML5, Cours Web 2 CSS3, Cours Web 3 JS, Cours Web 4 PHP, ateliers HTML/CSS/JS/PHP, Git.pdf, Symfony Cours 1 Introduction, Cours 2 Controleurs, Cours 3 Routing, Cours 4 Twig, Cours 5 Doctrine, Cours 6 Formulaires, Cours 7 Securite, et web25.pdf.