324 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			10 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->isVisible = ($blogentry->ctime <= time()) && (($blogentry->status == "released") || ($blogentry->status == "unlisted"));
 | |
| 			$blogentry->isPublic = ($blogentry->status == "released") && $blogentry->isVisible;
 | |
| 		}
 | |
| 		$renderIt = $CMS_INDEXING || $blogentry->isVisible;
 | |
| 
 | |
| 		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 . '">    [' . $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">→ Click here to continue reading ←</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_SITEMAP)) {
 | |
| 		foreach($posts as $k=>$v) {
 | |
| 			if ($v->isPublic) {
 | |
| 				echo "<url>\n\t<loc>" . htmlspecialchars($v->permalink) . "</loc>\n</url>\n";
 | |
| 			}
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 
 | |
| 	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->isVisible) { // Render the blog footer		
 | |
| 			//echo "<p class=\"author\">Written by $blogentry->author</p>";
 | |
| 			renderFooter();
 | |
| 		} else {
 | |
| 			echo("<h1>Private Post</h1>");
 | |
| 			echo("<p>This post has not yet been made public by the publisher. Please check back again later. Thank you.</p>");
 | |
| 		}
 | |
| 		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 = 0;
 | |
| 		$firstRendered = 0;
 | |
| 		foreach($posts as $k=>$v) {			
 | |
| 			if ($v->isPublic) {
 | |
| 				if (!isset($tagSearch) || in_array($tagSearch, $v->tags)) {
 | |
| 					if ($i++ >= $postsSkip) {
 | |
| 						if ($morePosts == 0) {
 | |
| 							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 {
 | |
| 								if ($firstRendered) {
 | |
| 									echo '<hr class="postSeparator">';
 | |
| 								}
 | |
| 								$firstRendered = 1;
 | |
| 								echo '<div class="post">';
 | |
| 								require $v->includeFile;
 | |
| 								renderFooter();
 | |
| 								echo "</div>";
 | |
| 							}
 | |
| 						}
 | |
| 						if (($i % POSTS_PAGE_SIZE) == 0) {
 | |
| 							$morePosts = 1;
 | |
| 						} else {
 | |
| 							if ($morePosts == 1) {
 | |
| 								$morePosts = 2;
 | |
| 								break;
 | |
| 							} else {
 | |
| 								$morePosts = 0;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		if (!isset($CMS_RSS)) {
 | |
| 			if ($morePosts == 2 || $postsSkip > 0)
 | |
| 				echo "<p><table class=\"blognav\"><tr>";
 | |
| 			if ($morePosts == 2)
 | |
| 				echo '<td><a href="' . "?p=blog$tagSearchUrl&s=" . ($postsPage+1) . '"><< Older posts</a></td>';
 | |
| 			if ($postsSkip > 0)
 | |
| 				echo '<td style="text-align:right;"><a href="' . "?p=blog$tagSearchUrl&s=" . ($postsPage-1) . '">Newer posts >></a></td>';
 | |
| 			if ($morePosts == 2|| $postsSkip > 0)
 | |
| 				echo "</tr></table></p>";
 | |
| 		}
 | |
| 	}
 | |
| 	if (!isset($CMS_RSS))
 | |
| 		echo "</blog>";
 | |
| ?>
 |