Rectangle 27 1

html PHP displaydownload directory files outside the webserver root?


// this way it works with accentuated letters in Windows
$Root = utf8_decode("G:\test"); // define the directory the index should be created for (can also be located outside the webserver root)

$AllowDownload = TRUE; // enclose file items with the anchor-tag (only makes sense when the files are in the webserver root)
// you need to place download.php in the same directory as indexer.php
$WebServerPath = dirname($_SERVER['SCRIPT_NAME']) . "/download.php?path="; // path where the indexed files can be accessed via a http URL (only required when $AllowDownload is TRUE)
<?php

// it must be the same as in indexer.php
$Root = utf8_decode("G:\test");

function checkFileIsInsideRootDirectory($path, $root_directory) {
    $realpath = realpath($path);

    if (!file_exists($realpath))
        die("File is not readable: " . $path);

    // detects insecure path with for example /../ in it
    if (strpos($realpath, $root_directory) === false || strpos($realpath, $root_directory) > 0)
        die("Download from outside of the specified root directory is not allowed!");
}

function forceDownload($path) {
    $realpath = realpath($path);

    if (!is_readable($realpath))
        die("File is not readable: " . $path);

    $savename = (basename($path));

    header("Pragmaes: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private", false);
    header("Content-type: application/force-download");
    header("Content-Transfer-Encoding: Binary");
    header("Content-length: " . filesize($path));
    header("Content-disposition: attachment; filename=\"$savename\"");

    readfile("$path");
    exit;
}

if (!isset($_GET['path']))
    die("Path not specified!");

$fullPath = $Root . $_GET['path'];

checkFileIsInsideRootDirectory($fullPath, $Root);

forceDownload($fullPath);
indexer

@Jopper As I wrote, you need only to change the config parameters in indexer.php (in fact only $WebServerPath is changed to hack the download url), and you need to create a new php script which handles the downloads, and it must be named according to the $webServerPath's value (download.php in this case).

And you have to place a new file called download.php in the same directory as indexer.php, with this content:

It is also possible to combine the two files into one, but it seemed to be simpler this way (and I didn't want to modify indexer.php).

Thanks for your ongoing support:) Where should I put the code and what does it need to replace?

To make this work, you need to change the configuration in indexer.php:

Your web server can not see the files outside the DocRoot, so it can not serve the files via the browser with direct links. You need to print their contents into the browser with readfile() with the headers properly set.

Note
Rectangle 27 1

html PHP displaydownload directory files outside the webserver root?


$WebServerPath = dirname("testalias");
Alias /testalias "G:/test"
<Directory "G:/test">
  Options Indexes FollowSymLinks MultiViews ExecCGI
  AllowOverride All
  Order allow,deny
  Allow from all
</Directory>

I've found a file in the XAMPP Apache config (conf) folder called "httpd.conf". I suppose this is the right file, but do I just paste the code (from your first code box) into that file, or do I overwrite something? Also, do I need to change the name of "testalias" to the name of the folder the Indexer.php file is in?

You have to change your apache configuration. The problem is not the php script, the problem is the webserver (which is not able to serve files outside web root, unless you configure it to).

and it should work!

Note
Rectangle 27 1

html PHP displaydownload directory files outside the webserver root?


$Root = realpath("."); // define the directory the index should be created for (can also be located outside the webserver root)
$AllowDownload = TRUE; // enclose file items with the anchor-tag (only makes sense when the files are in the webserver root)
$WebServerPath = dirname(getenv("SCRIPT_NAME")); // path where the indexed files can be accessed via a http URL (only required when $AllowDownload is TRUE)

However, you could modify this script to be able to do that in the way that styu has noted in his answer. You could then send your changes to the author of the script.

Notice "only makes sense when the files are in the webserver root" and "path where the indexed files can be accessed via a http URL". Which indicates that this script was not designed to be able to download files that are outside the web server root dir.

Note