Mini-cours de PHP - MySQL

Partie IV

Ce chapitre est consacré aux passages de données à un fichier PHP.

Pour transmettre les données d'un internaute à un fichier PHP, le plus simple est de les transmettre dans l'URL.

Après avoir un peu étudié le HTML, nous savons que nous pouvons indiquer une ancre (une position unique dans le fichier). Le nom du fichier est alors suivi d'un caractère spécial (#) suivi de la valeur d'un attribut id.

Lorsque les données sont transmises via l'URL, il faut également respecter des conventions.

  1. Les données sont transmises sous la forme clé=valeur.
  2. Le caractère spécial (?) suit le nom du fichier PHP et précède les couples de clé=valeur
  3. Le caractère spécial (&) sépare deux couples de clé=valeur.
  4. Le caractère spécial (=) sépare la clé de sa valeur.

On comprend aisément que ces caractères spéciaux ne peuvent pas faire partie d'un nom de clé ou d'une valeur.

URL : caractères autorisés

Exemple d'URL : http://www.pigné.be:80/chemin/vers/mon_fichier.php?cle1=valeur1&cle2=valeur2#valeurID

Une URL est composée de :

  1. Un nom de protocole. Par exemple, http://
  2. Un nom de domaine. Par exemple, www.pigné.be
  3. Éventuellement, un numéro de port. Par exemple, :80
  4. Généralement, un chemin vers le fichier. Par exemple, /chemin/vers/mon_fichier.php
  5. Éventuellement, les paramètres. Par exemple, ?cle1=valeur1&cle2=valeur2
  6. Éventuellement, une ancre. Par exemple, #valeurID

Comprendre les URL

https:// est le nom du protocole lorsque la communication entre le client (le navigateur web) et le serveur est cryptée. Ce qui sort de votre ordinateur (et y entre) est alors crypté.

Le www. peut souvent être omis.

Certains caractères accentués sont autorisés (selon l'extension)
Ainsi, dans un domaine .be, le caractère (é) n'a été autorisé que depuis le 11 juin 2013 (10 heures)

Le numéro du port (de communication du serveur) n'est quasi jamais indiqué. Le numéro du port = le numéro de la porte d'entrée. Rappel : Un ordinateur dispose d'environ 65.000 "portes" (d'entrées et de sorties). Lorsque le protocole est http://, le port par défaut est 80.

Lorsque le fichier est PHP, une ancre est rarement indiquée.

Une URL (= Uniform Resource Locator) = protocole + URI. (Voir URL)
Un protocole est un ensemble de règles de communication entre un client et un serveur.
Lorsque le client est un navigateur web, le protocole est "http://" ou "https://" (Voir http)
Lorsque le serveur est le système de fichiers, le protocole est "file:///"
URI = le chemin vers la ressource (le fichier).
La RFC 3986 définit, dans la section 2.3, les caractères autorisés dans le "path".

foo://example.com:8042/over/there?name=ferret#nose
\_/   \______________/\_________/ \_________/ \__/
 |           |            |            |        |
scheme     authority       path        query   fragment

2.3. Unreserved Characters

Characters that are allowed in a URI but do not have a reserved
   purpose are called unreserved.  These include uppercase and lowercase
   letters, decimal digits, hyphen, period, underscore, and tilde.

      unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

Des problèmes peuvent survenir avec des fichiers enregistrés sur le disque dur lorsqu'ils sont ensuite placés sur un serveur. En effet, dans le nom d'un fichier, l'OS de Microsoft autorise des caractères qui ne le sont pas dans la RFC 3986; tel que l'espace, les caractères accentués, ...

Il est hautement recommandé d'enregistrer, sur son disque dur, ses fichiers en respectant la RFC 3986.

Les 19 caractères suivants sont spéciaux, car ils ont une signification particulière :
 # ? = & : / [ ] @ ! $ ' ( ) * + , ; % 

Passage de paramètres

Pour passer une donnée à un fichier PHP, on peut créer un lien comme ceci :

<a href="tests/bonjour.php?prenom=Thibaut">Afficher Bonjour</a>

