Posez votre question Signaler

[PhP] Forcer le download. [Résolu]

Zep3k!GnO 2026Messages postés jeudi 22 septembre 2005Date d'inscription 22 avril 2015Dernière intervention - Dernière réponse le 5 mars 2012 à 14:41
Bonjour à tous.
Je voulais savoir comment on fait en PhP pour forcer l'utilisateur à télécharger un document (mon cas un PDF).
Que lorsque l'on clic sur le lien, on ait l'invite de télécharegement qui s'affiche.
Je sais que c'est avec des hearders mais je ne me souviens plus bien...
Merci à vous !
Lire la suite 
Réponse
+65
moins plus
Le script mentionné ci-dessus est TRÈS INSÉCURE

Si par exemple on se trouve sur un serveur linux, il suffit de lui passer, par exemple,la valeur "../../../../../../etc/passwd" pour downloader le fichier /etc/passwd... On peut virtuellement accéder à n'importe lequel fichier du serveur à l'aide de ce script.

Utiliser plutot ce script, qui utilise basename() afin de se limiter aux fichiers du répertoire local, par exemple.

<?php
$file=$_GET['file'];

if (($file != "") && (file_exists("./" . basename($file))))
{
$size = filesize("./" . basename($file));
header("Content-Type: application/force-download; name=\"" . basename($file) . "\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: $size");
header("Content-Disposition: attachment; filename=\"" . basename($file) . "\"");
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
readfile("./" . basename($file));
exit();
}
?>
Ajouter un commentaire
Réponse
+22
moins plus
Bonsoir,
je crois qu'il serait bon de répéter certaines choses importantes qui, semblerait-il, passent inaperçues aux yeux de beaucoup de gents:
ce genre de script est à bannir car il présente un énorme risque de sécurité. Pour illustrer mon propos, prenons un petit exemple.
Si l'on regarde attentivement au script montré orgueilleusement par notre ami armoric nous pouvons constater un gros problème. La variable qui contient le nom du fichier est dans l'argument $_REQUEST['file'].
Donc si l'on veut télécharger le fichier 'blabla.pdf' il suffit de faire l'appel à la page de la manière suivante:
download_file.php?file=blabla.pdf

jusque là, tout va bien dans le meilleur des mondes.
Problème... c'est qu'Internet n'est pas le meilleur des mondes. Bien au contraire, c'est un lieu où se tapissent les pires loups qui attendent la brebis égarée.

En termes concrêt voici ce qu'un hacker peux faire avec ce superbe script présenté plus haut (en supposant que le répertoire de stockage est /documents/downloads/

on commence par:
download_file.php?file=index.php
Pas de résultats, c'est que la racine du site est plus haut dans l'arborescence
donc on recommence avec un niveau supérieur:
download_file.php?file=../index.php
Toujours pas de résultats, on continue:
download_file.php?file=../../index.php
BINGO!!! je récupère le fichier index.php du site. En auscultant le code, je peux y trouver les chemins d'accès aux fichiers de configurations d'accès à la base de données... qu'il me suffira de donner en argument au merveilleux script dont nous parlons.

Ce qui fait que en moins de 5mn, j'ai parcouru l'arboresence du site et j'ai tous les codes d'accès à la base de données.

Merci... super code...

Pour ceux que ça intéresse, j'ai crée une source php facilement implémentable dans tout site voulant ajouter la fonction de téléchargement de fichier. Il s'agit d'un mécanisme de jetons avec lesquels vous donner accès à un fichier par l'intermédiaire d'un lien de téléchargement codé. Il n'est pas possible de télécharger autre chose que ce qui est mis à disposition et même si quelqu'un s'amuse à jouer avec les numéros de jetons tout ce qu'il pourra obtenir après de nombreuses tentatives, c'est un fichier qui était programmé au téléchargement. Donc pas de risques de sécurités.

Le script peut être téléchargé à l'adresse suivante:

http://www.phpcs.com//code.aspx?ID=48434


