HTTP

HM...
WAIT

Introduction au protocol HTTP

HTTP

Lorsque vous naviguez sur internet, vous utilisez un navigateur qui est en fait un client HTTP (HyperText Transfer Protocol). Ce protocole permet d'accéder à des resources distantes.

Serveur HTTP

De l'autre coté, des serveurs HTTP (ou serveurs web) sont à l'écoute permanente de requêtes et répondent à leurs clients.

On nommera par exemple Apache, Nginx ou Caddy

URL

Une resource peut être désignée par une adresse, que l'on nomme URL (Unified Resource Location), ou URI (Unified Resource Identifier). Cette URL est de la forme :

http://www.domain.com/path/to/resource.htm

Ou :

  • http est le protocole utilisé
  • www.domain.com est le nom d'hôte
  • path/to/resource.htm est la resource demandée

HTTP

Le protocole HTTP est un protocole requête/réponse, le serveur ne parle que lorsqu'il a reçu une requête bien formée.

Requête et réponses ont à peu près la même forme:

  • Une ligne particulière, indiquant:
    • La méthode et la page demandée (requête)
    • Le code de retour (serveur)
  • Des en-têtes (clé/valeur)
  • Du contenu

Exemple

Voici un exemple de requête/réponse HTTP, les lignes préfixées par > sont les messages envoyés par le client et celles préfixées par < sont celles reçues:

http://gregwar.com/hello.txt

> GET /hello.txt HTTP/1.1
> Host: gregwar.com
> 
< HTTP/1.1 200 OK
< Content-Length: 13
< Content-Type: text/plain
< 
< Hello world!

Ce protocole est très simple et lisible par un humain. Il est très important d'avoir connaissance de HTTP pour développer une application web. Certain plugins (Firebug, HTTPFox, Tamper data...) permettent de visualiser les échanges et/ou de faire des statistiques sur le trafic.

HTTP
EST
SIMPLE

VOUS DEVEZ
COMPRENDRE
HTTP...

...AVANT PHP

AYEZ TOUJOURS
UN MOYEN DE
REGARDER LES
REQUÊTES HTTP

...VRAIMENT!

Utilité des en-têtes

Les en-têtes peuvent servir à de nombreuses choses, généralement, on les utilise pour :

  • Modifier le type du fichier envoyé (Content-type)
  • Rediriger le client (Location)
  • Faire télécharger le fichier au client (Content-Disposition)
  • Contrôler l'expiration (Expires)
  • Changer le code de réponse
  • etc.

Passage de paramètres

Données GET

Les données "GET" sont des paramètres passés à la page. Il s'agit d'une manière de
transmettre une petite quantité d'informations directement dans une URL:

http://monsite.com/page.php?x=42&y=1337

x=42&y=1337 est ce que l'on appelle une Query String

Les formulaires

Les formulaires représentent à eux seuls une partie très importante du développement d'un site web. De manière générale, ils constituent la plus grosse partie de l'intéraction entre l'utilisateur et les données stockées sur le serveur.

Afin de proposer un formulaire à ses utilisateurs, il faut d'abord leur envoyer le formulaire lui même, ce dernier peut être représenté facilement en HTML:

<form method="post">
    Votre prénom :
    <input type="text" name="firstname" /><br />
    Votre nom : 
    <input type="text" name="lastname" /><br />

    <input type="submit" value="Envoyer" />
</form>

GET vs POST

L'attribut method de la balise <form> peut être défini à get ou à post. Ce choix détermine la manière dont les données du formulaire vont être transmise au serveur, dans le cas de get, les paramètres seront passés dans l'URL comme vu précédemment:

> GET /form.html?firstname=Marty&lastname=McFly HTTP/1.1
> ...
>

Dans le cas de post, les donnée seront alors transmises dans la partie "données" de la requête. Cette méthode est largement préférable pour l'écriture de formulaires:


> POST /form.html HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 30
> 
> firstname=Marty&lastname=McFly

Comme vous le constatez, la méthode HTTP utilisée est alors POST

CGI

Présentation

Le principe du CGI (Common Gateway Interface) est d'ajouter une fonctionnalité à un serveur web afin qu'il exécute un programme au lieu de simplement transférer une resource statique.

CGI: Common Gateway Interface

De la même manière que vous avez exécuté PHP en ligne de commande, le "binding" CGI permettra d'exécuter PHP au moment ou une resource est demmandée par un client. Ainsi, le code que vous aurez écrit sera exécuté et pourra accéder lui même à un ensemble de resource pour rendre le contenu de la page dynamique, c'est à dire différent selon l'utilisateur, la base de données etc.

Résumé

La "passerelle" CGI va alors exécuter un programme ou un script sur le serveur en lui passant les données liées à la requête.

Ce programme pourra alors intéragir avec les en-têtes HTTP qui seront envoyées en réponse ainsi que sur le contenu de la réponse.

Dans le cas de PHP, l'interpréteur sera executé sur le script demandé.

