Réalisation de sites web

Sommaire du site

Présentation
Comment apprendre
L'équipement
La page web
  Styles et CSS
  HTML, structure de la page
  HTML, éléments du corps
Le langage JavaScript
  JavaScript, objets "core"
  JavaScript, DOM, les bases
  JavaScript, DOM, node
  JavaScript, compléments
Le langage PHP, les bases
  PHP, fonctions utiles
  PHP pour le web
  PHP, compléments
SQL, introduction
  MySQL et PHP pour le web
  MySQL, plus loin...
Applications AJAX
Annexes utiles
  Fichier .htaccess
  Sécurité des sites web
  Conception d'un site web
  Référencement, syndication

Sommaire détaillé

Mentions légales.

Chapitres de cette page
Contenu  -> 

Page mise à jour le : 12-08-2015

Haut de la page

Gestion des formulaires
Adaptation des textes
Sessions et cookies
Gestion des en-têtes HTTP
Messagerie électronique
A suivre...

PHP pour le web

Gestion des formulaires

Une des applications les plus fréquentes de PHP est la gestion des formulaires web que soumet l'utilisateur.

Soyez prudents pour l'utilisation des données issues de formulaires car il se peut que des utilisateurs "indélicats" vous envoient du JavaScript ou des instructions de manipulation de bases de données.

La récupération des informations de formulaire se fait depuis les trois tableaux prédéfinis :

$_POST si l'attribut 'method'' du formulaire était 'post' ;
$_GET si l'attribut 'method'' du formulaire était 'get' ;
$_FILES si le formulaire transmet des fichiers.

La méthode 'get' ne présente pas un grand intérêt pour les formulaires. Car elle transmet les informations avec l'adresse de la page (URL). Ces informations sont limités en taille.

En revanche, il est parfois intéressant de transmettre des informations comme données complémentaires d'URL (QUERY_STRING ou chaîne de requête) depuis un lien. Dans ce cas elles seront récupérées comme si elles provenaient d'un formulaire dans le tableau '$_GET'.

Tableau '$_POST'

Ce sont des tableaux associatifs ils sont indexés selon le nom des champs (attribut 'name') dans le cas des formulaires ou  par les identifiants dans le cas de données complémentaires de l'URL.

Une démonstration sera probablement plus claire que de laborieuses explications :
formulaire avec méthode 'post' (nouvelle fenêtre ou onglet).

Pour que la liste à choix multiples puisse être traitée correctement par le PHP, il faut que l'attribut 'name' de l'élément 'select' soit défini sous forme de tableau.

On remarque que les cases non cochées ne sont pas dans le tableau '$_POST', il en est de même pour les boutons de validation non activés. Le tableau issu de la liste à choix multiples ne contient que les éléments sélectionnés, si aucun n'est sélectionné ce tableau ne se trouve pas dans '$_POST'.

Tableau '$_GET'

Le tableau '$_GET' se gère de la même façon que '$_POST'.

Cependant certains caractères de la chaîne de requête (QUERY_STRING) sont codés de façon particulière dans l'URL . Le décodage est implicite et le tableau '$_GET' contient des informations correctes.
Démonstration du formulaire avec méthode 'get'
(nouvelle fenêtre ou onglet).

L'utilisation de '$_GET' depuis l'URL est très proche de ce que l'on vient de voir. Si l'URL est :

...ma_page.php?nom=machin&age=25

On obtiendra le tableau '$_GET" :

[nom]=> machin
[age]=> 25

En savoir plus sur les tableaux '$_POST' et '$_GET' :
http://www.php.net/manual/fr/language.variables.external.php

Tableau '$_FILES'

Ce tableau existe quand le formulaire dispose d'au moins un champ où l'attribut 'type" est égal à 'file'. Donc quand le formulaire transmet un fichier.

Pour que la transmission du fichier se fasse il est nécessaire de placer dans l'élément 'form" l'attribut : 'enctype="multipart/form-data" ' et que la méthode soit 'post'.

A l'envoi chaque fichier sera transmis au serveur qui le place dans un répertoire temporaire.

La page d'exploitation du formulaire recevra  un tableau associatif '$_FILES' dont chaque composant est un tableau associatif indicé par le nom des champs de type 'file' du formulaire. Il y en a donc au moins un car chacun caractérise un fichier transmis.

Chacun de ces tableaux a cinq composantes :

Index Contenu
name nom du fichier tel qu'il est sur la machine de l'utilisateur
type type MIME du fichier transmis
tmp_name chemin complet d'accès au fichier placé sur le serveur
error code d'erreur : 0 indique que tout s'est bien passé
size taille du fichier en octets sur le serveur

