Переглянути джерело

Hello command line (static pages)

markseu 10 роки тому
батько
коміт
8d575d5bb0
6 змінених файлів з 335 додано та 232 видалено
  1. 1 15
      .htaccess
  2. 1 1
      README.md
  3. 7 3
      system/config/config.ini
  4. 118 112
      system/core/core-commandline.php
  5. 28 24
      system/core/core-webinterface.php
  6. 180 77
      system/core/core.php

+ 1 - 15
.htaccess

@@ -3,25 +3,11 @@ RewriteEngine on
 
 
 # Yellow dynamic pages
 # Yellow dynamic pages
 
 
-RewriteCond %{ENV:REDIRECT_STATUS} ^$
-RewriteRule ^(content|system)/ error404 [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^robots.txt$ system/config/robots.txt [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteCond %{REQUEST_URI} \.(css|js|jpg|png|woff)$
-RewriteRule ^media/plugins/(core-.+) system/core/$1 [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteCond %{REQUEST_URI} \.(css|js|jpg|png|woff)$
-RewriteRule ^media/plugins/(.+) system/plugins/$1 [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteCond %{REQUEST_URI} \.(css|js|jpg|png|woff)$
-RewriteRule ^media/themes/(.+) system/themes/$1 [L]
-
-RewriteCond yellow.php -F
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule ^ yellow.php [L]
 RewriteRule ^ yellow.php [L]
 DirectoryIndex index.html yellow.php
 DirectoryIndex index.html yellow.php
+RewriteRule ^(cache|content|system)/ error404.html [L]
 
 
 # Yellow static pages
 # Yellow static pages
 
 

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-Yellow 0.4.19
+Yellow 0.4.20
 =============
 =============
 [![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) 
 
 

+ 7 - 3
system/config/config.ini

@@ -15,12 +15,16 @@ pluginLocation = /media/plugins/
 themeLocation = /media/themes/
 themeLocation = /media/themes/
 systemDir = system/
 systemDir = system/
 configDir = system/config/
 configDir = system/config/
+coreDir = system/core/
 pluginDir = system/plugins/
 pluginDir = system/plugins/
 snippetDir = system/snippets/
 snippetDir = system/snippets/
 templateDir = system/templates/
 templateDir = system/templates/
 themeDir = system/themes/
 themeDir = system/themes/
 mediaDir = media/
 mediaDir = media/
 imageDir = media/images/
 imageDir = media/images/
+staticDir = cache/
+staticDefaultFile = index.html
+staticErrorFile = error404.html
 contentDir = content/
 contentDir = content/
 contentRootDir = default/
 contentRootDir = default/
 contentHomeDir = home/
 contentHomeDir = home/
@@ -31,6 +35,7 @@ configExtension = .ini
 errorPageFile = error(.*).txt
 errorPageFile = error(.*).txt
 newPageFile = new(.*).txt
 newPageFile = new(.*).txt
 textStringFile = language(.*).ini
 textStringFile = language(.*).ini
+robotsTextFile = robots.txt
 parser = markdownextra
 parser = markdownextra
 parserSafeMode = 0
 parserSafeMode = 0
 multiLanguageMode = 0
 multiLanguageMode = 0
@@ -40,6 +45,5 @@ webinterfaceUserHashAlgorithm = bcrypt
 webinterfaceUserHashCost = 10
 webinterfaceUserHashCost = 10
 webinterfaceUserFile = user.ini
 webinterfaceUserFile = user.ini
 webinterfaceFilePrefix = published
 webinterfaceFilePrefix = published
-commandlineDefaultFile = index.html
-commandlineErrorFile = error404.html
-commandlineSystemFile = .htaccess, system/config/robots.txt
+commandlineIgnoreLocation = 
+commandlineSystemFile = .htaccess

+ 118 - 112
system/core/core-commandline.php

@@ -5,7 +5,7 @@
 // Command line core plugin
 // Command line core plugin
 class YellowCommandline
 class YellowCommandline
 {
 {
-	const Version = "0.4.3";
+	const Version = "0.4.4";
 	var $yellow;				//access to API
 	var $yellow;				//access to API
 	var $content;				//number of content pages
 	var $content;				//number of content pages
 	var $media;					//number of media files
 	var $media;					//number of media files
@@ -13,14 +13,12 @@ class YellowCommandline
 	var $error;					//number of build errors
 	var $error;					//number of build errors
 	var $locationsArguments;	//locations with arguments detected
 	var $locationsArguments;	//locations with arguments detected
 	var $locationsPagination;	//locations with pagination detected
 	var $locationsPagination;	//locations with pagination detected
-	var $fileNamesPlugin;		//plugin files detected
 	
 	
 	// Handle plugin initialisation
 	// Handle plugin initialisation
 	function onLoad($yellow)
 	function onLoad($yellow)
 	{
 	{
 		$this->yellow = $yellow;
 		$this->yellow = $yellow;
-		$this->yellow->config->setDefault("commandlineDefaultFile", "index.html");
-		$this->yellow->config->setDefault("commandlineErrorFile", "error404.html");
+		$this->yellow->config->setDefault("commandlineIgnoreLocation", "");
 		$this->yellow->config->setDefault("commandlineSystemFile", ".htaccess");
 		$this->yellow->config->setDefault("commandlineSystemFile", ".htaccess");
 	}
 	}
 	
 	
@@ -28,8 +26,8 @@ class YellowCommandline
 	function onCommandHelp()
 	function onCommandHelp()
 	{
 	{
 		$help .= "version\n";
 		$help .= "version\n";
-		$help .= "build DIRECTORY [LOCATION]\n";
-		$help .= "clean DIRECTORY [LOCATION]\n";
+		$help .= "build [DIRECTORY LOCATION]\n";
+		$help .= "clean [DIRECTORY LOCATION]\n";
 		return $help;
 		return $help;
 	}
 	}
 	
 	
@@ -74,11 +72,11 @@ class YellowCommandline
 	{
 	{
 		$statusCode = 0;
 		$statusCode = 0;
 		list($dummy, $command, $path, $location) = $args;
 		list($dummy, $command, $path, $location) = $args;
-		if(!empty($path) && $path!="/" && (empty($location) || $location[0]=='/'))
+		if(empty($location) || $location[0]=='/')
 		{
 		{
 			if($this->checkStaticConfig())
 			if($this->checkStaticConfig())
 			{
 			{
-				$statusCode = $this->buildStatic($location, $path);
+				$statusCode = $this->buildStatic($path, $location);
 			} else {
 			} else {
 				$statusCode = 500;
 				$statusCode = 500;
 				list($this->content, $this->media, $this->system, $this->error) = array(0, 0, 0, 1);
 				list($this->content, $this->media, $this->system, $this->error) = array(0, 0, 0, 1);
@@ -95,60 +93,52 @@ class YellowCommandline
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
-	// Build static locations and files
-	function buildStatic($location, $path)
+	// Build static directories and files
+	function buildStatic($path, $location)
 	{
 	{
 		$this->yellow->toolbox->timerStart($time);
 		$this->yellow->toolbox->timerStart($time);
-		$pluginDir = $this->yellow->config->get("pluginDir");
-		$pathPlugin = rtrim($path.$this->yellow->config->get("pluginLocation"), '/');
+		$path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
 		$this->content = $this->media = $this->system = $this->error = $statusCode = 0;
 		$this->content = $this->media = $this->system = $this->error = $statusCode = 0;
-		$this->locationsArguments = $this->locationsPagination = $this->fileNamesPlugin = array();
+		$this->locationsArguments = $this->locationsPagination = array();
 		if(empty($location))
 		if(empty($location))
 		{
 		{
-			$statusCode = $this->cleanStatic($location, $path);
+			$statusCode = $this->cleanStatic($path, $location);
 			foreach($this->getStaticLocations() as $location)
 			foreach($this->getStaticLocations() as $location)
 			{
 			{
-				$statusCode = max($statusCode, $this->buildStaticLocation($location, $path, true));
+				$statusCode = max($statusCode, $this->buildStaticRequest($path, $location, true));
 			}
 			}
 			foreach($this->locationsArguments as $location)
 			foreach($this->locationsArguments as $location)
 			{
 			{
-				$statusCode = max($statusCode, $this->buildStaticLocation($location, $path, true));
+				$statusCode = max($statusCode, $this->buildStaticRequest($path, $location, true));
 			}
 			}
 			foreach($this->locationsPagination as $location)
 			foreach($this->locationsPagination as $location)
 			{
 			{
 				for($pageNumber=2; $pageNumber<=999; ++$pageNumber)
 				for($pageNumber=2; $pageNumber<=999; ++$pageNumber)
 				{
 				{
-					$statusCodeLocation = $this->buildStaticLocation($location.$pageNumber, $path, false, true);
+					$statusCodeLocation = $this->buildStaticRequest($path, $location.$pageNumber, false, true);
 					$statusCode = max($statusCode, $statusCodeLocation);
 					$statusCode = max($statusCode, $statusCodeLocation);
 					if($statusCodeLocation == 0) break;
 					if($statusCodeLocation == 0) break;
 				}
 				}
 			}
 			}
-			$fileNamesMedia = $this->yellow->toolbox->getDirectoryEntriesRecursive(
-				$this->yellow->config->get("mediaDir"), "/.*/", false, false);
-			$fileNamesSystem = preg_split("/,\s*/", $this->yellow->config->get("commandlineSystemFile"));
-			array_push($fileNamesSystem, $this->yellow->config->get("commandlineErrorFile"));
-			foreach($fileNamesMedia as $fileName)
+			$statusCode = max($statusCode, $this->buildStaticError($path, 404));
+			foreach($this->getStaticFilesMedia($path) as $fileNameSource=>$fileNameDest)
 			{
 			{
-				$statusCode = max($statusCode, $this->buildStaticFile($fileName, "$path/$fileName"));
+				$statusCode = max($statusCode, $this->buildStaticFile($fileNameSource, $fileNameDest, true));
 			}
 			}
-			foreach($this->fileNamesPlugin as $fileName)
+			foreach($this->getStaticFilesSystem($path) as $fileNameSource=>$fileNameDest)
 			{
 			{
-				$statusCode = max($statusCode, $this->buildStaticFile("$pluginDir$fileName", "$pathPlugin/$fileName"));
-			}
-			foreach($fileNamesSystem as $fileName)
-			{
-				$statusCode = max($statusCode, $this->buildStaticFile($fileName, "$path/".basename($fileName), false));
+				$statusCode = max($statusCode, $this->buildStaticFile($fileNameSource, $fileNameDest, false));
 			}
 			}
 		} else {
 		} else {
-			$statusCode = $this->buildStaticLocation($location, $path);
+			$statusCode = $this->buildStaticRequest($path, $location);
 		}
 		}
 		$this->yellow->toolbox->timerStop($time);
 		$this->yellow->toolbox->timerStop($time);
 		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic time:$time ms\n";
 		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic time:$time ms\n";
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
-	// Build static location
-	function buildStaticLocation($location, $path, $analyse = false, $probe = false)
+	// Build static request
+	function buildStaticRequest($path, $location, $analyse = false, $probe = false)
 	{		
 	{		
 		ob_start();
 		ob_start();
 		$_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
 		$_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
@@ -157,11 +147,12 @@ class YellowCommandline
 		$_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php";
 		$_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php";
 		$_REQUEST = array();
 		$_REQUEST = array();
 		$statusCode = $this->yellow->request();
 		$statusCode = $this->yellow->request();
-		if($statusCode != 404)
+		if($statusCode < 400)
 		{
 		{
-			$modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
-			$fileName = $this->getStaticFileName($location, $path);
+			$fileName = $this->yellow->toolbox->findStaticFileFromLocation($location, $path,
+				$this->yellow->config->get("staticDefaultFile"));
 			$fileData = ob_get_contents();
 			$fileData = ob_get_contents();
+			$modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
 			if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
 			if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
 			   !$this->yellow->toolbox->modifyFile($fileName, $modified))
 			   !$this->yellow->toolbox->modifyFile($fileName, $modified))
 			{
 			{
@@ -170,11 +161,7 @@ class YellowCommandline
 			}
 			}
 		}
 		}
 		ob_end_clean();
 		ob_end_clean();
-		if($statusCode==200 && $analyse)
-		{
-			$this->analyseStaticContent($fileData);
-			$this->analyseStaticMedia($fileData);
-		}
+		if($statusCode==200 && $analyse) $this->analyseStaticContent($fileData);
 		if($statusCode==404 && $probe) $statusCode = 0;
 		if($statusCode==404 && $probe) $statusCode = 0;
 		if($statusCode != 0) ++$this->content;
 		if($statusCode != 0) ++$this->content;
 		if($statusCode >= 400)
 		if($statusCode >= 400)
@@ -183,50 +170,57 @@ class YellowCommandline
 			echo "ERROR building content location '$location', ".$this->yellow->page->getStatusCode(true)."\n";
 			echo "ERROR building content location '$location', ".$this->yellow->page->getStatusCode(true)."\n";
 		}
 		}
 		if(defined("DEBUG") && DEBUG>=3) echo $fileData;
 		if(defined("DEBUG") && DEBUG>=3) echo $fileData;
-		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticLocation status:$statusCode location:$location\n";
+		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticRequest status:$statusCode location:$location\n";
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
-	// Build static file
-	function buildStaticFile($fileNameSource, $fileNameDest, $fileTypeMedia = true)
+	// Build static error
+	function buildStaticError($path, $statusCodeRequest)
 	{
 	{
-		if($fileNameSource != $this->yellow->config->get("commandlineErrorFile"))
+		ob_start();
+		$_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
+		$_SERVER["SERVER_NAME"] = $this->yellow->config->get("serverName");
+		$_SERVER["REQUEST_URI"] = $this->yellow->config->get("serverBase")."/";
+		$_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php";
+		$_REQUEST = array();
+		$statusCode = $this->yellow->request($statusCodeRequest);
+		$fileName = "$path/".$this->yellow->config->get("staticErrorFile");
+		if($statusCode == $statusCodeRequest)
 		{
 		{
-			$statusCode = $this->yellow->toolbox->copyFile($fileNameSource, $fileNameDest, true) &&
-				$this->yellow->toolbox->modifyFile($fileNameDest, filemtime($fileNameSource)) ? 200 : 500;
-		} else {
-			ob_start();
-			$_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
-			$_SERVER["SERVER_NAME"] = $this->yellow->config->get("serverName");
-			$_SERVER["REQUEST_URI"] = $this->yellow->config->get("serverBase")."/";
-			$_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php";
-			$_REQUEST = array();
-			$statusCodeRequest = 404;
-			$statusCode = $this->yellow->request($statusCodeRequest);
-			if($statusCode == $statusCodeRequest)
+			$statusCode = 200;
+			$fileData = ob_get_contents();
+			$modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
+			if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
+			   !$this->yellow->toolbox->modifyFile($fileName, $modified))
 			{
 			{
-				$statusCode = 200;
-				$modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
-				if(!$this->yellow->toolbox->createFile($fileNameDest, ob_get_contents(), true) ||
-				   !$this->yellow->toolbox->modifyFile($fileNameDest, $modified))
-				{
-					$statusCode = 500;
-					$this->yellow->page->error($statusCode, "Can't write file '$fileNameDest'!");
-				}
-			} else {
 				$statusCode = 500;
 				$statusCode = 500;
-				$this->yellow->page->error($statusCode, "Error $statusCodeRequest does not exist!");
+				$this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
 			}
 			}
-			ob_end_clean();
 		}
 		}
+		ob_end_clean();
+		++$this->system;
+		if($statusCode >= 400)
+		{
+			++$this->error;
+			echo "ERROR building error file '$fileName', ".$this->yellow->page->getStatusCode(true)."\n";
+		}
+		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticError status:$statusCode file:$fileName\n";
+		return $statusCode;
+	}
+	
+	// Build static file
+	function buildStaticFile($fileNameSource, $fileNameDest, $fileTypeMedia)
+	{
+		$statusCode = $this->yellow->toolbox->copyFile($fileNameSource, $fileNameDest, true) &&
+			$this->yellow->toolbox->modifyFile($fileNameDest, filemtime($fileNameSource)) ? 200 : 500;
 		if($fileTypeMedia) { ++$this->media; } else { ++$this->system; }
 		if($fileTypeMedia) { ++$this->media; } else { ++$this->system; }
 		if($statusCode >= 400)
 		if($statusCode >= 400)
 		{
 		{
 			++$this->error;
 			++$this->error;
 			$fileType = $fileTypeMedia ? "media file" : "system file";
 			$fileType = $fileTypeMedia ? "media file" : "system file";
-			echo "ERROR building $fileType '$fileNameSource', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
+			echo "ERROR building $fileType '$fileNameDest', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
 		}
 		}
-		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticFile status:$statusCode file:$fileNameSource\n";
+		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticFile status:$statusCode file:$fileNameDest\n";
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
@@ -266,38 +260,14 @@ class YellowCommandline
 		}
 		}
 	}
 	}
 	
 	
-	// Analyse static media, detect plugin files
-	function analyseStaticMedia($text)
-	{
-		$serverName = $this->yellow->config->get("serverName");
-		$serverBase = $this->yellow->config->get("serverBase");
-		$pluginLocation = $this->yellow->config->get("pluginLocation");
-		preg_match_all("#<(.*?)\"([^\"]*{$pluginLocation}[^\"]+)\"(.*?)>#", $text, $matches);
-		foreach($matches[2] as $match)
-		{
-			if(preg_match("/^\w+:\/+(.*?)(\/.*)$/", $match, $tokens))
-			{
-				if($tokens[1] != $serverName) continue;
-				$match = $tokens[2];
-			}
-			if(substru($match, 0, strlenu($serverBase.$pluginLocation)) != $serverBase.$pluginLocation) continue;
-			$fileName = rawurldecode(substru($match, strlenu($serverBase.$pluginLocation)));
-			if(is_null($this->fileNamesPlugin[$fileName]))
-			{
-				$this->fileNamesPlugin[$fileName] = $fileName;
-				if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticMedia type:plugin file:$fileName\n";
-			}
-		}
-	}
-	
 	// Clean static pages
 	// Clean static pages
 	function cleanCommand($args)
 	function cleanCommand($args)
 	{
 	{
 		$statusCode = 0;
 		$statusCode = 0;
 		list($dummy, $command, $path, $location) = $args;
 		list($dummy, $command, $path, $location) = $args;
-		if(!empty($path) && $path!="/" && (empty($location) || $location[0]=='/'))
+		if(empty($location) || $location[0]=='/')
 		{
 		{
-			$statusCode = $this->cleanStatic($location, $path);
+			$statusCode = $this->cleanStatic($path, $location);
 			echo "Yellow $command: Static page".(empty($location) ? "s" : "")." ".($statusCode!=200 ? "not " : "")."cleaned\n";
 			echo "Yellow $command: Static page".(empty($location) ? "s" : "")." ".($statusCode!=200 ? "not " : "")."cleaned\n";
 		} else {
 		} else {
 			$statusCode = 400;
 			$statusCode = 400;
@@ -306,16 +276,17 @@ class YellowCommandline
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
-	// Clean static directory and files
-	function cleanStatic($location, $path)
+	// Clean static directories and files
+	function cleanStatic($path, $location)
 	{
 	{
 		$statusCode = 200;
 		$statusCode = 200;
+		$path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
 		if(empty($location))
 		if(empty($location))
 		{
 		{
 			$statusCode = max($statusCode, $this->pluginCommand(array("all", "clean")));
 			$statusCode = max($statusCode, $this->pluginCommand(array("all", "clean")));
 			$statusCode = max($statusCode, $this->cleanStaticDirectory($path));
 			$statusCode = max($statusCode, $this->cleanStaticDirectory($path));
 		} else {
 		} else {
-			$statusCode = $this->cleanStaticFile($location, $path);
+			$statusCode = $this->cleanStaticFile($path, $location);
 		}
 		}
 		return $statusCode;
 		return $statusCode;
 	}
 	}
@@ -326,7 +297,7 @@ class YellowCommandline
 		$statusCode = 200;
 		$statusCode = 200;
 		if($this->isYellowDirectory($path))
 		if($this->isYellowDirectory($path))
 		{
 		{
-			if(is_file("$path/yellow.php") || !$this->yellow->toolbox->deleteDirectory($path, true))
+			if(is_file("$path/yellow.php") || $path=="/" || !$this->yellow->toolbox->deleteDirectory($path, true))
 			{
 			{
 				$statusCode = 500;
 				$statusCode = 500;
 				echo "ERROR cleaning pages: Can't delete directory '$path'!\n";
 				echo "ERROR cleaning pages: Can't delete directory '$path'!\n";
@@ -336,10 +307,11 @@ class YellowCommandline
 	}
 	}
 	
 	
 	// Clean static file
 	// Clean static file
-	function cleanStaticFile($location, $path)
+	function cleanStaticFile($path, $location)
 	{
 	{
 		$statusCode = 200;
 		$statusCode = 200;
-		$fileName = $this->getStaticFileName($location, $path);
+		$fileName = $this->yellow->toolbox->findStaticFileFromLocation($location, $path,
+			$this->yellow->config->get("staticDefaultFile"));
 		if($this->isYellowDirectory($path) && is_file($fileName))
 		if($this->isYellowDirectory($path) && is_file($fileName))
 		{
 		{
 			$entry = basename($fileName);
 			$entry = basename($fileName);
@@ -377,27 +349,62 @@ class YellowCommandline
 		$serverScheme = $this->yellow->config->get("serverScheme");
 		$serverScheme = $this->yellow->config->get("serverScheme");
 		$serverName = $this->yellow->config->get("serverName");
 		$serverName = $this->yellow->config->get("serverName");
 		$serverBase = $this->yellow->config->get("serverBase");
 		$serverBase = $this->yellow->config->get("serverBase");
-		return !empty($serverScheme) && !empty($serverName) && $this->yellow->toolbox->isValidLocation($serverBase) && $serverBase!="/";
+		return !empty($serverScheme) && !empty($serverName) &&
+			$this->yellow->toolbox->isValidLocation($serverBase) && $serverBase!="/";
 	}
 	}
 	
 	
-	// Return all static locations from file system
+	// Return static locations from file system
 	function getStaticLocations()
 	function getStaticLocations()
 	{
 	{
 		$locations = array();
 		$locations = array();
-		foreach($this->yellow->pages->index(true, true) as $page) array_push($locations, $page->location);
+		$serverScheme = $this->yellow->config->get("serverScheme");
+		$serverName = $this->yellow->config->get("serverName");
+		$serverBase = $this->yellow->config->get("serverBase");
+		$this->yellow->page->setRequestInformation($serverScheme, $serverName, $serverBase, "", "");
+		if($this->yellow->config->isExisting("commandlineIgnoreLocation"))
+		{
+			$regex = "#^".$this->yellow->config->get("commandlineIgnoreLocation")."#";
+		}
+		foreach($this->yellow->pages->index(true, true) as $page)
+		{
+			if(!empty($regex) && preg_match($regex, $page->location)) continue;
+			array_push($locations, $page->location);
+		}
 		if(!$this->yellow->pages->find("/") && $this->yellow->config->get("multiLanguageMode")) array_unshift($locations, "/");
 		if(!$this->yellow->pages->find("/") && $this->yellow->config->get("multiLanguageMode")) array_unshift($locations, "/");
 		return $locations;
 		return $locations;
 	}
 	}
 	
 	
-	// Return static file name from location
-	function getStaticFileName($location, $path)
+	// Return static media files
+	function getStaticFilesMedia($path)
 	{
 	{
-		$fileName = $path.$location;
-		if(!$this->yellow->toolbox->isFileLocation($location))
+		$files = array();
+		$fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive(
+			$this->yellow->config->get("mediaDir"), "/.*/", false, false);
+		foreach($fileNames as $fileName) $files[$fileName] = "$path/$fileName";
+		return $files;
+	}
+	
+	// Return static system files
+	function getStaticFilesSystem($path)
+	{
+		$files = array();
+		$fileNames = $this->yellow->toolbox->getDirectoryEntries(
+			$this->yellow->config->get("pluginDir"), "/\.(css|js|jpg|png|txt|woff)/", false, false);
+		foreach($fileNames as $fileName)
+		{
+			$files[$fileName] = $path.$this->yellow->config->get("pluginLocation").basename($fileName);
+		}
+		$fileNames = $this->yellow->toolbox->getDirectoryEntries(
+			$this->yellow->config->get("themeDir"), "/\.(css|js|jpg|png|txt|woff)/", false, false);
+		foreach($fileNames as $fileName)
 		{
 		{
-			$fileName .= $this->yellow->config->get("commandlineDefaultFile");
+			$files[$fileName] = $path.$this->yellow->config->get("themeLocation").basename($fileName);
 		}
 		}
-		return $fileName;
+		$fileNames = array();
+		array_push($fileNames, $this->yellow->config->get("commandlineSystemFile"));
+		array_push($fileNames, $this->yellow->config->get("configDir").$this->yellow->config->get("robotsTextFile"));
+		foreach($fileNames as $fileName) $files[$fileName] = "$path/".basename($fileName);
+		return $files;
 	}
 	}
 	
 	
 	// Return command help
 	// Return command help
@@ -431,8 +438,7 @@ class YellowCommandline
 	// Check if directory contains Yellow files
 	// Check if directory contains Yellow files
 	function isYellowDirectory($path)
 	function isYellowDirectory($path)
 	{
 	{
-		$fileNamesSystem = preg_split("/,\s*/", $this->yellow->config->get("commandlineSystemFile"));
-		return is_file("$path/yellow.php") || is_file("$path/$fileNamesSystem[0]");
+		return is_file("$path/yellow.php") || is_file("$path/".$this->yellow->config->get("commandlineSystemFile"));
 	}
 	}
 }
 }
 	
 	

+ 28 - 24
system/core/core-webinterface.php

@@ -5,7 +5,7 @@
 // Web interface core plugin
 // Web interface core plugin
 class YellowWebinterface
 class YellowWebinterface
 {
 {
-	const Version = "0.4.7";
+	const Version = "0.4.8";
 	var $yellow;				//access to API
 	var $yellow;				//access to API
 	var $active;				//web interface is active? (boolean)
 	var $active;				//web interface is active? (boolean)
 	var $userLoginFailed;		//web interface login failed? (boolean)
 	var $userLoginFailed;		//web interface login failed? (boolean)
@@ -47,7 +47,7 @@ class YellowWebinterface
 				$locationHeader = $this->yellow->toolbox->getLocationHeader(
 				$locationHeader = $this->yellow->toolbox->getLocationHeader(
 					$this->yellow->config->get("webinterfaceServerScheme"),
 					$this->yellow->config->get("webinterfaceServerScheme"),
 					$this->yellow->config->get("webinterfaceServerName"), $base, $activeLocation);
 					$this->yellow->config->get("webinterfaceServerName"), $base, $activeLocation);
-				$this->yellow->sendStatus($statusCode, false, $locationHeader);
+				$this->yellow->sendStatus($statusCode, $locationHeader, false);
 			}
 			}
 		}
 		}
 		return $statusCode;
 		return $statusCode;
@@ -184,8 +184,8 @@ class YellowWebinterface
 		}
 		}
 		if($statusCode == 0)
 		if($statusCode == 0)
 		{
 		{
-			$statusCode = $this->userLoginFailed ? 401 : 0;
-			$statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+			$statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
+			if($this->userLoginFailed) $this->yellow->page->error(401);
 		}
 		}
 		return $statusCode;
 		return $statusCode;
 	}
 	}
@@ -196,16 +196,17 @@ class YellowWebinterface
 		$statusCode = 0;
 		$statusCode = 0;
 		if(is_readable($fileName))
 		if(is_readable($fileName))
 		{
 		{
-			$statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, 0, false);
+			$statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
 		} else {
 		} else {
 			if($this->yellow->toolbox->isFileLocation($location) && $this->yellow->isContentDirectory("$location/"))
 			if($this->yellow->toolbox->isFileLocation($location) && $this->yellow->isContentDirectory("$location/"))
 			{
 			{
 				$statusCode = 301;
 				$statusCode = 301;
 				$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, "$location/");
 				$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, "$location/");
-				$this->yellow->sendStatus($statusCode, false, $locationHeader);
+				$this->yellow->sendStatus($statusCode, $locationHeader, false);
 			} else {
 			} else {
 				$statusCode = $this->userPermission ? 424 : 404;
 				$statusCode = $this->userPermission ? 424 : 404;
-				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
+				$this->yellow->page->error($statusCode);
 			}
 			}
 		}
 		}
 		return $statusCode;
 		return $statusCode;
@@ -225,15 +226,15 @@ class YellowWebinterface
 				{
 				{
 					$statusCode = 303;
 					$statusCode = 303;
 					$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location);
 					$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location);
-					$this->yellow->sendStatus($statusCode, false, $locationHeader);
+					$this->yellow->sendStatus($statusCode, $locationHeader, false);
 				} else {
 				} else {
 					$statusCode = 500;
 					$statusCode = 500;
-					$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+					$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
 					$this->yellow->page->error($statusCode, "Can't write file '$page->fileName'!");
 					$this->yellow->page->error($statusCode, "Can't write file '$page->fileName'!");
 				}
 				}
 			} else {
 			} else {
 				$statusCode = 500;
 				$statusCode = 500;
-				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $false);
 				$this->yellow->page->error($statusCode, $page->get("pageError"));
 				$this->yellow->page->error($statusCode, $page->get("pageError"));
 			}
 			}
 		}
 		}
