Forcer le téléchargement d’un fichier (PHP/.htaccess)

11 01 2012

Par défaut, quand vous chargez une URL dans la barre d’adresse d’un navigateur (Firefox, Safari, Chrome…), celui-ci adopte un comportement différent en fonction du type de fichier.

Si c’est une page web, une image ou un fichier texte par exemple, le navigateur va afficher le contenu de ce fichier dans sa fenêtre.

Par contre si c’est un fichier dont le type n’est pas pris en charge nativement par le navigateur (exemple : fichier excel, fichier Photoshop, ZIP, exécutable…), alors il va télécharger le fichier.

Parfois, on souhaite que le navigateur propose toujours le téléchargement, même pour les types pris en charge.

Pour cela, il faut que le serveur envoi des headers HTTP spécifiques qui vont indiquer au navigateur de toujours télécharger, on appelle ça le force download.

Sur un serveur Apache/PHP, il y a 2 façons de le faire :

Force download en PHP

L’idée est extrêmement simple : on balance les headers et ensuite on envoie le contenu du ficher avec la fonction readfile().

<?php
$filename = "Votre_Fichier.ext";

# Envoi des entêtes HTTP qui permettent de forcer le téléchargement
header("Content-disposition: attachment; filename=".$filename);
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/octet-stream");
header("Content-Length: ".filesize($filename));
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");

# Lecture & envoi du fichier au client (navigateur)
readfile($filename);
?>

Le header Content-Length est très important, c’est ce qui permettra au client de détecter la fin du téléchargement et aussi d’estimer le temps de téléchargement.

L’inconvénient de cette méthode, c’est que le script PHP continu de tourner pendant toute la durée du téléchargement, du coup on risque de se prendre une erreur max_execution_time.

Sans compter que si le script est merdique, il va consommer de la mémoire pour rien, voir bloquer les autres scripts (par exemple si vous n’avez pas libéré la session avec session_write_close(), ou encore si vous n’avez pas fermé une éventuelle connexion base de données).

C’est pour ça que je vais vous montrer une autre façon de le faire, plus propre.

Force download avec un .htaccess (Apache)

On peut faire la même chose directement avec Apache, via httpd.conf ou via un .htaccess, en utilisant les modules mod_headers et mod_mime :

ForceType application/octet-stream
Header set Content-Disposition attachment

Le seul petit problème est que si vous placez ça dans un htaccess, ces règles vont aussi s’appliquer au listing automatique de répertoires d’Apache (mod_autoindex).
Donc si vous accédez à http://monsite/mes-images/, vous aurez un téléchargement au lieu de l’affichage de la liste des fichiers du répertoire.

Heureusement, on peut facilement exclure le listing avec une directive FilesMatch :

<FilesMatch ".+">
    ForceType application/octet-stream
    Header set Content-Disposition attachment
</FilesMatch>

Et voilà ;)


Partager :

Ces icônes sont des liens vers des sites de partage de signet sociaux où les lecteurs peuvent partager et découvrir de nouveaux liens.
  • Digg
  • del.icio.us
  • Facebook
  • Digg -fr
  • Live
  • MisterWong Fr
  • Scoopeo
  • StumbleUpon
  • Technorati
  • Wikio FR

Actions

Informations

Et maintenant je fais quoi ?

Laisser un commentaire

Vous pouvez utiliser ces balises html : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>