Browse Source

Core update (better change handling)

markseu 10 years ago
parent
commit
06c837bdae
3 changed files with 94 additions and 58 deletions
  1. 1 1
      README.md
  2. 90 56
      system/core/core.php
  3. 3 1
      system/snippets/navigation.php

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-Yellow 0.4.23
+Yellow 0.4.24
 =============
 =============
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/markseu/yellowcms) 
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/markseu/yellowcms) 
 
 

+ 90 - 56
system/core/core.php

@@ -1,11 +1,11 @@
 <?php
 <?php
-// Copyright (c) 2013-2014 Datenstrom, http://datenstrom.se
+// Copyright (c) 2013-2015 Datenstrom, http://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 // Yellow main class
 // Yellow main class
 class Yellow
 class Yellow
 {
 {
-	const Version = "0.4.23";
+	const Version = "0.4.24";
 	var $page;				//current page
 	var $page;				//current page
 	var $pages;				//pages from file system
 	var $pages;				//pages from file system
 	var $config;			//configuration
 	var $config;			//configuration
@@ -169,9 +169,6 @@ class Yellow
 		$this->page = new YellowPage($this);
 		$this->page = new YellowPage($this);
 		$this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
 		$this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
 		$this->page->parseData($this->toolbox->getFileData($fileName), $cacheable, $statusCode, $pageError);
 		$this->page->parseData($this->toolbox->getFileData($fileName), $cacheable, $statusCode, $pageError);
-		$this->page->setHeader("Content-Type", "text/html; charset=UTF-8");
-		$this->page->setHeader("Last-Modified", $this->page->getModified(true));
-		if(!$this->page->isCacheable()) $this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
 		$this->text->setLanguage($this->page->get("language"));
 		$this->text->setLanguage($this->page->get("language"));
 		$this->page->parseContent();
 		$this->page->parseContent();
 		return $fileName;
 		return $fileName;
@@ -180,43 +177,22 @@ class Yellow
 	// Send page response
 	// Send page response
 	function sendPage()
 	function sendPage()
 	{
 	{
-		$this->template($this->page->get("template"));
-		$fileNameTheme = $this->config->get("themeDir").$this->page->get("theme").".css";
-		if(!is_file($fileNameTheme))
-		{
-			$this->page->error(500, "Theme '".$this->page->get("theme")."' does not exist!");
-		}
-		if(!$this->text->isLanguage($this->page->get("language")))
-		{
-			$this->page->error(500, "Language '".$this->page->get("language")."' does not exist!");
-		}
-		if(!is_object($this->page->parser))
+		$this->page->parseResponse();
+		$statusCode = $this->page->statusCode;
+		$lastModifiedFormatted = $this->page->getHeader("Last-Modified");
+		if($statusCode==200 && $this->page->isCacheable() && $this->toolbox->isFileNotModified($lastModifiedFormatted))
 		{
 		{
-			$this->page->error(500, "Parser '".$this->page->get("parser")."' does not exist!");
+			$statusCode = 304;
+			$this->page->clean($statusCode);
 		}
 		}
-		$statusCode = $this->page->statusCode;
 		if($statusCode==200 && $this->getRequestHandler()=="core" && $this->page->isExisting("redirect"))
 		if($statusCode==200 && $this->getRequestHandler()=="core" && $this->page->isExisting("redirect"))
 		{
 		{
 			$statusCode = 301;
 			$statusCode = 301;
 			$location = $this->toolbox->normaliseLocation($this->page->get("redirect"), $this->page->base, $this->page->location);
 			$location = $this->toolbox->normaliseLocation($this->page->get("redirect"), $this->page->base, $this->page->location);
 			$locationHeader = $this->toolbox->getLocationHeader($this->page->serverScheme, $this->page->serverName, "", $location);
 			$locationHeader = $this->toolbox->getLocationHeader($this->page->serverScheme, $this->page->serverName, "", $location);
 			$this->page->clean($statusCode, $locationHeader);
 			$this->page->clean($statusCode, $locationHeader);
-			$this->page->setHeader("Last-Modified", $this->page->getModified(true));
 			$this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
 			$this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
 		}
 		}
-		if($statusCode==200 && $this->page->isCacheable() &&
-		   $this->toolbox->isFileNotModified($this->page->getHeader("Last-Modified")))
-		{
-			$statusCode = 304;
-			if($this->page->isHeader("Cache-Control")) $responseHeader = "Cache-Control: ".$this->page->getHeader("Cache-Control");
-			$this->page->clean($statusCode, $responseHeader);
-		}
-		list($contentType) = explode(';', $this->page->getHeader("Content-Type"));
-		if($statusCode==200 && !$this->toolbox->isValidContentType($contentType, $this->page->getLocation()))
-		{
-			$statusCode = 500;
-			$this->page->error($statusCode, "Type '$contentType' does not match file name!");
-		}
 		if($this->page->isExisting("pageClean")) ob_clean();
 		if($this->page->isExisting("pageClean")) ob_clean();
 		if(PHP_SAPI != "cli")
 		if(PHP_SAPI != "cli")
 		{
 		{
@@ -229,6 +205,7 @@ class Yellow
 		{
 		{
 			foreach($this->page->headerData as $key=>$value) echo "Yellow::sendPage $key: $value<br/>\n";
 			foreach($this->page->headerData as $key=>$value) echo "Yellow::sendPage $key: $value<br/>\n";
 			$fileNameTemplate = $this->config->get("templateDir").$this->page->get("template").".php";
 			$fileNameTemplate = $this->config->get("templateDir").$this->page->get("template").".php";
+			$fileNameTheme = $this->config->get("themeDir").$this->page->get("theme").".css";
 			$parserName = $this->page->get("parser");
 			$parserName = $this->page->get("parser");
 			echo "Yellow::sendPage template:$fileNameTemplate theme:$fileNameTheme parser:$parserName<br/>\n";
 			echo "Yellow::sendPage template:$fileNameTemplate theme:$fileNameTheme parser:$parserName<br/>\n";
 		}
 		}
@@ -238,17 +215,18 @@ class Yellow
 	// Send file response
 	// Send file response
 	function sendFile($statusCode, $fileName, $cacheable)
 	function sendFile($statusCode, $fileName, $cacheable)
 	{
 	{
-		$lastModified = $this->toolbox->getHttpDateFormatted(filemtime($fileName));
-		if($statusCode==200 && $cacheable && $this->toolbox->isFileNotModified($lastModified))
+		$lastModifiedFormatted = $this->toolbox->getHttpDateFormatted(filemtime($fileName));
+		if($statusCode==200 && $cacheable && $this->toolbox->isFileNotModified($lastModifiedFormatted))
 		{
 		{
 			$statusCode = 304;
 			$statusCode = 304;
+			@header($this->toolbox->getHttpStatusFormatted($statusCode));
 		} else {
 		} else {
+			@header($this->toolbox->getHttpStatusFormatted($statusCode));
+			if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate");
+			@header("Content-Type: ".$this->toolbox->getMimeContentType($fileName));
+			@header("Last-Modified: ".$lastModifiedFormatted);
 			echo $this->toolbox->getFileData($fileName);
 			echo $this->toolbox->getFileData($fileName);
 		}
 		}
-		@header($this->toolbox->getHttpStatusFormatted($statusCode));
-		@header("Content-Type: ".$this->toolbox->getMimeContentType($fileName));
-		@header("Last-Modified: ".$lastModified);
-		if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate");
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 
 
@@ -261,18 +239,16 @@ class Yellow
 			if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate");
 			if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate");
 			if(!empty($responseHeader)) @header($responseHeader);
 			if(!empty($responseHeader)) @header($responseHeader);
 		} else {
 		} else {
-			if(!empty($responseHeader))
-			{
-				$this->page->header($responseHeader);
-				$this->page->header("Last-Modified: ".$this->toolbox->getHttpDateFormatted(time()));
-				if($statusCode>=301 && $statusCode<=303) $this->sendStaticRedirect();
-			}
+			if(!empty($responseHeader)) $this->page->header($responseHeader);
+			if($statusCode>=301 && $statusCode<=303) $this->sendStaticRedirect();
 		}
 		}
 	}
 	}
 
 
 	// Send static redirect response
 	// Send static redirect response
 	function sendStaticRedirect()
 	function sendStaticRedirect()
 	{
 	{
+		$lastModifiedFormatted = $this->toolbox->getHttpDateFormatted(time());
+		if(!$this->page->isHeader("Last-Modified")) $this->page->setHeader("Last-Modified", $lastModifiedFormatted);
 		echo "<!DOCTYPE html><html>\n<head>\n";
 		echo "<!DOCTYPE html><html>\n<head>\n";
 		echo "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
 		echo "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
 		echo "<meta http-equiv=\"refresh\" content=\"0;url=".htmlspecialchars($this->page->getHeader("Location"))."\" />\n";
 		echo "<meta http-equiv=\"refresh\" content=\"0;url=".htmlspecialchars($this->page->getHeader("Location"))."\" />\n";
@@ -389,6 +365,7 @@ class Yellow
 		$fileNameTemplate = $this->config->get("templateDir")."$name.php";
 		$fileNameTemplate = $this->config->get("templateDir")."$name.php";
 		if(is_file($fileNameTemplate))
 		if(is_file($fileNameTemplate))
 		{
 		{
+			$this->page->setLastModified(filemtime($fileNameTemplate));
 			global $yellow;
 			global $yellow;
 			require($fileNameTemplate);
 			require($fileNameTemplate);
 		} else {
 		} else {
@@ -399,10 +376,11 @@ class Yellow
 	// Execute snippet
 	// Execute snippet
 	function snippet($name, $args = NULL)
 	function snippet($name, $args = NULL)
 	{
 	{
-		$this->pages->snippetArgs = func_get_args();
 		$fileNameSnippet = $this->config->get("snippetDir")."$name.php";
 		$fileNameSnippet = $this->config->get("snippetDir")."$name.php";
 		if(is_file($fileNameSnippet))
 		if(is_file($fileNameSnippet))
 		{
 		{
+			$this->page->setLastModified(filemtime($fileNameSnippet));
+			$this->pages->snippetArgs = func_get_args();
 			global $yellow;
 			global $yellow;
 			require($fileNameSnippet);
 			require($fileNameSnippet);
 		} else {
 		} else {
@@ -426,6 +404,7 @@ class YellowPage
 	var $base;					//base location
 	var $base;					//base location
 	var $location;				//page location
 	var $location;				//page location
 	var $fileName;				//content file name
 	var $fileName;				//content file name
+	var $lastModified;			//last modification date
 	var $rawData;				//raw data of page
 	var $rawData;				//raw data of page
 	var $metaDataOffsetBytes;	//meta data offset
 	var $metaDataOffsetBytes;	//meta data offset
 	var $metaData;				//meta data
 	var $metaData;				//meta data
@@ -458,6 +437,7 @@ class YellowPage
 	// Parse page data
 	// Parse page data
 	function parseData($rawData, $cacheable, $statusCode = 0, $pageError = "")
 	function parseData($rawData, $cacheable, $statusCode = 0, $pageError = "")
 	{
 	{
+		$this->lastModified = 0;
 		$this->rawData = $rawData;
 		$this->rawData = $rawData;
 		$this->parserData = "";
 		$this->parserData = "";
 		$this->parser = NULL;
 		$this->parser = NULL;
@@ -517,8 +497,8 @@ class YellowPage
 			$this->set("title", $parsed[2]);
 			$this->set("title", $parsed[2]);
 		}
 		}
 		
 		
-		$shortHeader = $this->location == $this->yellow->pages->getHomeLocation($this->location);
-		$titleHeader = $shortHeader ? $this->get("sitename") : $this->get("title")." - ".$this->get("sitename");
+		$titleHeader = ($this->location == $this->yellow->pages->getHomeLocation($this->location)) ?
+			$this->get("sitename") : $this->get("title")." - ".$this->get("sitename");
 		if($this->get("titleContent") == "-") $this->set("titleContent", "");
 		if($this->get("titleContent") == "-") $this->set("titleContent", "");
 		if(!$this->isExisting("titleContent")) $this->set("titleContent", $this->get("title"));
 		if(!$this->isExisting("titleContent")) $this->set("titleContent", $this->get("title"));
 		if(!$this->isExisting("titleHeader")) $this->set("titleHeader", $titleHeader);
 		if(!$this->isExisting("titleHeader")) $this->set("titleHeader", $titleHeader);
@@ -586,6 +566,32 @@ class YellowPage
 		return $output;
 		return $output;
 	}
 	}
 	
 	
+	// Parse page response
+	function parseResponse()
+	{
+		$this->yellow->template($this->get("template"));
+		if(!$this->isCacheable()) $this->setHeader("Cache-Control", "no-cache, must-revalidate");
+		if(!$this->isHeader("Content-Type")) $this->setHeader("Content-Type", "text/html; charset=utf-8");
+		if(!$this->isHeader("Content-Modified")) $this->setHeader("Content-Modified", $this->getModified(true));
+		if(!$this->isHeader("Last-Modified")) $this->setHeader("Last-Modified", $this->getLastModified(true));
+		if(!is_file($this->yellow->config->get("themeDir").$this->get("theme").".css"))
+		{
+			$this->error(500, "Theme '".$this->get("theme")."' does not exist!");
+		}
+		if(!$this->yellow->text->isLanguage($this->get("language")))
+		{
+			$this->error(500, "Language '".$this->get("language")."' does not exist!");
+		}
+		if(!is_object($this->parser))
+		{
+			$this->error(500, "Parser '".$this->get("parser")."' does not exist!");
+		}
+		if(!$this->yellow->toolbox->isValidContentType($this->getHeader("Content-Type"), $this->getLocation()))
+		{
+			$this->error(500, "Type '".$this->getHeader("Content-Type")."' does not match file name!");
+		}
+	}
+	
 	// Set page response header
 	// Set page response header
 	function setHeader($key, $value)
 	function setHeader($key, $value)
 	{
 	{
@@ -691,13 +697,27 @@ class YellowPage
 		return $this->yellow->toolbox->getUrl($this->serverScheme, $this->serverName, $this->base, $this->location);
 		return $this->yellow->toolbox->getUrl($this->serverScheme, $this->serverName, $this->base, $this->location);
 	}
 	}
 	
 	
-	// Return page modification date, Unix time or HTTP format
+	// Return page content modification date, Unix time or HTTP format
 	function getModified($httpFormat = false)
 	function getModified($httpFormat = false)
 	{
 	{
 		$modified = strtotime($this->get("modified"));
 		$modified = strtotime($this->get("modified"));
 		return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($modified) : $modified;
 		return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($modified) : $modified;
 	}
 	}
 	
 	
+	// Set last modification date, Unix time
+	function setLastModified($modified)
+	{
+		$this->lastModified = max($this->lastModified, $modified);
+	}
+	
+	// Return last modification date, Unix time or HTTP format
+	function getLastModified($httpFormat = false)
+	{
+		$modified = max($this->lastModified, $this->getModified(), $this->yellow->config->getModified(),
+			$this->yellow->text->getModified(), $this->yellow->plugins->getModified());
+		return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($modified) : $modified;
+	}
+	
 	// Return page status code, number or HTTP format
 	// Return page status code, number or HTTP format
 	function getStatusCode($httpFormat = false)
 	function getStatusCode($httpFormat = false)
 	{
 	{
@@ -726,6 +746,7 @@ class YellowPage
 		if(!$this->isExisting("pageClean") && $statusCode>0)
 		if(!$this->isExisting("pageClean") && $statusCode>0)
 		{
 		{
 			$this->statusCode = $statusCode;
 			$this->statusCode = $statusCode;
+			$this->lastModified = 0;
 			$this->headerData = array();
 			$this->headerData = array();
 			if(!empty($responseHeader)) $this->header($responseHeader);
 			if(!empty($responseHeader)) $this->header($responseHeader);
 			$this->set("pageClean", (string)$statusCode);
 			$this->set("pageClean", (string)$statusCode);
@@ -942,7 +963,7 @@ class YellowPageCollection extends ArrayObject
 		return $this->filterValue;
 		return $this->filterValue;
 	}
 	}
 	
 	
-	// Return last modification date for page collection, Unix time or HTTP format
+	// Return page collection modification date, Unix time or HTTP format
 	function getModified($httpFormat = false)
 	function getModified($httpFormat = false)
 	{
 	{
 		$modified = 0;
 		$modified = 0;
@@ -1402,10 +1423,12 @@ class YellowText
 class YellowPlugins
 class YellowPlugins
 {
 {
 	var $plugins;		//registered plugins
 	var $plugins;		//registered plugins
+	var $modified;		//plugin modification date
 
 
 	function __construct()
 	function __construct()
 	{
 	{
 		$this->plugins = array();
 		$this->plugins = array();
+		$this->modified = 0;
 	}
 	}
 	
 	
 	// Load plugins
 	// Load plugins
@@ -1415,7 +1438,11 @@ class YellowPlugins
 		$path = $yellow->config->get("coreDir");
 		$path = $yellow->config->get("coreDir");
 		foreach($yellow->toolbox->getDirectoryEntries($path, "/^core-.*\.php$/", true, false) as $entry) require_once($entry);
 		foreach($yellow->toolbox->getDirectoryEntries($path, "/^core-.*\.php$/", true, false) as $entry) require_once($entry);
 		$path = $yellow->config->get("pluginDir");
 		$path = $yellow->config->get("pluginDir");
-		foreach($yellow->toolbox->getDirectoryEntries($path, "/^.*\.php$/", true, false) as $entry) require_once($entry);
+		foreach($yellow->toolbox->getDirectoryEntries($path, "/^.*\.php$/", true, false) as $entry)
+		{
+			$this->modified = max($this->modified, filemtime($entry));
+			require_once($entry);
+		}
 		foreach($this->plugins as $key=>$value)
 		foreach($this->plugins as $key=>$value)
 		{
 		{
 			$this->plugins[$key]["obj"] = new $value["class"];
 			$this->plugins[$key]["obj"] = new $value["class"];
@@ -1441,6 +1468,12 @@ class YellowPlugins
 		return $this->plugins[$name]["obj"];
 		return $this->plugins[$name]["obj"];
 	}
 	}
 	
 	
+	// Return plugins modification date, Unix time or HTTP format
+	function getModified($httpFormat = false)
+	{
+		return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($this->modified) : $this->modified;
+	}
+	
 	// Check if plugin exists
 	// Check if plugin exists
 	function isExisting($name)
 	function isExisting($name)
 	{
 	{
@@ -1613,9 +1646,9 @@ class YellowToolbox
 	}
 	}
 	
 	
 	// Check if file is unmodified since last HTTP request
 	// Check if file is unmodified since last HTTP request
-	function isFileNotModified($lastModified)
+	function isFileNotModified($lastModifiedFormatted)
 	{
 	{
-		return isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$lastModified;
+		return isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$lastModifiedFormatted;
 	}
 	}
 	
 	
 	// Check if clean URL is requested
 	// Check if clean URL is requested
@@ -1629,7 +1662,8 @@ class YellowToolbox
 	{
 	{
 		$ok = false;
 		$ok = false;
 		$extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
 		$extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
-		if($contentType == "text/html")
+		$tokens = explode(';', $contentType);
+		if($tokens[0] == "text/html")
 		{
 		{
 			if($this->isFileLocation($location))
 			if($this->isFileLocation($location))
 			{
 			{
@@ -1640,7 +1674,7 @@ class YellowToolbox
 		} else {
 		} else {
 			if($this->isFileLocation($location))
 			if($this->isFileLocation($location))
 			{
 			{
-				if(!empty($extension) && preg_match("/^.*$extension$/", $contentType)) $ok = true;
+				if(!empty($extension) && preg_match("/^.*$extension$/", $tokens[0])) $ok = true;
 			}
 			}
 		}
 		}
 		return $ok;
 		return $ok;
@@ -2043,7 +2077,7 @@ class YellowToolbox
 			"png" => "image/png",
 			"png" => "image/png",
 			"txt" => "text/plain",
 			"txt" => "text/plain",
 			"woff" => "application/font-woff");
 			"woff" => "application/font-woff");
-		$contentType = "text/html; charset=UTF-8";
+		$contentType = "text/html; charset=utf-8";
 		$extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : "";
 		$extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : "";
 		if(array_key_exists(strtoloweru($extension), $mimeTypes)) $contentType = $mimeTypes[$extension];
 		if(array_key_exists(strtoloweru($extension), $mimeTypes)) $contentType = $mimeTypes[$extension];
 		return $contentType;
 		return $contentType;
@@ -2177,7 +2211,7 @@ class YellowToolbox
 		return @rename($fileNameSource, $fileNameDest);
 		return @rename($fileNameSource, $fileNameDest);
 	}
 	}
 	
 	
-	// Set file modification time, Unix time
+	// Set file modification date, Unix time
 	function modifyFile($fileName, $modified)
 	function modifyFile($fileName, $modified)
 	{
 	{
 		return @touch($fileName, $modified);
 		return @touch($fileName, $modified);

+ 3 - 1
system/snippets/navigation.php

@@ -1,6 +1,8 @@
+<?php $pages = $yellow->pages->top() ?>
+<?php $yellow->page->setLastModified($pages->getModified()) ?>
 <div class="navigation">
 <div class="navigation">
 <ul>
 <ul>
-<?php foreach($yellow->pages->top() as $page): ?>
+<?php foreach($pages as $page): ?>
 <li><a<?php echo $page->isActive() ? " class=\"active\"" : "" ?> href="<?php echo $page->getLocation() ?>"><?php echo $page->getHtml("titleNavigation") ?></a></li>
 <li><a<?php echo $page->isActive() ? " class=\"active\"" : "" ?> href="<?php echo $page->getLocation() ?>"><?php echo $page->getHtml("titleNavigation") ?></a></li>
 <?php endforeach ?>
 <?php endforeach ?>
 </ul>
 </ul>