Ce qui suit le nom du fichier PHP est ?prenom=Thibaut.
Le ? indique que ce qui suit sont des couples de clé/valeur.
La clé et la valeur sont séparées par le signe =; la clé précède le signe =, la valeur le suit.

bonjour.php (code complet)

<?php
  $prenom=$_GET['prenom'];
  echo "Bonjour, ".$prenom." !";
?>

Tout ce qui est passé par l'URL se trouve dans la super-variable $_GET.

Ce qui est passé par l'URL est prenom=Thibaut
La valeur de $_GET['prenom'] est Thibaut.

Afficher Bonjour

On constate que s'affiche dans la barre des URLs du navigateur : [...]tests/bonjour.php?prenom=Thibaut. Et, comme vous pouvez taper ce que vous voulez dans cette barre, vous pouvez la modifier et remplacer, par exemple, Thibaut par Marc; puis exécuter la page en tapant sur la touche Enter). Si, au lieu d'afficher un message, le script PHP permet de modifier le contenu de la base de données, l'internaute peut modifier la base de données. La sécurité est donc relative à la complexité de la valeur transmise. Si, dans un courriel, on vous demande de cliquer sur un lien pour confirmer votre inscription sur le site et que, dans la barre des URLs, s'affiche
[...]tests/confirm.php?key=2fd4e1c67a2d28fced849ee1bb76e7391b93eb12, modifier cette valeur n'affectera pas la base de données, car votre nouvelle clé n'existe pas dans la base de données. Ici, la sécurité est donc excellente.

Pour passer plusieurs données par l'URL, il faut que chaque couple clé/valeur soit séparé par &.

<a href="tests/bonjour.php?nom=PIGN%C3%89&prenom=Thibaut">Afficher un bonjour complet</a>

Les trois caractères principaux caractères spéciaux sont : ? = &

Afficher un bonjour complet

<?php
  /* Il n'est pas obligatoire de récupérer les paramètres dans l'ordre
  qui ont été donnés dans l'URL */
  $prenom=$_GET['prenom'];
  $nom=$_GET['nom'];
  /* Évidemment, on peut utiliser les variables dans l'ordre qu'on veut
  Ici, le prénom puis le nom (alors que, dans l'URL, on donne le nom puis le prénom) */
  echo "Bonjour, ".$prenom." ".$nom." !";
?>

Pourquoi PIGN%C3%89 et non PIGNÉ ?

Vous connaissez la réponse ! É ne fait pas partie des 66 caractères que vous pouvez choisir sans risque ... Si votre navigateur est "occidental" ainsi que le serveur, il est très probable que les caractères accentués seront correctement interprétés. Cependant, la RFC 3986 est faite pour le monde entier. Ne pas la respecter, c'est prendre un risque. Pour vos visiteurs asiatiques, il est probable que votre code ne fonctionne pas correctement.

Après avoir compris la signification des quatre caractères spéciaux -  # ? = &  - vous en découvrez un cinquième (%). Sa signification sera découverte lorsque nous aborderons la fonction urlencode().

urlencode()

La fonction urlencode() permet d'encoder les caractères accentués, les espaces, ...

Normalement, la clé ne devrait pas être encodée, car son nom devrait respecter les règles de nommage d'une variable (JavaScript, C, C++, ...). Pensez comme un programmeur !

Pour encoder une valeur (voire un nom de domaine, un chemin de fichier, une clé), cliquez ici

Dans une URL, la valeur ne doit pas être entourée de guillemets ou d'apostrophes, même si c'est un mot. Mais, si c'est une phrase, n'oubliez pas d'encoder le caractère espace.

La fonction PHP urlencode() remplace souvent les caractères spéciaux par une séquence de caractères débutant par le caractère spécial (%)

L'URL encodée n'a pas besoin d'être décodée. Elle est tout simplement correcte et il n'est pas nécessaire de décoder ce qui est bon, compréhensible (pour le navigateur web).

