Access protection using Apache’s .htaccess and PHP

Sometimes it is necessary to limit access to certain files and folders based on your own PHP backend authentication script, i.e. you cannot use Apache’s built-in user authentication, but rather rely on backend authentication provided by your PHP framework.

The following script demonstrates a simple approach to realize access protection using a .htaccess file in combination with a backend PHP authentication script (index.php). The .htaccess file redirects requests to a PHP file called index.php residing in the data directory you want to protect. The index.php file handles the backend authorization process, as well as returns the corresponding file on success and the corresponding HTTP error code on error.

  1. .htaccess
    # restrict access to server files, such as .htaccess
    <Files .ht*>
      order allow,deny
      deny from all
    </Files>
    
    <IfModule mod_rewrite.c>
       RewriteEngine On
       #RewriteBase /
    
       # redirect to /your_data_dir/index.php
       RewriteCond %{REQUEST_URI} !(/your_data_dir/index.php.*)
       RewriteRule ^(.+)$ /your_data_dir/index.php?$1 [QSA,L]
    </IfModule>
    
  2. index.php

    try {

    if (!$DO_SOME_BACKEND_AUTH_CHECKING) {
    header($_SERVER[“SERVER_PROTOCOL”] . ” 403 Forbidden”);
    flush();
    exit;
    }

    $queryString = $_SERVER[‘QUERY_STRING’];

    if ($queryString == ”) {
    throw new Exception(‘No resource specified.’);
    }

    $queryStringParts = explode(“/”, $queryString);
    $saneQueryStringParts = “”; //clean path

    if (count($queryStringParts) < 1) { throw new Exception('No resource specified.'); }foreach ($queryStringParts as $p) { $saneQueryStringParts .= ( $saneQueryStringParts != '' ? '/' : '') . basename($p); }$file = $queryStringParts[count($queryStringParts) - 1]; $filePath = YOUR_DATA_PATH . $saneQueryStringParts;if ($file == '' || $saneQueryStringParts == '' || !file_exists($filePath)) { //send HTTP-404 header($_SERVER["SERVER_PROTOCOL"] . " 404 Not Found"); flush(); exit; }$finfo = finfo_open(FILEINFO_MIME_TYPE);if ($finfo === false) throw new Exception('Failed to determine mime-type.');$mime = finfo_file($finfo, $filePath);if ($mime === false) throw new Exception('Failed to determine mime-type.');header('Content-type: ' . $mime); header('Content-Disposition: attachment; filename="' . $file . '"'); readfile($filePath); } catch (Exception $e) { header($_SERVER["SERVER_PROTOCOL"] . " 500 Internal Server Error"); flush(); exit; } [/php]

Using this approach you can refer to your files and folders using their original structures, such as http://your_server/data_dir/images/img_1.png. The .htaccess file will redirect this request to the authentication script index.php residing in /data_dir/index.php using /images/img_1.png as query string. The query string will be converted by basename() for safe use and the resulting file will be returned.

You need PHP’s FileInfo package in order to use index.php, see http://php.net/manual/en/book.fileinfo.php for more information.

Optionally, you could create an alias in .htaccess (or directly in the vhost settings) that redirects requests to resources inside /data/… to a location outside of your DOCUMENT_ROOT, like so:

    Alias /data /your/data/directory
    <Directory "/your/data/directory">
      ...
    </Directory>

You may also like...

2 Responses

  1. Hey great site I really enjoyed the read thank you for posting such valuable info and keeping up with the latest trends.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.