phpInfo.netLes ArchivesLes éléPHPants

  
  Accueil
  Trucs & Astuces
  Scripts
  Regex
  Annuaire
  Articles

.
      
 Articles   Les Magic Quotes  Par J-Pierre DEZELUS   15 Septembre 2000    »  Objectif
 »  A l'origine
 »  Les Magic Quotes
 »  Où est le problème alors ?
 »  La Solution
 »  Quelques exemples
 »  Liens


Objectif

Qui ne s'est jamais perdu dans les AddSlashes et les StripSlashes ?
Quand faut-il les utiliser ? Et quel est leur fonction exacte ?
Derrière tout cela se cachent les Magic Quotes ... Mais qui sont réellement ces Guillemets Magiques ? Quel rôle jouent-ils dans cette histoire ?

Cet article va tenter de répondre à toutes ces questions, et à quelques autres.

A l'origine

Supposons que vous souhaitiez insérer dans votre base de données MySQL la valeur "d'ailleurs" dans le champ origine de la table individu.
Vous allez exécuter la requête suivante :

INSERT INTO individu (origine) VALUES ('d\'ailleurs')

Vous avez fait précéder l'apostrophe d'un anti-slash pour que MySQL ne confonde pas l'apostrophe contenu dans la chaîne avec celui de la fin de chaîne.
Tout fonctionne correctement parce que la valeur a été mise 'en dur' dans la requête.

Mais supposons maintenant que les valeurs proviennent d'un champ de formulaire. L'utilisateur qui les saisit ne va pas s'amuser à placer un anti-slash devant chaque apostrophe.
C'est votre rôle de programmeur, et PHP a décidé de vous aider en vous fournissant la fonction AddSlashes(). Cette fonction place dans la chaîne un anti-slash devant chaque caractère spécial : ' (guillement simple), " (guillement double), \ (anti-slash), NULL (caractère null).


$chaine
= "d'ici";
echo
addslashes($chaine); // Donne "d\'ici"


Appliqué à l'exemple de tout à l'heure cela donne :


$val
= addslashes($valeur_saisie);
$sql = "INSERT INTO individu (origine) VALUES ('".$val."')"


Tout aurait pu aller pour le mieux dans le meilleur des mondes, si PHP n'avait pas décidé d'améliorer encore le sort des programmeurs en proposant de nouvelles fonctionnalités : les Magic Quotes.
Enfin 'améliorer', il faut voir ...

Les Magic Quotes

En effet, il peut vite devenir très lourd d'utiliser la fonction AddSlashes() pour modifier chaque valeur saisie, avant de l'insérer en base.

Pour simplifier la tâche du programmeur, il est donc possible de configurer PHP pour lui faire ajouter lui-même les anti-slash sur les valeurs saisies.

C'est le rôle des variables de configuration magic_quotes_gpc et magic_quotes_runtime du fichier php.ini (ou php3.ini).

magic_quotes_gpc = On
magic_quotes_runtime = Off

Si magic_quotes_gpc est positionné à 'On', PHP échappera toutes les valeurs saisies pour les opérations GPC (Get/Post/Cookie), donc entre autres celles provenant de formulaires.

Si magic_quotes_runtime est positionné à 'On', PHP échappera toutes les valeurs des fonctions qui retournent des données d'une source externe, comme les bases de données (MySQL) et les fichiers texte.

Où est le problème alors ?

Le problème est simple. C'est que vous allez écrire un programme qui tient compte de la configuration de PHP sur votre machine et des valeurs de magic_quotes_gpc et magic_quotes_runtime.

Si vous avez positionné magic_quotes_gpc à On, vous n'allez donc pas utiliser la fonction AddSlashes avant d'insérer des données saisies en base.
Par contre, si maintenant vous faites tourner votre programme sur une autre machine dont la variable magic_quotes_gpc à Off, vous allez générer des requêtes SQL qui ne seront pas correctement interprétées, puisque les valeurs saisies ne seront pas échappées. Les programmes provoqueront alors des erreurs du type "Warning: 0 is not a MySQL result index in test.php3 on line 44".

A l'inverse, si vous avez positionné magic_quotes_runtime à Off, les valeurs récupérées de vos bases de données pourront être affichées directement, sans autre traitement.
Par contre, une machine ayant magic_quotes_runtime à On récupèrera des valeurs échappées, c'est à dire contenant des \. C'est pour cela que l'on voit parfois dans des forums, des news ou des livres d'or des \ dans les textes saisis par les utilisateurs.

La Solution

Il y a en fait plusieurs solutions. Dans tous les cas de toute façon, il faut essayer d'écrire des programmes qui tourneront quelle que soit la configuration de PHP.

Ce n'est pas le cas de phpMyAdmin par exemple qui demande à avoir la variable magic_quotes_gpc positionnée à On pour fonctionner correctement. Parce ses développeurs n'ont pas voulu insérer dans leur code les différents tests que nous allons décrire maintenant.


Le 1er test consiste à vérifier l'état de la variable magic_quotes_gpc afin de savoir quel traitement appliquer sur les saisies avant de les entrer en base ou de les afficher.
La fonction get_magic_quotes_gpc() va nous donner l'information.

