Comment forcer le téléchargement de fichiers avec PHP


125

Je veux exiger qu'un fichier soit téléchargé lorsque l'utilisateur visite une page Web avec PHP. Je pense que cela a quelque chose à voir avec file_get_contents, mais je ne sais pas comment l'exécuter.

$url = "http://example.com/go.exe";

Après avoir téléchargé un fichier avec, header(location)il ne redirige pas vers une autre page. Ça s'arrête juste.


duplication possible du téléchargement de la page
hakre

Réponses:


234

Lisez la documentation sur la fonction PHP intégrée readfile

$file_url = 'http://www.myremoteserver.com/file.exe';
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary"); 
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\""); 
readfile($file_url); 

Assurez-vous également d'ajouter le type de contenu approprié en fonction de votre fichier application / zip, application / pdf, etc. - mais uniquement si vous ne souhaitez pas déclencher la boîte de dialogue Enregistrer sous.


6
Pourquoi est-ce nécessaire?
john

Je veux dire si son autre que le fichier .exe que seulement .Else cela devrait fonctionner correctement.
Pit Digger

7
N'oubliez pas de vider ;-) ob_clean (); affleurer(); / * avant * / readfile ($ file_url);
Ash

Donc, si vous avez un gros fichier de 10 Go, php essaie de charger tout ce fichier?
GDY

exit () doit être appelé à la fin pour éviter tout problème potentiel (en parlant d'expérience :-)
ykay dit Réintégrer Monica

42
<?php
$file = "http://example.com/go.exe"; 

header("Content-Description: File Transfer"); 
header("Content-Type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"". basename($file) ."\""); 

readfile ($file);
exit(); 
?>

Ou, lorsque le fichier ne peut pas être ouvert avec le navigateur, vous pouvez simplement utiliser l'en- Locationtête:

<?php header("Location: http://example.com/go.exe"); ?>

1
Le nom de fichier dans votre en-tête ne doit pas être $file(qui contient la partie http) mais un nom de fichier valide.
Fabio

1
Il n'y a pas de type de support d' application / téléchargement forcé ; utilisez plutôt application / octet-stream .
Gumbo

fonctionne très bien! Mais ajoute 'au nom de fichier stocké. Veuillez utiliser: filename = ". Basename ($ file));
harry4516

@ harry4516 modifié selon votre conclusion
Marek Sebera

Ne fonctionne pas cher en cas d'image png pour moi. Merci.
Kamlesh

40
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"file.exe\""); 
echo readfile($url);

est correct

ou meilleur pour le type de fichiers exe

header("Location: $url");

@Fabio: ajoutera plus de détails
genesis

C'était super facile. Ça a marché. À quoi sert alors file-Get_contents? Juste curieux. Merci.
john

pour le télécharger sur votre serveur
genesis

10
Supprimez simplement 'echo' avant 'readfile ()' car la valeur de retour est spécifiée comme "Renvoie le nombre d'octets lus dans le fichier. Si une erreur se produit, FALSE est renvoyé et à moins que la fonction n'ait été appelée comme @readfile (), un message d'erreur est imprimé. ". Vous vous retrouverez donc avec le contenu du fichier + le nombre entier à la fin du contenu.
Mladen B.

22

Affichez d'abord votre fichier et définissez sa valeur dans url.

index.php

<a href="download.php?download='.$row['file'].'" title="Download File">

download.php

<?php
/*db connectors*/
include('dbconfig.php');

