web-dev-qa-db-fra.com

En-têtes HTTP pour le téléchargement de fichiers

J'ai écrit un script PHP qui gère les téléchargements de fichiers, détermine quel fichier est demandé et définit les en-têtes HTTP appropriés pour déclencher le navigateur pour réellement télécharger le fichier (plutôt que de l'afficher dans le navigateur ).

J'ai maintenant un problème où certains utilisateurs ont signalé que certains fichiers n'étaient pas identifiés correctement (donc quelle que soit l'extension, le navigateur le considérera comme une image GIF). Je suppose que c'est parce que je n'ai pas défini le "Content-type" dans l'en-tête de réponse. Est-ce très probablement le cas? Si oui, existe-t-il un type assez générique qui pourrait être utilisé pour tous les fichiers, plutôt que d'essayer de prendre en compte tous les types de fichiers possibles?

Actuellement, je ne définis que la valeur "Content-disposition: attachment; filename = arandomf.ile"

Mise à jour: J'ai suivi ce guide ici pour créer un processus plus robuste pour les téléchargements de fichiers ( http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php / ), mais il y a un délai important entre le moment où le script est exécuté et le moment où la boîte de dialogue de téléchargement du navigateur apparaît. Quelqu'un peut-il identifier le goulot d'étranglement qui cause cela?

Voici ma mise en œuvre:

/**
 * Outputs the specified file to the browser.
 *
 * @param string $filePath the path to the file to output
 * @param string $fileName the name of the file
 * @param string $mimeType the type of file
 */
function outputFile($filePath, $fileName, $mimeType = '') {
    // Setup
    $mimeTypes = array(
        'pdf' => 'application/pdf',
        'txt' => 'text/plain',
        'html' => 'text/html',
        'exe' => 'application/octet-stream',
        'Zip' => 'application/Zip',
        'doc' => 'application/msword',
        'xls' => 'application/vnd.ms-Excel',
        'ppt' => 'application/vnd.ms-PowerPoint',
        'gif' => 'image/gif',
        'png' => 'image/png',
        'jpeg' => 'image/jpg',
        'jpg' => 'image/jpg',
        'php' => 'text/plain'
    );

    $fileSize = filesize($filePath);
    $fileName = rawurldecode($fileName);
    $fileExt = '';

    // Determine MIME Type
    if($mimeType == '') {
        $fileExt = strtolower(substr(strrchr($filePath, '.'), 1));

        if(array_key_exists($fileExt, $mimeTypes)) {
            $mimeType = $mimeTypes[$fileExt];
        }
        else {
            $mimeType = 'application/force-download';
        }
    }

    // Disable Output Buffering
    @ob_end_clean();

    // IE Required
    if(ini_get('zlib.output_compression')) {
        ini_set('zlib.output_compression', 'Off');
    }

    // Send Headers
    header('Content-Type: ' . $mimeType);
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Transfer-Encoding: binary');
    header('Accept-Ranges: bytes');

    // Send Headers: Prevent Caching of File
    header('Cache-Control: private');
    header('Pragma: private');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

    // Multipart-Download and Download Resuming Support
    if(isset($_SERVER['HTTP_RANGE'])) {
        list($a, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
        list($range) = explode(',', $range, 2);
        list($range, $rangeEnd) = explode('-', $range);

        $range = intval($range);

        if(!$rangeEnd) {
            $rangeEnd = $fileSize - 1;
        }
        else {
            $rangeEnd = intval($rangeEnd);
        }

        $newLength = $rangeEnd - $range + 1;

        // Send Headers
        header('HTTP/1.1 206 Partial Content');
        header('Content-Length: ' . $newLength);
        header('Content-Range: bytes ' . $range - $rangeEnd / $size);
    }
    else {
        $newLength = $size;
        header('Content-Length: ' . $size);
    }

    // Output File
    $chunkSize = 1 * (1024*1024);
    $bytesSend = 0;

    if($file = fopen($filePath, 'r')) {
        if(isset($_SERVER['HTTP_RANGE'])) {
            fseek($file, $range);

            while(!feof($file) && !connection_aborted() && $bytesSend < $newLength) {
                $buffer = fread($file, $chunkSize);
                echo $buffer;
                flush();
                $bytesSend += strlen($buffer);
            }

            fclose($file);
        }
    }
}
49
Wilco

Selon RFC 2046 (extensions de messagerie Internet polyvalentes) :

L'action recommandée pour une mise en œuvre qui reçoit un
L'entité "application/octet-stream" consiste simplement à proposer de mettre les données dans un fichier

J'irais donc pour celui-là.

36
Greg

Comme expliqué par le lien d'Alex, vous manquez probablement l'en-tête Content-Disposition au dessus de Content-Type.

Donc quelque chose comme ça:

Content-Disposition: attachment; filename="MyFileName.ext"
46
Pascal

Vous pouvez essayer ceci script de téléchargement forcé . Même si vous ne l'utilisez pas, cela vous orientera probablement dans la bonne direction:

<?php

$filename = $_GET['file'];

// required for IE, otherwise Content-disposition is ignored
if(ini_get('zlib.output_compression'))
  ini_set('zlib.output_compression', 'Off');

// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));

if( $filename == "" ) 
{
  echo "<html><title>eLouai's Download Script</title><body>ERROR: download file NOT SPECIFIED. USE force-download.php?file=filepath</body></html>";
  exit;
} elseif ( ! file_exists( $filename ) ) 
{
  echo "<html><title>eLouai's Download Script</title><body>ERROR: File not found. USE force-download.php?file=filepath</body></html>";
  exit;
};
switch( $file_extension )
{
  case "pdf": $ctype="application/pdf"; break;
  case "exe": $ctype="application/octet-stream"; break;
  case "Zip": $ctype="application/Zip"; break;
  case "doc": $ctype="application/msword"; break;
  case "xls": $ctype="application/vnd.ms-Excel"; break;
  case "ppt": $ctype="application/vnd.ms-PowerPoint"; break;
  case "gif": $ctype="image/gif"; break;
  case "png": $ctype="image/png"; break;
  case "jpeg":
  case "jpg": $ctype="image/jpg"; break;
  default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers 
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
exit();
5
OIS