2010-12-03 30 views
7

Je développe un système qui permet aux utilisateurs enregistrés (qui pourraient être n'importe qui) de télécharger des fichiers. J'ai bloqué mime-types etc pour tenter de restreindre les fichiers aux types .doc, .docx et .pdf, mais pour plus de sécurité, ils sont téléchargés dans un dossier en dehors du webroot.Comment puis-je autoriser un utilisateur à télécharger un fichier stocké en dehors du site Web?

D'autres utilisateurs peuvent ensuite choisir de télécharger les fichiers. Comment puis-je leur permettre de faire cela? Évidemment, je ne peux pas simplement mettre un lien vers le fichier, car il est en dehors du webroot. Je ne suis pas sûr de savoir comment atteindre le fichier! Je suppose que je peux utiliser les fonctions du fichier php pour obtenir le fichier, mais comment puis-je le 'servir' à l'utilisateur qui l'a demandé?

Quelles sont les implications de sécurité de tout cela?

Merci.

+0

duplication possible de [Autoriser les utilisateurs à télécharger des fichiers en dehors de webroot] (http://stackoverflow.com/questions/3884677/allow-users-to-download-files-outside-webroot) – Gordon

+0

vous savez que c'est vraiment tout à fait dangereux? Vous remarquerez que les sites utilisent un nom de domaine différent pour le contenu téléchargé par l'utilisateur. –

+1

@Tom sauf si vous indiquez pourquoi c'est dangereux, ce n'est pas dangereux. – Gordon

Répondre

10

Vous avez besoin d'un script PHP qui effectue les opérations suivantes:

  1. Définissez l'en-tête-tête correctement (en fonction de ce que l'utilisateur est en cours de téléchargement)
  2. Définissez la longueur du contenu de type de contenu correctement (en fonction du la taille du fichier)
  3. Ouvrez le fichier pour la lecture (vous pouvez utiliser fopen)
  4. lire le fichier et la sortie de son contenu dans le flux de sortie
  5. Fait

Vous pouvez également utiliser la fonction readfile pour faire la même chose. Voici un exemple à partir du site de PHP:

<?php 
$file = 'monkey.gif'; 

if (file_exists($file)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/octet-stream'); 
    header('Content-Disposition: attachment; filename='.basename($file)); 
    header('Content-Transfer-Encoding: binary'); 
    header('Expires: 0'); 
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
    header('Pragma: public'); 
    header('Content-Length: ' . filesize($file)); 
    ob_clean(); 
    flush(); 
    readfile($file); 
    exit; 
} 
?> 
+0

qui ne résout que la moitié de la question – Gordon

+1

Un exemple légèrement plus complet ici, y compris le type mime et éventuellement plus de casse correcte - http: // stackoverflow.com/questions/4275830/4277145 # 4277145; Gordon, qu'est-ce qui manque? –

0

Voir les réponses à cette question similaire: Refer to a file outside the website tree for downloading purposes, qui relie la PHP header function manual page.

+1

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et fournir le lien pour référence. Les réponses à lien uniquement peuvent devenir invalides si la page liée change. – Musa

+0

Point pris - à l'heure actuelle, j'ai juste le temps d'ajouter un peu plus d'informations sur les ressources liées, donc pour l'instant c'est ce que j'ai fait. –

0

Vous pouvez mettre votre répertoire de fichiers en racine et appliquer des règles de réécriture de mod pour sécuriser et montrer un chemin virtuel aux utilisateurs au lieu du vrai chemin.

+0

Pouvez-vous m'en dire plus à ce sujet? Le répertoire se trouve dans/userfiles du répertoire personnel. Quelles règles dois-je appliquer? Comment afficher un chemin virtuel? Merci. – Sharon

+0

Vous pouvez éditer votre fichier .htaccess et définir une règle comme RewriteRule^download.php $ download.php? Path = yourpath/$ 1.doc Votre utilisateur peut seulement voir download.php – Adeel

+0

Cela annule à peu près les avantages de la sécurité de le mettre à l'extérieur le document racine en premier lieu. –

0

les opérations suivantes:

$fileName = basename($_GET['file']); 
$path = 'path/to/data/'.$fileName; 

// define $mimeType and $isAuthenticated 

if ($isAuthenticated && file_exists($path)) { 
    // serve file 
    header('Content-type: '.$mimeType); 
    header('Content-Disposition: attachment; filename="'.$fileName.'"'); 
    readfile($path); 
} else { 
    // 404 
} 

Cela aura probablement besoin de plus d'en-têtes pour répondre à vos besoins, mais vous devriez avoir une idée de comment cela peut être utilisé.