Dans une URL, le nom de domaine est insensible à la casse (mais pas le reste de l'URL).

Bref, vous l'avez compris passer des paramètres contenant des caractères "spéciaux" dans une URL, c'est à vos risques et périls.

urlencode().

Après avoir récupéré la donnée (dans le code PHP), celle-ci est souvent utilisée pour construire une requête SQL ou comme paramètre d'une fonction.

$_GET

L'avantage du passage de paramètres par l'URL est qu'il n'est pas nécessaire de créer préalablement un formulaire dans le fichier HTML. Cette méthode convient si la clé est simple (tel que le nom d'une variable en C) et que la valeur est simple (nombre entier ou nom d'une variable en C).

Au prochain chapitre, un exemple de cette méthode sera vu. En l'occurrence, on transmet au fichier PHP dédié à la suppression d'un enregistrement (dans une table précise) le numéro de l'enregistrement à supprimer.

Inconvénients :

Méthode GET

L'avantage du formulaire est que le navigateur crée une URL correcte (avec method="get"). Il applique automatiquement la fonction urlencode().

Prénom :

Regardez l'URL après avoir cliqué sur le bouton.

        <form method="get" action="tests/bonjour.php">
          <p>
            Prénom : <input name="prenom" /> <input type="submit" />
          </p>
        </form>

Nom :
Prénom :

        <form action="tests/bonjour2.php">
          <p>
            Nom : <input name="nom" value="D'Hainaut" /><br />
            Prénom : <input name="prenom" value="Xavier François" /> <input type="submit" />
          </p>
        </form>

Si la méthode n'est pas précisée, method="get" sera utilisée (par le navigateur).

Regardez l'URL après avoir cliqué sur le bouton.

La méthode suivante est performante.

Méthode POST

https

Toute donnée sensible doit être envoyée en utilisant le protocole https.

La plupart des hébergeurs offre cette possibilité gratuitement. Utilisez-la !
Les données sont alors cryptées entre le navigateur et le serveur avec lequel il communique.

L'envoi de données ne peut se faire, en toute sécurité, que via le protocole https

Lorsque la méthode POST est utilisée, les données sont envoyées dans l'entête du fichier; ce qui, pratiquement, ôte toute limitation de taille.

Si method="post" est indiqué mais que l'attribut action est absent, le fichier s'appelle lui-même. Ceci est parfois utile. Le code ci-dessus illustre ce cas.

urlencode.php (extrait)

        <form method="post">
          <p>URL d'un fichier, clé ou valeur (dans une URL) :<br>
            <input size="70" name="url" required="required"
            pattern="[^#?=&:/\x5B\x5D@!$'()*+,;%]+" />
          </p>
          <!--Concernant la valeur de l'attribut pattern
          => voir : http://pigné.be/Thibaut/cours/LeWeb/mini_cours_javascript/annexRegExpr.htm -->
          <p>Sont interdits, dans le champ ci-dessus, les 19 caractères -
 # ? = & : / [ ] @ ! $ ' ( ) * + , ; %  - car ils ont une signification spéciale et ne doivent, dès lors, pas être encodés..</p> <p> <input type="submit" /> </p> <p> <?php if (isset($_POST['url'])) { $old=$_POST['url']; $new=urlencode($old); echo "Dans une URL, <code class='code'>$old</code> doit s'écrire <code class='code'>$new</code>"; } ?> </p> </form>

Dans une balise <form>, on écrit method="post" ou method="get" (sans majuscule).

Prénom :

Code HTML :

        <form method="post" action="tests/bonjour3.php">
          <p>
            Prénom : <input name="prenom">
            <input type="submit">
          </p>
        </form>

L'attribut action permet d'indiquer le nom du fichier (PHP) situé sur le serveur qui devra traiter les données qui lui seront envoyés après le clic sur le bouton.

bonjour3.php (code complet)

<?php
  $prenom=$_POST['prenom'];
  echo "Bonjour, ".$prenom." !";
?>

Le nom d'une super-variable pré-définie ne s'écrit pas en minuscule.

$_POST

Au prochain chapitre, un exemple de cette méthode sera vu. En l'occurrence, on transmet au fichier PHP dédié à l'insertion d'un enregistrement (dans une table précise).


Lors de l'étude du mini-cours sur le JavaScript, un type d'<input /> n'a pas été vu le type="hidden". Et, pour cause, car il permet d'envoyer une donnée "cachée" (= qui n'apparaît pas à l'écran, mais bien dans le code source du fichier).

Prénom :

Code HTML :

        <form method="post" action="tests/bonjour4.php">
          <p>
            Prénom : <input name="prenom" />
            <input type="hidden" name="secret" value="0123" />
            <input type="submit" />
          </p>
        </form>

bonjour4.php (code complet)

<?php
  $prenom=$_POST['prenom'];
  $secret=$_POST['secret'];
  echo "Bonjour, le mot de passe de ".$prenom." est : ".$secret." !";
?>

Une utilisation non-triviale du champ caché sera vue au prochain chapitre.

empty()

La fonction empty() permet de savoir si une variable est définie et vide. Elle est souvent utilisée avec les super-variables $_GET et $_POST car un formulaire renvoie toujours une string (et jamais un nombre). Elle est souvent préférable à la fonction isset()

Extrait de https://phppot.com/php/isset-vs-empty-vs-is_null/

"" "string" NULL false 0 undefined
empty() true false true true true true
is_null() false false true false false error
isset() true true false true true false

if(!empty($_POST["pseudo"]) AND !empty($_POST["passwd"])) {
 $pseudo=htmlspecialchars($_POST["pseudo"]);
 $passwd=htmlspecialchars($_POST["passwd"]);
}

/* input type="number" */
$isDataValid=true;

if(empty($_POST["num_fard"])){$isDataValid=false;}
else{$num_fard=intval($_POST["num_fard"],10); if($num_fard<1) $isDataValid=false; }

 /* La base doit être précisée (ici, 10 pour une base décimale) pour éviter que
  "042" (en base octale) soit converti en 34 (en base décimale) */
 /* intval() retourne 0 en cas d'échec (ou les premiers caractères numériques entier) */
 /* Si la valeur doit être un entier positif non nul (cas des clés étrangères),
 => ajouter une condition : if($num_fard<1) ... */

}

