Saft
Author: Markus Mayer – check out the source at GitHub.
Saft automatically publishes selected server spaces to the World Wide Web. It transforms image, video and plain text files into Web documents without the use of a database. Its static nature combined with a sly caching makes it super fast and also very secure.
An entire website is generated from a bunch of files that are filtered and parsed as needed. Once a page is loaded, it is instantly cached. As long as this cache is up to date, subsequent visitors access this cached page. This will ensure the responsiveness and the use of minimal processing power. Saft will easily handle heavy traffic, which is useful if a page ever gets fireballed.
The engine comes with built-in Sitemaps, Atom feeds, HTML and JSON output, inline linking prevention, simple output filtering and a useful debug mode.

Index page – Saft default.

Permalink page – Saft default.

The Sitemap.

Error page with enabled debug mode.
Contents
- Installation
- Writing Entries
- Entry Creation
- Entry Assets
- Scheduled Entries
- Categories, Authors
- Note on Markdown
- Caching
- Force Cache Update
- Output Filtering
- Customization
- Templates
- Site Navigation
- Extension
1. Installation
Saft requires a web server running a Unix-like operating system, Apache 2 with mod_rewrite enabled and htaccess file support, and PHP 5.3 or higher with JSON, MBSTRING and POSIX extensions installed.
Download Saft from GitHub and follow the installation instructions inside the readme file or below.
- Configure the files
/app/saft/app.phpand/htaccess. Instructions on configuration are found inside those. - Replace “domain.tld” with the corresponding domain name in
/robots.txt. - Move all directories and files to beloved server space. Thereby it does not matter if this is the domain root, a subdomain or a subdirectory.
- Create at least one content pot, which act as bin where to drop content files. Therefore, navigate to directory
/potand create as many subdirectories as liked in there. Only use names without special characters and spaces. - Rename
htaccessto.htaccessand make sure that the file permissions of all items are set properly. Once the site is successfully deployed, turn off the debug mode and enable the built-in caching, if not already done so.
2. Writing Entries
First of all, text files should be encoded using Unicode (UTF-8). This will prevent Saft from possibly printing out strange characters if special characters, such as “ß”, or double-byte charactes, like “液汁” or “ジュース”, are used.
Any decent text editor should have the option to edit and save text files as Unicode (UTF-8); have a look on the settings.
Entry Creation
To create an entry, save an image, video or plain text file to a so-called content pot, which is a subdirectory of /pot, with its name in the following format:
YYYYMMDD permalink.extension
(e.g. “20110113 lone-starr.txt”)
Above example would have been published on the 13th January of 2011. Under the assumption that it is stored in /pot/entries, it would be accessible via the permalink URI “entries/2011/01/13/lone-starr/”. Only use names without special characters and spaces for permalinks.
If the entry is a text file, a custom page title and a page description that will show up on search results pages (this is the meta description between the HTML head tags) can be added to the top of the file. The title always must come on the very first line. If there is no title available, the permalink will be used for the title creation. In the case of a missing description it is simply omitted.
title: Lone Starr meets Lord Helmet
description: The commander of the Imperious Forces …
Right below this, leave an empty line and start writing the entry. Saft uses Markdown for formatting, but writing HTML is fine, too.
Entry Assets
An Asset is similar to an entry, but with a bit different naming scheme.
YYYYMMDD permalink N.extension
(e.g. “20110113 lone-starr 7.gif”)
Above example would be an asset of the entry “Lone Starr” with the ID-number “7”. By this number, assets can easily be added to the corresponding entry when writing. Use the following syntax:
[@N]
(e.g. “[@7]”)
If an asset with the respective ID exists, the above anchor syntax is replaced with an image or video element; text files are injected as preformatted blocks, which is useful for ASCII art. Leftovers get automatically appended at the end of an entry in ascending order.
Assets of an entry should always be stored in that same directory as the corresponding entry itself. They won’t be taken into account otherwise. Although this behavior can be changed easily, it hardly makes sense. Instructions can be found inside /app/saft/permalink/permalink.php, though.
Scheduled Entries
Entries with a date set in the future will automatically show up when that date has arrived.
Categories
… or authors can be achieved by naming content pots properly, which requires enabled content pot filtering in /app/saft/app.php. However, only one of those; Saft won’t reflect nested directory trees.
Note on Markdown
Saft uses an adapted version of PHP Markdown, which is a port to PHP of the Markdown program written by John Gruber by Michel Fortin. It incorporates the behavior of Newlines and Multiple underscores in words from Github Flavored Markdown, HTML tables from PHP Markdown Extra and it accepts spaces in links.
To get started with Markdown, go over the excellent Markdown Syntax Guide at Daring Fireball. The differences from traditional Markdown are listed below.
Saft treats newlines in paragraph-like content as real line breaks, i.e.
It’s Mega Maid. She’s gone from suck to blow.becomes
It’s Mega Maid.
She’s gone from suck to blow.ignores multiple underlines in words to not italicize just a part of a word, i.e.
please_please_dont_make_a_fuss just_plain_yogurtbecomes
please_please_dont_make_a_fuss
just_plain_yogurtallows spaces in links, i.e.
<http://domain.tld/an example>becomes
and supports HTML tables, i.e.
ID | Name | Rank -- | ----------- | --------- 1 | Skroob | President 2 | Dark Helmet | Lordbecomes
ID Name Rank 1 Skroob President 2 Dark Helmet Lord
3. Caching
The built-in caching can serve up to a few hundred requests per second. Running ApacheBench on localhost to rule out network latency.
$ ab -n 1000 -c 20 -k http://localhost/entries/2011/01/13/lone-starr/
Time taken for tests: 1.541 seconds
Requests per second: 649.00 [#/sec] (mean)
Time per request: 30.817 [ms] (mean)
Time per request: 1.541 [ms] (mean, across all concurrent requests)
Transfer rate: 10559.94 [Kbytes/sec] received
This is anything but bad, but it is not as fast as a cache without any PHP involved would be. To bypass PHP and use funky caching instead, uncomment the respective section inside .htaccess. Running ApacheBench again.
$ ab -n 1000 -c 20 -k http://localhost/entries/2011/01/13/lone-starr/
Time taken for tests: 0.649 seconds
Requests per second: 1541.40 [#/sec] (mean)
Time per request: 12.975 [ms] (mean)
Time per request: 0.649 [ms] (mean, across all concurrent requests)
Transfer rate: 25010.36 [Kbytes/sec] received
The funky cache is more than twice as fast. It comes with one drawback, though. If Maat is not used for editing and the content is being modified, the cached page must be manually removed from the cache directory in order to reflect the changes.
Funky caching is currently only usable for permalink pages. This is due to the fact that scheduled entries would not show up automatically without any script function involved, and that it would be costly to have this work in conjunction with paginated, filtered index pages using htaccess.
Force Cache update
The built-in caching is smart enough to detect new entries, but in some cases it gropes in the dark. It cannot detect new entries in nested directory trees nor does it catch renamed ones. To ensure that the cache is up to date, remove 0_REMOVE-TO-FORCE-CACHE-UPDATE.txt from the respective content pot. This forces Saft to update the cache when needed.
If funky caching is enabled, the engine also won’t output any changes that have been applied to an entry as long as the old cache exists. Therefore, remove the cached page from the cache directory. Or use Maat for editing instead.
4. Output Filtering
The filtering is done via the URI and may be turned on or off inside /app/saft/app.php. It can be filtered by
so-called content pot; call it author, category or similar; i.e.
/entries/year, i.e.
/2011/month (2 digits!), i.e.
/01/a range of months (season), i.e.
/01-03/and all combined, i.e.
/entries/2011/ /entries/2011/01/ /entries/2011/01-03/ /entries/01-03/ /entries/01/
5. Customization
With a little knowledge in Cascading Style Sheets, a whole new appearance can merely be achieved by editing /asset/saft/standard.css; with additional knowledge in HTML and PHP, one should be capable of creating and customizing templates, rewriting the engine or parts thereof.
Templates
There are three different page-type templates by default.
- The index is responsible for any entry listing.
- The permalink is responsible for the output of an entry.
- The archive is more of a chronological activity map. It links to filtered entry list pages and requires the date filter to be turned on inside
/app/saft/app.php. If the archive should be omitted, but date filtering not; simply remove the archive folder itself.
Each of them is dependent on its respective output protocol extension. In order to change the output, edit the respective extension.
/app/saft/PAGE-TYPE/PROTOCOL.php
(e.g. /app/saft/index/html.php)
The same goes for all the other supported protocols such as HTML, JSON, etc. Saft does not use a template language, just PHP. To disable one of those output protocol extensions, just remove it from its respective page-type folder.
The page-type itself (e.g. /app/saft/index/index.php) contains core logics and should not be altered, unless one is doing something custom.
Site Navigation
To customize the “index”, “previous”, “next” and “archive” link names, pass the new names as properties to the navigation class. Replace the respective line in each /app/saft/PAGE-TYPE/html.php file with e.g.
$nav = new Nav('index', 'previous', 'next', 'archive');
Thereby it is important to preserve the order of the properties. The latter may be omitted, but never the ones in-between nor before (e.g. “index” followed by “previous” would be okay, but “previous” alone would not; because “previous” would become the new “index” then).
Delve into /app/saft/nav.php to achieve more comprehensive adjustments on the site navigation or the pagination.
6. Extension
Maat
The extension adds a minimalist bridge for authors. It lets you create, edit, remove, and uploading of content with a standard Web browser. Maat also enables basic collaboration. There is documentation on the project page.