Quelques remarques.

* Il est souhaitable de placer dans le formulaire un champ caché de nom 'MAX_FILE_SIZE' et ayant pour valeur la taille maximale des fichiers à transmettre (en octets) :

<input name="MAX_FILE_SIZE" value="4096" type="hidden">

Dans ce cas si le fichier dépasse cette taille il n'est pas envoyé (on évite de perdre du temps de transfert) et le code 'error' vaut 2.(constante PHP 'UPLOAD_ERR_FORM_SIZE').

Cependant comme il n'est pas certain que tous les navigateurs gèrent ce champ, il est utile de vérifier aussi la taille du fichier transmis.

* Sur certains postes utilisateur (notamment Windows), le type MIME du fichier transmis est basé sur son extension. Celle-ci peut être incorrecte. Il est prudent de faire une vérification complémentaire du type de fichier.

Rangement du fichier

Comme le fichier a été transmis dans un répertoire temporaire du serveur et qu'il y a un nom arbitraire, il est nécessaire de le placer dans un répertoire adapté avec un nom correct. Pour cela on peut utiliser une des fonctions du système de fichiers :

    copy (source, destination);
ou
    rename(ancien, nouveau);

A nouveau une démonstration :

formulaire d'envoi de fichiers (nouvelle fenêtre ou onglet).

En savoir plus sur le tableau '$_FILES' :
http://www.php.net/manual/fr/features.file-upload.post-method.php

Adaptation des textes

Les textes envoyés par les formulaires peuvent poser des problèmes d'exploitation s'ils contiennent des caractères tels que les apostrophes, guillemets ou caractères spéciaux de l'HTML ('<').

Guillemets magiques

La neutralisation des guillemets et apostrophes est importante si le texte doit être entré dans une base de données car les ordres du système de gestion utilise ces caractères comme délimiteurs. On a aussi le problème si ces textes doivent être insérés dans du code HTML.

La fonction qui neutralise ces caractères est :
addslashes(texte); elle renvoie 'texte' avec les apostrophes, guillemets et anti-slashs échappés.
et :
stripslashes(texte); qui réalise la fonction inverse.

Malheureusement ce n'est pas si simple. En effet, certaines configurations de serveur réalisent implicitement la fonction 'addsclashes' lors de la transmission des données de formulaire. Il ne faut donc pas réaliser cette action deux fois. Pour le savoir, on utilise la fonction :
get_magic_quotes_gpc(); (sans paramètre) elle renvoie 'TRUE' si la neutralisation est active.

Une solution plus simple consiste à tester sur son serveur et à construire le code adapté. Mais dans ce cas vos fichiers ne seront plus portables.

Si les données doivent être placées dans une base de données, il est préférable d'utiliser les fonctions d'échappement du système de gestion des données qui seront plus efficaces et adaptées.
Par exemple pour MySQL, on utilisera la fonction : mysql_real_escape_string(texte);

Voici une discussion intéressante sur ce sujet :
http://www.php.net/manual/fr/security.magicquotes.php

Caractères spéciaux de l'HTML

Si le texte reçu doit être mis dans une page HTML, il faut aussi se protéger aussi des caractères tels que '<', '&', ...

htmlentities(texte, ENT_QUOTES); va réaliser la conversion du paramètre 'texte'.

Cette fonction neutralise aussi les guillemets et apostrophes. Donc si les données viennent d'un formulaire il faut savoir si ces caractères n'ont pas déjà été traités.

Sessions et cookies

Notion de cookie

Un cookie (ou témoin) est une information enregistrée sur la machine de l'utilisateur. Elle a un nom et une valeur. Le cookie est associé à un domaine (Internet) et a une date de péremption au delà de laquelle le cookie est effacé du poste.

Les utilisateurs peuvent configurer leur navigateur afin qu'il n'accepte pas les cookies ou seulement certains. Les utilisateurs peuvent aussi effacer les cookies.

Le cookie est un élément important si l'on souhaite que des informations soient conservées lorsque l'utilisateur navigue sur les pages d'un site (par exemple pour conserver ses droits d'accès). Pour cela un mécanisme plus perfectionné est mis en place, celui de sessions.

Sessions

Vu du développeur une session correspond à un tableau associatif $_SESSION dans lequel il est possible de stocker des informations qui seront accessibles depuis les différentes pages du site.