/* input type="date" => AAAA-MM-JJ */
if(!empty($_POST["dateProduct"])) {

  $dateProduct=$_POST["date1"]; $tab=explode("-",$dateProduct);
  if(!preg_match("/^[0-9]{4}$/",$tab[0])) $tab[0]="2000";
  if(!preg_match("/^(0[1-9]|1[0-2])$/",$tab[1])) $tab[1]="02";
  if(!preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])$/",$tab[2])) $tab[2]="31";
  if(!checkdate($tab[1],$tab[2],$tab[0])) $isDataValid=false;

}

/* input type="number" step="0.01" */
if(!empty($_POST["nombreReel"])) { /* = nombre ayant un POINT décimal */

/*
 Si la chaîne de caractères ne contient aucun '.', 'e', ou 'E',
 et que la valeur numérique est dans l'intervalle de représentation des entiers
 (notamment, qu'elle est plus petite que PHP_INT_MAX),
 alors la chaîne de caractères sera transformée en entier.
 Dans les autres cas, elle sera interprétée comme un nombre décimal.

 La valeur est fournie par la portion initiale de la chaîne de caractères.
 Si la chaîne de caractères commence par une donnée numérique valide,
 ce sera la valeur utilisée. Sinon, la valeur sera de 0 (zéro).
 Une donnée numérique valide est un signe optionnel,
 suivi par un ou plusieurs chiffres (contenant, optionnellement, un point décimal),
 suivi par, éventuellement, un exposant.
 L'exposant est un 'e' ou 'E' suivi par un ou plusieurs chiffres.

$foo = 1 + "10.5";                // $foo est un nombre à virgule flottante (11.5)
$foo = 1 + "-1.3e3";              // $foo est un nombre à virgule flottante (-1299)
$foo = 1 + "bob-1.3e3";           // $foo est un entier (1)
$foo = 1 + "bob3";                // $foo est un entier (1)
$foo = 1 + "10 Small Pigs";       // $foo est un entier (11)
$foo = 4 + "10.2 Little Piggies"; // $foo est un nombre à virgule flottante (14.2)
$foo = "10.0 pigs " + 1;          // $foo est un nombre à virgule flottante (11)
$foo = "10.0 pigs " + 1.0;        // $foo est un nombre à virgule flottante (11)
*/
}