On pourra utiliser le code suivant ($valeur_saisie est issu d'un champ de formulaire) :

<?php

function MyAddSlashes($chaine ) {
  return(
get_magic_quotes_gpc() == 1 ?
          
$chaine :
          
addslashes($chaine) );
}

function
MyStripSlashes($chaine) {
  return(
get_magic_quotes_gpc() == 1 ?
          
stripslashes($chaine) :
          
$chaine );
}

$val = MyAddSlashes($valeur_saisie);
$sql = "INSERT INTO individu VALUES ('".$val."')";
$resultat = mysql_db_query($cfgBase, $sql);

$val = MyStripSlashes($valeur_saisie);
echo
"Valeur saisie : ".$val;

?>

Nous avons utilisé dans ce script la fonction StripSlashes() qui permet de supprimer les anti-slash d'une chaîne.


Le second test se fait sur la variable magic_quotes_runtime afin de savoir le traitement à appliquer sur les données récupérées de bases de données ou de fichiers.
La fonction get_magic_quotes_runtime() va nous donner l'information.

On pourra utiliser le code suivant :

<?php

function MyStripSlashes_2($chaine) {
  return(
get_magic_quotes_runtime() == 1 ?
          
stripslashes($chaine) :
          
$chaine );
}
  
$sql = "SELECT origine FROM individu";
$resultat = mysql_db_query($cfgBase, $sql);
$enr = mysql_fetch_array($resultat);
echo
"Valeur : ".MyStripSlashes_2($enr[0]);

?>

Ce deuxième test peut-être évité en utilisant cette 3ème possibilité :

<?php

set_magic_quotes_runtime
(1);
  
$sql = "SELECT origine FROM individu";
$resultat = mysql_db_query($cfgBase, $sql);
$enr = mysql_fetch_array($resultat);
echo
"Valeur : ".stripslashes($enr[0]);

?>

On positionne dynamiquement dans le script la variable magic_quotes_runtime à On en utilisant la fonction set_magic_quotes_runtime(). Il n'est donc plus nécessaire de faire de test, puisque l'on a modifié la configuration de PHP (uniquement le temps d'exécution du script).

Quelques exemples

Pour illustrer tout ce qui vient d'être dit voici sous forme de quatre exemples les principaux cas de figure que l'on peut rencontrer.

Pour la démonstration, j'ai utilisé le script suivant. Je disposais aussi d'un fichier texte test.txt contenant la chaîne "d'ici" et une base de données 'test' avec une table 'test' et un enregistrement contenant aussi la chaîne "d'ici".

La variable magic_quotes_gpc a dû être modifiée à chaque fois dans le fichier php.ini, tandis que nous avons utilisé une case à cocher 'mqr' et la fonction get_magic_quotes_runtime() pour modifier magic_quotes_runtime de façon dynamique.

<?php

function MyStripSlashes( $chaine ) {
  return(
get_magic_quotes_gpc() == 1 ?
          
stripslashes($chaine) :
          
$chaine );
}

// On positionne magic_quotes_runtime
set_magic_quotes_runtime($mqr == 'on' ? 1 : 0);

echo
"get_magic_quotes_gpc: <B>";
echo
get_magic_quotes_gpc()."</B><BR>\n";

echo
"get_magic_quotes_runtime: <B>";
echo
get_magic_quotes_runtime()."</B><BR>\n";

echo
"<FORM METHOD=POST ACTION=''>\n";
$val = MyStripSlashes( $champ );
echo
"<INPUT TYPE='text' NAME='champ' VALUE=\"".$val."\">";
echo
"&nbsp;&nbsp;<INPUT TYPE='submit' VALUE='Ok'><BR>\n";
echo
"<INPUT TYPE='checkbox' NAME='mqr'";
echo (
$mqr == "on" ? " CHECKED" : "").">";
echo
"<B>set_magic_quotes_runtime</B>\n";
echo
"</FORM>\n";

// --- Test sur Saisie ---------------------
if (isset($champ))
  echo
"Valeur saisie: <B>".$champ."</B><BR><BR>";
// -----------------------------------------

// --- Test sur Fichier --------------------
$fichier = "test.txt";
$fp = fopen($fichier, "r");
$chaine = fgets($fp, filesize($fichier));
echo
"Fichier: <B>".$chaine."</B><BR><BR>";
fclose($fp);
// -----------------------------------------

// --- Test sur Base -----------------------
mysql_connect("localhost", "root", "");
$sql = "SELECT test FROM test";
$resultat = mysql_db_query("test", $sql);
$enr = mysql_fetch_array($resultat);
echo
"Champ: <B>".$enr[0]."</B>";
// -----------------------------------------

?>

Voici le résultat des différents tests :


Ici, magic_quotes_gpc et magic_quotes_runtime sont tous les deux à Off. Aucun anti-slash n'est ajouté. Ni à la saisie, ni à la lecture en base, ni à la lecture du fichier.


Maintenant, magic_quotes_gpc est à Off et magic_quotes_runtime à On. On voit que les données issues de la base et du fichier sont échappées.


Nous mettons magic_quotes_gpc à On et magic_quotes_runtime à Off. Ce sont uniquement les saisies qui sont échappées.


Enfin, magic_quotes_gpc et magic_quotes_runtime sont mis à On. Les saisies, les lectures en base et en fichiers sont maintenant échappées.



Liens

Voici quelques liens pour aller un peu plus loin.

 » AddSlashes, StripSlashes
 » get_magic_quotes_gpc, get_magic_quotes_runtime, set_magic_quotes_runtime
 » magic_quotes_gpc, magic_quotes_runtime
Synseo