[Help] List Folder Content and Generate Download Files

Hello,

I tried to make a php script which get the list of files on certain folder outside the www root server and generate a download links for that. Tried to search but yet to find an answer.

This script below, is working fine before when I develop it under linux, but when I move to windows using XAMPP server, it doesn’t seem like working at all. The listing is however worked, but then the link to the folder deeper and the download link is not working at all.

It would be appreciated for any kind of help, maybe pointing out the real problem, material to read or compare, or maybe someone kind enough to fix the code. Really I would appreciate it.

Please do forgive my messy script as I just started learning PHP in a few weeks.


<?php
// File name test.php
// Class download Author: Mourad Boufarguine / EPT <mourad.boufarguine@gmail.com>  ----- start here ------

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

// Class Download ----- end here -------

// Begin the real code

$path_input = "";
// get input
if (isset($_GET['path']))
    $path_input = $_GET['path'];

//$basepath = '/home/apronouva/Music';
$basepath = 'D:/Audiophile';

// build directory name
$path = $basepath . '/' . $path_input;

// outside basepath? wtf
if (strncmp(realpath($path), $basepath, strlen($basepath))) {
    // go back to hell
    $path = $basepath;
}

// download action if this is file
if (is_file($path)) {
        $tarikmang = new download($path, $file, "on", 20);
        $tarikmang->download_file();
        exit(0);
}

// view action if this is directory
if (!($handle = opendir($path)))
    die("Error!");

// cut out the base directory
$path_input = substr(realpath($path), strlen($basepath));

// our array
$listing = array();

/* looping */
while (false !== ($file = readdir($handle))) {
    // hide current dir relative path
    if ($file == ".")
        continue;
    
    // print filename
    $fullpath = $path . "/" . $file;
    
    if (is_file($fullpath)) {
        $listing[$file]["url"] = "<a href=\\"test.php?path=" . $path_input . "/" . $file . "\\">";
        $listing[$file]["type"] = "file";
    }
    else if (is_dir($fullpath)) {
        $listing[$file]["url"] = "<a href=\\"test.php?path=" . $path_input . "/" . $file . "\\">";
        $listing[$file]["type"] = "DIR";
    }
}

ksort($listing);

$listing[">> Upper Directory <<"] = $listing[".."];
unset($listing[".."]);

echo "<h2>FILE MP3</h2><br />";
// listing
foreach($listing as $key => $val) {
    if ($listing[$key]["type"] != "file")
        continue;
    echo $listing[$key]["url"] . $key . "</a><br />";
}

echo "<h2>DIRECTORY</h2><br />";
// listing
foreach($listing as $key => $val) {
    if ($listing[$key]["type"] != "DIR")
        continue;
    echo $listing[$key]["url"] . $key . "</a><br />";
}
closedir($handle);

?>

Best regards,
Chibifish