A static site generator in PHP

Published on Friday 15 April 2016. Tagged as GeneralPHP.

Having a static site generator to manage a site has a lot of benefits. And you can make one from scratch in a few hours using PHP. I'll also explain how to make user friendly URLs using the .htaccess file.

Benefits of a Static Site Generator

The main principle of making high performance system: rebuild your pages only when something changed, not every time they are viewed. Or said in another way: if you want to performe magic, don't forget to hide the rabbit first.

Another important benefit: you can have only the prefabricated pages on your public webserver and having a separate local CMS to generate them offline.Dynamic systems aka WordPress need the complete system on the public server, thus making you more vulnerable for hacks.

More on this on Smashing Magazine.

Making my own Static Site Generator

For the admin side, I use a simple local test server with PHP and MySql (XAMPP). The data of each post is stored in a MySQL database, edited with PhpMyAdmin, both come with a standard XAMPP install. I will then be using PHP and PDO to retrieve the data, build the pages and store them in a 'cache' folder.

After each update, I only need to publish this 'cache' folder to the public server using FTP - I use Filezilla for this. On the public server hosting my blog, the pages will be served directly out of the cache folder. I won't go over every line of code here. I'll just take the important parts and document them.

I have already picked a code highlighter, but I'll implement that part later.

The code

To make friendly URLs, I use the .htaccess file in the root directory of my blog to redirect all requests to the index.php file:

RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.+)$ ./index.php?url=$1

In the index.php file, the request is captured. Then, only for 127.0.0.1 (localhost) the requests for the admin interface are routed to the class App, function handleRequest(). All other requests are met by loading a file out of the 'cache' folder:

define('BASE',getcwd());

$request=isset( $_GET['url'] )?$_GET['url']:'index';

if($_SERVER['HTTP_HOST']=='127.0.0.1' && explode( '/', $request )[0]=='dc-admin' ){
	include( BASE.'/sys/core_functions.php' );
	call_user_func( array( new App( require( BASE.'/data/config.php') ), 'handleRequest' ) );
	exit();	
}

$file=BASE.'/cache/'.str_replace( '/', '_', $request ).'.php';
include( file_exists($file)?$file:BASE.'/cache/404.php' );

Generating the Cache Files

In my admin interface, there is a button to 'Regenerate cache'. For now, I only need to generate 3 types of pages:

For each of these I use PHP output buffering to capture the HTML otherwise sent to the browser and save it to a file:

	function rebuildPost($key){
		$app=$this->config['app'];
		$request=array('index');
		$post=$this->getPost($key);
		ob_start();
		include(BASE.'/sys/post.php');
		file_put_contents(BASE.'/cache/'.$key.'.php', ob_get_contents() );
		ob_end_clean();
	}

The result is what you see now. In the near future, I will put samples on GitHub so that you can look at the entire code.

Tomorrow's post will be about syntax highlighting and loading extra CSS (if necessary) when the page is loaded.