PHP et HTTP

Fonctionnement

En général, les scripts php sont identifiés par leur extension .php. Lorsque le serveur web se voit demander un fichier de ce type, il exécute l'interpréteur au lieu de transmettre son contenu vers le client.

Exemple

Par exemple, si le fichier date.php se trouve sur le serveur web et contient le script suivant:

Bonjour, il est <?php echo date('H:i:s'); ?> !

Lorsque le client demandera la resource /date.php, si le serveur est équipé du mod PHP, il recevra une réponse du style:

Bonjour, il est 13:37:42 !

Toute sortie standard sera automatiquement envoyée en tant que données de la réponse HTTP.

Notez ici tout l'interêt de pouvoir ouvrir et fermer les balises <?php ?>, cela vous permet alors d'utiliser PHP uniquement aux emplacements dynamique de votre page web et de rédiger le reste normalement.

Serveur embarqué

L'outil php en ligne de commande est proposé avec un serveur embarqué qui vous permettra de lancer simplement un serveur web depuis n'importe quel dossier.

php -S 127.0.0.1:8080

Cette commande lancera un serveur web avec PHP depuis le dossier courant sur le port 8080. Il suffira donc d'ouvrir un navigateur à l'adresse http://127.0.0.1:8080 pour accéder aux pages.

Serveur intégré

$ cat index.php
<?php echo "Hello world!\n"; ?>
$ php -S 127.0.0.1:8080
$ firefox http://127.0.0.1:8080/

Exemple de structure

Il est par exemple parfaitement possible d'ouvrir et de fermer des structures de contrôles et de poursuivre le document comme ceci:

<?php

$volumes = ['La communauté de l\'anneau', 
    'Les deux tours', 'Le retour du roi'];

?>

Les volumes :
<ul>
    <?php foreach ($volumes as $volume) { ?>
        <li><?php echo $volume; ?></li>
    <?php } ?>
</ul>

Variables superglobales

La paserelle PHP met à votre disposition des variables spéciales nommées superglobales. Elles contiennent des informations sur la requête en cours :

  • $_SERVER: Contient les informations sur la requête HTTP
  • $_GET: Variables GET
  • $_POST: Variables POST
  • $_COOKIES: Cookies définis
  • $_SESSION: Données de la session

Attention à la sécurité

Attention: Les valeurs de ces variables sont, pour la plupart, fournies par l'utilisateur, on ne peut donc pas compter sur leur présence, leur format ou leur valeur d'un point de vue sécurité.

Données GET

En PHP PHP, les variables GET seront accessibles directement dans le tableau $_GET :

<?php

var_dump($_GET);

/* 
 array(2) {
  ["x"]=>
  string(2) "42"
  ["y"]=>
  string(4) "1337"
}
*/

Récupération des valeurs POST

Lors de la réception d'une requête POST, PHP mettra à votre disposition le tableau superglobal $_POST qui contiendra les associations clé/valeurs postées par l'utilisateur:

<?php

var_dump($_POST); 

/*
array(2) {
  ["firstname"]=>
  string(5) "Marty"
  ["lastname"]=>
  string(5) "McFly"
}
*/

Les en-têtes

Comme vu précédemment, le serveur HTTP, tout comme le client, inclut des en-têtes lors de sa réponse. Ces en-têtes peuvent indiquer le type des données contenues, leur longueur, l'encodage, l'heure du serveur, des cookies et un très grand nombre d'informations. Elles sont sous cette forme:

HTTP/1.1 200 OK
Server: Apache
Content-Type: text/html
Date: Fri, 21 Dec 2012 03:53:16 GMT
Content-Length: 334

(data)

En PHP, il est possible de les modifier à l'aide de la fonction header. Exemple typique, lorsque vous désirez transmettre des données qui doivent être comprise par le client comme étant d'un autre type que celui définit par défaut (text/html), comme par exemple une image:


<?php

// Créé une image rouge de 100x100
$i = imagecreatetruecolor(100, 100);
imagefill($i, 0, 0, 0xff0000);

// Précise au navigateur du client que le contenu
// est une image jpeg, et non pas une page HTML
// (text/html est le type par défaut)
header('Content-type: image/jpeg');

// Envoie l'image au client et libère ses resources
imagejpeg($i);
imagedestroy($i);

Attention à header()

Attention: lorsque vous envoyez des données, le serveur commence à répondre au client et lui transmet "au fur et à mesure" la réponse. Ce qui signifie que la méthode header() provoquera une erreur si vous l'appelez après avoir envoyé un élément de données au client.

Les cookies

Les cookies sont des clé/valeurs stockées par le client HTTP. Lors de la réponse d'un serveur, un certain nombre de définitions de cookies peuvent avoir lieu à l'aide de l'en-tête Set-cookie. Ces valeurs sont fournies plus tard par le client à chaque requête avec l'en-tête Cookie.

