web-dev-qa-db-fra.com

Forcer à télécharger un fichier en utilisant PHP

J'ai un fichier CSV sur mon serveur. Si un utilisateur clique sur un lien, celui-ci devrait être téléchargé, mais il s'ouvrira dans la fenêtre de mon navigateur.

Mon code ressemble à ce qui suit

<a href="files/csv/example/example.csv">
    Click here to download an example of the "CSV" file
</a>

C'est un serveur web normal sur lequel tout mon travail de développement est effectué.

J'ai essayé quelque chose comme:

<a href="files/csv/example/csv.php">
    Click here to download an example of the "CSV" file
</a>

Maintenant le contenu de mon fichier csv.php:

header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');

Maintenant, mon problème est le téléchargement, mais pas mon fichier CSV. Il crée un nouveau fichier.

61
Roland

.htaccess Solution

Pour forcer le téléchargement de tous les fichiers CSV sur votre serveur, ajoutez votre fichier .htaccess:

AddType application/octet-stream csv

Solution PHP

header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
readfile("/path/to/yourfile.csv");
101
robjmills

Ou vous pouvez le faire en utilisant HTML5. Simplement avec 

<a href="example.csv" download>download not open it</a>
21
AtanuCSE

Cela ne peut pas être fait de manière fiable, car il appartient au navigateur de décider quoi faire avec une URL qu'il lui a été demandé de récupérer.

Vous pouvez suggérer} _ _ au navigateur qu'il devrait proposer immédiatement de "sauvegarder sur le disque" en envoyant un en-tête Content-disposition:

header("Content-disposition: attachment");

Je ne sais pas dans quelle mesure cela est pris en charge par différents navigateurs. L’alternative est d’envoyer un flux de type application/octet de type contenu, mais c’est un hack (vous dites en gros au navigateur "je ne vous dis pas de quel type de fichier il s’agit" et en fonction du fait que les navigateurs proposent alors une boîte de dialogue de téléchargement) et causeraient des problèmes avec Internet Explorer.

Plus d'informations à ce sujet dans la FAQ de Web Authoring.

Edit Vous avez déjà basculé sur un fichier PHP pour fournir les données, ce qui est nécessaire pour définir l'en-tête Content-disposition (à moins que certains paramètres Apache trop compliqués ne le permettent également). Il ne reste plus maintenant qu’à ce fichier PHP pour lire le contenu du fichier CSV et pour l’imprimer - le filename=example.csv dans l’en-tête ne fait que suggérer au navigateur client le nom à utiliser pour le fichier; récupérer les données du fichier sur le serveur.

15
Michael Borgwardt

Voici une solution plus sécurisée pour le navigateur:

    $fp = @fopen($yourfile, 'rb');

    if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
{
    header('Content-Type: "application/octet-stream"');
    header('Content-Disposition: attachment; filename="yourname.file"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header("Content-Transfer-Encoding: binary");
    header('Pragma: public');
    header("Content-Length: ".filesize($yourfile));
}
else
{
    header('Content-Type: "application/octet-stream"');
    header('Content-Disposition: attachment; filename="yourname.file"');
    header("Content-Transfer-Encoding: binary");
    header('Expires: 0');
    header('Pragma: no-cache');
    header("Content-Length: ".filesize($yourfile));
}

fpassthru($fp);
fclose($fp);
12
Franz

Configurez votre serveur pour envoyer le fichier avec le type de support application/octet-stream.

7
Gumbo

Belle solution propre:

<?php
    header('Content-Type: application/download');
    header('Content-Disposition: attachment; filename="example.csv"');
    header("Content-Length: " . filesize("example.csv"));

    $fp = fopen("example.csv", "r");
    fpassthru($fp);
    fclose($fp);
?>
2
vdbuilder

Cela signifie que votre navigateur peut gérer ce type de fichier.

Si vous ne l'aimez pas, la méthode la plus simple serait d'offrir des fichiers Zip. Tout le monde peut gérer les fichiers Zip, et ils sont téléchargeables par défaut.

2
StampedeXV

Une réponse précédente sur cette page explique comment utiliser .htaccess pour forcer le téléchargement de tous les fichiers d’un certain type. Cependant, la solution ne fonctionne pas avec tous les types de fichiers sur tous les navigateurs. C'est un moyen plus fiable:

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

Vous devrez peut-être vider le cache de votre navigateur pour que cela fonctionne correctement.

1
Chris Harrison

Si vous le faites avec votre application elle-même ... J'espère que ce code vous aidera.

HTML

En href - vous devez ajouter download_file.php avec votre URL:

<a class="download" href="'/download_file.php?fileSource='+http://www.google.com/logo_small.png" target="_blank" title="YourTitle">

PHP

/* Here is the Download.php file to force download stuff */

<?php
    $fullPath = $_GET['fileSource'];
    if($fullPath) {
        $fsize = filesize($fullPath);
        $path_parts = pathinfo($fullPath);
        $ext = strtolower($path_parts["extension"]);

        switch ($ext) {
            case "pdf":
                header("Content-Disposition: attachment; filename=\"" . $path_parts["basename"]."\""); // Use 'attachment' to force a download
                header("Content-type: application/pdf"); // Add here more headers for diff. extensions
                break;

            default;
                header("Content-type: application/octet-stream");
                header("Content-Disposition: filename=\"" . $path_parts["basename"]."\"");
        }

        if($fsize) { // Checking if file size exist
            header("Content-length: $fsize");
        }
        readfile($fullPath);
        exit;
    }
?>
0
hussain

Pour forcer le téléchargement, vous pouvez utiliser l'en-tête Content-Type: application/force-download, pris en charge par la plupart des navigateurs:

function downloadFile($filePath)
{
    header('Content-Type: application/force-download');
    header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
    header('Content-Length: ' . filesize($filePath));
    readfile($filePath);
}

UNE MEILLEURE FAÇON

Télécharger des fichiers de cette façon n'est pas la meilleure idée, surtout pour les gros fichiers. PHP aura besoin de plus de temps CPU/mémoire pour lire et afficher le contenu des fichiers. Lors du traitement de gros fichiers, les limites de temps/mémoire peuvent être dépassées.

Une meilleure solution consiste à utiliser PHP pour authentifier et accorder l'accès à un fichier. Le traitement de fichiers doit être délégué à un serveur Web à l'aide de la méthode X-SENDFILE (nécessite une configuration de serveur Web):

Après avoir configuré le serveur Web pour gérer X-SENDFILE, remplacez simplement readfile($filePath) par header('X-SENDFILE: ' . $filePath) et le serveur Web se chargera de la diffusion des fichiers, ce qui nécessitera moins de ressources que l'utilisation de PHP readfile.

(Pour Nginx, utilisez X-Accel-Redirect en-tête au lieu de X-SENDFILE)

Remarque: Si vous finissez par télécharger des fichiers vides, cela signifie que vous n'avez pas configuré votre serveur Web pour gérer l'en-tête X-SENDFILE. Consultez les liens ci-dessus pour savoir comment configurer correctement votre serveur Web.

0
Dima L.