Frage

Ich verwende gezwungen Download meist Reißverschluss und mp3s vor Ort zum Download ich habe ( http: //pr1pad.kissyour. net ) - Downloads in google analytics zu verfolgen, in der Datenbank und realen Download-Pfad zu verbergen:

Es ist diese:

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);
    }
}

Es ist auf LAMP mit CI 1.7.2 - Es ist meine eigene Methode ist verschiedener zusammengestellt von How-Tos alle über das Internet, weil während der Entwicklung, diese Probleme kamen:  - Server Grenze . ini_set nicht geholfen haben, so habe ich gepuffert _fullread statt normalen fread, die verwendet wurde, insted @readonly  - ob_end_flush (), weil Site hat in CI1.7.2 und ich brauchte Puffer zu reinigen

Jetzt ... Es funktioniert nicht. Es tat, dann hielt sie erwartete Größe / Downloadzeit zeigt - ich versuchte, es zu bereinigen, und während ich den Code Aufräumen, etwas passiert, ich weiß nicht, was und in alle Vorversion - es nicht funktioniert (keine Änderung in den Einstellungen auch immer) - bearbeiten . funktionieren nicht = alles in Browser-Fenster gibt

Also habe ich gesagt, schrauben Sie es, ich werde hier.

Also, ich sehe grundsätzlich für Skript oder eine Funktion, die ich zu meinem Output-Modell setzen und tun:

  • Rufen Sie Kraft-Download (in Chrome Start herunterladen, in IE, FF, öffnen Sie Safari die modal Öffnen / Speichern / Abbrechen)
  • anzeigen Größe der Datei und die geschätzte dl Zeit (das ist bis zu Browser, ich weiß, aber zuerst muß, Browser weiß Dateigröße
  • WORK (! Getestet und bestätigt) in IE6,7,8, FF3, Opera, Chrome & Safari und auf PC + Mac (Linux ... Ich weiß nicht wirklich interessieren) - das ist für Kopfteil
  • auf dem Server, habe ich auch so etwas wie 56MB Speichergrenze, die ich nicht hinzufügen können, so dass auch wichtig

Vielen Dank im Voraus.

Bearbeiten : Jetzt habe ich mehr geschraubt fühlen dann nie / vor, da ich Download mit .htaccess zu zwingen versucht - während es funktionierte, es hatte einige kleinere / Haupt (pick Ihre) Probleme

  • zeigte vollständigen Pfad (minor für mich)
  • es wartet, bis ganzer Download beendet ist (zeigt als „Verbinden“) und dann zeigen, es herunterzuladen - und Downloads in einer Sekunde (Haupt für mich)

Nun, obwohl ich .htaccess gelöscht, es wartet noch, bis der Download abgeschlossen ist (als ob es wurde das Herunterladen zuerst in der Cache) und es ist nur connected erhalten und offen zeigen / Speichern-Dialog.

War es hilfreich?

Lösung

So, habe ich diesen Code (Es modifizierte Version von fortsetzbar http-Download im Internet gefunden)

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();
}

und dann im Modell:

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);

}

Es funktioniert wie auf Win / MAC in allen mentiond Browser erwartet -. Bisher keine Probleme mit ihm

Andere Tipps

Okay, das ist eine alte Frage und Adam bereits akzeptierte seine eigene Antwort, so vermutlich hat er dies für sich selbst zu arbeiten, aber er hat nicht erklärt, warum es funktionierte. Eine Sache, die mir auffiel, war in der Frage, die er die Header verwendet:

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

Während in der Lösung, die er verwendet:

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

Er erklärte nicht, warum er diese verändert, aber ich vermute, dass es die Verwendung von SSL bezieht. Ich löste vor kurzem ein ähnliches Problem in der Software, die sowohl Download über HTTP ermöglichen muss und HTTPS, mit der nach dem richtigen Header hinzuzufügen:

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

