Pregunta

Estoy usando descarga forzada a descargar su mayoría cremalleras y mp3 en el sitio que hice ( http: //pr1pad.kissyour. neto) - para realizar un seguimiento de las descargas en Google analytics, en la base de datos y para ocultar ruta de descarga real:

Es esto:

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á en la lámpara con IC 1.7.2 - Es mi propio método formulado a partir de diversos tutoriales en todo el Internet, debido a que durante Desarrollos, estos problemas surgieron:  - límite del servidor . ini_set no han ayudado, por lo que utiliza _fullread almacenan temporalmente en su lugar fread normal, que fue utilizado insted de @readonly  - ob_end_flush (), porque el sitio se hizo en CI1.7.2 y que necesitaba para limpiar búfer

Ahora ... No funciona. Lo hizo, luego se detuvo tamaño que muestra el tiempo / descarga esperado - me trató de limpiarlo y mientras yo estaba limpiando el código, algo pasó, no sé qué y en cualquier versión anterior - que no han funcionado (ningún cambio en la configuración de ningún tipo) - editar . no funcionan = salidas todo en la ventana del navegador

Así que dije, atornillarlo, voy a mirar aquí.

Así que, básicamente busco script o función, que puedo poner a mi modelo de salida y haré:

  • Llamada fuerza-descarga (en el inicio Chrome descarga, en IE, FF, Safari abrir el modal de abrir / guardar / cancelar)
  • Mostrar tamaño del archivo y el tiempo estimado dl (eso depende del navegador, lo sé, pero en primer lugar, el navegador debe saber tamaño del archivo
  • TRABAJO (! Probado y confirmado) en IE6,7,8, FF3, Opera, Chrome y Safari y en PC + Mac (Linux ... Realmente no me importa) - eso es parte de cabecera
  • en el servidor, también tengo algo así como límite de memoria de 56 MB, que no puedo añadir, por lo que también es importante

Gracias de antemano.

Editar : ahora me siento más que nunca la pata / antes, desde que traté de descarga a la fuerza con .htaccess - problemas mientras trabajaba, tenía pocos menor / mayor (recoger el suyo)

  • se mostró ruta completa (sin importancia para mí)
  • se espera hasta que haya finalizado la descarga total (mostrando como "conectar") y luego simplemente mostrar que está descargando - y descargas en un segundo (importantes para mí)

Ahora, a pesar de que he eliminado .htaccess, todavía espera a que se complete la descarga (como si se estaba descargando para almacenar en caché en primer lugar) y que sólo de conseguir connected y mostrar abrir / guardar cuadro de diálogo.

¿Fue útil?

Solución

Por lo tanto, utiliza este código (Se modificó la versión de descarga http resumable encontrado en 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();
}

y después en el 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);

}

Se trabaja como se espera en todos los navegadores mentiond en Win / MAC -. Hasta el momento, no hay problemas con él

Otros consejos

Bueno, esto es una cuestión de edad y Adam ya aceptaron su propia respuesta, por lo que presumiblemente él consiguió este trabajo por sí mismo, pero no explicó por qué funcionó. Una cosa que la vi fue en la pregunta que utiliza los encabezados:

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

Mientras que en la solución que utiliza:

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

Él no explicó por qué cambió estos, pero sospecho que se refiere al uso de SSL. He resuelto recientemente un problema similar en el software que necesita descargar sobre HTTP y HTTPS para permitir, mediante el siguiente para agregar el encabezado correcto:

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

Con suerte alguien encontrará la información de este contestar una adición útil a la anterior.

Hay una cosa que me parece raro: Usted está llamando ob_end_flush() al inicio de la función. En realidad, esto limpia el búfer de salida, sino que también da salida a todo lo que el cliente primero (supongo que incluye contenido-Headers establecidos por CodeIgniter). Cambiar la llamada a ob_end_clean(), borra la memoria intermedia y la descarta. Esto le dará una salida limpia para generar sus propias cabeceras.

Otro consejo:

En lugar de leer el archivo como un arroyo y pasarlo por bloques, usted podría dar una oportunidad a esta función:

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

Este se encarga de casi todo.

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

Asumo _fullread está dentro de una clase? Si el código es similar a los anteriores, entonces $this-> no funcionaría.

¿Tiene que muestre el contenido del archivo a la pantalla si usted comentó a cabo todas las cosas cabecera?

Sólo un tiro en la oscuridad ... cada cabecera que envío mi código 'fuerza de descarga' (que no es tan bien probado que el suyo) es el mismo que el suyo, salvo que llamo: header ( "Cache-Control: privado", false);

en lugar de: header ( "Cache-Control: público", FALSE);

No sé si eso va a ayudar o no.

Si usted va a hacer este tipo de "Echo un vistazo con php" método, entonces no será capaz de mostrar un tiempo restante, o un tamaño esperado para los usuarios. ¿Por qué? Porque si el navegador intenta reanudar la descarga en el medio, que no hay manera de manejar este caso en PHP.

Si usted tiene un archivo de descarga normal, Apache es capaz de soportar descargas resumidas a través de HTTP, pero en el caso está en pausa una descarga, Apache no tiene manera de saber dónde en sus cosas de guión fueron ejecutar cuando un cliente solicita la siguiente parte.

En esencia, cuando un navegador hace una pausa una descarga, se dará por terminada la conexión con el servidor web en su totalidad. Al reanudar la descarga, la conexión se vuelve a abrir, y la solicitud contiene una bandera que dice "empezar desde el número de bytes X". Pero al servidor web mirando a su PHP anterior, ¿de dónde viene el byte X viene?

Mientras que en teoría podría ser posible para el servidor para identificar dónde reanudar la secuencia de comandos en el caso de una descarga interrumpida, Apache no trata de averiguar dónde reanudar. Como resultado, la cabecera se envía al navegador indica que el servidor no soporta hoja de vida, que apaga los elementos del archivo tamaño y plazo previstos en la mayoría de los principales navegadores.

EDIT: Parece que podría ser capaz de manejar este caso, pero va a tomar una gran cantidad de código de su parte. Ver http://www.php.net/manual/en/function .fread.php # 84115 .

En lugar de tratar de ocultar su downloadpath del mundo que sea inaccesible desde el exterior y sólo acceder a los archivos con la secuencia de comandos. para ello, coloque un archivo .htaccess (un archivo de texto llamado' .htaccess' no se olvide punto inicial) en el directorio. El contenido de la .htaccess sería la siguiente:

order deny,allow
deny from all
allow from localhost

Ahora tratando de acceder a la ruta de * mundo hará que el servidor web a crear un 401 prohibido.

Seguridad por oscuridad no es lo que desea.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top