I. Définition

Les tableaux superglobaux (dits aussi auto-globaux) sont une nouveauté de PHP 4.2.0, les versions antérieures n'en possèdent pas.

De façon générale, une variable superglobale est automatiquement disponible dans tous les environnements d'exécution. Elle a donc une portée globale.

Un environnement d'exécution possède son propre espace de variable. Pour connaître une variable dans plusieurs environnements, il faut la déclarer à l'aide du mot réservé global.
Par exemple, une fonction ne connait pas les variables du script, pour y remédier, on déclare celles que l'on souhaite utiliser dans la fonction avec global.

Exemple :

 
Sélectionnez
  1. function printLink($link) { 
  2. global $color; 
  3. echo "<a style=\"color:$color;\" href=\"$link\">Visitez $link !</a>"; 
  4. } 
  5. $color = "yellow"; 
  6. printLink("http://www.developpez.com")  

II. Utilisation

Les tableaux superglobaux ne peuvent être utilisés qu'avec la version PHP 4.2.0 (et supérieures).

En pratique, une variable superglobale est simplement disponible dans tout contexte d'utilisation, que ce soit dans le script, dans une méthode de classe, dans une fonction... sans avoir à utiliser la directive global.

Il n'est pas possible (pour l'instant du moins) de créer soi-même des variables superglobales, on ne peut qu'utiliser celles déjà existantes comme définies dans la Liste des tableaux superglobaux.

Ces variables sont des tableaux associatifs. C'est-à-dire qu'à une clé est associée une valeur pouvant être un nombre, une chaîne de caractères, un tableau... Les clés de ces tableaux sont les noms des variables qu'ils référencent.

Exemple :

 
Sélectionnez
  1. function printLink($link) { 
  2. echo "<a style=\"color:".$GLOBALS["color"].";\" href=\"$link\">Visitez $link !</a>"; 
  3. } 
  4. $color = "yellow"; 
  5. printLink("http://www.developpez.com")  

Comme les tableaux superglobaux remplacent d'anciennes variables obsolètes mais toujours présentes, ces dernières peuvent encore être utilisées. Dans ce cas, ne pas oublier la directive global.

III. Liste des tableaux superglobaux

Ces tableaux ne sont disponibles que sur les serveurs équipés de la version 4.2.0 et suivantes de PHP. Pour les versions antérieures, il faut utiliser les variables dites obsolètes du tableau suivant.

A noter, que certaines variables peuvent être simultanément disponibles dans plusieurs tableaux superglobaux à la fois. Par exemple, le tableau $GLOBALS reprend chacune des variables disponibles dans tous les autres tableaux superblobaux. Autre exemple, un paramètre passé dans l'URL à un script sera référencé dans $_GET et dans $_REQUEST.

Nom Description Nom obsolète
$GLOBALS Contient toutes les variables disponibles dans l'environnement d'exécution global. -
$_SERVER Contient les variables fournies par le serveur web. $HTTP_SERVER_VARS
$_GET Contient les variables fournies en paramètre au script via la méthode GET du protocole HTTP. $HTTP_GET_VARS
$_POST Contient les variables fournies par un formulaire via la méthode POST du protocole HTTP. $HTTP_POST_VARS
$_COOKIES Contient les variables fournies par les cookies via le protocole HTTP. $HTTP_COOKIE_VARS
$_FILES Contient les variables fournies suite à un chargement de fichier par un formulaire via la méthode POST du protocole HTTP. $HTTP_POST_FILES
$_ENV Contient les variables fournies par l'environnement. Ce peut être des variables du Shell sous lequel s'exécute PHP, les variables CGI... $HTTP_ENV_VARS
$_REQUEST Contient les variables fournies au script par n'importe quel mécanisme. -
$_SESSION Contient les variables de la session en cours dans le script. $HTTP_SESSION_VARS

IV. Liste des variables du serveur

Ces variables sont référencées dans le tableau superglobal $_SERVER.