Cordialement
masternico 494Messages postés dimanche 5 octobre 2003Date d'inscription 1 septembre 2011Dernière intervention - 28 févr. 2011 à 21:44
Je ne suis pas sûr que tu ais bien compris nos interventions. Toutes les commandes php utilisées dans ce script sont légitimes et il est évident que les concepteurs du language ne feront rien par rapport qu problème soulevé ici puisqu'il peut être nécéssaire à un script d'atteindre des fichiers un peut partout sur le disque dur.
Par contre, l'utilisation combinée de ses instructions tel que c'est actuellement le cas dans le script présente une grosse faille de sécurité que je te mets au défit d'invalider.
Pourquoi faudrait-il que les webmaster se prennent la tête à sécuriser outre-mesure des accès disque quand il suffit au codeur de modifier son script?
Répondre
kelsett 357Messages postés dimanche 9 juillet 2006Date d'inscription 13 octobre 2014Dernière intervention - 1 mars 2011 à 12:00
Je ne considère pas ça exactement comme une faille, c'est tout. Question de point de vue ;) personnellement, je prends jamais un script tel qu'il est, c'est pour moi seulement une clé pour arriver à ce que je veux, mais à moi de réfléchir un peu pour améliorer ce que je trouve ;)
Répondre
révision- 20 mars 2011 à 14:29
Ce n'est pas une faille: le "?var=x" accepte toute valeur de x, c'est comme ça
Il ne s'agit pas non plus à un script d'atteindre des fichiers un peu partout dans le disque dur, d'ailleurs ce n'est pas adéquat de parcourir avec des "../..", on met les chemins en constante dans des fichiers à part (suffit que l'arborescence change et ça part en vrille).
Conclusion: c'est au développeur de verrouiller là où il ne faut pas lire.
Enfin le script n'est pas à bannir, il suffirait de soumettre $file à une regexp et de retirer (dans ce cas) tout "../../n" (c'est la base quand on récupère une variable "inconnue", on vérifie qu'elle est dans le format attendu), allez une ligne supplémentaire avec preg_replace
Répondre
masternico 494Messages postés dimanche 5 octobre 2003Date d'inscription 1 septembre 2011Dernière intervention - 20 mars 2011 à 16:18
Merci, ça fait du bien de voir que l'on se comprend enfin : il faut bien modifier ce script de manière à en renforcer la sécurité.
Donc, puisqu'il n'est pas sécurisé, c'est qu'il représente une faille de sécurité (CQFD).

Bien sûr, il suffit au programmeur de faire un nettoyage des paramètres d'appels, ce qui, comme tu le rappel si bien, est le BABA de la programmation php.

Alors si tu es prêt à proposer une version sécurisée de ce script, fais toi plaisir, mais pour l'heure, je maintiens qu'il est dangeureux de l'utiliser tel qu'il est, ce qui revient à dire que je maintiens qu'il est à proscrire.

Merci encore.
Répondre
révision- 21 mars 2011 à 00:55
Ce n'est pas que le script est à proscrire, c'est juste qu'il ne prend pas en compte ladite faille. C'est le terme proscrire qui est inadéquat. Le script est incomplet en terme de sécurité c'est un fait.
La version sécurisée est proposée dans le dernier paragraphe juste avec un preg_replace (une ligne en plus dans le script pour empêcher le parcours de répertoire).
Ceci dit, je crois que l'on joue tous avec les mots mais que tout le monde a compris
Répondre
Ajouter un commentaire
Réponse
+6
moins plus
<a href="download-doc.php?file=ton_fichier">telecharger </a>

Tom fichier download

La var file c'est ton fichier

<?
$file=$_GET['file'];

//telechargement
$taille=filesize("doc/$file");
header("Content-Type: application/force-download; name=\"$file\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: $taille");
header("Content-Disposition: attachment; filename=\"$file\"");
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
readfile("doc/$file");
exit();
?>
Zep3k!GnO 2026Messages postés jeudi 22 septembre 2005Date d'inscription 22 avril 2015Dernière intervention - 29 mars 2006 à 10:09
Yep, merci , c'est le post ou t'avais mis ca que je ne retrouvait plus... Merci beaucoup :D
Bonne journée.
Répondre
liliana23info 8Messages postés jeudi 4 juin 2009Date d'inscription 4 juin 2009Dernière intervention - 4 juin 2009 à 19:35
salut?stp tu peux m'aider en php?
Répondre
masternico 494Messages postés dimanche 5 octobre 2003Date d'inscription 1 septembre 2011Dernière intervention - 15 sept. 2008 à 22:23
Salut boulinette. Merci pour ton script.
Le "binary" dans la clause "transfert-encoding" me résout mon propblème.
Répondre
shinmei- 17 oct. 2011 à 17:10
Vous êtes fous d'utiliser ce script. Il permet de downloader n'importe quel fichier passé via GET, c'est très très très insecure !
Répondre
aya- 2 févr. 2012 à 11:36
merci pour ton scipt
Répondre
Ajouter un commentaire
Réponse
+3
moins plus
J'ai essayé la version de boulinette qui ne marche pas chez moi...
Ensuite j'ai testé la proposition de Masternico, c'est sans doute très bien mais je n'ai pas très bien compris l'utilisation du schmilblik d'autant que ça créait un maximum d'erreurs (sans doute dûes à une mauvaise installation de ma part)

En farfouillant j'ai fini par trouver une solution simple et qui doit être suffisamment sécurisée étant donné qu'elle utilise le .htaccess

ça consiste tout simplement à créer un .htaccess avec pour contenu ceci :

<FilesMatch "\.(?i:pdf)$">  
  ForceType application/octet-stream  
  Header set Content-Disposition attachment  
</FilesMatch>


si ça peut aider ...

Il est à noter que cette méthode ne marche pas sur certains serveurs, notamment FREE
Ajouter un commentaire
Réponse
+2
moins plus
Bien sûr, il faut réfléchir avant d'utiliser ce code, ce que tu as cité n'est qu'un exemple parmi tant d'autres car il est évidemment possible de provoquer beaucoup plus de dégâts que ce que tu as dit (je pense notamment au téléchargement forcé de virus/trojans et autres... imagine un bot téléchargé par plusieurs milliers de personnes, le hacker se verrait en mesure d'attaquer de plus gros sites) et il est évident qu'il faut sécuriser ce script pour ne pouvoir accéder qu'à certains fichiers/dossiers/extensions.
Ajouter un commentaire
Réponse
+1
moins plus
Après test du code qui ne fonctionne pas sur IE chez moi non plus, voici ce que j'ai trouvé en fouinant à peine et qui fonctionne tant sur Fx qu'IE :

<? 
$dir="/path/to/file/";
if (isset($_REQUEST["file"])) {
    $file=$dir.$_REQUEST["file"];
    header("Content-type: application/force-download");
    header("Content-Transfer-Encoding: Binary");
    header("Content-length: ".filesize($file));
    header("Content-disposition: attachment; filename=\"".basename($file)."\"");
    readfile("$file");
} else {
    echo "No file selected";
}
 ?> 


Trouvé sur http://www.higherpass.com/php/Tutorials/File-Download-Security/.
Ajouter un commentaire
Réponse
+1
moins plus
Non désolé ^^ ce code ne fonctionne pas non plus, ou peut être sur les anciennes versions mais sur IE8 ou Firefox 3 cela ne fonctionne pas, ca présente toujours la fenêtre de demande de téléchargement.
Ajouter un commentaire
Réponse
+1
moins plus
Bonjour !

ça marche avec des PDF, mais avec des JPG par exemple ? j'arrive pas a faire marcher !!!
J'utilise :
$fichier = "monchemin_/classement.xjpg;
header("Content-type: application/force-download");
header("Content-disposition: attachment; filename=$fichier");

Pour certains c'est une méthode à l'arrache, mais on ne pourra pas aller dans ma BDD, car les code de connexion sont dans un include caché (ne me demandez pas comment j'ai fait c'est mon chef de projet qui a gérer ça.. trop compliqué pour moi lol)

Et ça marche trs bien sous IE8, mais uniquement avec les PDF, j'ai testé avec un XLS et un JPG et les fichiers que je téléchargent sont vides... :(

Quelqu'un connait-il le problème ?

Merci

Ju'
Ajouter un commentaire
Réponse
+0
moins plus
okay bin je testerai ça et je dirai si j'ai des soushis :D
MErci
Ajouter un commentaire
Réponse
+0
moins plus
100% d'accord...
Ajouter un commentaire
Réponse
+0
moins plus
Bonsoir,

Je cherchais depuis un petit moment comment faire ça, et ce script fonctionne merveilleusement bien... sous Chrome. Sous Internet Explorer lorsque le téléchargement est censé commencer, le navigateur affiche un message : "Internet Explorer a bloqué le téléchargement de fichiers... {etc}" et sous Firefox il y a l'habituel "Voulez vous enregistrer ce fichier" etc.

Y a t'il une meilleure technique ?

Merci
Ajouter un commentaire
Réponse
+0
moins plus
C'est bien ça : le problème est que le script ne fonctionnait pas sous IE au niveau des headers, visiblement, j'ai fait profiter d'une source que j'avais trouvée et qui effectivement fonctionnait chez moi (Fx 3.0.11 et IE...6.0, j'avoue, je ne m'en sers pas vraiment) pour indiquer quels headers semblaient les bons, mais je pensais évident que tout l'enrobage est fonction de ce qu'on veut en faire ensuite.
Cela dit, j'aurais peut-être dû préciser qu'utiliser des variables POST est un minimum (et encore...) pour les débutants, oui.
Ajouter un commentaire
Réponse
+0
moins plus
Même... en POST le problème persiste:
J'ai juste à faire une page avec deux frames dont une que j'utilise pour afficher une page de ton site (index par exemple).
Du coup, comme j'ai la main sur la page de ton site (d'une frame à l'autre je peux faire ce que je veux), j'y rajoute un script d'appel ajax (le tout se passe en interne sur mon ordi. Je ne touche à rien sur la page d'origine qui se trouve sur le serveur).
Ensuite, comme la page de ton site est autorisée a effectuer une requette ajax sur ton site (normal), je déclenche la procédure qui se charge d'envoyer une requette POST avec les paramètres d'appels qu'il faut pour demander à télécharger n'importe quel fichier de ton site.
Le retour se fait aussi grâce la page de ton site que j'ai modifiée. La seule différence, c'est qu'au lieu que mon navigateur n'interprète la page HTML que je reçois en retour, c'est à moi de la décoder. Mais là encore, rien de bien sorcier:
j'ouvre une popup et j'y écris tout simplement ce que je reçois de ton site... donc la popup me propose ton fichier en téléchargement...

C'est le BABA du Xsite-scripting (cross-site scriping)

Les mains dans le nez, les doigts dans les poches...
Ajouter un commentaire
Réponse
+0
moins plus
En effet, le script reste par lui même fonctionnel !

Comme le dit masternico, il sera très simple de passer n'importe quel fichier en paramètre. Et même les fichiers .htaccess / .htpasswd / .htgroup / robot.txt !!! Oui le readfile de php étant natif et possédant les droits de lecture, il permettra de lire n'importe quel fichier dant le documentRoot du site.

Ne jamais passer de nom de dossier dans la variable, et au contraire placer en dur le répertoire où se trouve le(s) fichier(s) a télécharger dans le script php et de bien contrôler l'existance de la ressource à délivrer.

Autre point, je cherche à ce que GG Analytics puisse 'tracker' les fichiers downloadés !!
Qq. à t-il une idée ?

Il me vient l'idée de forcer le download via HTML à partir d'un meta refresh et donc de placer le code GGAT dans la page ...
kelsett 357Messages postés dimanche 9 juillet 2006Date d'inscription 13 octobre 2014Dernière intervention - 2 juil. 2009 à 11:24
Il me vient l'idée de forcer le download via HTML à partir d'un meta refresh et donc de placer le code GGAT dans la page ...

Oui, ou alors peut être ajouter automatiquement l'url de tes fichiers sur ton plan de site...
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Bon en fait j'ai trouvé mon problème,

C'est tout simplement parceque j'ai eu de la chance avec le PDF ... ^^ ça ne marchais pas avec les autres types de fichiers car j'avais laissé des balises HTML trainé et un include intégrant du HTML.

Maintenant ça marche mieux :)

