Cours sur HTTP * url : https://en.wikipedia.org/wiki/Uniform_Resource_Identifier avec des exemples. query, fragment. chemin : pas forcément un vrai chemin. * header fields https://en.wikipedia.org/wiki/List_of_HTTP_header_fields * stateless * safe methods * idempotent methods * cacheable * status code & reason phrase https://en.wikipedia.org/wiki/List_of_HTTP_status_codes * cache : forward/reverse ; browser/machine/proxy/ISP https://en.wikipedia.org/wiki/Web_cache * compression https://en.wikipedia.org/wiki/HTTP_compression * auth * HTTPS https://en.wikipedia.org/wiki/HTTPS serveurs web : un programme qui sait répondre à une requête HTTP par une réponse HTTP. exemples : apache, nginx.
HyperText Transfer Protocol ; c'est le langage que parlent le serveur web et le navigateur web pour se communiquer les pages
Élément le plus fondamental du web, et aussi le plus caché pour le grand public
HTTPS est la version sécurisée de HTTP : les messages sont chiffrés, et donc illisibles pour quiconque les intercepterait entre le client et le serveur ex: wifi public
Le web est un ensemble de ressources (documents — ou autre !), liées entre elles
Chaque ressource a une adresse (ce qui permet de la récupérer, et de la lier à d'autres ressources)
Les adresses sont appelées URL (ou plus généralement URI)
La syntaxe des URL a été créée pour le web, mais est utilisée dans de nombreux autres contextes
userinfo host port ┌───────┴───────┐ ┌────┴────────┐ ┌┴┐ http://john.doe:password@www.example.com:123/forum/questions/?tag=networking&order=newest#top └─┬─┘ └───────────┬───────────────────────┘└─┬─────────────┘└────────┬─────────────────┘└┬─┘ scheme authority path query fragment
La partie « scheme » indique le protocole à utiliser pour récupérer la ressource
La partie « authority » indique à qui il faut s'adresser pour récupérer la ressource
La partie « path » indique le chemin vers la ressource sur le serveur
La partie « query » permet d'indiquer des paramètres (pour filtrer ou mettre en forme la ressource)
La partie « fragment » identifie une sous-partie de la ressource (par exemple une section d'une page HTML)
Autres exemples de la syntaxe URI
Remarque : il y a de nombreuses variations pour les noms des différentes parties d'une URL
Commandes : GET, POST, HEAD, PUT, DELETE…
Champs d'en-tête : Host, User-Agent, Accept… seul Host est obligatoire
Exemple, le client veut accéder à la ressource
http://www.toto.fr/blog/posts/243.html?order=newest#top
GET /blog/posts/243.html?order=newest HTTP/1.1
Host: www.toto.fr
Accept: text/html
Accept-Charset: utf-8
Connection: keep-alive
NB: le fragment n'est pas transmis, il est géré uniquement par le client
Codes : 200 (OK), 404 (not found), 500 (internal server error)…
Champs de réponse : Content-type, Last-Modified, Location…
HTTP/1.1 200 OK
Date: Mon, 05 Jan 2015 12:12:12 GMT
Last-Modified: Wed, 02 Jan 2013 18:18:18 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 323
Connection: close
<html>
<head> <title>Le blog de Toto</title> </head>
<body> <p>Bienvenue sur mon blog !</p> </body>
</html>
netcat example.com 80 <demo/requete.txt
ça devrait donner qqch comme demo/reponse.txt
Il existe de nombreux serveurs web (au sens logiciel), les plus utilisés étant Apache et nginx
Rôle du programme serveur : reçoit des requêtes HTTP et renvoie des réponses HTTP (qui peuvent contenir n'importe quoi)
En pratique, on a souvent besoin que les URL correspondent à des fichiers
un des rôles principaux du programme serveur est d'interpréter le chemin demandé dans la requête comme un chemin dans le système de fichiers
Interprétation pas directe ! On ne veut pas que tout le système de fichiers de la machine soit accessible sur le web…
le chemin demandé est « traduit »
Typiquement, le serveur considère que la racine de l'URL (chemin /
)
correspond à un répertoire fixé — typiquement /var/www/html
— appelé « web root » ou « document root »
la « traduction » est plus ou moins une simple concaténation des chemins :
l'URL
http://www.toto.fr/bidule/truc/machin.html
sera interprétée comme correspondant au fichier
/var/www/html/bidule/truc/machin.html
sur le serveur
On dit que le serveur web « sert » le contenu du répertoire /var/www/html
à la racine du site
Si le chemin traduit de l'URL correspond à un fichier (HTML, ou image, PDF, audio…), c'est lui que le serveur envoie en réponse.
Si le chemin traduit ne correspond à rien, le serveur enverra une erreur 404 (on peut configurer ce comportement)
Si le chemin correspond à un répertoire le serveur regarde s'il contient un fichier index.html
si oui, c'est ce fichier qu'il sert
sinon, ça dépend de la configuration : il peut renvoyer une 404, une 403, ou générer une page pour montrer le contenu du répertoire
Si besoin que le contenu d'un site soit dynamique, par exemple dépende d'une base de données, il faut que le serveur génère du HTML
Il va déléguer cette tâche à d'autres programmes, typiquement à l'interpréteur PHP
Utilisation de Common Gateway Interface, ou bien exécution en fonction de l'extension du fichier
directory index https://en.wikipedia.org/wiki/Webserver_directory_index .htaccess ? https://en.wikipedia.org/wiki/.htaccess CGI https://en.wikipedia.org/wiki/Common_Gateway_Interface /cgi-bin/ lancer script shell avec env|sort et date (ou java !) historiquement ça marchait comme ça autre technique : serveur exécute en fonction de l'extension du fichier -& php
PHP a été conçu au départ pour mettre des bouts de programme au milieu d'une page HTML
<!DOCTYPE html>
<html>
<head><title>Ma page</title><meta charset="UTF-8" /></head>
<body>
<h2>Les nombres</h2>
<p>Voici les nombres de 1 à 10000 :
<?php
for ($i = 1; $i <= 10000; $i++) {
echo "$i, ";
}
?>
</p>
</body>
</html>
C'est une page HTML avec des blocs d'instructions encadrées
par <?php
et ?>
<?
?>
permettent de définir des PI (« processing
instruction ») ;php
indique que ces instructions sont du PHP.Ce qui est en dehors de ces blocs est affiché tel quel
Les blocs sont remplacés par le résultat de l'exécution des instructions
Regarder le code source de la page : noter bien qu'il ne subsiste aucune trace du code PHP !
nombres.php
nombres.php
Le navigateur ne voit jamais le code PHP : il ne récupère que de l'HTML !
Les navigateurs ne savent d'ailleurs pas interpréter un fichier PHP. Si vous essayez d'en ouvrir un en local avec Firefox, il devrait vous proposer de le télécharger, comme pour tout type de fichier qu'il ne connaît pas.
<?php
// variables et calculs
$titre = "Page démo";
$contenu = "Le contenu sera généré par mon programme";
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<title><?php echo $titre; ?></title>
</head>
<body>
<h1><?php echo $titre; ?></h1>
<p><?php echo $contenu; ?></p>
</body>
</html>
php.ini
) :log_errors
(on/off) et la variable de config error_log
(chemin absolu vers un fichier de log)display_errors
(on/off).htaccess
(un guide ;
solution pour activer le log)ini_set
, par exemple ini_set('display_errors', 'on')
.
Cependant en cas de parse error, le script n'est pas exécuté du
tout, et donc le ini_set
n'a aucun effet…display_errors
est off
et n'est modifiable que par un admin.header
header("Location: http://google.fr");
(PHP se charge alors de passer un code 302)header("Content-type: text/plain;");
pour renvoyer du texte brut par ex. (exemples texte, html par défaut)header('Content-Disposition: attachment; filename="exemple.html"');
va proposer la page à l'enregistrement (démo)header
modifie l'en-tête HTTP, qui est avant le HTML header
:
même un saut de ligne suffit à provoquer une erreur « Headers already sent »
démo et explications
<pre>
<?php
echo "One\n";
ob_start(); /* on active l'output buffering :
* tout ce qui suit sera enregistré
* dans un buffer au lieu d'être affiché
*/
echo "Two\n";
include "demo/fichier.txt";
$var = ob_get_clean(); /* on désactive l'OB, on
* récupère le contenu du
* buffer, et on le vide.
*/
echo "Three\n";
echo "Contenu du buffer :\n « " . $var . " »\n";
?>
</pre>
One Three Contenu du buffer : « Two Coucou, je suis un fichier ! Au revoir »
Elles sont accessibles partout
Ce sont des tableaux associatifs
$_POST
: contient les données passées dans le corps d'une requête POST
$_GET
: contient les paramètres de l'URL (même si la requête était POST
!)
Démo GET$_SERVER
: données du serveur,
on y trouve notamment
$_SERVER['REQUEST_URI']
)$_SERVER['PATH_INFO']
).$_ENV
: données sur l'environnement$_FILES $_COOKIE $_SESSION
: feront l'objet de cours spécifiquesRappel : phpinfo()
affiche la configuration PHP de votre serveur et la valeur de toutes les superglobales (Voir)
Si on utilise une variable qui n'existe pas, un avertissement (notice) est lancé
il n'y a pas d'erreur, PHP considère que la variable a la valeur null
Ne pas s'appuyer là-dessus : s'il y a un avertissement, c'est pour une bonne raison (code pas propre, plus difficile à maintenir)
isset
if (isset($toto))
echo "La variable \$toto existe, voilà son contenu : $toto";
else
echo "La variable \$toto n'existe pas";
Le code précédent ne génère aucun avertissement.A priori, dans du code propre et bien organisé, on n'a jamais besoin de isset()
!
isset
est très souvent utilisée pour vérifier que les tableaux
$_GET
ou $_POST
contiennent un paramètre donné
key_exists
, qui risque moins
de cacher une erreur dans le code :
if (key_exists('toto', $_GET))
$toto = $_GET['toto'];
else
$toto = '';
array_key_exists est un peu plus lent (genre 2 fois) à cause de l'appel de fonction. c'est pas bien méchant. ça reste O(1) normalement.empty()
empty
permet de vérifier qu'une variable est « vide »,
c'est-à-dire que
false
Attention, dans la liste des valeurs égales à false
, il y a notamment la chaîne '0'
!
même si vous savez que votre variable contient une chaîne, empty()
ne vous permet pas de vérifier qu'elle est vraiment vide !
si vraiment besoin de manipuler des variables
qui n'existent pas forcément,
il est conseillé d'utiliser plutôt isset
et un test explicite
(hors cas très particuliers).
Il est également très fortement déconseillé d'utiliser empty($maVariable)
si la variable
est censée exister : cela peut cacher des erreurs dans le code (erreur dans le nom de variable, par exemple).
si besoin de tester qu'une variable est « vide », utiliser plutôt !$maVariable
ou $maVariable == false
(comparaison volontairement faible),
ou mieux, comparer explicitement à la valeur vide qui vous intéresse : $maChaine === ''
ou $monTableau === []
.
Pour résumer, il est encore plus déconseillé d'utiliser empty
que isset
.
Détails sur isset
et empty
, leur relation avec null
, et quand les utiliser : the definitive guide to PHP’s isset
and empty