Pergunta

Eu estou usando o download forçado a baixar a maioria fecha e mp3s no local que eu fiz ( http: //pr1pad.kissyour. net) - para rastrear downloads no Google Analytics, no banco de dados e para esconder caminho de download real:

É o seguinte:

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

Está na lâmpada com CI 1.7.2 - É o meu próprio método juntos de vários how-tos por toda a internet, porque durante developement, estes problemas surgiu: - limite do servidor . ini_set não ajudou, então eu usei tamponada _fullread fread vez normal, que foi usado insted de @readonly - ob_end_flush (), porque o site está fizeram em CI1.7.2 e eu precisava tampão limpo

Agora ... ele não funciona. Ele fez, então ele parou, mostrando o tempo tamanho / download esperado - eu tentei limpá-lo e enquanto eu estava limpando o código, alguma coisa aconteceu, eu não sei o que e em qualquer versão anterior - não ter trabalhado (nenhuma mudança nas configurações de qualquer) - editar :. não trabalhe = saídas tudo em janela do navegador

Então eu disse, dane-se, eu vou olhar aqui.

Então, eu basicamente olhar para o script ou função, o que eu posso colocar a minha modelo de saída e vai fazer:

  • Chamada força-download (no início Chrome download, no IE, FF, Safari abra o modal / open salvar / cancelar)
  • Mostrar tamanho do arquivo eo tempo de dl estimado (que é até navegador, eu sei, mas em primeiro lugar, o navegador deve saber o tamanho do arquivo
  • TRABALHO (testado e confirmado!) Em IE6,7,8, FF3, Opera, Chrome e Safari e no PC + Mac (Linux ... Eu realmente não me importo) - isso é parte do cabeçalho
  • no servidor, eu também tenho algo como limite de memória 56MB, o que eu não posso adicionar, de modo que também é importante

Agradecemos antecipadamente.

Editar : Agora me sinto mais ferrado do que nunca / antes, desde que eu tentei força download com .htaccess - enquanto ele trabalhou, teve algumas pequenas / grandes (escolha seu) problemas

  • mostrou caminho completo (menor para mim)
  • espera até que o download inteiro está terminado (mostrando como "conexão") e depois é só mostrá-la de download - e os downloads no primeiro segundo (grandes para mim)

Agora, embora eu deletei .htaccess, ele ainda espera até que o download está completo (como se ele estava baixando para o cache primeiro) e é só pegar de connected e mostrar / Open Save Dialog.

Foi útil?

Solução

Então, eu usei esse código (É versão do Download http resumable modificado encontrado na 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, em seguida, no modelo:

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

}

Ele funciona como esperado em todos navegador mentiond no Win / MAC -. Até agora, nenhum problema com ele

Outras dicas

Ok, isso é uma questão antiga e Adam já aceitou a sua própria resposta, então, presumivelmente, ele tem esse trabalho para si mesmo, mas ele não explicou por que ele trabalhou. Uma coisa que o que eu notei foi na questão que ele usou os cabeçalhos:

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

Considerando que a solução que ele usou:

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

Ele não explicou por que ele mudou estes, mas eu suspeito que se refere ao uso de SSL. Recentemente, resolveu um problema semelhante no software que precisa habilitar o download sobre HTTP e HTTPS, usando o seguinte para adicionar o cabeçalho correto:

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

Esperemos que alguém vai encontrar as informações nesta resposta uma adição útil para o acima.

Há uma coisa que eu acho estranho: Está a ligar ob_end_flush() no início da função. Isso realmente limpa o buffer de saída, mas também saídas de tudo para o cliente em primeiro lugar (eu assumo incluindo set Content-cabeçalhos por CodeIgniter). Alterar a chamada para ob_end_clean(), ele limpa o buffer e descarta. Isto lhe dará um começo limpo para gerar seus próprios cabeçalhos.

Outra dica:

Em vez de ler o arquivo como um fluxo e passá-la no bloco-sábio, você poderia dar a esta função uma tentativa:

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

Este cuida de quase tudo.

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

Eu assumo _fullread está dentro de uma classe? Se a aparência de código como o acima $this-> então não iria funcionar.

Será que isso saída o conteúdo do arquivo para a tela se você comentada todo o material de cabeçalho?

Apenas um tiro no escuro ... cada cabeçalho que eu mando no meu código 'força download' (que não é tão bem testado quanto o seu) é a mesma que a sua, só que eu ligue para: header ( "Cache-Control: private", false);

em vez de: header ( "Cache-Control: público", FALSE);

Eu não sei se isso ajuda a vontade ou não.

Se você estiver indo para fazer este tipo de "Eco-lo com php" método, então você não vai ser capaz de mostrar um tempo restante, ou um tamanho esperado para os usuários. Por quê? Porque se as tentativas do navegador para retomar o download no meio, você não tem nenhuma maneira de lidar com esse caso em PHP.

Se você tem um download de arquivo normal, Apache é capaz de suportar de downloads retomaram sobre HTTP, mas no caso de um download está em pausa, o Apache tem nenhuma maneira de descobrir onde no seu script coisas estavam executando quando um cliente pede o próximo pedaço.

Essencialmente, quando um navegador faz uma pausa um download, ele vai terminar a ligação ao servidor web inteiramente. Quando retomar o download, a conexão é reaberto, e que o pedido contenha uma bandeira dizendo "Iniciar a partir do número de bytes X". Mas, para o servidor web olhar para o seu PHP acima, onde é que bytes X vem?

Embora, em teoria, pode ser possível para o servidor para identificar onde retomar seu script em caso de um download interrompido, Apache não tenta descobrir por onde recomeçar. Como resultado, o cabeçalho enviado para os estados do navegador que o servidor não retomar o apoio, que desliga os itens tamanho do arquivo e limite de tempo de espera na maioria dos principais navegadores.

EDIT: Parece que você pode ser capaz de lidar com este caso, mas ele vai ter um monte de código de sua parte. Consulte http://www.php.net/manual/en/function .fread.php # 84115 .

Em vez de tentar esconder sua downloadpath do mundo de faz-lo inacessível a partir do exterior e apenas acessar os arquivos com o script acima. para isso você colocar um arquivo .htaccess (um arquivo de texto chamado' .htaccess' não se esqueça ponto à esquerda) no diretório. Conteúdo do htaccess seria esta:

order deny,allow
deny from all
allow from localhost

Agora, tentando acessar o caminho do mundo * fará com que o servidor web criar um 401 proibido.

Segurança através da obscuridade não é o que você quer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top