@@ -257,15 +258,15 @@ class YellowWebinterface
 				{
 				{
 					$statusCode = 303;
 					$statusCode = 303;
 					$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location);
 					$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location);
-					$this->yellow->sendStatus($statusCode, false, $locationHeader);
+					$this->yellow->sendStatus($statusCode, $locationHeader, false);
 				} else {
 				} else {
 					$statusCode = 500;
 					$statusCode = 500;
-					$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+					$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
 					$this->yellow->page->error($statusCode, "Can't write file '$page->fileName'!");
 					$this->yellow->page->error($statusCode, "Can't write file '$page->fileName'!");
 				}
 				}
 			} else {
 			} else {
 				$statusCode = 500;
 				$statusCode = 500;
-				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
 				$this->yellow->page->error($statusCode, $page->get("pageError"));
 				$this->yellow->page->error($statusCode, $page->get("pageError"));
 			}
 			}
 		}
 		}
@@ -283,10 +284,10 @@ class YellowWebinterface
 			{
 			{
 				$statusCode = 303;
 				$statusCode = 303;
 				$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
 				$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
-				$this->yellow->sendStatus($statusCode, false, $locationHeader);
+				$this->yellow->sendStatus($statusCode, $locationHeader, false);
 			} else {
 			} else {
 				$statusCode = 500;
 				$statusCode = 500;
-				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, false);
+				$this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false);
 				$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
 				$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
 			}
 			}
 		}
 		}
