simpub/blog.php
Markus Koch 01a6042468 Add blog param utime to mark the entry as updated
Add utime => strtotime(<date>) to the $blogentry header to enable
the feature for the post. It will still be sorted by ctime, but the post
will show the utime with an updated note in the date field instead.
2017-08-06 09:40:52 +02:00

299 lines
9.5 KiB
PHP

<?php
/*
* blog.php : This file provides the meta data parser for the CMS. It generates the temporary
* file containing the sorted posts. It also handles pre-parsing of embedded content
* such as images.
*/
if (!isset($CMS_ACTIVE)) exit();
require_once "shared.php";
if (isset($_GET['b'])) { // Blog post selector
$postUrl = $_GET['b'];
preg_match("/^[a-z0-9\\-" . POSTS_DIR_SEP . "]*$/", $postUrl, $matches); // SECURITY: Only lowercase a-z + numbers
if (!$matches)
unset($postUrl);
else {
$postUrl=substr($postUrl, 0, POSTS_MAX_FILENAME);
$postUrl=POSTS_ROOT . str_replace(POSTS_DIR_SEP, "/", $postUrl) . ".php";
if (!file_exists($postUrl)) {
unset($postUrl);
}
}
}
$postsPage = 0;
$postsSkip = 0;
if (isset($_GET['s'])) { // Page selector for post listing
if (is_numeric($_GET['s']) && $_GET['s'] < 100) { // SECURITY: MAX 100 pages
$postsPage = (int)$_GET['s'];
$postsSkip = $postsPage * POSTS_PAGE_SIZE;
}
}
$tagSearchUrl = "";
if (isset($_GET['t'])) { // Tag search
$tagSearch = $_GET['t'];
preg_match("/^[a-z0-9]*$/", $tagSearch, $matches); // SECURITY: Only lowercase a-z + numbers
if (!$matches)
unset($tagSearch);
else {
$tagSearch=substr($tagSearch, 0, POSTS_TAG_SEARCH); // SECURITY: Max search length POSTS_TAG_SEARCH
$tagSearchUrl="&t=$tagSearch";
}
}
$userPassword = "";
if (isset($_POST['password'])) { // Protected sections
$userPassword = $_POST['password'];
preg_match("/^[a-z0-9]*$/", $userPassword, $matches); // SECURITY: Only lowercase a-z + numbers
if (!$matches)
$userPassword = "";
else {
$userPassword=substr($userPassword, 0, 32); // SECURITY: Max PW len = 32
}
}
// --- $postUrl is now safe to use! (Full FS path)
// --- $postsPage is now safe to use!
// --- $tagSearch is now safe to use!
// --- $userPassword is now safe to use!
// Function called by the individual post headers to determin whether to display it and
// to configure / complete the metadata.
function renderPost() {
global $CMS_INDEXING;
global $blogentry;
global $counters;
global $meta;
global $pageTitle;
global $postUrl;
global $htmlHead;
global $CMS_RSS;
$counters['figure'] = 1;
$counters['video'] = 1;
$counters['sources'] = 1;
$meta['sources'] = array();
$blogentry->file = substr($blogentry->file, strlen(POSTS_ROOT), -4);
if (!(($posts = apcu_fetch('posts')) && isset($posts[$blogentry->file]) && $blogentry=$posts[$blogentry->file])) {
//echo "[DBG] Regenerate meta info block...";
if (!isset($blogentry->file))
$blogentry->file = "";
if (!isset($blogentry->title))
$blogentry->title = "Untitled";
if (!isset($blogentry->description))
$blogentry->description = $blogentry->title;
if (!isset($blogentry->author))
$blogentry->author = "Anonymous";
if (!isset($blogentry->status))
$blogentry->status = "private";
if (!isset($blogentry->ctime))
$blogentry->ctime = time();
if (!isset($blogentry->tags))
$blogentry->tags = "untagged";
$blogentry->tags = explode(',', $blogentry->tags);
sort($blogentry->tags);
$blogentry->permalink = getServerUrl() . "/?p=blog&b=" . str_replace("/", POSTS_DIR_SEP, $blogentry->file);
$blogentry->isPublic = ($blogentry->status == "released");
}
$renderIt = $CMS_INDEXING || ($blogentry->status == "released") || ($blogentry->status == "unlisted");
if ($renderIt && !isset($CMS_RSS)) {
if (isset($postUrl) && !$CMS_INDEXING) { // Set meta information
$pageTitle = $blogentry->title;
$htmlHead .= '<meta name="description" content="' . $blogentry->description . '">
<meta name="keywords" content="' . join(",", $blogentry->tags) . '">
<meta name="author" content="' . $blogentry->author . '">';
}
echo "<blogheading><table><tr><td><h1><a href=\"$blogentry->permalink\">$blogentry->title</a></h1></td>";
//echo '<td class="date">' . date("l, F jS Y, H:i", $blogentry->ctime) . "</td></tr></table></blogheading>";
echo '<td class="head"><span class="author">' . $blogentry->author . '</span> | <span title="Original release: ' . date("l, F jS Y, H:i", $blogentry->ctime) . '" class="date">';
if (isset($blogentry->utime)) {
echo "Updated " . date("l, F jS Y, H:i", $blogentry->utime);
} else {
echo date("l, F jS Y, H:i", $blogentry->ctime);
}
echo "</span></td></tr></table></blogheading>";
}
return $renderIt;
}
function renderFooter() {
global $CMS_SINGLE_POST;
global $counters;
global $meta;
$i = 1;
$renderExt = isset($CMS_SINGLE_POST) && $CMS_SINGLE_POST;
if ($renderExt && $counters['sources'] > 1) {
echo '<hr class="sourceSeparator"><p class="sources">Sources:<br>';
foreach ($meta['sources'] as $v) {
echo '<span id="src' . $i . '">&nbsp;&nbsp;&nbsp;&nbsp;[' . $i++ . ']: <a href="' . $v . '">' . $v . '</a></span><br>';
}
echo '</p><hr class="sourceSeparator">';
}
global $blogentry;
echo '<p class="tags">Tags: ';
foreach ($blogentry->tags as $v) {
echo '<a href="/?p=blog&t=' . $v . '">' . $v . '</a> ';
}
echo "</p>";
}
function extended() {
global $CMS_SINGLE_POST;
global $blogentry;
$renderExt = isset($CMS_SINGLE_POST) && $CMS_SINGLE_POST;
if ($renderExt) {
echo '<span id="more"></span>';
}
else {
echo '<p><a href="' . $blogentry->permalink . '#more">&rarr; Click here to continue reading &larr;</a></p>';
}
return $renderExt;
}
function password($pw) {
global $userPassword;
if ("$userPassword" == "$pw") {
echo '<span id="prot"></span>';
return true;
}
else {
echo "<p>";
if ($userPassword == "")
echo "This section is protected. To view it, enter the correct password.";
else
echo "The password you entered is incorrect! Please try again.";
?>
<form action="#prot" method="post">
<input type="password" name="password"> <input type="submit" value="Unlock section">
</form>
</p>
<?php
}
}
//apcu_clear_cache();
if (!($posts = apcu_fetch('posts'))) {
$CMS_INDEXING = true;
//echo "[DBG] Regenerate post index";
$posts = array();
foreach ($blogDirs as $dirName) {
// Find all posts
$Directory = new RecursiveDirectoryIterator('b/' . $dirName . '/');
$Iterator = new RecursiveIteratorIterator($Directory);
$objects = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
// Load Meta data and put it into one big archive
//$posts = array();
foreach($objects as $file => $object){
ob_start(); // These ob_lines will prevent output of actual HTML (the function already does this?!)
require "$file";
$blogentry->includeFile = $file;
//echo "<hr>";
ob_end_clean(); // Enable output, drop cached
//array_push($posts, $blogentry);
$posts[$blogentry->file] = $blogentry;
}
# Create list of columns relevant for sorting
$sort = array();
foreach($posts as $k=>$v) {
$sort['ctime'][$k] = $v->ctime;;
// $sort['author'][$k] = $v->author;
}
// Now sort the entries
// Multiple keys: array_multisort($sort['author'], SORT_ASC, $sort['title'], SORT_ASC,$posts);
array_multisort($sort['ctime'], SORT_DESC, $posts);
}
// Store to cache
apcu_store('posts', $posts, CACHE_POSTS_TTL);
$CMS_INDEXING = false;
}
if (!isset($CMS_RSS))
echo "<blog>";
if (isset($postUrl)) { // Display post
$CMS_SINGLE_POST = true;
echo '<div class="post">';
// Header is rendered in renderPost()
require $postUrl; // This will render the body
//if ($blogentry->isPublic) { // Render the blog footer
//echo "<p class=\"author\">Written by $blogentry->author</p>";
renderFooter();
//}
echo '</div>';
}
else {
//echo "<h1>Blog posts</h1>";
if (isset($tagSearch)) {
echo "<h1 class=\"bloginfoheader\"><table border=0 style='width: 100%;'><tr><td>Archive for '$tagSearch'</td>";
if (RSS_ENABLED) {
echo '<td style="text-align:right;padding:6px; padding-bottom: 0px; "><a href="/rss.php?t=' . $tagSearch . '" title="RSS Feed for \'' . $tagSearch . '\'"><img src="img/rss.svg" style="width: 32px;"></a></td>';
}
echo '</tr></table></h1>';
$pageTitle = "Archive for '$tagSearch'";
}
if (isset($CMS_RSS) && RSS_SHOW_FULL) {
$CMS_SINGLE_POST = true;
}
$i = 0;
$morePosts = false;
foreach($posts as $k=>$v) {
if ($v->isPublic) {
if (!isset($tagSearch) || in_array($tagSearch, $v->tags)) {
if ($i++ >= $postsSkip) {
if (isset($CMS_RSS)) {
if (!isset($latestDisplayedPost)) {
$latestDisplayedPost = $v->ctime;
}
echo '<item>
<title>' . $v->title . '</title>
<description><![CDATA[';
require $v->includeFile;
renderFooter();
echo ']]></description>
<link><![CDATA[' . $v->permalink . ']]></link>
<guid isPermaLink="true"><![CDATA[' . $v->permalink . ']]></guid>
<pubDate>' . date($RSS_DATE_FORMAT, $v->ctime) . '</pubDate>
<dc:creator>' . $v->author . '</dc:creator>
</item>';
} else {
echo '<div class="post">';
require $v->includeFile;
renderFooter();
echo "</div>";
echo '<hr class="postSeparator">';
}
if (($i % POSTS_PAGE_SIZE) == 0) {
$morePosts = true;
break;
}
}
}
}
}
if ($morePosts || $postsSkip > 0)
echo "<p><table class=\"blognav\"><tr>";
if ($morePosts)
echo '<td><a href="' . "?p=blog$tagSearchUrl&s=" . ($postsPage+1) . '">&lt;&lt; Older posts</a></td>';
if ($postsSkip > 0)
echo '<td style="text-align:right;"><a href="' . "?p=blog$tagSearchUrl&s=" . ($postsPage-1) . '">Newer posts &gt;&gt;</a></td>';
if ($morePosts || $postsSkip > 0)
echo "</tr></table></p>";
}
if (!isset($CMS_RSS))
echo "</blog>";
?>