Question

J'utilise le téléchargement forcé pour télécharger la plupart zips et mp3s sur le site je l'ai fait ( http: //pr1pad.kissyour. net ) - pour le suivi des téléchargements dans Google Analytics, dans la base de données et pour cacher réel chemin de téléchargement:

Il est ceci:

extending CI model

... - bunch of code

function _fullread ($sd, $len) {
 $ret = '';
 $read = 0;
 while ($read < $len && ($buf = fread($sd, $len - $read))) {
  $read += strlen($buf);
  $ret .= $buf;
 }
 return $ret;
}

function download(){    
    /* DOWNLOAD ITSELF */

    ini_set('memory_limit', '160M');
    apache_setenv('no-gzip', '1');
    ob_end_flush();

    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: public",FALSE);
    header("Content-Description: File Transfer");
    header("Content-type: application/octet-stream");
     if (isset($_SERVER['HTTP_USER_AGENT']) && 
      (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false))
      header('Content-Type: application/force-download'); //IE HEADER
    header("Accept-Ranges: bytes");
    header("Content-Disposition: attachment; filename=\"" . basename("dir-with-    files/".$filename) . "\";");
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: " . filesize("dir-with-files/".$filename));

    // Send file for download
    if ($stream = fopen("dir-with-files/$filename", 'rb')){
     while(!feof($stream) && connection_status() == 0){
      //reset time limit for big files
      set_time_limit(0);
      print($this->_fullread($stream,1024*16));
      flush();
     }
     fclose($stream);
    }
}

Il est LAMP avec CI 1.7.2 - Il est ma propre méthode à partir de diverses tutoriaux partout sur l'internet, parce que pendant Developement, ces problèmes sont survenus:  - limite du serveur . ini_set n'ont pas aidé, alors j'ai utilisé BUFFERED _fullread fread à la place normale, qui a été utilisé insted de @readonly  - ob_end_flush (), parce que le site est fait dans CI1.7.2 et je devais nettoyer tampon

... Il ne fonctionne pas. Il a fait, puis il a cessé de montrer la taille attendue / temps de téléchargement - j'ai essayé de le nettoyer et pendant que je nettoyais le code, quelque chose est arrivé, je ne sais pas quoi et tout version précédente - il n'a pas travaillé (aucun changement dans les paramètres que ce soit) - modifier :. ne fonctionnent pas = sorties tout dans la fenêtre du navigateur

Alors je l'ai dit, vis, je vais regarder ici.

Alors, je regarde essentiellement pour le script ou la fonction, que je peux mettre à mon modèle de sortie et je ferai:

  • Appel force téléchargement (en début Chrome télécharger, dans IE, FF, ouvrez Safari le modal ouvrir / enregistrer / annuler)
  • Afficher la taille du fichier et le temps dl estimé (qui est à navigateur, je sais, mais d'abord, le navigateur doit savoir filesize
  • TRAVAIL (! Testé et confirmé) à IE6,7,8, FF3, Opera, Chrome et Safari et sur PC + Mac (Linux ... Je ne me soucie pas vraiment) - qui est pour une partie d'en-tête
  • sur le serveur, j'ai aussi quelque chose comme limite de mémoire de 56 Mo, que je ne peux pas ajouter, si c'est également important

Je vous remercie à l'avance.

Modifier : Maintenant, je me sens plus que jamais foiré / avant, car j'ai essayé de forcer le téléchargement avec .htaccess - alors qu'il travaillait, il y avait peu de mineur / majeur (choisir la vôtre) problèmes

  • il a montré le chemin complet (mineur pour moi)
  • il attend que tout téléchargement est terminé (comme montrant « connexion ») et puis juste montrer qu'il est le téléchargement - et téléchargements en une seconde (majeur pour moi)

Maintenant, bien que je supprimé .htaccess, il attend encore jusqu'à ce que le téléchargement est terminé (comme si elle était en cours de téléchargement pour mettre en cache en premier) et juste obtenir de connected et montrer boîte de dialogue Ouvrir / Enregistrer.

Était-ce utile?

La solution

Alors, j'ai utilisé ce code (sa version modifiée de resumable télécharger http trouvé sur Internet)

function _output_file($file, $path)
{
    $size = filesize($path.$file);

    @ob_end_clean(); //turn off output buffering to decrease cpu usage

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

    header('Content-Type: application/force-download');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    /* The three lines below basically make the 
    download non-cacheable */
    header("Cache-control: no-cache, pre-check=0, post-check=0");
    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, $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);
    }

    /* output the file itself */
    $chunksize = 1*(1024*1024); //you may want to change this
    $bytes_send = 0;
    if ($file = fopen($path.$file, 'rb'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

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

die();
}

puis dans le modèle:

function download_file($filename){
    /*
        DOWNLOAD
    */
    $path = "datadirwithmyfiles/"; //directory

    //track analytics

    include('includes/Galvanize.php'); //great plugin
    $GA = new Galvanize('UA-XXXXXXX-7');
    $GA->trackPageView();

    $this->_output_file($filename, $path);

}

Il fonctionne comme prévu dans tous les navigateurs sur Windows mentiond / MAC -. À ce jour, aucun problème avec elle

Autres conseils

D'accord, cela est une question ancienne et Adam a déjà accepté sa propre réponse, on peut donc supposer qu'il a obtenu ce travail pour lui-même, mais il n'a pas expliqué pourquoi il a travaillé. Une chose que j'ai remarqué l'était dans la question qu'il a utilisé les en-têtes:

header("Pragma: public");
header("Cache-Control: public",FALSE);

Alors que dans la solution qu'il a utilisé:

header("Cache-control: private");
header('Pragma: private');

Il n'a pas expliqué pourquoi il a changé ces derniers mais je soupçonne que ce qui a trait à l'utilisation de SSL. J'ai récemment résolu un problème similaire dans le logiciel qui doit permettre le téléchargement sur HTTP et HTTPS, en utilisant ce qui suit pour ajouter l'en-tête:

if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) {
    header("Cache-control: private");
    header('Pragma: private');
} else {
    header('Pragma: public');
}

Il faut espérer que quelqu'un va trouver l'information dans cette réponse un complément utile à ce qui précède.

Il y a une chose que je trouve bizarre: Vous appelez ob_end_flush() au début de la fonction. Cela nettoie en fait le tampon de sortie, mais il génère également tout au client d'abord (je suppose notamment Content-en-têtes définis par CodeIgniter). Changer l'appel à ob_end_clean(), il efface le tampon et défausse. Cela vous donnera un démarrage propre pour générer vos propres têtes.

Une autre astuce:

Au lieu de lire le fichier en tant que flux et le transmettre par bloc, vous pouvez donner à cette fonction un essai:

// ...
if (file_exists("dir-with-files/$filename")) {
   readfile($file);
}

Cela prend soin de presque tout.

print($this->_fullread($stream,1024*16));

Je suppose que _fullread est dans une classe? Si le code ressemble à ce qui précède alors $this-> ne fonctionnerait pas.

-t-elle sortie le contenu du fichier à l'écran si vous avez commenté sur toutes les choses d'en-tête?

Juste un coup de feu dans l'obscurité ... chaque en-tête que je vous envoie dans mon code « téléchargement de force » (ce qui est pas aussi bien testés que le vôtre) est le même que le vôtre, sauf que j'appelle: header ( "Cache-Control: private", false);

au lieu de: header ( "Cache-Control: public", FALSE);

Je ne sais pas si cela peut aider ou non.

Si vous allez faire ce genre de « l'écho avec php » méthode, vous ne serez pas en mesure de montrer un temps restant ou une taille attendue à vos utilisateurs. Pourquoi? Parce que si le navigateur tente de reprendre le téléchargement au milieu, vous avez aucun moyen de traiter ce cas en PHP.

Si vous avez un téléchargement de fichier normal, Apache est capable de supporter la reprise de téléchargements sur HTTP, mais dans le cas d'un téléchargement est en pause, Apache n'a aucun moyen de déterminer où vos choses de script exécutaient lorsqu'un client demande la morceau suivant.

Pour l'essentiel, lorsqu'un navigateur se met en pause un téléchargement, il mettra fin à la connexion au serveur Web entièrement. Lorsque vous reprenez le téléchargement, la connexion est rouverte, et la demande contient un drapeau en disant « Démarrer du numéro octet X ». Mais pour le serveur Web regardant votre PHP ci-dessus, d'où vient l'octet X à partir?

Alors qu'en théorie, il pourrait être possible pour le serveur pour identifier où reprendre votre script en cas d'un téléchargement interrompu, Apache ne pas essayer de savoir où reprendre. En conséquence, l'en-tête envoyé au navigateur indique que le serveur ne supporte pas reprise, qui désactive les filesize attendus et les éléments limite de temps dans la plupart des principaux navigateurs.

EDIT: Il semble que vous pourriez être en mesure de traiter ce cas, mais il va prendre beaucoup de code de votre part. Voir http://www.php.net/manual/en/function .fread.php # 84115 .

Au lieu d'essayer de cacher votre downloadpath du monde le rendre inaccessible de l'extérieur et accéder uniquement les fichiers avec le script ci-dessus. pour ce faire, vous mettez un fichier .htaccess (un fichier texte nommé » .htaccess' ne pas oublier premier point) dans le répertoire. Contenu du htaccess serait ceci:

order deny,allow
deny from all
allow from localhost

essayant d'accéder au chemin du * monde fera le serveur web créer une 401 interdite.

La sécurité par l'obscurité est pas ce que vous voulez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top