PHP Classes

File: class.Bf_Download.php

Recommend this page to a friend!
  Classes of Mourad Boufarguine   Bf_Download   class.Bf_Download.php   Download  
File: class.Bf_Download.php
Role: Class source
Content type: text/plain
Description: The class file
Class: Bf_Download
Serve files for download with resume support
Author: By
Last change: Fix a bug when fopen returns an invalid stream resource resulting in an infinite loop (Thanks to Brian Clark)
Date: 14 years ago
Size: 8,152 bytes
 

Contents

Class file image Download
<?php

/**********************************************************************
**
** A class to download files
** Version 1.0
** Features :
** - hide the real path to the file
** - allow / disallow download resuming
** - partial download (useful for download managers)
** - rename the file on the fly
** - limit download speed
**
** Author: Mourad Boufarguine / EPT <mourad.boufarguine@gmail.com>
**
** License: Public Domain
** Warranty: None
**
***********************************************************************/

class Bf_Download{
   
   
// just one array to gather all the properties of a download
   
private $properties = array("path" => "", // the real path to the file
                               
"name" => "", // to rename the file on the fly
                               
"extension" => "", // extension of the file
                               
"type" => "", // the type of the file
                               
"size" => "", // the file size
                               
"resume" => "", // allow / disallow resuming
                               
"max_speed" => "" // speed limit (ko) ( 0 = no limit)
                               
);

   
// the constructor
   
public function __construct($path, $name="", $resume="off", $max_speed=0){ // by default, resuming is NOT allowed and there is no speed limit
       
$name = ($name == "") ? substr(strrchr("/".$path,"/"),1) : $name; // if "name" is not specified, th file won't be renamed
       
$file_extension = strtolower(substr(strrchr($path,"."),1)); // the file extension
       
switch( $file_extension ) { // the file type
           
case "mp3": $content_type="audio/mpeg"; break;
            case
"mpg": $content_type="video/mpeg"; break;
            case
"avi": $content_type="video/x-msvideo"; break;
            case
"wmv": $content_type="video/x-ms-wmv";break;
            case
"wma": $content_type="audio/x-ms-wma";break;
            default:
$content_type="application/force-download";
        }
       
$file_size = filesize($path); // the file size
       
$this->properties = array(
                                   
"path" => $path,
                                   
"name" => $name,
                                   
"extension" =>$file_extension,
                                   
"type"=>$content_type,
                                   
"size" => $file_size,
                                   
"resume" => $resume,
                                   
"max_speed" => $max_speed
                                   
);
    }
   
   
// public function to get the value of a property
   
public function get_property ($property){
        if (
array_key_exists($property,$this->properties) ) // check if the property do exist
           
return $this->properties[$property]; // get its value
       
else
            return
null; // else return null
   
}
   
   
// public function to set the value of a property
   
public function set_property ($property, $value){
        if (
array_key_exists($property, $this->properties) ){ // check if the property do exist
           
$this->properties[$property] = $value; // set the new value
           
return true;
        } else
            return
false;
    }
   
   
// public function to start the download
   
public function download_file(){
        if (
$this->properties['path'] == "" ) // if the path is unset, then error !
           
echo "Nothing to download!";
        else {
           
// if resuming is allowed ...
           
if ($this->properties["resume"] == "on") {
                if(isset(
$_SERVER['HTTP_RANGE'])) { // check if http_range is sent by browser (or download manager)
                   
list($a, $range)=explode("=",$_SERVER['HTTP_RANGE']);
                   
ereg("([0-9]+)-([0-9]*)/?([0-9]*)",$range,$range_parts); // parsing Range header
                   
$byte_from = $range_parts [1]; // the download range : from $byte_from ...
                   
$byte_to = $range_parts [2]; // ... to $byte_to
               
} else
                    if(isset(
$_ENV['HTTP_RANGE'])) { // some web servers do use the $_ENV['HTTP_RANGE'] instead
                       
list($a, $range)=explode("=",$_ENV['HTTP_RANGE']);
                       
ereg("([0-9]+)-([0-9]*)/?([0-9]*)",$range,$range_parts); // parsing Range header
                       
$byte_from = $range_parts [1]; // the download range : from $byte_from ...
                       
$byte_to = $range_parts [2]; // ... to $byte_to
                   
}else{
                       
$byte_from = 0; // if no range header is found, download the whole file from byte 0 ...
                       
$byte_to = $this->properties["size"] - 1; // ... to the last byte
                   
}
                if (
$byte_to == "") // if the end byte is not specified, ...
                   
$byte_to = $this->properties["size"] -1; // ... set it to the last byte of the file
               
header("HTTP/1.1 206 Patial Content"); // send the partial content header
            // ... else, download the whole file
           
} else {
               
$byte_from = 0;
               
$byte_to = $this->properties["size"] - 1;
            }
           
           
$download_range = $byte_from."-".$byte_to."/".$this->properties["size"]; // the download range
           
$download_size = $byte_to - $byte_from; // the download length
           
            // download speed limitation
           
if (($speed = $this->properties["max_speed"]) > 0) // determine the max speed allowed ...
               
$sleep_time = (8 / $speed) * 1e6; // ... if "max_speed" = 0 then no limit (default)
           
else
               
$sleep_time = 0;
           
           
// send the headers
           
header("Pragma: public"); // purge the browser cache
           
header("Expires: 0"); // ...
           
header("Cache-Control:"); // ...
           
header("Cache-Control: public"); // ...
           
header("Content-Description: File Transfer"); //
           
header("Content-Type: ".$this->properties["type"]); // file type
           
header('Content-Disposition: attachment; filename="'.$this->properties["name"].'";');
           
header("Content-Transfer-Encoding: binary"); // transfer method
           
header("Content-Range: $download_range"); // download range
           
header("Content-Length: $download_size"); // download length
           
            // send the file content
           
$fp=fopen($this->properties["path"],"r"); // open the file
           
if(!fp) exit; // if $fp is not a valid stream resource, exit
           
fseek($fp,$byte_from); // seek to start of missing part
           
while(!feof($fp)){ // start buffered download
               
set_time_limit(0); // reset time limit for big files (has no effect if php is executed in safe mode)
               
print(fread($fp,1024*8)); // send 8ko
               
flush();
               
usleep($sleep_time); // sleep (for speed limitation)
           
}
           
fclose($fp); // close the file
           
exit;
        }
    }
}
?>