/*function to set your files*/
function output_file($file, $name, $mime_type='')
{
    if(!is_readable($file)) die('File not found or inaccessible!');
    $size = filesize($file);
    $name = rawurldecode($name);
    $known_mime_types=array(
        "htm" => "text/html",
        "exe" => "application/octet-stream",
        "zip" => "application/zip",
        "doc" => "application/msword",
        "jpg" => "image/jpg",
        "php" => "text/plain",
        "xls" => "application/vnd.ms-excel",
        "ppt" => "application/vnd.ms-powerpoint",
        "gif" => "image/gif",
        "pdf" => "application/pdf",
        "txt" => "text/plain",
        "html"=> "text/html",
        "png" => "image/png",
        "jpeg"=> "image/jpg"
    );

    if($mime_type==''){
        $file_extension = strtolower(substr(strrchr($file,"."),1));
        if(array_key_exists($file_extension, $known_mime_types)){
            $mime_type=$known_mime_types[$file_extension];
        } else {
            $mime_type="application/force-download";
        };
    };
    @ob_end_clean();
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');
    header('Content-Type: ' . $mime_type);
    header('Content-Disposition: attachment; filename="'.$name.'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        } else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    } else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    $chunksize = 1*(1024*1024);
    $bytes_send = 0;
    if ($file = fopen($file, 'r'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while(!feof($file) &&
            (!connection_aborted()) &&
            ($bytes_send<$new_length)
        )
        {
            $buffer = fread($file, $chunksize);
            echo($buffer);
            flush();
            $bytes_send += strlen($buffer);
        }
        fclose($file);
    } else
        die('Error - can not open file.');
    die();
}
set_time_limit(0);

/*set your folder*/
$file_path='uploads/'."your file";

/*output must be folder/yourfile*/

output_file($file_path, ''."your file".'', $row['type']);

/*back to index.php while downloading*/
header('Location:index.php');
?>

2
D'où avez-vous obtenu cela? Cela semble puissant
Axel A. García

@ jundell-agbo intéressant et pour un fichier crt?
fralbo

Cela fonctionne également pour un très gros fichier. Excellente solution. Mais` $ chunksize = 1 * (1024 * 1024); `est lent. J'ai essayé avec plusieurs valeurs et j'ai remarqué que `$ chunksize = 8 * (1024 * 1024);` utilise toute la bande passante disponible.
Linga

16

Si vous devez télécharger un fichier d'une taille supérieure à la limite de mémoire autorisée ( memory_limitparamètre ini), ce qui provoquerait l' PHP Fatal error: Allowed memory size of 5242880 bytes exhaustederreur, vous pouvez le faire:

// File to download.
$file = '/path/to/file';

// Maximum size of chunks (in bytes).
$maxRead = 1 * 1024 * 1024; // 1MB

// Give a nice name to your download.
$fileName = 'download_file.txt';

// Open a file in read mode.
$fh = fopen($file, 'r');

// These headers will force download on browser,
// and set the custom file name for the download, respectively.
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');

// Run this until we have read the whole file.
// feof (eof means "end of file") returns `true` when the handler
// has reached the end of file.
while (!feof($fh)) {
    // Read and output the next chunk.
    echo fread($fh, $maxRead);

    // Flush the output buffer to free memory.
    ob_flush();
}

// Exit to make sure not to output anything else.
exit;

J'ai juste essayé ça et ça a tué mon serveur. J'ai écrit un grand nombre d'erreurs dans mes journaux.
Daniel Williams

Il serait utile de savoir de quoi parlent les journaux.
Parziphal

Ouais désolé, le fichier journal est devenu si gros que je devais juste le bombarder, donc je n'ai pas pu le voir.
Daniel Williams

Je devais configurer quelque chose comme ça sur un serveur auquel j'avais un accès très limité. Mon script de téléchargement continuait à rediriger vers la page d'accueil et je ne pouvais pas comprendre pourquoi. Maintenant, je sais que le problème était une erreur de mémoire et ce code l'a résolu.
Gavin le

Si vous utilisez simplement, ob_flush()il peut y avoir l'erreur: ob_flush (): impossible de vider le tampon. Aucun tampon à vider . enveloppez-le avec if (ob_get_level() > 0) {ob_flush();}(Référence stackoverflow.com/a/9182133/128761 )
vee

11

Une modification de la réponse acceptée ci-dessus, qui détecte également le type MIME à l'exécution:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
header('Content-Type: '.finfo_file($finfo, $path));

$finfo = finfo_open(FILEINFO_MIME_ENCODING);
header('Content-Transfer-Encoding: '.finfo_file($finfo, $path)); 

header('Content-disposition: attachment; filename="'.basename($path).'"'); 
readfile($path); // do the double-download-dance (dirty but worky)

4

Le code suivant est un moyen correct d'implémenter un service de téléchargement en php comme expliqué dans le tutoriel suivant

header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=\"$file_name\"");
set_time_limit(0);
$file = @fopen($filePath, "rb");
while(!feof($file)) {
    print(@fread($file, 1024*8));
    ob_flush();
    flush();
}

1
Vous avez deux variables dans ce code: file_nameet filePath. Pas très bonne pratique de codage. Surtout sans explication. Lien vers un didacticiel externe inutile.
Khom Nazid

2

essaye ça:

header('Content-type: audio/mp3'); 
header('Content-disposition: attachment; 
filename=“'.$trackname'”');                             
readfile('folder name /'.$trackname);          
exit();


1

Vous pouvez également diffuser des téléchargements qui consommeront beaucoup moins de ressources. exemple:

$readableStream = fopen('test.zip', 'rb');
$writableStream = fopen('php://output', 'wb');

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="test.zip"');
stream_copy_to_stream($readableStream, $writableStream);
ob_flush();
flush();

Dans l'exemple ci-dessus, je télécharge un test.zip (qui était en fait le zip du studio Android sur ma machine locale). php: // output est un flux en écriture seule (généralement utilisé par echo ou print). après cela, il vous suffit de définir les en-têtes requis et d'appeler stream_copy_to_stream (source, destination). La méthode stream_copy_to_stream () agit comme un tube qui prend l'entrée du flux source (flux de lecture) et la dirige vers le flux de destination (flux d'écriture) et évite également le problème de la mémoire autorisée épuisée afin que vous puissiez réellement télécharger des fichiers plus gros que votre PHP memory_limit.


Qu'entendez-vous par le téléchargement est diffusé?
Parsa Yazdani

1
@ParsaYazdani Cela signifie que les données téléchargées seront fragmentées. Veuillez consulter le concept de streaming pour plus de détails. Remarque: ce n'est pas le seul à streamer (chunk) télécharger le fichier en PHP. Mais c'est sûrement l'une des méthodes les plus simples.
Saud Qureshi

0

Les réponses ci-dessus fonctionnent. Mais, j'aimerais contribuer à une méthode sur la façon de l'exécuter en utilisant GET

sur votre page html / php

$File = 'some/dir/file.jpg';
<a href="<?php echo '../sumdir/download.php?f='.$File; ?>" target="_blank">Download</a>

et download.phpcontient

$file = $_GET['f']; 

header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);

header("Content-type: application/".$ext);
header('Content-length: '.filesize($file));
header("Content-Disposition: attachment; filename=\"$basename\"");
ob_clean(); 
flush();
readfile($file);
exit;

cela devrait fonctionner sur tous les types de fichiers. cela n'est pas testé avec POST, mais cela pourrait fonctionner.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.