Dans ce tutoriel je vous propose de découvrir comment sécuriser le téléchargements de fichiers en PHP. Le principe est de permettre aux gens de télécharger un fichier sans forcément donner un accès direct au chemin de ce dernier (on souhaite par exemple que la personne soit connectée pour lancer le téléchargement).
Renvoyer les bons headers
La première étape consiste à renvoyer les bons headers, qui vont permettre au navigateur de réagir en fonction.
$file = "/var/www/monsite/protected/MonFichier.zip";
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-disposition: attachment; filename="' . basename($file) . '"');
// Ici le code pour renvoyer le fichier
Ensuite il peut être tentant d'utiliser un readfile()
pour renvoyer le fichier depuis PHP mais le problème de cette méthode est qu'elle va obliger PHP à fonctionner pendant toute la phase de téléchargement, ce qui peut rapidement poser problème (surtout avec de gros fichiers).
Apache : XSendFile
Apache dispose d'un module capable de comprendre les headers X-Sendfile
qui permet de renvoyer un fichier directement. Ce module n'est pas disponible par défaut et il vous faudra l'installer :
sudo apt-get install libapache2-mod-xsendfile
Une fois installé il va falloir modifier la configuration de notre Virtual Host pour indiquer à Apache le dossier autorisé par XSendfile
<VirtualHost *:80>
....
XSendFile On
XSendFilePath /var/www/monsite/protected/
...
</VirtualHost>
Maintenant il est possible d'utiliser le header X-Sendfile afin de renvoyer le fichier :
$file = "/var/www/monsite/protected/MonFichier.zip";
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-disposition: attachment; filename="' . basename($file) . '"');
header('X-Sendfile: ' . $file);
Nginx : X-Accel
Nginx dispose aussi d'un système similaire X-Accel qui permet de faire une redirection interne en fonction d'un header. Il faut commencer par configurer notre Virtual host.
server {
...
location /downloads {
internal;
alias /var/www/monsite/protected/;
}
}
Maintenant il faut renvoyer le bon header via PHP afin d'indiquer à nginx d'utiliser cet alias :
$file = "/var/www/monsite/protected/MonFichier.zip";
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-disposition: attachment; filename="' . basename($file) . '"');
header('X-Accel-Redirect: /downloads/'.basename($file));