Hoffentlich wird jemand die Informationen in dieser Antwort eine sinnvolle Ergänzung zu dem oben finden.

Es ist eine Sache, die ich seltsam finde: Sie ob_end_flush() die Funktion zu Beginn anrufen. Dies reinigt tatsächlich den Ausgabepuffer, aber es gibt auch alles an den Client zuerst (Ich gehe davon aus, einschließlich Inhalt Headers gesetzt von CodeIgniter). Ändern Sie den Aufruf an ob_end_clean(), löscht er den Puffer und verwirft sie. Dadurch erhalten Sie einen sauberen Start für Ihre eigenen Header zu erzeugen.

Noch ein Tipp:

Statt die Datei als ein Strom von Lesen und es auf blockweise vorbei, können Sie dieser Funktion einen Versuch geben:

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

Diese kümmert sich um fast alles.

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

Ich gehe davon aus _fullread innerhalb einer Klasse ist? Wenn der Code wie die oben schaut dann würde $this-> nicht funktionieren.

Ist es die Dateiinhalte auf dem Bildschirm ausgegeben, wenn Sie alle Header Sachen kommentiert aus?

Nur ein Schuss im Dunkeln ... jeder Header, die ich in meiner ‚Kraft Download‘ Code (was wie bei Ihnen nicht so gut getestet ist) ist das gleiche wie Sie, es sei denn ich rufe: header ( "Cache-Control: private", false);

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

Ich weiß nicht, ob das hilft oder nicht.

Wenn Sie diese Art von tun werden Methode „es mit php echo out“, dann werden Sie nicht in der Lage sein, eine verbleibende Zeit anzuzeigen, oder eine erwartete Größe für Ihre Benutzer. Warum? Denn wenn der Browser des Download in der Mitte wieder aufnehmen will, haben Sie keine Möglichkeit, diesen Fall in PHP zu verarbeiten.

Wenn Sie eine normale Datei herunterladen haben, ist Apache der Lage, Downloads über HTTP wiederaufgenommen Tragen, aber in dem Fall ein Download angehalten wird, hat Apache keine Möglichkeit, herauszufinden, wo in Ihrem Skript Dinge ausführt wurden, wenn ein Client für das fragt nächste Brocken.

Im Wesentlichen, wenn ein Browser einen Download pausiert, wird die Verbindung zum Webserver vollständig beenden. Wenn Sie den Download wieder aufnehmen, wird die Verbindung wieder geöffnet, und enthält die Anforderung eine Flagge zu sagen „Start von Byte-Zahl X“. Aber auf den Webserver auf Ihrem PHP-Suche oben, wo kommt Byte X kommen aus?

Während in der Theorie könnte es möglich sein, dass der Server, auf dem zu identifizieren, das Skript im Fall eines unterbrochenen Download wieder aufnehmen, Apache nicht versucht, herauszufinden, wo fortzusetzen. Im Ergebnis führen die Header an den Browser gesendet, dass der Server nicht wieder aufnehmen unterstützt, welche die erwartete Dateigröße und Zeitlimit Produkte in den meisten gängigen Browsern schaltet sich aus.

EDIT: Es scheint, dass Sie diesen Fall zu behandeln, vielleicht in der Lage, aber es wird eine Menge Code auf Ihrer Seite zu nehmen. Siehe http://www.php.net/manual/en/function .fread.php # 84115 .

Anstatt zu versuchen, Ihre downloadpath aus der Welt macht es von außen unzugänglich und nur die Dateien mit den obigen Skript Zugriff zu verbergen. so zu tun, setzen Sie eine .htaccess-Datei (eine Textdatei namens‘.htaccess' nicht vergessen führenden Punkt) im Verzeichnis. Inhalt der .htaccess wäre dies:

order deny,allow
deny from all
allow from localhost

Nun versuchen, den Weg für den Zugriff von * Welt der Webserver ein 401 verboten schaffen machen wird.

Sicherheit durch Unklarheit ist nicht das, was Sie wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top