@@ -302,11 +303,11 @@ class YellowWebinterface
 		{
 		{
 			$statusCode = 303;
 			$statusCode = 303;
 			$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
 			$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
-			$this->yellow->sendStatus($statusCode, false, $locationHeader);
+			$this->yellow->sendStatus($statusCode, $locationHeader, false);
 		} else {
 		} else {
 			$statusCode = 302;
 			$statusCode = 302;
 			$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $home);
 			$locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $home);
-			$this->yellow->sendStatus($statusCode, false, $locationHeader);
+			$this->yellow->sendStatus($statusCode, $locationHeader, false);
 		}
 		}
 		return $statusCode;
 		return $statusCode;
 	}
 	}
@@ -321,7 +322,7 @@ class YellowWebinterface
 			$this->yellow->config->get("serverScheme"),
 			$this->yellow->config->get("serverScheme"),
 			$this->yellow->config->get("serverName"),
 			$this->yellow->config->get("serverName"),
 			$this->yellow->config->get("serverBase"), $location);
 			$this->yellow->config->get("serverBase"), $location);
-		$this->yellow->sendStatus($statusCode, false, $locationHeader);
+		$this->yellow->sendStatus($statusCode, $locationHeader, false);
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 
 
@@ -405,8 +406,9 @@ class YellowWebinterface
 	// Return new page
 	// Return new page
 	function getPageNew($serverScheme, $serverName, $base, $location, $fileName, $rawData)
 	function getPageNew($serverScheme, $serverName, $base, $location, $fileName, $rawData)
 	{
 	{
-		$page = new YellowPage($this->yellow, $serverScheme, $serverName, $base, $location, $fileName);
-		$page->parseData($rawData, 0, false);
+		$page = new YellowPage($this->yellow);
+		$page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
+		$page->parseData($rawData, false);
 		$page->fileName = $this->yellow->toolbox->findFileFromTitle(
 		$page->fileName = $this->yellow->toolbox->findFileFromTitle(
 			$page->get($this->yellow->config->get("webinterfaceFilePrefix")), $page->get("title"), $fileName,
 			$page->get($this->yellow->config->get("webinterfaceFilePrefix")), $page->get("title"), $fileName,
 			$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
 			$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
@@ -441,13 +443,15 @@ class YellowWebinterface
 	// Return modified page
 	// Return modified page
 	function getPageUpdate($serverScheme, $serverName, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile)
 	function getPageUpdate($serverScheme, $serverName, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile)
 	{
 	{
-		$page = new YellowPage($this->yellow, $serverScheme, $serverName, $base, $location, $fileName);
-		$page->parseData($this->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), 0, false);
+		$page = new YellowPage($this->yellow);
+		$page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
+		$page->parseData($this->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), false);
 		if(empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
 		if(empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
 		if($this->yellow->toolbox->isFileLocation($location) && !$page->isError())
 		if($this->yellow->toolbox->isFileLocation($location) && !$page->isError())
 		{
 		{
-			$pageSource = new YellowPage($this->yellow, $serverScheme, $serverName, $base, $location, $fileName);
-			$pageSource->parseData($rawDataSource, 0, false);
+			$pageSource = new YellowPage($this->yellow);
+			$pageSource->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
+			$pageSource->parseData($rawDataSource, false);
 			$prefix = $this->yellow->config->get("webinterfaceFilePrefix");
 			$prefix = $this->yellow->config->get("webinterfaceFilePrefix");
 			if($pageSource->get($prefix)!=$page->get($prefix) || $pageSource->get("title")!=$page->get("title"))
 			if($pageSource->get($prefix)!=$page->get($prefix) || $pageSource->get("title")!=$page->get("title"))
 			{
 			{

+ 180 - 77
system/core/core.php

@@ -5,7 +5,7 @@
 // Yellow main class
 // Yellow main class
 class Yellow
 class Yellow
 {
 {
-	const Version = "0.4.19";
+	const Version = "0.4.20";
 	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
@@ -15,6 +15,7 @@ class Yellow
 
 
 	function __construct()
 	function __construct()
 	{
 	{
+		$this->page = new YellowPage($this);
 		$this->pages = new YellowPages($this);
 		$this->pages = new YellowPages($this);
 		$this->config = new YellowConfig($this);
 		$this->config = new YellowConfig($this);
 		$this->text = new YellowText($this);
 		$this->text = new YellowText($this);
@@ -33,6 +34,10 @@ class Yellow
 		$this->config->setDefault("themeLocation", "/media/themes/");
 		$this->config->setDefault("themeLocation", "/media/themes/");
 		$this->config->setDefault("systemDir", "system/");
 		$this->config->setDefault("systemDir", "system/");
 		$this->config->setDefault("configDir", "system/config/");
 		$this->config->setDefault("configDir", "system/config/");
+		$this->config->setDefault("staticDir", "cache/");
+		$this->config->setDefault("staticDefaultFile", "index.html");
+		$this->config->setDefault("staticErrorFile", "error404.html");
+		$this->config->setDefault("coreDir", "system/core/");
 		$this->config->setDefault("pluginDir", "system/plugins/");
 		$this->config->setDefault("pluginDir", "system/plugins/");
 		$this->config->setDefault("snippetDir", "system/snippets/");
 		$this->config->setDefault("snippetDir", "system/snippets/");
 		$this->config->setDefault("templateDir", "system/templates/");
 		$this->config->setDefault("templateDir", "system/templates/");
@@ -50,6 +55,7 @@ class Yellow
 		$this->config->setDefault("errorPageFile", "error(.*).txt");
 		$this->config->setDefault("errorPageFile", "error(.*).txt");
 		$this->config->setDefault("newPageFile", "new(.*).txt");
 		$this->config->setDefault("newPageFile", "new(.*).txt");
 		$this->config->setDefault("textStringFile", "text(.*).ini");
 		$this->config->setDefault("textStringFile", "text(.*).ini");
+		$this->config->setDefault("robotsTextFile", "robots.txt");
 		$this->config->setDefault("parser", "markdownextra");
 		$this->config->setDefault("parser", "markdownextra");
 		$this->config->setDefault("parserSafeMode", "0");
 		$this->config->setDefault("parserSafeMode", "0");
 		$this->config->setDefault("multiLanguageMode", "0");
 		$this->config->setDefault("multiLanguageMode", "0");
@@ -65,7 +71,7 @@ class Yellow
 		ob_start();
 		ob_start();
 		$statusCode = 0;
 		$statusCode = 0;
 		list($serverScheme, $serverName, $base, $location, $fileName) = $this->getRequestInformation();
 		list($serverScheme, $serverName, $base, $location, $fileName) = $this->getRequestInformation();
-		$this->page = new YellowPage($this, $serverScheme, $serverName, $base, $location, $fileName);
+		$this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
 		foreach($this->plugins->plugins as $key=>$value)
 		foreach($this->plugins->plugins as $key=>$value)
 		{
 		{
 			if(method_exists($value["obj"], "onRequest"))
 			if(method_exists($value["obj"], "onRequest"))
@@ -78,9 +84,10 @@ class Yellow
 		if($statusCode == 0)
 		if($statusCode == 0)
 		{
 		{
 			$this->pages->requestHandler = "core";
 			$this->pages->requestHandler = "core";
-			$statusCode = $this->processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, true);
+			$statusCode = $this->processRequest($serverScheme, $serverName, $base, $location, $fileName, true);
 		}
 		}
-		if($this->page->isError() || $statusCodeRequest>=400) $statusCode = $this->processRequestError($statusCodeRequest);
+		if($statusCodeRequest >= 400) $this->page->error($statusCodeRequest, "Request error");
+		if($this->page->isError()) $statusCode = $this->processRequestError();
 		ob_end_flush();
 		ob_end_flush();
 		$this->toolbox->timerStop($time);
 		$this->toolbox->timerStop($time);
 		if(defined("DEBUG") && DEBUG>=1) echo "Yellow::request status:$statusCode location:$location<br/>\n";
 		if(defined("DEBUG") && DEBUG>=1) echo "Yellow::request status:$statusCode location:$location<br/>\n";
@@ -89,59 +96,69 @@ class Yellow
 	}
 	}
 	
 	
 	// Process request
 	// Process request
-	function processRequest($serverScheme, $serverName, $base, $location, $fileName, $statusCode, $cacheable)
+	function processRequest($serverScheme, $serverName, $base, $location, $fileName, $cacheable)
 	{
 	{
-		$handler = $this->getRequestHandler();
-		if($statusCode == 0)
+		if(is_readable($fileName))
 		{
 		{
-			if(is_readable($fileName))
+			if($cacheable) $fileName = $this->getStaticFile($location, $fileName);
+			if($this->toolbox->isRequestCleanUrl($location))
 			{
 			{
-				if($this->toolbox->isRequestCleanUrl($location))
-				{
-					$statusCode = 303;
-					$locationArgs = $this->toolbox->getLocationArgsCleanUrl($this->config->get("contentPagination"));
-					$locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location.$locationArgs);
-					$this->sendStatus($statusCode, false, $locationHeader);
-				} else {
-					$statusCode = 200;
-					$fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $statusCode, $cacheable);
-				}
+				$statusCode = 303;
+				$locationArgs = $this->toolbox->getLocationArgsCleanUrl($this->config->get("contentPagination"));
+				$locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location.$locationArgs);
+				$this->sendStatus($statusCode, $locationHeader, false);
+			} else if($this->isStaticFile($fileName)) {
+				$statusCode = 200;
+				$statusCode = $this->sendFile($statusCode, $fileName, $cacheable);
 			} else {
 			} else {
-				if(($this->toolbox->isFileLocation($location) && $this->isContentDirectory("$location/")) ||
-				   ($location=="/" && $this->config->get("multiLanguageMode")))
-				{
-					$statusCode = 301;
-					$location = $this->toolbox->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage()."/";
-					$locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
-					$this->sendStatus($statusCode, false, $locationHeader);
-				} else {
-					$statusCode = 404;
-					$fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $statusCode, $cacheable);
-				}
+				$statusCode = 200;
+				$fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode);
+				$statusCode = $this->sendPage();
 			}
 			}
-		} else if($statusCode >= 400) {
-			$fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $statusCode, $cacheable);
+		} else {
+			if($cacheable) $fileName = $this->getStaticFile("", "");
+			if(($this->toolbox->isFileLocation($location) && $this->isContentDirectory("$location/")) ||
+			   ($location=="/" && $this->config->get("multiLanguageMode")))
+			{
+				$statusCode = 301;
+				$location = $this->toolbox->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage()."/";
+				$locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location);
+				$this->sendStatus($statusCode, $locationHeader, false);
+			} else if($this->isStaticFile($fileName)) {
+				$statusCode = 404;
+				$statusCode = $this->sendFile($statusCode, $fileName, $cacheable);
+			} else {
+				$statusCode = 404;
+				$fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode);
+				$statusCode = $this->sendPage();
+			}
+		}
+		if(defined("DEBUG") && DEBUG>=1)
+		{
+			$handler = $this->getRequestHandler();
+			echo "Yellow::processRequest handler:$handler file:$fileName<br/>\n";
 		}
 		}
-		if($this->page->statusCode != 0) $statusCode = $this->sendPage();
-		if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequest handler:$handler file:$fileName<br/>\n";
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
 	// Process request with error
 	// Process request with error
-	function processRequestError($statusCodeRequest)
+	function processRequestError()
 	{
 	{
 		ob_clean();
 		ob_clean();
-		$handler = $this->getRequestHandler();
-		if($statusCodeRequest >= 400) $this->page->error($statusCodeRequest, "Request error");
-		$fileName = $this->readPage($this->page->serverScheme, $this->page->serverName, $this->page->base, $this->page->location,
-			$this->page->fileName, $this->page->statusCode, $this->page->cacheable, $this->page->get("pageError"));
+		$fileName = $this->readPage($this->page->serverScheme, $this->page->serverName, $this->page->base,
+			$this->page->location, $this->page->fileName, $this->page->cacheable, $this->page->statusCode,
+			$this->page->get("pageError"));
 		$statusCode = $this->sendPage();
 		$statusCode = $this->sendPage();
-		if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequestError handler:$handler file:$fileName<br/>\n";
-		return $statusCode;		
+		if(defined("DEBUG") && DEBUG>=1)
+		{
+			$handler = $this->getRequestHandler();
+			echo "Yellow::processRequestError handler:$handler file:$fileName<br/>\n";
+		}
+		return $statusCode;
 	}
 	}
 	
 	
 	// Read page from file
 	// Read page from file
-	function readPage($serverScheme, $serverName, $base, $location, $fileName, $statusCode, $cacheable, $pageError = "")
+	function readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode, $pageError = "")
 	{
 	{
 		if($statusCode >= 400)
 		if($statusCode >= 400)
 		{
 		{
@@ -149,8 +166,9 @@ class Yellow
 			$fileName = strreplaceu("(.*)", $statusCode, $fileName);
 			$fileName = strreplaceu("(.*)", $statusCode, $fileName);
 			$cacheable = false;
 			$cacheable = false;
 		}
 		}
-		$this->page = new YellowPage($this, $serverScheme, $serverName, $base, $location, $fileName);
-		$this->page->parseData($this->toolbox->getFileData($fileName), $statusCode, $cacheable, $pageError);
+		$this->page = new YellowPage($this);
+		$this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName);
+		$this->page->parseData($this->toolbox->getFileData($fileName), $cacheable, $statusCode, $pageError);
 		$this->page->setHeader("Content-Type", "text/html; charset=UTF-8");
 		$this->page->setHeader("Content-Type", "text/html; charset=UTF-8");
 		$this->page->setHeader("Last-Modified", $this->page->getModified(true));
 		$this->page->setHeader("Last-Modified", $this->page->getModified(true));
 		if(!$this->page->isCacheable()) $this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
 		if(!$this->page->isCacheable()) $this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
@@ -216,9 +234,26 @@ class Yellow
 		}
 		}
 		return $statusCode;
 		return $statusCode;
 	}
 	}
+	
+	// Send file response
+	function sendFile($statusCode, $fileName, $cacheable)
+	{
+		$lastModified = $this->toolbox->getHttpTimeFormatted(filemtime($fileName));
+		if($statusCode==200 && $cacheable && $this->toolbox->isFileNotModified($lastModified))
+		{
+			$statusCode = 304;
+		} else {
+			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;
+	}
 
 
 	// Send status response
 	// Send status response
-	function sendStatus($statusCode, $cacheable, $responseHeader = "")
+	function sendStatus($statusCode, $responseHeader, $cacheable)
 	{
 	{
 		if(PHP_SAPI != "cli")
 		if(PHP_SAPI != "cli")
 		{
 		{
@@ -252,9 +287,27 @@ class Yellow
 		$base = empty($base) ? $this->config->get("serverBase") : $base;
 		$base = empty($base) ? $this->config->get("serverBase") : $base;
 		$location = $this->toolbox->getLocationClean();
 		$location = $this->toolbox->getLocationClean();
 		$location = substru($location, strlenu($base));
 		$location = substru($location, strlenu($base));
-		$fileName = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"),
-			$this->config->get("contentRootDir"), $this->config->get("contentHomeDir"),
-			$this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
+		if(preg_match("/\.(css|js|jpg|png|txt|woff)$/", $location))
+		{
+			$pluginLocationLength = strlenu($this->config->get("pluginLocation"));
+			$themeLocationLength = strlenu($this->config->get("themeLocation"));
+			if(substru($location, 0, $pluginLocationLength+5) == $this->config->get("pluginLocation")."core-")
+			{
+				$fileName = $this->config->get("coreDir").substru($location, $pluginLocationLength);
+			} else if(substru($location, 0, $pluginLocationLength) == $this->config->get("pluginLocation")) {
+				$fileName = $this->config->get("pluginDir").substru($location, $pluginLocationLength);
+			} else if(substru($location, 0, $themeLocationLength) == $this->config->get("themeLocation")) {
+				$fileName = $this->config->get("themeDir").substru($location, $themeLocationLength);
+			} else if($location == "/".$this->config->get("robotsTextFile")) {
+				$fileName = $this->config->get("configDir").$this->config->get("robotsTextFile");
+			}
+		}
+		if(empty($fileName))
+		{
+			$fileName = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"),
+				$this->config->get("contentRootDir"), $this->config->get("contentHomeDir"),
+				$this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
+		}
 		return array($serverScheme, $serverName, $base, $location, $fileName);
 		return array($serverScheme, $serverName, $base, $location, $fileName);
 	}
 	}
 	
 	
@@ -271,7 +324,33 @@ class Yellow
 		return $this->pages->requestHandler;
 		return $this->pages->requestHandler;
 	}
 	}
 	
 	
-	// Check if content directory exists
+	// Return static file
+	function getStaticFile($location, $fileName)
+	{
+		if(PHP_SAPI != "cli")
+		{
+			if(!empty($location))
+			{
+				$fileNameStatic = $this->toolbox->findStaticFileFromLocation($location,
+					$this->config->get("staticDir"), $this->config->get("staticDefaultFile"));
+			} else {
+				$fileNameStatic = $this->config->get("staticDir").$this->config->get("staticErrorFile");
+			}
+			if(is_readable($fileNameStatic)) $fileName = $fileNameStatic;
+		}
+		return $fileName;
+	}
+	
+	// Check if static file
+	function isStaticFile($fileName)
+	{
+		$staticDirLength = strlenu($this->config->get("staticDir"));
+		$systemDirLength = strlenu($this->config->get("systemDir"));
+		return substru($fileName, 0, $staticDirLength) == $this->config->get("staticDir") ||
+		substru($fileName, 0, $systemDirLength) == $this->config->get("systemDir");
+	}
+	
+	// Check if content directory
 	function isContentDirectory($location)
 	function isContentDirectory($location)
 	{
 	{
 		$path = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"),
 		$path = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"),
@@ -279,7 +358,7 @@ class Yellow
 		return is_dir($path);
 		return is_dir($path);
 	}
 	}
 	
 	
-	// Update content configuration
+	// Update configuration
 	function updateConfig()
 	function updateConfig()
 	{
 	{
 		list($pathRoot, $pathHome) = $this->toolbox->findRootConfig($this->config->get("contentDir"),
 		list($pathRoot, $pathHome) = $this->toolbox->findRootConfig($this->config->get("contentDir"),
@@ -359,23 +438,29 @@ class YellowPage
 	var $cacheable;				//page is cacheable? (boolean)
 	var $cacheable;				//page is cacheable? (boolean)
 	var $statusCode;			//status code
 	var $statusCode;			//status code
 
 
-	function __construct($yellow, $serverScheme, $serverName, $base, $location, $fileName)
+	function __construct($yellow)
 	{
 	{
 		$this->yellow = $yellow;
 		$this->yellow = $yellow;
+		$this->metaData = array();
+		$this->headerData = array();
+	}
+
+	// Set request information
+	function setRequestInformation($serverScheme, $serverName, $base, $location, $fileName)
+	{
 		$this->serverScheme = $serverScheme;
 		$this->serverScheme = $serverScheme;
 		$this->serverName = $serverName;
 		$this->serverName = $serverName;
 		$this->base = $base;
 		$this->base = $base;
 		$this->location = $location;
 		$this->location = $location;
 		$this->fileName = $fileName;
 		$this->fileName = $fileName;
-		$this->metaData = array();
-		$this->headerData = array();
-		$this->statusCode = 0;
 	}
 	}
 	
 	
 	// Parse page data
 	// Parse page data
-	function parseData($rawData, $statusCode, $cacheable, $pageError = "")
+	function parseData($rawData, $cacheable, $statusCode = 0, $pageError = "")
 	{
 	{
 		$this->rawData = $rawData;
 		$this->rawData = $rawData;
+		$this->parserData = "";
+		$this->parser = NULL;
 		$this->parserSafeMode = $this->yellow->config->get("parserSafeMode");
 		$this->parserSafeMode = $this->yellow->config->get("parserSafeMode");
 		$this->active = $this->yellow->toolbox->isActiveLocation($this->location, $this->yellow->page->location,
 		$this->active = $this->yellow->toolbox->isActiveLocation($this->location, $this->yellow->page->location,
 			$this->yellow->pages->getHomeLocation($this->yellow->page->location));
 			$this->yellow->pages->getHomeLocation($this->yellow->page->location));
@@ -383,8 +468,7 @@ class YellowPage
 			$this->yellow->config->get("contentDir"));
 			$this->yellow->config->get("contentDir"));
 		$this->cacheable = $cacheable;
 		$this->cacheable = $cacheable;
 		$this->statusCode = $statusCode;
 		$this->statusCode = $statusCode;
-		if(!empty($pageError)) $this->error($statusCode, $pageError);
-		$this->parseMeta();
+		$this->parseMeta($pageError);
 	}
 	}
 	
 	
 	// Parse page data update
 	// Parse page data update
@@ -397,7 +481,6 @@ class YellowPage
 			{
 			{
 				$this->statusCode = 200;
 				$this->statusCode = 200;
 				$this->rawData = fread($fileHandle, filesize($this->fileName));
 				$this->rawData = fread($fileHandle, filesize($this->fileName));
-				$this->metaData = array();
 				fclose($fileHandle);
 				fclose($fileHandle);
 				$this->parseMeta();
 				$this->parseMeta();
 			}
 			}
@@ -405,10 +488,10 @@ class YellowPage
 	}
 	}
 	
 	
 	// Parse page meta data
 	// Parse page meta data
-	function parseMeta()
+	function parseMeta($pageError = "")
 	{
 	{
-		$fileDate = date("c", is_readable($this->fileName) ? filemtime($this->fileName) : 0);
-		$this->set("modified", $fileDate);
+		$this->metaData = array();
+		$this->set("modified", date("c", is_readable($this->fileName) ? filemtime($this->fileName) : 0));
 		$this->set("title", $this->yellow->toolbox->createTextTitle($this->location));
 		$this->set("title", $this->yellow->toolbox->createTextTitle($this->location));
 		$this->set("sitename", $this->yellow->config->get("sitename"));
 		$this->set("sitename", $this->yellow->config->get("sitename"));
 		$this->set("author", $this->yellow->config->get("author"));
 		$this->set("author", $this->yellow->config->get("author"));
@@ -445,6 +528,7 @@ class YellowPage
 		$this->set("pageEdit", $this->yellow->toolbox->getUrl(
 		$this->set("pageEdit", $this->yellow->toolbox->getUrl(
 			$this->yellow->config->get("webinterfaceServerScheme"), $this->yellow->config->get("webinterfaceServerName"),
 			$this->yellow->config->get("webinterfaceServerScheme"), $this->yellow->config->get("webinterfaceServerName"),
 			$this->yellow->config->get("serverBase"), rtrim($this->yellow->config->get("webinterfaceLocation"), '/').$this->location));
 			$this->yellow->config->get("serverBase"), rtrim($this->yellow->config->get("webinterfaceLocation"), '/').$this->location));
+		if(!empty($pageError)) $this->set("pageError", $pageError);
 		foreach($this->yellow->plugins->plugins as $key=>$value)
 		foreach($this->yellow->plugins->plugins as $key=>$value)
 		{
 		{
 			if(method_exists($value["obj"], "onParseMeta")) $value["obj"]->onParseMeta($this, $this->rawData);
 			if(method_exists($value["obj"], "onParseMeta")) $value["obj"]->onParseMeta($this, $this->rawData);
@@ -997,16 +1081,18 @@ class YellowPages
 		{
 		{
 			if(defined("DEBUG") && DEBUG>=2) echo "YellowPages::scanChildren location:$location<br/>\n";
 			if(defined("DEBUG") && DEBUG>=2) echo "YellowPages::scanChildren location:$location<br/>\n";
 			$this->pages[$location] = array();
 			$this->pages[$location] = array();
+			$serverScheme = $this->yellow->page->serverScheme;
+			$serverName = $this->yellow->page->serverName;
+			$base = $this->yellow->page->base;
 			if(empty($location))
 			if(empty($location))
 			{
 			{
 				$rootLocations = $this->yellow->toolbox->findRootLocations($this->yellow->config->get("contentDir"),
 				$rootLocations = $this->yellow->toolbox->findRootLocations($this->yellow->config->get("contentDir"),
 					$this->yellow->config->get("contentRootDir"));
 					$this->yellow->config->get("contentRootDir"));
 				foreach($rootLocations as $rootLocation)
 				foreach($rootLocations as $rootLocation)
 				{
 				{
-					$page = new YellowPage($this->yellow,
-						$this->yellow->page->serverScheme, $this->yellow->page->serverName, $this->yellow->page->base,
-						$rootLocation, "");
-					$page->parseData("", 0, false);
+					$page = new YellowPage($this->yellow);
+					$page->setRequestInformation($serverScheme, $serverName, $base, $rootLocation, "");
+					$page->parseData("", false);
 					array_push($this->pages[$location], $page);
 					array_push($this->pages[$location], $page);
 				}
 				}
 			} else {
 			} else {
@@ -1025,13 +1111,13 @@ class YellowPages
 						$fileData = "";
 						$fileData = "";
 						$statusCode = 0;
 						$statusCode = 0;
 					}
 					}
-					$page = new YellowPage($this->yellow,
-						$this->yellow->page->serverScheme, $this->yellow->page->serverName, $this->yellow->page->base,
+					$page = new YellowPage($this->yellow);
+					$page->setRequestInformation($serverScheme, $serverName, $base,
 						$this->yellow->toolbox->findLocationFromFile($fileName, $this->yellow->config->get("contentDir"),
 						$this->yellow->toolbox->findLocationFromFile($fileName, $this->yellow->config->get("contentDir"),
 						$this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"),
 						$this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"),
 						$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")),
 						$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")),
 						$fileName);
 						$fileName);
-					$page->parseData($fileData, $statusCode, false);
+					$page->parseData($fileData, false, $statusCode);
 					array_push($this->pages[$location], $page);
 					array_push($this->pages[$location], $page);
 				}
 				}
 			}
 			}
@@ -1318,7 +1404,7 @@ class YellowPlugins
 	function load()
 	function load()
 	{
 	{
 		global $yellow;
 		global $yellow;
-		$path = dirname(__FILE__);
+		$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) require_once($entry);
@@ -1745,6 +1831,14 @@ class YellowToolbox
 		}
 		}
 		return $invalid ? "" : $path;
 		return $invalid ? "" : $path;
 	}
 	}
+	
+	// Return static file path from location
+	function findStaticFileFromLocation($location, $path, $fileDefault)
+	{
+		$path = rtrim($path, '/').$location;
+		if(!$this->isFileLocation($location)) $path .= $fileDefault;
+		return $path;
+	}
 
 
 	// Return file or directory that matches token
 	// Return file or directory that matches token
 	function findFileDirectory($path, $token, $tokenFailback, $directory, &$found, &$invalid)
 	function findFileDirectory($path, $token, $tokenFailback, $directory, &$found, &$invalid)
@@ -1927,6 +2021,22 @@ class YellowToolbox
 	{
 	{
 		return gmdate("D, d M Y H:i:s", $timestamp)." GMT";
 		return gmdate("D, d M Y H:i:s", $timestamp)." GMT";
 	}
 	}
+				
+	// Return MIME content type
+	function getMimeContentType($fileName)
+	{
+		$mimeTypes = array(
+			"css" => "text/css",
+			"js" => "application/javascript",
+			"jpg" => "image/jpeg",
+			"png" => "image/png",
+			"txt" => "text/plain",
+			"woff" => "application/font-woff");
+		$contentType = "text/html; charset=UTF-8";
+		$extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : "";
+		if(array_key_exists(strtoloweru($extension), $mimeTypes)) $contentType = $mimeTypes[$extension];
+		return $contentType;
+	}
 	
 	
 	// Return URL
 	// Return URL
 	function getUrl($serverScheme, $serverName, $base, $location)
 	function getUrl($serverScheme, $serverName, $base, $location)
@@ -2009,17 +2119,10 @@ class YellowToolbox
 		return @rmdir($path);
 		return @rmdir($path);
 	}
 	}
 	
 	
-	// Return file data
+	// Return file data, empty string if not found
 	function getFileData($fileName)
 	function getFileData($fileName)
 	{
 	{
-		$fileData = "";
-		$fileHandle = @fopen($fileName, "r");
-		if($fileHandle)
-		{
-			$fileData = fread($fileHandle, filesize($fileName));
-			fclose($fileHandle);
-		}
-		return $fileData;
+		return is_readable($fileName) ? file_get_contents($fileName) : "";
 	}
 	}
 
 
 	// Create file
 	// Create file