Skip to content

Instantly share code, notes, and snippets.

@SnugglePilot
Last active July 2, 2018 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SnugglePilot/efb48ffaf3e91a3c55e4b71b93d8c6c5 to your computer and use it in GitHub Desktop.
Save SnugglePilot/efb48ffaf3e91a3c55e4b71b93d8c6c5 to your computer and use it in GitHub Desktop.
the LUX Web Engine: a simple not-a-blog thing
<?php
// LUX Web Engine - created bespoke for SnugglePilot.com.
// Created by Andy Moore. Run this code at your own risk. "Whatever" license I guess.
// Changelog/instructions: http://snugglepilot.com/?p=lux%20web%20engine
// v8 - Updated July 2nd, 2018
// ##############
// Configuration:
// ##############
$contentPath = "content/"; // relative folder to your content (text) files
$imagePath = "images/"; // relative folder to your image files
$defaultFile = "default"; // what content (text) file to show if no other is specified
$failFile = "404"; // what content (text) file to show if something was specified, but doesn't exist
$suffix = ".txt"; // what extension your content files have.
// so, eg, "content/default.txt" will be what is shown when you first load this page.
// Patterns are regular-expressions. Try using this site to make your own: https://regexr.com/
$linkPattern = "/\[[\w\d -'\|]+\]/"; // What we turn into links. default: [Link] or [real file|Label]
$imagePattern = "/\[[\w\d]+\.[\w\d]+\]/"; // What we turn into images. default: [image.png]
$boldPattern = "/\*.*?\*/"; // What we turn bold. default: *bold*
$italicsPattern = "/(?:^| )_.*?_/"; // What we turn into italics. default: _italics_
$hrPattern = "/(?:[\r\n])---[\r\n]/"; // What we turn into an <HR>. default: --- (alone on a line)
$quotePattern = "/^> .*$/m"; // What we turn into a quote. default: >
$bulletedListCharacter = "*"; // What we use to indicate a bulleted list.
$numberedListCharacter = "#"; // What we use to indicate a numbered list.
$lineBreakListTolerance = 1; // How many line breaks starts a new list?
$linkSplitCharacter = "|"; // What we use to split a link description, eg [link|displayed text]
$latestEntryKeyword = "<<LATEST_ENTRIES>>"; // What we turn into a list of recently updated things.
$numberOfLatestEntries = 5; // How many latest entries to display.
// #######################################################
// Not much to edit after this, unless you really want to.
// #######################################################
// Global variables. We don't use these in the content; they are available if you want to include
// them in the header or the footer.
$pageTitle = ""; // Populated by ParseContent
$pageModifyDate = ""; // Populated by ParseContent
$content = ParseContent(); // Generate content and populate the above global vars.
// This actually renders the page:
include("header.php"); // Just HTML, put what you like here.
echo $content;
include("footer.php"); // Just HTML, put what you like here.
// #######################################################
// This is the heavy-lifting main-parser for the site.
function ParseContent() {
global $latestEntryKeyword, $numberOfLatestEntries, $bulletedListCharacter, $numberedListCharacter;
// Fetch appropriate content.
$content = GetRelevantContent();
// Parse [Links] to other content.
// Eg, if you write [Link] it will instead display this as an <a href="link.txt">Link</a>.
// Will turn spaces into underscores automatically. make sure your content files are all lower case.
$content = ParseLinkTags($content);
// Parse [image.png] references:
// Same as links but shows images instead. make sure they are lower case.
$content = ParseImageTags($content);
// Generate latest entries lists with magic keyword:
// (this is an unstyled hack right now but it works. Just put the magic word in your document and it'll be fine)
if (strpos($content, $latestEntryKeyword) !== false) {
$content = str_replace($latestEntryKeyword, GetLatestEntries($numberOfLatestEntries), $content);
}
// Parse formatting things:
$content = ParseList($content, $bulletedListCharacter, "ul"); // lists should come before bold because they use the same character.
$content = ParseList($content, $numberedListCharacter, "ol");
$content = ParseQuotes($content);
$content = ParseBoldTags($content);
$content = ParseItalicsTags($content);
$content = ParseHRTags($content);
// This converts newline characters to <BR> characters:
$content = nl2br($content);
return $content;
}
// This checks the URL and fetches the relevant content.
function GetRelevantContent() {
global $contentPath, $suffix, $failFile, $defaultFile, $pageTitle, $pageModifyDate;
if (isset($_GET["p"])) {
// A specific page has been requested:
$contentFile = $_GET["p"];
$contentFile = str_replace("%20", " ", $contentFile);
if ($contentFile != $defaultFile) {
$pageTitle = $contentFile;
}
} else {
// Falling back to default file:
$contentFile = $defaultFile;
}
$fileFullPath = $contentPath . $contentFile . $suffix;
if (!file_exists($fileFullPath)) {
// Show error file - invalid link:
$fileFullPath = $contentPath . $failFile . $suffix;
$pageTitle = $failFile;
if (!file_exists($fileFullPath)) {
// Great, the error file doesn't exist.
http_response_code(404);
echo "<html><head><title>404</title></head><body>Site owner hasn't set up a 404 page.</body></html>";
die();
}
}
$pageModifyDate = TimeElapsed("@".filemtime($fileFullPath));
return file_get_contents($fileFullPath);
}
function ParseQuotes($content) {
global $quotePattern;
$matches = GetPatternMatch($content, $quotePattern);
for ($i = 0; $i < count($matches); $i++) {
// strip out the tag
$targetPhrase = substr($matches[$i], 1);
$targetPhrase = "<blockquote>".$targetPhrase."</blockquote>";
$content = str_replace($matches[$i], $targetPhrase, $content);
}
return $content;
}
function ParseBoldTags($content) {
global $boldPattern;
$matches = GetPatternMatch($content, $boldPattern);
for ($i = 0; $i < count($matches); $i++) {
// strip out the tag
$targetPhrase = substr($matches[$i], 1, strlen($matches[$i])-2);
$targetPhrase = "<strong>".$targetPhrase."</strong>";
$content = str_replace($matches[$i], $targetPhrase, $content);
}
return $content;
}
function ParseItalicsTags($content) {
global $italicsPattern;
$matches = GetPatternMatch($content, $italicsPattern);
for ($i = 0; $i < count($matches); $i++) {
// strip out the tag
$targetPhrase = substr($matches[$i], 2, strlen($matches[$i])-3);
$targetPhrase = " <em>".$targetPhrase."</em>";
$content = str_replace($matches[$i], $targetPhrase, $content);
}
return $content;
}
function ParseHRTags($content) {
global $hrPattern;
$matches = GetPatternMatch($content, $hrPattern);
for ($i = 0; $i < count($matches); $i++) {
$targetPhrase = "<br/><hr/>";
$content = str_replace($matches[$i], $targetPhrase, $content);
}
return $content;
}
function ParseList($content, $listCharacter, $listType) {
global $lineBreakListTolerance;
// grabbed this from: https://stackoverflow.com/questions/2344563/a-regex-that-converts-text-lists-to-html-in-php
$listPattern = "/^\\".$listCharacter." .*$/m";
$matches = GetPatternMatch($content, $listPattern);
for ($i = 0; $i < count($matches); $i++) {
// strip out the tag
$targetPhrase = substr($matches[$i], 2);
// This puts each dot in it's own list:
$targetPhrase = "<".$listType."><li>".$targetPhrase."</li></".$listType.">";
$content = str_replace($matches[$i], $targetPhrase, $content);
}
// This removes double </ul><ul> tags to simplify things:
// {0,2} for the \n tag would be better but that doesn't properly capture mushed together html :/
$content = preg_replace("/(\<\/".$listType."\>\n{1,".$lineBreakListTolerance."}(.*)\<".$listType."\>*)+/","", $content);
return $content;
}
// Just a loop to fire GetTextLink a whole bunch.
function ParseLinkTags($content) {
global $linkPattern, $linkSplitCharacter;
$matches = GetPatternMatch($content, $linkPattern);
for ($i = 0; $i < count($matches); $i++) {
// strip out the braces
$reference = substr($matches[$i], 1, strlen($matches[$i])-2);
$label = $reference;
// check for split links (eg: [real link|displayed text])
$split = explode($linkSplitCharacter, $reference, 2);
if (count($split) == 2) {
if (strlen($split[0]) <= 0) {
// We can't make a link if the pre-split area is size zero. eg: [|display text]
return $content;
} else {
// in case the last half of the split fails, let's at least trim the pipe out.
$reference = $split[0];
}
if (strlen($split[1]) > 0) {
// We only use the label if it has content. [realLink|] will pretend you didn't use a pipe.
$label = $split[1];
}
}
$link = GetTextLink($reference, $label);
$content = str_replace($matches[$i], $link, $content);
}
return $content;
}
// This converts a word to a text link from your content folder.
function GetTextLink($for, $label) {
$formatted = trim(strtolower($for));
$replacedSpaces = str_replace(" ", "%20", $formatted);
$link = "<a href='?p=".$replacedSpaces."'>".$label."</a>";
return $link;
}
// Just a loop to fire GetImageTag a whole bunch.
function ParseImageTags($content) {
global $imagePattern;
$matches = GetPatternMatch($content, $imagePattern);
for ($i = 0; $i < count($matches); $i++) {
$content = str_replace($matches[$i], GetImageTag($matches[$i]), $content);
}
return $content;
}
// This converts a filename to a proper image link.
function GetImageTag($filename) {
global $imagePath;
$reference = substr($filename, 1, strlen($filename)-2);
$reference = strtolower($reference);
return "<img src='".$imagePath.$reference."'/>";
}
// HTML-formats a nice list of the latest N updated content files.
function GetLatestEntries($listLength) {
global $contentPath, $suffix;
$files = glob($contentPath."*".$suffix);
$files = array_combine($files, array_map("filemtime", $files));
arsort($files);
if ($listLength > count($files)) {
$listLength = count($files);
}
$entries = "<hr>";
for ($i = 0; $i < $listLength; $i++) {
$flatName = basename(key($files));
$flatName = str_replace($suffix, "", $flatName);
$entries .= "<br>";
$entries .= GetTextLink($flatName, $flatName);
$entries .= " (".TimeElapsed("@".current($files)).")";
next($files);
}
$entries .= "<br><br><hr>";
return $entries;
}
// Shortcut to fetch the regex pa ttern.
function GetPatternMatch($content, $pattern) {
preg_match_all($pattern, $content, $matches);
return $matches[0];
}
// Stole this from stack overflow to make nice dates.
// Will show "updated 10 seconds ago" or "updated a year ago".
function TimeElapsed($datetime, $full = false) {
$now = new DateTime;
$ago = new DateTime($datetime);
$diff = $now->diff($ago);
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
$string = array(
'y' => 'year',
'm' => 'month',
'w' => 'week',
'd' => 'day',
'h' => 'hour',
'i' => 'minute',
's' => 'second',
);
foreach ($string as $k => &$v) {
if ($diff->$k) {
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
} else {
unset($string[$k]);
}
}
if (!$full) $string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment