Domanda

sto usando scaricare costretto a scaricare la maggior parte cerniere e MP3 sul sito che ho fatto ( http: //pr1pad.kissyour. netto) - per tenere traccia di download in Google Analytics, nel database e per nascondere reale percorso di download:

E 'questo:

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

E 'su LAMP con CI 1.7.2 - E' il mio proprio metodo messo insieme da varie how-to tutti su Internet, perché durante developement, questi problemi si avvicinò:  - limite del server . ini_set non hanno aiutato, _fullread quindi usato tamponato fread invece normale, che è stato utilizzato invece di @readonly  - ob_end_flush (), perché il sito è fatto in CI1.7.2 e avevo bisogno di pulire tampone

Ora ... Non funziona. Lo ha fatto, poi si è fermato che mostra il tempo di formato / download previsto - ho cercato di ripulirlo e mentre stavo pulendo il codice, è successo qualcosa, non so cosa e in qualsiasi versione precedente - non hanno lavorato (nessun cambiamento nelle impostazioni di sorta) - modifica :. non funzionano = uscite tutto in finestra del browser

Così ho detto, avvitare, cercherò qui.

Quindi, io in fondo cerco script o funzione, che posso mettere al mio modello di uscita e lo farò:

  • Chiama forza-download (a inizio Chrome scaricare, in IE, FF, Safari aprire il modale aprire / salvare / annullare)
  • Visualizza dimensione del file e il tempo stimato dl (che è fino al browser, lo so, ma in primo luogo, il browser deve conoscere la dimensione del file
  • LAVORO (! Testato e confermato) in IE6,7,8, FF3, Opera, Chrome e Safari e su PC + Mac (Linux ... Io non mi interessa) - questo è parte di intestazione
  • sull'assistente, ho anche qualcosa come limite di memoria 56MB, che non posso aggiungere, in modo che sia anche importante

Grazie in anticipo.

Modifica : Ora mi sento più che mai fregato / prima, da quando ho provato a forzare il download con .htaccess - mentre ha funzionato, aveva poche minore / maggiore (pick vostro) problemi

  • ha mostrato il percorso completo (minore per me)
  • si aspetta fino a quando tutto il download è finito (che mostra come "collegamento") e poi basta mostrare che è il download - e download in un secondo (importanti per me)

Ora, anche se ho cancellato .htaccess, aspetta ancora fino a completamento del download (proprio come se fosse il download di cache prima) ed è solo di ottenere connected e mostrare Apri / Salva finestra di dialogo.

È stato utile?

Soluzione

Così, ho usato questo codice (E 'modificato la versione di http scaricare resumable trovato su 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();
}

e poi in modello:

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

}

Funziona come previsto in tutti i browser mentiond su Win / MAC -. Finora, nessun problema con esso

Altri suggerimenti

Va bene, questa è una vecchia domanda e Adam già accettato la sua risposta, quindi presumibilmente ha ottenuto questo a lavorare per se stesso, ma non ha spiegato perché ha funzionato. Una cosa che ho notato è la nella questione ha usato le intestazioni:

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

considerando che la soluzione ha usato:

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

Non ha spiegato perché ha cambiato questi ma ho il sospetto che riguarda l'utilizzo di SSL. Recentemente ho risolto un problema simile nel software che ha bisogno di attivare il download su HTTP e HTTPS, utilizzando il seguente per aggiungere la corretta intestazione:

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

Speriamo che qualcuno troverà le informazioni in questa risposta un'utile aggiunta a quanto sopra.

C'è una cosa che trovo strana: Si chiama ob_end_flush() all'inizio della funzione. Questo pulisce realtà il buffer di uscita, ma emette anche tutto al client primo (presumo compresi contenuto-Headers fissati dalla CodeIgniter). Modificare la chiamata a ob_end_clean(), azzera il buffer e la scarta. Questo vi darà un nuovo inizio per la generazione le proprie intestazioni.

Un altro consiglio:

Invece di leggere il file come un ruscello e passandolo sul blocco-saggio, si potrebbe dare questa funzione una prova:

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

Questo si prende cura di quasi tutto.

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

Presumo _fullread è all'interno di una classe? Se il codice è simile quanto sopra, allora $this-> non funzionerebbe.

Lo fa in uscita il contenuto del file alla schermata se si ha commentato fuori tutte le cose di testa?

Solo un salto nel buio ... ogni intestazione che mando nel mio codice 'forza scaricare' (che non è così ben collaudato come il vostro) è uguali ai suoi, tranne che io chiamo: intestazione ( "Cache-Control: private", false);

al posto di: intestazione ( "Cache-Control: public", false);

Non so se questo aiuterà o no.

Se avete intenzione di fare questo genere di "Echo fuori con php" metodo, allora non sarà in grado di mostrare un tempo rimanente, o un formato previsto per gli utenti. Perché? Perché se il browser tenta di riprendere il download in mezzo, non si ha modo di gestire questo caso in PHP.

Se si dispone di un normale file di download, Apache è in grado di supportare ripreso download su HTTP, ma nel caso un download è in pausa, Apache non ha modo di capire dove le tue cose di script sono stati l'esecuzione quando un cliente chiede la prossimo pezzo.

In sostanza, quando un browser fa una pausa un download, si terminerà la connessione al server web del tutto. Quando si riprende il download, la connessione viene riaperto, e la richiesta contiene una bandiera dicendo "Start a partire dal numero di byte X". Ma al server web guardando il tuo PHP sopra, dove non byte X viene?

Mentre in teoria potrebbe essere possibile per il server per identificare dove per riprendere lo script in caso di un download interrotto, Apache non tenta di capire dove riprendere. Di conseguenza, l'intestazione inviato al browser afferma che il server non supporta curriculum, che disattiva le voci di dimensione del file e limite di tempo previsto nella maggior parte dei principali browser.

EDIT: Sembra che potrebbe essere in grado di gestire questo caso, ma sta andando a prendere un sacco di codice da parte vostra. Vedere http://www.php.net/manual/en/function .fread.php # 84115 .

Invece di cercare di nascondere il proprio downloadpath dal mondo renderlo inaccessibile dall'esterno e accedere solo i file con lo script di cui sopra. per farlo si mette un file .htaccess (un file di testo chiamato' .htaccess' non dimenticare punto iniziale) nella directory. Contenuto del .htaccess sarebbe questo:

order deny,allow
deny from all
allow from localhost

Ora si cerca di accedere al percorso da * mondo farà il webserver creare un 401 proibito.

Sicurezza attraverso l'oscurità non è ciò che si desidera.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top