Les cookies peuvent donc être définis grâce à l'en-tête Set-cookie, mais PHP met à notre disposition la fonction setcookie:

<?php

if (isset($_COOKIE['seen']))
{
    echo "J'ai l'impression de vous connaître";
}
else
{
    // Definit le cookie seen à 1, qui expire 
    // dans une heure (=3600 secondes)
    setcookie('seen', 1, time()+3600);
    echo 'Tiens, un nouveau visage !';
}

Suppression de cookies

Les cookies peuvent être supprimés de la manière suivante:

<?php

// Pour supprimer un cookie, vous devez indiquer
// une date d'expiration dans le passé et utiliser
// une chaîne vide ou false en tant que valeur
setcookie('seen', false, time()-3600);

Attention aux cookies

Attention 1: comme header(), setcookie() doit être appelée avant tout envoi de données.

Attention 2: définir une chaîne de caractère vide ou la valeur false dans votre cookie essaiera de le supprimer, si vous souhaitez stocker un booléen, utilisez 0 et 1.

Attention 3: n'ayez pas confiance en les valeurs que vous obtenez dans le tableau $_COOKIE, il peut contenir tout ce que l'utilisateur souhaite. En effet, même si le serveur les définit, ils sont stockés en clair et modifiable à volonté par le client.

NEVER TRUST
USER INPUT

<?php
// Don't trust 
$name = $_GET['name'];
// Don't trust
$name = $_POST['name'];
// Don't trust
$name = $_COOKIE['name'];
// ...

Les sessions

Imaginez que vous deviez créer un système d'identification pour sécuriser l'accès à un site web, les cookies pourraient être utilisés mais les données ne peuvent pas être stockées "en clair", étant donné que l'utilisateur a parfaitement accès à leur contenu.

Problème: créer un système d'identification ?

Pour répondre à ce problème, PHP vous propose une surcouche aux cookies nommée sessions. Les sessions sont constituées d'un jeton généré aléatoirement (par exemple: aa244c586762dce6f29530fd87192d89). Ce jeton permet de "reconnaître" le visiteur. Ainsi, lorsqu'un client fournit son jeton (que l'on nomme généralement identifiant de session, ou sessid), le serveur consulte une base de données ou un fichier dont le nom contient le jeton et y retrouve des informations. Contrairement aux informations stockées dans les cookies, celles des sessions ne peuvent pas être modifiées ou même connues du visiteur et sont donc sécurisées.

Principe des sessions:

  • "Jeton" de sécurité: sessid
  • Base de donnée ou fichiers coté serveur

Ainsi, les données sont sécurisées car elles ne peuvent pas être modifiées arbitrairement par le client

THE SESSION SHOW

  • Browser: Hello Server, I'm ryan, my password is admin
  • Server:
    • Check that the password is good... ok
    • Generate random token aef6172e
    • Write ryan to sessions/aef6172e
    • Ok Ryan, take this token: aef6172e
  • Browser: Hello Server, I hold aef6172e
  • Server: Hi, Ryan!

Utilisation des sessions

L'utilisation de tout ce mécanisme se fait automatiquement à l'aide de la fonction PHP session_start() et du tableau $_SESSION:

<?php

// Initie le système de sessions de PHP, doit 
// être fait avant l'envoi de données
session_start();

if (isset($_SESSION['count'])) {
    $_SESSION['count']++;
} else {
    $_SESSION['count'] = 1;
}

echo 'Je t\'ai vu ' . $_SESSION['count'] . 
    ' fois';

Ce compteur ne peut pas être faussé par le client, ou plus exactement il ne peut pas être amené à une valeur arbitraire. En revanche, le client peut choisir de supprimer son cookie de session, c'est à dire jeter son jeton de sécurité, le compteur repartira alors à 0.

Est-ce qu'un visiteur de votre site peut lire votre code source PHP?

  • Oui
  • Non

Un visiteur peut définir arbitrairement les valeurs de...

  • $_GET
  • $_GET et $_POST
  • $_GET, $_POST et $_COOKIE
  • $_GET, $_POST, $_COOKIE et $_SESSION

Les sessions....

  • N'ont rien à voir avec les cookies
  • S'appuient sur les cookies
  • Sont nécessaire pour le bon fonctionnement des cookies

Est-ce qu'un utilisateur peut choisir de ne jamais enregistrer les variables de $_COOKIE ?

  • Oui
  • Non

Est-ce qu'un utilisateur peut accepter les cookies, mais refuser les sessions ?

  • Oui
  • Non

Est-il possible de lire un cookie depuis Javascript (coté client)?

  • Oui
  • Non

Les données d'un formulaire seront "passées" dans quelle variable?

  • $_GET
  • $_POST
  • Ça dépend

Est-il possible de changer les en-têtes de la réponse HTTP depuis du code PHP?

  • Oui
  • Non

Ce code est-t-il correct?:

<?php
echo "Redirection en cours...";
header("location: /elsewhere");
  • Oui
  • Non