Preprocessing with mod_rewrite and PHP

Ever had the need to publish a large set of HTML files, images and javascripts with transparent user management?

My first thought was Basic Auth with htpasswd and htgroups, there’s even an SQL extension so this seems like a good solution, right?

Its not. Basic Auth does not handle logouts very well, rather the browsers seems to store the login credentials and pass it along with every new request header. I was struggling with this until i came up with an idea.

what if we could rewrite all the incoming requests to a PHP script for preprocessing…

This way we can store our archive outside of the public webroot and force all requests to pass thru our handler, if mod_rewrite for some reason would stop working then there would be no way for the web to reach the archive (which is what we want).

The redirect is handled by Apaches mod_rewrite. The following example redirects all requests for https://domain.se/test/ to our preprocessor.

RewriteEngine On
RewriteRule ^test/(.+) /preprocessor.php?file=$1 [L]

For basic parsing we first need to set some response headers for MIME type and file size. Since css and javascript files are interpreted as text we need exceptions based on file endings.

<?php
/**
 * ASBRA - PHP Plain File Preprocessor
 *
 * Depends on Apaches mod_rewrite to redirect all traffic from target url
 * to the preprocessor.php scripts.
 *
 * @copyright 2019 ASBRA AB
 * @author Nimpen J. Nordström <j@asbra.nu>
 */

# Rewrite path (outside of public root!)

	$_GET['file'] = '/dir_outside_of_webroot/'.$_GET['file'];

# Mime type & file size

	$finfo     = finfo_open( FILEINFO_MIME_TYPE );
	$mime_type = finfo_file( $finfo, $_GET['file'] );
	finfo_close( $finfo );

	$filesize = filesize( $_GET['file'] );

	# There is a bug with finfo_file()

	$extension = pathinfo($_GET['file'],PATHINFO_EXTENSION);

	if     ( $extension == 'css' ) $mime_type = 'text/css';
	elseif ( $extension == 'js' )  $mime_type = 'application/javascript';

# Send headers

	header( "Content-Type: $mime_type" );
	header( "Content-Length: $filesize" );

# Send file data

	readfile( $_GET['file'] );

To handle the user authentication i used an old project AsbraCMS (the version without SQL)

# Check if user is logged in

	require('asbraCMS.php');

	if(!isset($_SESSION['logged_in'])) { 
		header( "Location: /login.php" );
		die(); 
	}

Thats it!

My many hours of research compressed into a small article ;)