Pregunta

Estoy escribiendo un script PHP que permite al usuario descargar un archivo. Básicamente la idea es evitar que el archivo que se descarga más de X veces, ya que se paga el contenido, y el enlace no debe ser repartidas.

Dado que los archivos serán bastante grande, debe ser bueno para poner en práctica la reanudación. He leído la estándar, pero es bastante largo y permite cierta flexibilidad. Ya que necesito para hacerlo rápidamente, preferiría un establo, la implementación de esta característica a prueba.

me puede punto cualquiera a tal un guión?

¿Fue útil?

Solución

Parece que he encontrado lo que necesitaba yo. De manera que otro puede beneficiarse de esto, aquí está el enlace: http://www.coneural.org/florian/papers/04_byteserving.php

Y por si acaso la página original se detiene al trabajo (el guión es bastante viejo ya), que aquí hay una copia del mismo:

<?php 
/*

The following byte serving code is (C) 2004 Razvan Florian. You may find the latest version at 
http://www.coneural.org/florian/papers/04_byteserving.php

*/
function set_range($range, $filesize, &$first, &$last){
  /*
  Sets the first and last bytes of a range, given a range expressed as a string 
  and the size of the file.

  If the end of the range is not specified, or the end of the range is greater 
  than the length of the file, $last is set as the end of the file.

  If the begining of the range is not specified, the meaning of the value after 
  the dash is "get the last n bytes of the file".

  If $first is greater than $last, the range is not satisfiable, and we should 
  return a response with a status of 416 (Requested range not satisfiable).

  Examples:
  $range='0-499', $filesize=1000 => $first=0, $last=499 .
  $range='500-', $filesize=1000 => $first=500, $last=999 .
  $range='500-1200', $filesize=1000 => $first=500, $last=999 .
  $range='-200', $filesize=1000 => $first=800, $last=999 .

  */
  $dash=strpos($range,'-');
  $first=trim(substr($range,0,$dash));
  $last=trim(substr($range,$dash+1));
  if ($first=='') {
    //suffix byte range: gets last n bytes
    $suffix=$last;
    $last=$filesize-1;
    $first=$filesize-$suffix;
    if($first<0) $first=0;
  } else {
    if ($last=='' || $last>$filesize-1) $last=$filesize-1;
  }
  if($first>$last){
    //unsatisfiable range
    header("Status: 416 Requested range not satisfiable");
    header("Content-Range: */$filesize");
    exit;
  }
}

function buffered_read($file, $bytes, $buffer_size=1024){
  /*
  Outputs up to $bytes from the file $file to standard output, $buffer_size bytes at a time.
  */
  $bytes_left=$bytes;
  while($bytes_left>0 && !feof($file)){
    if($bytes_left>$buffer_size)
      $bytes_to_read=$buffer_size;
    else
      $bytes_to_read=$bytes_left;
    $bytes_left-=$bytes_to_read;
    $contents=fread($file, $bytes_to_read);
    echo $contents;
    flush();
  }
}