Nom Description
argv Tableau des arguments passés au script dans le cas où celui-ci est lancé en ligne de commande depuis un Shell.
argc Nombre de paramètres passés au script (dans le cas ligne de commande).
DOCUMENT_ROOT Racine à partir de laquelle est exécuté le script.
PHP_SELF Nom du fichier du script en cours par rapport au DOCUMENT_ROOT.
REQUEST_METHOD Méthode de la requète invoquée pour accéder à la page. Avec le protocole HTTP/1.0, les méthodes possibles sont : GET, POST, HEAD, PUT.
REQUEST_URI URI (Uniform Resource Identifier) qui a été fournie pour accéder à la page.
QUERY_STRING Question posée au script (si elle existe). Ce sont les paramètres passés au script.
SCRIPT_FILENAME Chemin absolu jusqu'au script courant.
SCRIPT_NAME Nom du script courant. Utilisé dans le champs method des formulaires pour que le script s'appelle lui-même.
PATH_TRANSLATED Chemin de la page dans le système de fichier réel du serveur. Est différent du chemin virtuel traduit pour l'extérieur.
GATEWAY_INTERFACE Numéro de révision de l'interface CGI du serveur.
SERVER_NAME Nom du serveur qui exécute le script. Ce peut-être un hôte virtuel. Tel que défini par la directive VIRTUAL_HOST d'Apache.
SERVER_SOFTWARE Chaîne de caractères d'identification du serveur. Contenu du champs Server de l'entête HTTP. Par exemple : Apache/1.3.9 (Unix) Debian/GNU.
SERVER_PROTOCOL Nom et révision du protocole utilisé pour transférer au client la page issue du script. En général : HTTP/1.0 ou HTTP/1.1.
SERVER_ADMIN Identifiant de l'administrateur du serveur tel que défini par la directive SERVER_ADMIN d'Apache.
SERVER_PORT Numéro de port utilisé sur le serveur. Traditionnellement, vaut 80.
SERVER_SIGNATURE Chaîne de caractères contenant le numéro de version du serveur ainsi que le nom d'hôte virtuel.
HTTP_ACCEPT Contenu du champs Accept de l'entête HTTP. C'est la liste des types MIME. Par exemple : text/html, application/xml, image/gif.
HTTP_ACCEPT_CHARSET Contenu du champs Accept-Charset de l'entête HTTP. C'est le type d'encodage des caractères utilisé.
HTTP_ACCEPT_ENCODING Contenu du champs Accept-Encoding de l'entête HTTP. C'est le type d'encodage des données utilisé. C'est en général de la compression. Par exemple : gzip.
HTTP_ACCEPT_LANGUAGE Contenu du champs Accept-Language de l'entête HTTP. C'est la langue utilisée. Par exemple : fr.
HTTP_CONNECTION Contenu du champs Accept-Connection de l'entête HTTP. C'est le type de la connexion établie entre le client et le serveur (persistente ou non), par exemple : Keep-Alive ou close.
HTTP_HOST Contenu du champs Host de l'entête HTTP en cas de virtual hosting.
HTTP_REFERER Adresse de la page qui a conduit le client à la page courante.
HTTP_USER_AGENT Contenu du champs User-Agent de l'entête HTTP. C'est le nom et la version du navigateur utilisé par le client pour consulter la page en cours. Ainsi que le système d'exploitation et autres informations. Par exemple : Mozilla/5.0 Galeon/1.0.2 (X11;Linux i686; U;) Gecko/20011224.
REMOTE_ADDR Adresse IP du client qui demande la page.
REMOTE_PORT Le numéro de port utilisé sur la machine cliente pour établir la communication avec le serveur.
Script de départ
echo "<form action=\"".$_SERVER["SCRIPT_NAME"]."\" method=\"POST\">";
echo "<input type=\"text\" name=\"nom\" />";
echo "<input type=\"submit\" />";
echo "</form>";
Script d'arrivée
echo "Vous êtes ".$_POST["nom"].".";

V. Portée des variables référencées

On a vu qu'à partir de PHP 4.2.0 les variables référencées dans les tableaux superglobaux ne sont accessibles que par l'intermédiaire de ces tableaux. Auparavant, les variables référencées pouvaient être accédées directement, via un global si nécessaire (dans les fonctions et méthodes).

Ce changement repose sur un paramètrage par défaut du fichier de configuration php.ini qui a été changé. Le paramètre register_global était à On, en PHP 4.2.0 il passe à Off par défaut. Mais il est toujours possible de le changer manuellement afin de revenir à la situation antérieure ou les variables référencées par ces tableaux superglobaux étaient directement accessibles.

Avec register_global = On, appel de la page page.php?id=41&nom=robert :
 
Sélectionnez
  1. <?php 
  2.  function afficher() { 
  3.   global $nom 
  4.   echo "Vous êtes ".$nom; 
  5.  } 
  6.  echo "$id, $nom"; 
  7.  afficher(); 
  8. ?>  
Affiche :
 
Sélectionnez
  1. 41, robert 
  2. Vous êtes robert  
Avec register_global = Off, appel de la page page.php?id=41&nom=robert :
 
Sélectionnez
  1. <?php 
  2.  function afficher() { 
  3.   echo "Vous êtes ".$_GET["nom"]; 
  4.  } 
  5.  echo $_GET["id"].", ".$_GET["nom"]; 
  6.  afficher(); 
  7. ?>  
Affiche :
 
Sélectionnez
  1. 41, robert 
  2. Vous êtes robert  

VI. Pourquoi des tableaux superglobaux ?

Pourquoi avoir introduit cette nouveauté dans PHP 4.2.0 ? Tout simplement pour des raisons de sécurité.

