How to redirect Apache "Index of ..." page?

I am trying to achieve authenticated file listing in Apache using PHP via Apache's autoindex module.

The way I imagined it was to have Apache run a PHP script as a header file. I've managed to get Apache run PHP correctly for the header file and it detects login cookies fine, too. But it seems that Apache runs the header file as a separate request which means if I try to send a redirection header from PHP it is not run.

My (simplified) Apache config:

DocumentRoot "/path/to/files_root"
Alias /~extra "/path/to/extra-data"

<Directory "/path/to/extra-data">
    Options -Indexes -MultiViews +Includes
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

IndexOptions FancyIndexing HTMLTable SuppressHTMLPreamble
AddType text/html .php .html .htm
AddOutputFilter INCLUDES .php
AddHandler application/x-httpd-php .php
HeaderName "/~extra/HEADER.php"

My HEADER.php file:

<?php

if ( ! my_validate_cookie_function()) {
    header('HTTP/1.1 302 Found');
    header('Location: http://login.example.com/');
    exit(1);
}

So, the header isn't sent to the browser. Setting Apache environment viariables doesn't seem to work, as they are long gone the moment HEADER.php is finished executing.

The cookie itself is encrypted, hence need for PHP to validate it.

Any suggestions how to achieve the desired effect?

Answers


You should insert an index.php file to your directory with the following code in the <body> tag.

function fileindex($folder) {
    if (!is_dir($folder)) {
        return array(); //empty if not a folder
    }
    $list = scandir($folder);
    array_shift($list); //first two values are always . & ..
    array_shift($list);
    return $list;
}
/* auth stuff here */
if (is_auth) {
    echo "<h1> Index of ".getcwd()."</h1>\n<ul>";
    echo "\n<li><a href=\"/\">Parent Directory</a>";
    foreach (fileindex(".") as $i) {
        echo "\n<li><a href=\"".$i."\">".htmlentities($i, ENT_QUOTES|"ENT_HTML401", "UTF-8", true)."</a></li>";
    }
    echo "</ul>";
}

Now since you have told me you cannot use index.php, you should use Apache to redirect the directory to wherever/other.php?directory=path and work from there.

In .htaccess the solution would be

RewriteCond %{REQUEST_URI} -d
RewriteRule ^(.*)$ wherever/other.php?directory=$1 [L]

Most notably, however, you would need to edit the PHP code slightly to accomodate for the folder being a $_GET parameter rather than a getcwd() and fileindex(".").


You can use this code:

<Directory "/path/to/files_root">
  DirectoryIndex redirected_page.php
</Directory>

The 1 in exit(1) maybe the problem. Try to remove that number.

I know that exit is a alias for die and die prints every text to the client.

By the way I would like to suggest to use mod_rewrite. You can check with RewriteCond if the cookie exists. If you want to check more e.g. session variables this won't work.


Here's what I finally ended up with. Kudos go to Scott S who hinted me towards the solution.

Apache config:

ServerName listing.example.com
# A path to a location which you wanted listed
DocumentRoot "/path/to/listed/location"

<Directory "/path/to/listed/location">
    # Ignore .htaccess files
    AllowOverride None
    # Disable Apache's own indexing, CGI execution and Apache Includes
    Options -Indexes -MultiViews -ExecCGI -Includes FollowSymLinks
    Order allow,deny
    Allow from all
</Directory>

<Directory "/path/to/php/listing/app">
    Options -MultiViews ExecCGI
    Order allow,deny
    Allow from all
</Directory>

<IfModule dir_module>
    # index.php should not be listed here as we will not want PHP scripts to be executed
    DirectoryIndex index.html index.htm
</IfModule>

<IfModule alias_module>
    # This is for CSS/JS files
    Alias /~media /path/to/php/listing/app/media
</IfModule>

<IfModule xsendfile_module>
    # Because the files listed might be large, we want to pass the file handling
    # to Apache via XSendFile Module
    # @see: https://tn123.org/mod_xsendfile/
    XSendFile on
    XSendFilePath "/path/to/listed/location"
</IfModule>

# Uncomment the two setting below if your listing a mounted drive
# EnableSendfile Off
# EnableMMAP Off

<IfModule rewrite_module>
    RewriteEngine On
    # Make sure there are trailing slashes for Directory URLs
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
    RewriteRule ^(.*[^/])$ $1/ [R=302,L]
    # Pass all file+dir requests to a PHP handler
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
    RewriteRule .* /path/to/php/listing/app/index.php/$0 [L]
</IfModule>

And (a very simplified version of) my php script:

<?php

if (my_authentication_check()) {
    $requested_path = realpath($_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI']);
    $filename = substr($requested_path, strrpos($requested_path, DIRECTORY_SEPARATOR) + 1);

    if ($requested_path) {
        if (is_dir($requested_path)) {
            // Show dir contents
            $dir_contents = scandir($requested_path);
        } else {
            // Pass file download to XSendFile module
            header('X-Sendfile: ' . $requested_path);
            header('Content-Type: ' . my_get_file_mime($filename));
            exit;
        }
    } else {
        // display 404 error
    }
} else {
    // redirect to login screen, or display an error... whatever you fancy
}

I actually use Kohana framework with my own libraries to handle authentication checks, display the listing, etc. You will have to take file permissions into account, too. E.g. on *nix systems you will need to check dirs for executable permission, while on Windows read access is enough.


Need Your Help

Ways to choose color theme of a website

javascript css class colors themes

On some websites you can choose a color theme of a website by clicking a button. Seems like nothing sophisticated, however is there any state of the art techniques to do that (maybe toggle between