function byteserve($filename){
  /*
  Byteserves the file $filename.  

  When there is a request for a single range, the content is transmitted 
  with a Content-Range header, and a Content-Length header showing the number 
  of bytes actually transferred.

  When there is a request for multiple ranges, these are transmitted as a 
  multipart message. The multipart media type used for this purpose is 
  "multipart/byteranges".
  */

  $filesize=filesize($filename);
  $file=fopen($filename,"rb");

  $ranges=NULL;
  if ($_SERVER['REQUEST_METHOD']=='GET' && isset($_SERVER['HTTP_RANGE']) && $range=stristr(trim($_SERVER['HTTP_RANGE']),'bytes=')){
    $range=substr($range,6);
    $boundary='g45d64df96bmdf4sdgh45hf5';//set a random boundary
    $ranges=explode(',',$range);
  }

  if($ranges && count($ranges)){
    header("HTTP/1.1 206 Partial content");
    header("Accept-Ranges: bytes");
    if(count($ranges)>1){
      /*
      More than one range is requested. 
      */

      //compute content length
      $content_length=0;
      foreach ($ranges as $range){
        set_range($range, $filesize, $first, $last);
        $content_length+=strlen("\r\n--$boundary\r\n");
        $content_length+=strlen("Content-type: application/pdf\r\n");
        $content_length+=strlen("Content-range: bytes $first-$last/$filesize\r\n\r\n");
        $content_length+=$last-$first+1;          
      }
      $content_length+=strlen("\r\n--$boundary--\r\n");

      //output headers
      header("Content-Length: $content_length");
      //see http://httpd.apache.org/docs/misc/known_client_problems.html for an discussion of x-byteranges vs. byteranges
      header("Content-Type: multipart/x-byteranges; boundary=$boundary");

      //output the content
      foreach ($ranges as $range){
        set_range($range, $filesize, $first, $last);
        echo "\r\n--$boundary\r\n";
        echo "Content-type: application/pdf\r\n";
        echo "Content-range: bytes $first-$last/$filesize\r\n\r\n";
        fseek($file,$first);
        buffered_read ($file, $last-$first+1);          
      }
      echo "\r\n--$boundary--\r\n";
    } else {
      /*
      A single range is requested.
      */
      $range=$ranges[0];
      set_range($range, $filesize, $first, $last);  
      header("Content-Length: ".($last-$first+1) );
      header("Content-Range: bytes $first-$last/$filesize");
      header("Content-Type: application/pdf");  
      fseek($file,$first);
      buffered_read($file, $last-$first+1);
    }
  } else{
    //no byteserving
    header("Accept-Ranges: bytes");
    header("Content-Length: $filesize");
    header("Content-Type: application/pdf");
    readfile($filename);
  }
  fclose($file);
}

function serve($filename, $download=0){
  //Just serves the file without byteserving
  //if $download=true, then the save file dialog appears
  $filesize=filesize($filename);
  header("Content-Length: $filesize");
  header("Content-Type: application/pdf");
  $filename_parts=pathinfo($filename);
  if($download) header('Content-disposition: attachment; filename='.$filename_parts['basename']);
  readfile($filename);
}

//unset magic quotes; otherwise, file contents will be modified
set_magic_quotes_runtime(0);

//do not send cache limiter header
ini_set('session.cache_limiter','none');


$filename='myfile.pdf'; //this is the PDF file that will be byteserved
byteserve($filename); //byteserve it!
?>

Otros consejos

Debe utilizar PEAR HTTP_Download. Es bastante fácil de usar y permite reanudar la descarga de archivos simplemente:

http://pear.php.net /manual/en/package.http.http-download.intro.php

Basado en esto:

http: / /w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/

(que también se puede utilizar)

He hecho un pequeño lib que hace lo hace PECL http_send_file extensión:

http://php.net/manual/en/function. http-send-archivo.php

(que también se puede utilizar)

El lib se asemeja al http_send_file, pero si usted no tiene la opción de instalar la lib PECL, se podría utilizar el lib http-send-file:

https://github.com/diversen/http-send-file

http://us3.php.net/manual/en/ function.fread.php

Una alternativa es dejar que el servidor web puede manejar http redirigiendo al archivo en cuestión.

Un script PHP puede hacer todas las comprobaciones necesarias (seguridad, autenticación, validar el archivo, incrementando el número de descargas) y cualquier otra tarea antes de llamar a header ( "Location $ urltofile");

I probado esto con Apache. Interrupción / descargar trabajos curriculum vitae. configuración de los tipos MIME del servidor determinará el comportamiento del cliente. Para Apache, en caso de insolvencia en mime.types no son adecuadas, las directivas de configuración para mod_mime podrían ir en un archivo .htaccess en el directorio del archivo a descargar. Si realmente necesario, éstas podrían incluso por escrito por el script PHP antes de que vuelve a dirigir.

Tal vez en lugar de la aplicación de servidor web en un servidor web (dawg!) Que podría utilizar mod gatillo antes de la descarga en lighttpd o mod X-Sendfile disponible tanto para lighttpd y Apache 2?

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