Du point de vue du système, les informations de session sont dans un fichier situé sur le serveur et associé à l'utilisateur connecté au site. Ce fichier a un nom qui 'identifie la session. Il s'agit donc de faire en sorte que l'identifiant de session soit accessible sur toutes les pages du site et qu'il corresponde bien à l'utilisateur connecté.

Pour cela le mécanisme des cookies est intéressant. Un cookie placé sur le poste de l'utilisateur contient l'identifiant de session. Ce cookie a une date d'expiration nulle ce qui fait qu'il sera automatiquement supprimé si l'utilisateur ferme son navigateur. Cette méthode est simple et efficace elle a toutefois un inconvénient car le monde n'accepte pas les cookies !

Donc une autre possibilité existe : passer l'identifiant de session dans l'adresse en complément de l'URL. C'est un peu plus lourd à gérer.

Gestion des sessions

session_start(); cette fonction sans paramètre crée une nouvelle session ou ouvre celle existante. Elle doit être appelée avant tout accès aux variables de session (le tableau $_SESSION n'existe pas avant l'appel de cette fonction).

Si l'on souhaite utiliser le mécanisme des cookies cette fonction doit être appelée avant toute sortie d'information.

Les sessions par cookies posent un problème à Kompozer. En effet ce logiciel n'accepte pas que l'on écrive quelque chose avant la ligne "<!DOCTYPE ...".
Pour y remédier, il est nécessaire d'utiliser le module complémentaire "HandCoder" qui permettra l'écriture en tout début de page.

Cette fonction ne doit être appelée qu'une fois par page.

session_id(); utilisée sans paramètre, cette fonction renvoie l'identifiant de session actuel.
session_id(id); remplace l'identifiant de session par celui transmis en paramètre. Cela doit être fait avant l'appel de 'session_start()'.

SID S'il s'agit de sessions sans cookies, cette constante, définie après l'ouverture de session, contient la chaîne complète d'identification de session à transmettre dans l'URL. Dans ce cas de sessions avec cookies, elle contient la chaîne vide.
Attention, même si les cookies sont admis mais que l'on utilise la méthode "sans cookies", SID contient une information valide.

Exemple 1, session par cookies (PHP en rouge).

<?php
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <title>
      t1
    </title>
  </head>
  <body>
    <?php
    if (isset ($_SESSION['temoin']))
      echo $_SESSION['temoin'];
    else {
      $_SESSION['temoin']= 'témoin enregistré';
      echo "Insertion du témoin";
    }
    ?>
    <a href="t1.php">Lien</a>
  </body>
</html>

Exemple 2, session sans cookie (PHP en rouge, les ajouts sont soulignés).

<?php
if (isset ($_GET['PHPSESSID']))
  session_id($_GET['PHPSESSID']);

session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <title>
      t1
    </title>
  </head>
  <body>
    <?php
    if (isset ($_SESSION['temoin']))
      echo $_SESSION['temoin'];
    else {
      $_SESSION['temoin']= 'témoin enregistré';
      echo "Insertion du témoin";
    }
    ?>
    <a href="t1.php?<?php echo htmlspecialchars( SID); ?>">Lien</a>
  </body>
</html>

On voit que cette méthode est un peu plus lourde que la précédente. Par ailleurs il n'existe pas de méthode simple pour savoir si les cookies sont acceptés ou non.

La fonction "htmlspecialchars()" neutralise les éventuels caractères spéciaux HTMLen cas d'attaque du site.

Si la configuration du PHP a défini l'option 'session.use_trans_sid', l'identifiant de session (SID) sera ajouté automatiquement aux URL relatives.

Quelle méthode choisir ?

Si vous destinez votre site à un large public et que des informations doivent être conservées durant la navigation (type "panier de courses"), la méthode sans cookies est indispensable.
Par contre, si les informations à conserver ne concernent que quelques internautes (utilisateurs privilégiés par exemple) la méthode avec cookies peut convenir dans la mesure où ces utilisateurs sont prévenus de cette nécessité.

Paradoxe

Certains internautes désactivent les cookies dans un but de protection de la vie privée.
Malheureusement, les attaques de sites par vol de session sont plus faciles à réaliser lorsque l'identifiant de session est placé dans l'URL.

Gestion des cookies

On a vu que l'on pouvait conserver des informations avec la technique des sessions. Cependant ces informations sont perdues si l'internaute quitte son navigateur. Dans certains cas on souhaite les garder plus longtemps, par exemple pour enregistrer des préférences.

Dans ce cas il faut gérer les cookies.

setcookie(nom, valeur, expire); pose un cookie nommé 'nom' avec pour contenu 'valeur' et dont l'expiration sera fixée à 'expire', c'est un 'timestamp' (nombre de seconde après le 1° janvier 1970 à 0h).