Non pas que PHP lui-même comporte des failles de sécurité (en fait si, mais c'est pas le sujet de cet article), mais les webdesigners qui programment en PHP ne font pas toujours suffisamment attention à ce qu'ils écrivent. Permettant ainsi aux internautes malveillants d'induire le script en erreur ou de lui faire faire des choses qui n'étaient pas prévues.

Voici un petit exemple, notre script script.php va inclure un fichier de configuration via une commande include() qui contient par exemple les informations nécessaires (login, mot de passe, nom de la base) pour se connecter à une base de données MySQL. Le nom de ce fichier est normalement passé en paramètre via un formulaire (méthode GET ou POST).

Script.php :

 
Sélectionnez
  1. <?php 
  2.  include($config_file); 
  3.  ... 
  4. ?>  

Un petit malin pourait avoir l'idée d'aller regarder le code source HTML de votre formulaire formulaire.php.

 
Sélectionnez
  1. <form action="script.php" method="POST"> 
  2. <input type="hidden" name="config_file" value="config_bd.php" />  

Libre à lui, à partir de là, d'exécuter votre script d'arrivée sans passer par l'intermédiaire du formulaire, et en lui passant des paramètres en argument.

Adresse tapée dans le navigateur par le hacker :

 
Sélectionnez
  1. script.php?config_file=/etc/passwd  

Ainsi votre script a été détourné pour afficher le fichier de mot de passe du serveur ! Il connait maintenant tous les utilisateurs de votre système (les mots de passe sont généralement cryptés).

Les include() préfixés ou suffixés par une chaîne de caractères constante ne sont pas mieux lotis.

Dans l'exemple suivant, un chemin relatif permet la remontée dans le système de fichiers.

 
Sélectionnez
  1. script.php?config_file=../../../etc/passwd 
  2. include("common/config/$config_file"); 

Dans l'exemple suivant, une chaîne de caractères terminée par le caractère spécial de fin de chaîne %00 dit à PHP d'ignorer le suffixe "inc".

 
Sélectionnez
  1. script.php?config_file=../../etc/passwd%00 
  2. include("myfiles/".$config_file."inc"); 

Comment remédier à ces attaques ? En étant plus rigoureux dans sa programmation ! L'exemple suivant montre une méthode sûre.

 
Sélectionnez
  1. <?php 
  2.  $files = array{"config_db.php", "config_user.php", "config_forum.php"} 
  3.  if(in_array($config_file,$files)) { 
  4.   require($config_file); 
  5.  } else { 
  6.   echo "C'est pas beau de pirater les sites web !"; 
  7.  } 
  8. ?>  

Dans cet exemple, on vérifie que le nom de fichier reçu par le script appartient à une liste prédéterminée, si tel est le cas, on l'inclu. Sinon, c'est qu'il y a un problème !

Il existe de nombreuses fonctions travaillant sur les fichiers qui sont succeptibles d'être détournées (inclusion, ouverture, exécution de fichier): require(), include(), include_once(), require_once(), file(), readfile(), fpassthru(), exec(), fopen()...

Il est donc nécessaire d'être très vigilant lors de la programmation en PHP et de deviner quelles sont toutes les actions malveillantes succeptibles d'êtres exécutées à travers vos scripts. Il s'agit donc d'être particulièrement paranoïaque et de protéger toutes les variables en les vérifiant systématiquement.

D'ailleurs ce problème n'est pas réservé aux fichiers. Toutes les autres variables sont consernées. Ainsi les id de sessions peuvent être falsifiées, les id de message à supprimer d'un forum aussi...

Alors, au lieu de faire démesurément confiance aux variables créée automatiquement dans l'espace d'exécution (par global_register) à partir des paramètres passés au script, on utilise les tableaux globaux $HTTP_ENV_VARS, $HTTP_GET_VARS $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS et $HTTP_SESSION_VARS (créés automatiquement par la directive de configuration track_vars mise à On).

Ainsi, utiliser $HTTP_POST_VARS["config_file"] permet de se prémunir contre les attaques précédentes.

Par contre cette relative sécurité peut être détournée par un hacker qui enregistre sur son ordinateur votre formulaire, en modifie le code pour changer le <input type="hidden" name="config_file" value="config_bd.php" /> en <input type="hidden" name="config_file" value="/etc/passwd%00" /> et valider le formulaire pour vous pirater !

Depuis PHP 4.2.0 ces tableau globaux sont devenus obsolètes. Et il faut alors utliser les tableaux superglobaux.

VII. Liens

VII-A. Tableaux superglobaux

VII-B. Sécurité

Pour de plus amples informations sur cette question de sécurité, je vous recommande la lecture de cet article de Thomas Oertli : Secure Programming in PHP (en anglais).

Un autre document très intéressant, traduit en français celui-là, Exploitation des vulnérabilités avec les applications PHP de Shaun Clowes SecureReality.