empty(), htmlspecialchars(), intval().

isset()

La fonction isset() permet de savoir si une variable est définie et est différente de NULL. Elle est souvent utilisée avec les super-variables $_GET et $_POST. Elle permet de savoir si la clé existe.

isset().

exit()

La fonction exit() permet d'afficher un message et termine le script courant. La fonction die() est un alias (un autre nom pour le même code).

exit().

mail()

Il est possible d'envoyer un courriel. Ceci est utile pour envoyer par exemple un courriel de confirmation d'une commande, de validation d'une adresse e-mail, un message depuis un formulaire (pour garder son adresse e-mail secrète), ...

Rappel. La production et l'envoi de courriels par programmation permet de faire du "spamming". Envoyer un courriel à une personne qui ne souhaite pas recevoir vos courriels est une agression. Les actes méchants sont punissables.

Il n'est pas possible de tester l'envoi de courriels en local (sauf si vous avez installé un serveur de mail sur votre ordinateur, tel que Mercury). Si votre site est hébergé par un hébergeur (payant), il vous est possible d'envoyer des courriels (limités en taille et en nombre).

Code PHP (complet)

<?php
  $destinataire="xxx@yyy.be";
  $sujet="Test de la fonction mail()";
  $message="Test réussi !";
  //mail($destinataire, $sujet, $message);
?>

Il suffit de remplacer xxx@yyy.be par votre adresse e-mail.
Pour éviter le spamming, la fonction mail() a été mise en commentaire.

L'utilisation de la fonction mail() est très facile. La fonction mail() retourne true, si le courriel est envoyé.

Le fait que le courriel soit envoyé n'implique pas qu'il sera reçu. Notamment, si l'adresse e-mail est erronée, si la boîte aux lettres du destinataire est pleine. De plus, votre courriel peut être mis dans le dossier "spam".


Il est possible d'envoyer les données d'un formulaire dans un courriel. Et donc, de créer un formulaire de contact.

Sujet :
Message :
Mon adresse e-mail : (facultatif)

Pour éviter le spamming, la fonction mail() a été mise en commentaire.

Code HTML (ci-dessus)

        <fieldset>
          <form action="tests/mail2.php" method="post">
            <p>
              Sujet : <input name="sujet" /><br />
              Message :
              <textarea name="message" rows="10" cols="70">
</textarea><br />
              Mon adresse e-mail : <input name="emailExpediteur" type="email" /> (facultatif)<br />
              <input type="submit" /><br />
              <span class="note">Pour éviter le spamming, la fonction <code>mail()</code> a été
              mise en commentaire.</span>
            </p>
          </form>
        </fieldset>

mail2.php (code complet)

<?php
  $sujet=""; if (isset($_POST['sujet'])) $sujet=$_POST['sujet'];
  $message=""; if (isset($_POST['message'])) $message=$_POST['message'];
  $de=""; if (isset($_POST['emailExpediteur'])) $de=$_POST['emailExpediteur'];
  if ( empty($sujet) || empty($message) ) exit("Message non envoyé !");

  $destinataire="xxx@yyy.be";
  $headers = "From: ".$de;
  //if(mail($destinataire, $sujet, $message, $headers)) echo("Message envoyé.");
?>

$headers = "From: ".$de; : ce code est donné tel que. Ces codes HTML et PHP sont minimalistes afin de se concentrer sur l'essentiel.

Pour plus d'info sur la fonction mail(), cliquez ici.

De plus, dans le cadre de ce mini-cours, ne sont pas abordés l'envoi de courrier au format HTML, l'envoi de pièce jointes, ni l'input de type="file", ni les moyens de distinguer un humain d'un robot (reCaptcha), ni la vérification des données, côté serveur, via des expressions régulières, ...