Better status handling

This commit is contained in:
markseu 2013-11-29 13:16:14 +01:00
parent 9f60667bb1
commit b8d7052a27
2 changed files with 281 additions and 228 deletions

View file

@ -5,20 +5,20 @@
// Yellow main class
class Yellow
{
const Version = "0.1.21";
const Version = "0.1.22";
var $page; //current page data
var $pages; //current page tree from file system
var $toolbox; //toolbox with helpers
var $config; //configuration
var $text; //text strings
var $toolbox; //toolbox with helpers
var $plugins; //plugins
function __construct()
{
$this->pages = new Yellow_Pages($this);
$this->config = new Yellow_Config($this);
$this->text = new Yellow_Text($this);
$this->toolbox = new Yellow_Toolbox();
$this->config = new Yellow_Config();
$this->text = new Yellow_Text();
$this->plugins = new Yellow_Plugins();
$this->config->setDefault("sitename", "Yellow");
$this->config->setDefault("author", "Yellow");
@ -48,7 +48,7 @@ class Yellow
$this->config->setDefault("errorPageFile", "error(.*).txt");
$this->config->setDefault("textStringFile", "text_(.*).ini");
$this->config->load($this->config->get("configDir").$this->config->get("configFile"));
$this->text->load($this->config->get("configDir").$this->config->get("textStringFile"), $this->toolbox);
$this->text->load($this->config->get("configDir").$this->config->get("textStringFile"));
}
// Handle request
@ -101,14 +101,6 @@ class Yellow
{
$statusCode = 200;
$fileName = $this->readPage($serverBase, $location, $fileName, $cacheable, $statusCode);
if($this->page->isExisting("redirect") && $handler=="core")
{
$statusCode = 301;
$locationHeader = $this->toolbox->getHttpLocationHeader($serverName, $serverBase, $this->page->get("redirect"));
$this->page->statusCode = 0;
$this->header($locationHeader);
$this->sendStatus($statusCode, $locationHeader);
}
} else {
$statusCode = 303;
$locationArgs = $this->toolbox->getLocationArgsCleanUrl();
@ -186,16 +178,26 @@ class Yellow
}
$statusCode = $this->page->statusCode;
if($statusCode==200 && $this->getRequestHandler()=="core" && $this->page->isExisting("redirect"))
{
$statusCode = 301;
$location = $this->page->get("redirect");
if(preg_match("/^[^\/]+$/", $location)) $location = $this->toolbox->getDirectoryLocation($this->page->getLocation()).$location;
$this->page->clean($statusCode, $this->toolbox->getHttpLocationHeader($this->config->get("serverName"), "", $location));
$this->page->setHeader("Last-Modified", $this->page->getModified(true));
$this->page->setHeader("Cache-Control", "no-cache, must-revalidate");
}
if($statusCode==200 && $this->page->isCacheable() &&
$this->toolbox->isFileNotModified($this->page->getHeader("Last-Modified")))
{
ob_clean();
$statusCode = 304;
$this->page->clean($statusCode);
}
if($this->page->isExisting("pageClean")) ob_clean();
if(PHP_SAPI != "cli")
{
@header($this->toolbox->getHttpStatusFormatted($statusCode));
if($statusCode != 304) foreach($this->page->headerData as $key=>$value) @header("$key: $value");
foreach($this->page->headerData as $key=>$value) @header("$key: $value");
}
if(defined("DEBUG") && DEBUG>=1)
{
@ -206,12 +208,12 @@ class Yellow
}
// Send status response
function sendStatus($statusCode, $text = "")
function sendStatus($statusCode, $responseHeader = "")
{
if(PHP_SAPI != "cli")
{
@header($this->toolbox->getHttpStatusFormatted($statusCode));
if(!empty($text)) @header($text);
if(!empty($responseHeader)) @header($responseHeader);
}
}
@ -327,9 +329,9 @@ class Yellow
}
// Set a response header
function header($text)
function header($responseHeader)
{
$tokens = explode(':', $text, 2);
$tokens = explode(':', $responseHeader, 2);
$this->page->setHeader(trim($tokens[0]), trim($tokens[1]));
}
}
@ -487,10 +489,22 @@ class Yellow_Page
// Respond with error page
function error($statusCode, $pageError = "")
{
if(!$this->isExisting("pageError"))
if(!$this->isExisting("pageError") && $statusCode>0)
{
$this->statusCode = $statusCode;
$this->set("pageError", empty($pageError) ? "Template/snippet error" : $pageError);
$this->set("pageError", empty($pageError) ? "Template/snippet error!" : $pageError);
}
}
// Respond without page content
function clean($statusCode, $responseHeader = "")
{
if(!$this->isExisting("pageClean") && $statusCode>0)
{
$this->statusCode = $statusCode;
$this->headerData = array();
if(!empty($responseHeader)) $this->yellow->header($responseHeader);
$this->set("pageClean", (string)$statusCode);
}
}
@ -544,6 +558,13 @@ class Yellow_Page
return $this->yellow->pages->serverBase.$this->location;
}
// Return full page URL, with server name
function getUrl()
{
return $this->yellow->toolbox->getHttpUrl($this->yellow->config->get("serverName"),
$this->yellow->pages->serverBase, $this->location);
}
// Return page modification time, Unix time
function getModified($httpFormat = false)
{
@ -799,8 +820,8 @@ class Yellow_Pages
function __construct($yellow)
{
$this->pages = array();
$this->yellow = $yellow;
$this->pages = array();
}
// Return empty page collection
@ -948,6 +969,213 @@ class Yellow_Pages
}
}
// Yellow configuration
class Yellow_Config
{
var $yellow; //access to API
var $modified; //configuration modification time
var $config; //configuration
var $configDefaults; //configuration defaults
function __construct($yellow)
{
$this->yellow = $yellow;
$this->modified = 0;
$this->config = array();
$this->configDefaults = array();
}
// Load configuration from file
function load($fileName)
{
$fileData = @file($fileName);
if($fileData)
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Config::load file:$fileName<br/>\n";
$this->modified = filemtime($fileName);
foreach($fileData as $line)
{
if(preg_match("/^\//", $line)) continue;
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if(!empty($matches[1]) && !strempty($matches[2]))
{
$this->set($matches[1], $matches[2]);
if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Config::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
}
// Set default configuration
function setDefault($key, $value)
{
$this->configDefaults[$key] = $value;
}
// Set configuration
function set($key, $value)
{
$this->config[$key] = $value;
}
// Return configuration
function get($key)
{
return $this->isExisting($key) ? $this->config[$key] : $this->configDefaults[$key];
}
// Return configuration, HTML encoded
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
// Return configuration strings
function getData($filterEnd = "")
{
$config = array();
if(empty($filterEnd))
{
$config = $this->config;
} else {
foreach($this->config as $key=>$value)
{
if(substru($key, -strlenu($filterEnd)) == $filterEnd) $config[$key] = $value;
}
}
return $config;
}
// Return configuration modification time, Unix time
function getModified($httpFormat = false)
{
return $httpFormat ? $this->yellow->toolbox->getHttpTimeFormatted($this->modified) : $this->modified;
}
// Check if configuration exists
function isExisting($key)
{
return !is_null($this->config[$key]);
}
}
// Yellow text strings
class Yellow_Text
{
var $yellow; //access to API
var $modified; //text modification time
var $text; //text strings
var $language; //current language
function __construct($yellow)
{
$this->yellow = $yellow;
$this->modified = 0;
$this->text = array();
}
// Load text strings from file
function load($fileName)
{
$path = dirname($fileName);
$regex = "/".basename($fileName)."/";
foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false) as $entry)
{
$fileData = @file("$path/$entry");
if($fileData)
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Text::load file:$path/$entry<br/>\n";
$this->modified = max($this->modified, filemtime("$path/$entry"));
$language = "";
foreach($fileData as $line)
{
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if($matches[1]=="language" && !empty($matches[2])) { $language = $matches[2]; break; }
}
foreach($fileData as $line)
{
if(preg_match("/^\//", $line)) continue;
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if(!empty($language) && !empty($matches[1]) && !strempty($matches[2]))
{
$this->setLanguageText($language, $matches[1], $matches[2]);
if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Text::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
}
}
// Set current language
function setLanguage($language)
{
$this->language = $language;
}
// Set text string for specific language
function setLanguageText($language, $key, $value)
{
if(is_null($this->text[$language])) $this->text[$language] = array();
$this->text[$language][$key] = $value;
}
// Return text string for specific language
function getLanguageText($language, $key)
{
return ($this->isLanguageText($language, $key)) ? $this->text[$language][$key] : "[$key]";
}
// Return text string
function get($key)
{
return $this->isExisting($key) ? $this->text[$this->language][$key] : "[$key]";
}
// Return text string, HTML encoded
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
// Return text strings for specific language
function getData($language, $filterStart = "")
{
$text = array();
if(!is_null($this->text[$language]))
{
if(empty($filterStart))
{
$text = $this->text[$language];
} else {
foreach($this->text[$language] as $key=>$value)
{
if(substru($key, 0, strlenu("language")) == "language") $text[$key] = $value;
if(substru($key, 0, strlenu($filterStart)) == $filterStart) $text[$key] = $value;
}
}
}
return $text;
}
// Return text modification time, Unix time
function getModified($httpFormat = false)
{
return $httpFormat ? $this->yellow->toolbox->getHttpTimeFormatted($this->modified) : $this->modified;
}
// Check if text string for specific language exists
function isLanguageText($language, $key)
{
return !is_null($this->text[$language]) && !is_null($this->text[$language][$key]);
}
// Check if text string exists
function isExisting($key)
{
return !is_null($this->text[$this->language]) && !is_null($this->text[$this->language][$key]);
}
}
// Yellow toolbox with helpers
class Yellow_Toolbox
{
@ -1182,6 +1410,7 @@ class Yellow_Toolbox
case 304: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Not modified"; break;
case 401: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Unauthorised"; break;
case 404: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Not found"; break;
case 409: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Conflict"; break;
case 424: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Does not exist"; break;
case 500: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Server error"; break;
default: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Unknown status";
@ -1195,16 +1424,22 @@ class Yellow_Toolbox
return gmdate("D, d M Y H:i:s", $timestamp)." GMT";
}
// Return HTTP location header
function getHttpLocationHeader($serverName, $serverBase, $location)
// Return HTTP URL
function getHttpUrl($serverName, $serverBase, $location)
{
if(preg_match("/^(http|https):\/\//", $location))
{
$locationHeader = "Location: $location";
$url = $location;
} else {
$locationHeader = "Location: http://$serverName$serverBase$location";
$url = "http://$serverName$serverBase$location";
}
return $locationHeader;
return $url;
}
// Return HTTP location header
function getHttpLocationHeader($serverName, $serverBase, $location)
{
return "Location: ".self::getHttpUrl($serverName, $serverBase, $location);
}
// Return directory location
@ -1308,7 +1543,7 @@ class Yellow_Toolbox
if(preg_match("/^(blockquote|br|div|h\d|hr|li|ol|p|pre|ul)/i", $elementName)) $string .= ' ';
if(preg_match("/^\/(code|pre)/i", $elementName)) $string = preg_replace("/^(\d+\n){2,}$/", "", $string);
$string = preg_replace("/\s+/s", " ", $string);
if(substru($string, 0 , 1)==" " && (empty($output) || substru($output, -1)==' ')) $string = substru($string, 1);
if(substru($string, 0, 1)==" " && (empty($output) || substru($output, -1)==' ')) $string = substru($string, 1);
$length = strlenu($string);
$output .= substru($string, 0, $length < $lengthMax ? $length : $lengthMax-1);
$lengthMax -= $length;
@ -1433,191 +1668,6 @@ class Yellow_Toolbox
}
}
// Yellow configuration
class Yellow_Config
{
var $config; //configuration
var $configDefaults; //configuration defaults
function __construct()
{
$this->config = array();
$this->configDefaults = array();
}
// Load configuration from file
function load($fileName)
{
$fileData = @file($fileName);
if($fileData)
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Config::load file:$fileName<br/>\n";
foreach($fileData as $line)
{
if(preg_match("/^\//", $line)) continue;
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if(!empty($matches[1]) && !strempty($matches[2]))
{
$this->set($matches[1], $matches[2]);
if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Config::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
}
// Set default configuration
function setDefault($key, $value)
{
$this->configDefaults[$key] = $value;
}
// Set configuration
function set($key, $value)
{
$this->config[$key] = $value;
}
// Return configuration
function get($key)
{
return $this->isExisting($key) ? $this->config[$key] : $this->configDefaults[$key];
}
// Return configuration, HTML encoded
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
// Return configuration strings
function getData($filterEnd = "")
{
$config = array();
if(empty($filterEnd))
{
$config = $this->config;
} else {
foreach($this->config as $key=>$value)
{
if(substru($key, -strlenu($filterEnd)) == $filterEnd) $config[$key] = $value;
}
}
return $config;
}
// Check if configuration exists
function isExisting($key)
{
return !is_null($this->config[$key]);
}
}
// Yellow text strings
class Yellow_Text
{
var $text; //text strings
var $language; //current language
function __construct()
{
$this->text = array();
}
// Load text strings from file
function load($fileName, $toolbox)
{
$path = dirname($fileName);
$regex = "/".basename($fileName)."/";
foreach($toolbox->getDirectoryEntries($path, $regex, true, false) as $entry)
{
$fileData = @file("$path/$entry");
if($fileData)
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Text::load file:$path/$entry<br/>\n";
$language = "";
foreach($fileData as $line)
{
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if($matches[1]=="language" && !empty($matches[2])) { $language = $matches[2]; break; }
}
foreach($fileData as $line)
{
if(preg_match("/^\//", $line)) continue;
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
if(!empty($language) && !empty($matches[1]) && !strempty($matches[2]))
{
$this->setLanguageText($language, $matches[1], $matches[2]);
if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Text::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
}
}
// Set current language
function setLanguage($language)
{
$this->language = $language;
}
// Set text string for specific language
function setLanguageText($language, $key, $value)
{
if(is_null($this->text[$language])) $this->text[$language] = array();
$this->text[$language][$key] = $value;
}
// Return text string for specific language
function getLanguageText($language, $key)
{
return ($this->isLanguageText($language, $key)) ? $this->text[$language][$key] : "[$key]";
}
// Return text string
function get($key)
{
return $this->isExisting($key) ? $this->text[$this->language][$key] : "[$key]";
}
// Return text string, HTML encoded
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
// Return text strings for specific language
function getData($language, $filterStart = "")
{
$text = array();
if(!is_null($this->text[$language]))
{
if(empty($filterStart))
{
$text = $this->text[$language];
} else {
foreach($this->text[$language] as $key=>$value)
{
if(substru($key, 0, strlenu("language")) == "language") $text[$key] = $value;
if(substru($key, 0, strlenu($filterStart)) == $filterStart) $text[$key] = $value;
}
}
}
return $text;
}
// Check if text string for specific language exists
function isLanguageText($language, $key)
{
return !is_null($this->text[$language]) && !is_null($this->text[$language][$key]);
}
// Check if text string exists
function isExisting($key)
{
return !is_null($this->text[$this->language]) && !is_null($this->text[$this->language][$key]);
}
}
// Yellow plugins
class Yellow_Plugins
{

View file

@ -5,7 +5,7 @@
// Command line core plugin
class Yellow_Commandline
{
const Version = "0.1.4";
const Version = "0.1.5";
var $yellow; //access to API
// Initialise plugin
@ -149,7 +149,7 @@ class Yellow_Commandline
{
$fileName = $this->getStaticFileName($location, $path);
$fileData = ob_get_contents();
if($statusCode == 301) $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
if($statusCode>=301 && $statusCode<=303) $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
$fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
} else {
if(!$this->yellow->toolbox->isFileLocation($location))
@ -164,8 +164,8 @@ class Yellow_Commandline
$fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
}
} else {
$statusCode = 500;
$this->yellow->page->error($statusCode, "Invalid file name for type '$contentType'!");
$statusCode = 409;
$this->yellow->page->error($statusCode, "Type '$contentType' does not match file name!");
}
}
if(!$fileOk)
@ -217,20 +217,23 @@ class Yellow_Commandline
// Return static location corresponding to content type
function getStaticLocation($location, $contentType)
{
$extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
if($contentType == "text/html")
if(!empty($contentType))
{
if($this->yellow->toolbox->isFileLocation($location))
$extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
if($contentType == "text/html")
{
if(!empty($extension) && $extension!=".html") $location .= ".html";
}
} else {
if($this->yellow->toolbox->isFileLocation($location))
{
if(empty($extension)) $location .= ".unknown";
if($this->yellow->toolbox->isFileLocation($location))
{
if(!empty($extension) && $extension!=".html") $location .= ".html";
}
} else {
if(preg_match("/^(\w+)\/(\w+)/", $contentType, $matches)) $extension = ".$matches[2]";
$location .= "index$extension";
if($this->yellow->toolbox->isFileLocation($location))
{
if(empty($extension)) $location .= ".unknown";
} else {
if(preg_match("/^(\w+)\/(\w+)/", $contentType, $matches)) $extension = ".$matches[2]";
$location .= "index$extension";
}
}
}
return $location;