Donc voilà je transmets, au cas où ça pourrait aider quelqu'un ;)
ambro- 5 août 2009 à 13:56
pourriez-vous m'envoyer l'intégralité votre script final pour le téléchargement des fichiers sur Internet ?
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
application/octet-stream est le type officiel.
application/force-download n'est pas reconnu par les navigateurs web, ce qui signifie que le header est traité comme un application/octet-stream.
Ajouter un commentaire
Réponse
+0
moins plus
je me suis prie 2 portes dans la tronche aujourd'hui , j'avais pas vu qu'elles ne s'ouvrer pas
Ajouter un commentaire
Réponse
+0
moins plus
Bonjour,
je pense que ceci peut vous être utile !
http://webinfobazar.com/header-location-telechargement-dun-fichier-php/

d'autres tutos/astuces sont en cours de réalisation :)
Ajouter un commentaire
Réponse
-1
moins plus
Je crois que c\'est une chose qui ne concerne que le navigateur en fonction du type MIME du document qu\'on lui propose.

Si par exemple un serveur lui envoie un document possédant le type MIME d\'un pdf et que le navigateur inclut la lecture des pdf alors celui -ci le lira directement, par contre pour un type MIME qu\'il ne sait pas traiter il proposera le téléchargement.

Une solution pour pallier à ça serait de donner le type MIME
application/octet-stream (grâce à la fonction header justement):
header('Content-Type: application/octet-stream')
puis d\'envoyer le pdf mais il faut que la personne en face sache comment l\'ouvrir une fois téléchargé...
Ajouter un commentaire
Réponse
-1
moins plus
Salut =)

Il me semble que tu peux le faire avec le code :
header('Content-Disposition: attachment; filename="document.pdf"');

++
Ajouter un commentaire
Ce document intitulé «  [PhP] Forcer le download.  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes.

Le fait d'être membre vous permet d'avoir des options supplémentaires.