File download consists of front-end GUI and back-end code .

Caution: Never use include or require for uploaded files. Serve them as static or use file_get_contents(), readfile() etc.

Standard GUIAdvanced GUIBack-end
Standard Front-end Page

The Download form sends GET request to the back-end.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
div.form {
    padding: 0.5rem 2rem 0; 
    background-color: #eee;
    line-height: 1.8rem;
}
</style>
</head>
<body>
    <div class="form">
        <div>File Download Form</div>
        <label>Download using link:</label><br />
        <a href="download_handler.php?download=flowers.jpg">flowers.jpg</a><br />
        <label>Download using javascript:</label><br />
        <button onclick="download(this)">flowers.jpg</button>
    </div>
<script>
function download(btn){
    var fileName = btn.innerHTML;
    window.location = 'download_handler.php?download=' + fileName;
};
</script>    
</body>
</html>
Standard GUI Demo

The Download form may send GET or POST request to the server. 

Click on button on link to download file
Advanced Front-end Page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.download-form {
    padding: 0.5rem 2rem 0.5rem; 
    background-color: #eee;
    line-height: 1.8rem;
    float:left;
}
.download-form-img {
    width: 80px;
    display: block;
    margin: 0 auto;
    cursor: pointer;
}
.download-form-floated {
    float: left;
    text-align: center;
    padding:0.5rem;
}
.download-form-floated::after {
    content: '';
    clear:both;
}
.download-form-file-list {
    margin-left: -0.5rem;
}
</style>
</head>
<body>
    <div class="download-form">
        <div style="font-weight:700;">File List Form</div>
        <label>Get files list then click to download:</label><br />
        <button onclick="get_list()">Get File List</button>
        <div class="download-form-file-list"></div>
    </div>
<script>

function send_get_request(url, callback) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            callback(this);
        }
    };
    xmlhttp.open("GET", url, true);
    xmlhttp.send();
}

function get_list() {
    var file_list = document.getElementsByClassName('download-form-file-list')[0];
    file_list.innerHTML = '';
    send_get_request("list_handler.php?list=all", function(result){
        var myObj = JSON.parse(result.responseText);
        for(var i in myObj) {
            var file_name = myObj[i];
            add_file_btn(file_list,file_name);
        }
    });
}

function add_file_btn(file_list,file_name) {
    var file_div = document.createElement("DIV");
    file_div.className = "download-form-floated";
    file_list.appendChild(file_div);
    var file_img = document.createElement("IMG");
    file_img.className = "download-form-img";
    file_div.appendChild(file_img);
    file_img.src = "list_handler.php?list=" + file_name;
    var file_cap = document.createElement("DIV");
    file_cap.innerHTML = file_name;
    file_div.appendChild(file_cap);
    file_img.onclick = function() {
        window.location = 'download_handler.php?download=' + file_name;
    }
}

</script>    
</body>
</html>
Advanced GUI Demo

 

code here

Download Handler
<?php

    $downloadDir = './downloads';
    require_once "FileDownloader.php";
    new FileDownloader($downloadDir);

    
List Handler
<?php

//query download directory
$downloadsPath = './downloads';
$thumbsDir = 'thumbs';

if (isset($_GET['list'])) {
    if ($_GET['list'] === 'all') {
        
        //get sorted file array and filter '..' and '.'
        $files = array_diff(scandir($downloadsPath), array('..', '.', $thumbsDir));

        //return filenames to front-end as json
        echo json_encode($files);
        
    } else {
        
        $fileName = filter_var($_GET['list'],FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        
        //replace non-image filenames with avatars
        if (substr($fileName,-4)=='.pdf') {
            $fileName = "pdf.png";
        }
        $filePath = "$downloadsPath/$thumbsDir/$fileName";
        
        //return thumbs jpg or png 
        if (file_exists($filePath)) {
            @readfile($filePath);
        }
    }    
}
Download Class
<?php

class FileDownloader {
    
    function __construct($downloadDir = '.')
    {
        if (isset($_GET['download'])) {
            $fileName = filter_var($_GET['download'],FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            $this->do_download("$downloadDir/$fileName");
        }
    }

    private function do_download($filePath)
    {   //check if file exists
        if (!file_exists($filePath)) {
            echo "File named <b>$filePath</b> does not exist."; 
            return;
        }
        //get mime type from file name extension
        $fileExt = strtolower(substr(strrchr($filePath,"."),1)); 
        switch ($fileExt) {
            case "pdf": $mime="application/pdf"; break;
            case "exe": $mime="application/octet-stream"; break;
            case "zip": $mime="application/zip"; break;
            case "doc": $mime="application/msword"; break;
            case "xls": $mime="application/vnd.ms-excel"; break;
            case "ppt": $mime="application/vnd.ms-powerpoint"; break;
            case "gif": $mime="image/gif"; break;
            case "png": $mime="image/png"; break;
            case "jpe": 
            case "jpeg":
            case "jpg": $mime="image/jpg"; break;
            default: $mime="application/force-download";
        }
        //send headers and file contents
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private",false);
        header("Content-Type: $mime");
        header("Content-disposition: attachment; fileName=\"". basename($filePath) ."\""); 
        header("Set-Cookie: fileDownload=true; path=/ ");
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: " . @filesize($filePath));
        set_time_limit(0);
        @readfile($filePath); 
        exit;
    }
}