Si 'expire' n'est pas présent, il est considéré valoir 0, dans ce cas le cookie sera détruit à la fermeture du navigateur.

Si 'valeur' est aussi absente, le cookie 'nom' est effacé.

Cette fonction doit être appelée avant toute sortie d'information.

Accès aux cookies

Tout simplement dans le tableau associatif '$ _COOKIE'.

Gestion des en-têtes HTTP

Au début de tout envoi vers la machine de l'utilisateur, le serveur transmet un en-tête conforme au protocole HTTP. Il indique notamment la nature du document ou des informations de redirection ou d'erreur.

Dans certains cas, il peut être utile de créer un en-tête particulier. PHP le permet avec la fonction 'header();'.

header(texte);

Cette fonction produit 'texte' comme en-tête.

Cette fonction doit être appelée avant toute autre sortie.

Voyons quelques utilisations.

Redirection

Le paramètre doit commencer par "Location : " qui sera suivi par l'adresse absolue de la page :
header("Location: http://www.site.com/nouvelle_page.php";

Cette possibilité est utile dans le cas où selon le déroulement du script (instructions 'if' ou 'switch') on veut envoyer une ou autre page.

S'il s'agit d'une redirection permanente, il est préférable de la faire directement au niveau du serveur par le fichier '.htaccess".

Forcer un téléchargement

Pour que l'utilisateur soit invité à télécharger un fichier plutôt que de l'afficher dans la fenêtre du navigateur, il faut envoyer deux en-têtes, l'une pour indiquer le type du document, l'autre pour définir le nom du fichier à sauvegarder.

header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="notice.pdf"');
include("document.pdf");

Il s'agit d'un document "PDF", l'utilisateur sera invité à l'obtenir sous le nom 'notice.pdf'. La fonction 'include' produit le document.

Messagerie électronique

Le PHP dispose d'une fonction pour envoyer un message électronique. Notez cependant que parfois cette fonction est limitée par le gestionnaire du serveur afin d'éviter la production de "spams".

On peut aussi, depuis le PHP, adresser directement un serveur SMTP (envoi de messages électroniques) en utilisant la fonction 'fsockopen()'. Il faut pour cela avoir quelques connaissances du protocole SMTP.
On trouve aussi sur le web des scripts PHP qui gèrent cela très bien.

mail(dest, sujet, corps, cpl);

Envoie à l'adresse électronique 'dest' le texte 'corps' avec comme objet 'sujet', le dernier paramètre 'cpl' permet de compléter l'en-tête du message (voir ci-dessous). Cette fonction renvoie TRUE si elle a réussi.

S'il y a plusieurs destinataires,  leurs adresses électroniques doivent être séparées par une virgule suivie d'un espace.

Compléments d'en-tête

Il s'agit de lignes, séparées par '\n' et commençant par un mot-clef, utiles à l'acheminement du message, en voici quelques uns.

Mot clef Rôle
From: Généralement obligatoire, adresse de l'expéditeur.
Reply-To: Adresse pour la réponse
Cc: Destinataires en copie
Bcc: Destinataires invisibles

Il peut y en avoir d'autres, notamment si le message est au format HTML.

L'en-tête doit se terminer par un double saut de ligne : "\n\n".

Exemple :

//Les variables $exp, $dst, $dst_c, $sujet, $message ont été initialisées

$header= "From: $exp\nReply-To: $exp\n";
$header .= "Bcc: $dst\n";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-type: text/html; charset=UTF-8\n";
$header .= "Content-Transfer-Encoding: 8bit\n\n";

if (mail ($exp, $sujet, htmlentities($message, ENT_QUOTES), $header))
    $msg= "Message transmis, nous vous remercions.";
else
    $msg= "Une erreur s'est produite, le message n'est pas transmis !";

Notons, dans l'en-tête, l'utilisation des guillemets, non seulement pour évaluer les variables mais aussi pour que '\n' soit traité correctement.

La fonction 'htmlentities' pour le corps du message protège des caractères spéciaux pour l'HTML.

* Remarque concernant cet exemple qui est utilisé pour un formulaire d'envoi : le message est envoyé à l'expéditeur (accusé d'envoi) et le destinataire le reçoit en copie cachée.

Il faut être prudent si l'on crée un formulaire d'envoi de message afin qu'il ne soit pas utilisé par des producteurs de SPAM.

Les adresses peut aussi être spécifiées sous la forme :
nom <destinataire@domaine.tld>

A suivre...

.Encore quelques fonctions de la bibliothèque PHP