yellow/system/core/core.php

1181 lines
35 KiB
PHP
Raw Normal View History

2013-04-07 18:04:09 +00:00
<?php
// Copyright (c) 2013 Datenstrom, http://datenstrom.se
2013-04-07 18:04:09 +00:00
// This file may be used and distributed under the terms of the public license.
2013-04-07 18:04:09 +00:00
// Yellow main class
class Yellow
{
const Version = "0.1.2";
2013-04-14 22:41:04 +00:00
var $page; //current page data
2013-05-01 20:16:05 +00:00
var $pages; //current page tree from file system
2013-04-14 22:41:04 +00:00
var $toolbox; //toolbox with helpers
var $config; //site configuration
var $text; //site text strings
var $plugins; //site plugins
2013-04-07 18:04:09 +00:00
function __construct()
{
2013-04-14 22:41:04 +00:00
$this->toolbox = new Yellow_Toolbox();
2013-04-07 18:04:09 +00:00
$this->config = new Yellow_Config();
2013-04-14 22:41:04 +00:00
$this->text = new Yellow_Text();
$this->plugins = new Yellow_Plugins();
$this->config->setDefault("sitename", "Yellow");
$this->config->setDefault("author", "Yellow");
$this->config->setDefault("language", "en");
2013-04-07 18:04:09 +00:00
$this->config->setDefault("parser", "markdown");
$this->config->setDefault("template", "default");
2013-04-14 22:41:04 +00:00
$this->config->setDefault("yellowVersion", Yellow::Version);
$this->config->setDefault("baseLocation", $this->toolbox->getBaseLocation());
2013-04-07 18:04:09 +00:00
$this->config->setDefault("stylesLocation", "/media/styles/");
$this->config->setDefault("imagesLocation", "/media/images/");
2013-04-14 22:41:04 +00:00
$this->config->setDefault("pluginsLocation", "media/plugins/");
2013-04-07 18:04:09 +00:00
$this->config->setDefault("systemDir", "system/");
$this->config->setDefault("configDir", "system/config/");
$this->config->setDefault("pluginDir", "system/plugins/");
$this->config->setDefault("snippetDir", "system/snippets/");
$this->config->setDefault("templateDir", "system/templates/");
$this->config->setDefault("contentDir", "content/");
$this->config->setDefault("contentHomeDir", "1-home/");
2013-04-14 22:41:04 +00:00
$this->config->setDefault("contentDefaultFile", "page.txt");
2013-04-07 18:04:09 +00:00
$this->config->setDefault("contentExtension", ".txt");
2013-04-14 22:41:04 +00:00
$this->config->setDefault("configExtension", ".ini");
2013-04-07 18:04:09 +00:00
$this->config->setDefault("systemExtension", ".php");
$this->config->setDefault("configFile", "config.ini");
2013-04-14 22:41:04 +00:00
$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);
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Start and handle request
function request()
{
$this->toolbox->timerStart($time);
$this->plugins->load();
$this->processRequest();
$this->toolbox->timerStop($time);
if(defined("DEBUG") && DEBUG>=1) echo "Yellow::request time:$time ms<br>\n";
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Process request
2013-04-07 18:04:09 +00:00
function processRequest()
{
2013-04-14 22:41:04 +00:00
$statusCode = 0;
$baseLocation = $this->config->get("baseLocation");
$location = $this->getRelativeLocation($baseLocation);
2013-04-07 18:04:09 +00:00
$fileName = $this->getContentFileName($location);
2013-04-14 22:41:04 +00:00
foreach($this->plugins->plugins as $key=>$value)
{
2013-04-07 18:04:09 +00:00
if(method_exists($value["obj"], "onRequest"))
2013-04-14 22:41:04 +00:00
{
2013-04-07 18:04:09 +00:00
$statusCode = $value["obj"]->onRequest($baseLocation, $location, $fileName);
if($statusCode) break;
2013-04-14 22:41:04 +00:00
}
}
if($statusCode == 0) $statusCode = $this->processRequestFile($baseLocation, $location, $fileName, $statusCode);
if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequest status:$statusCode location:$location<br>\n";
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Process request for a file
function processRequestFile($baseLocation, $location, $fileName, $statusCode, $cache = true)
{
if($statusCode == 0)
{
if(is_readable($fileName))
{
$time = gmdate("D, d M Y H:i:s", filemtime($fileName))." GMT";
if(isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$time && $cache)
{
$statusCode = 304;
$this->sendStatus($statusCode);
} else {
$statusCode = 200;
header("Content-Type: text/html; charset=UTF-8");
if($cache)
{
header("Last-Modified: ".$time);
} else {
header("Cache-Control: no-cache");
header("Pragma: no-cache");
header("Expires: 0");
}
$fileHandle = @fopen($fileName, "r");
if($fileHandle)
{
$fileData = fread($fileHandle, filesize($fileName));
fclose($fileHandle);
} else {
die("Server problem: Can't read file '$fileName'!");
}
}
} else {
if($this->toolbox->isFileLocation($location) && is_dir($this->getContentDirectory("$location/")))
{
$statusCode = 301;
$this->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$baseLocation$location/");
} else {
$statusCode = 404;
}
}
}
if($statusCode >= 400)
{
header($this->toolbox->getHttpStatusFormated($statusCode));
header("Content-Type: text/html; charset=UTF-8");
2013-05-01 20:16:05 +00:00
$fileName = strreplaceu("(.*)", $statusCode, $this->config->get("configDir").$this->config->get("errorPageFile"));
2013-04-14 22:41:04 +00:00
$fileHandle = @fopen($fileName, "r");
if($fileHandle)
{
$fileData = fread($fileHandle, filesize($fileName));
fclose($fileHandle);
} else {
die("Configuration problem: Can't open file '$fileName'!");
}
}
2013-05-01 20:16:05 +00:00
if(!empty($fileData)) $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode);
2013-04-14 22:41:04 +00:00
if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequestFile base:$baseLocation file:$fileName<br>\n";
return $statusCode;
}
// Send status response
function sendStatus($statusCode, $text = "")
{
header($this->toolbox->getHttpStatusFormated($statusCode));
2013-05-01 20:16:05 +00:00
if(!empty($text)) header($text);
2013-04-14 22:41:04 +00:00
}
// Send page response
function sendPage($baseLocation, $location, $fileName, $fileData, $statusCode)
{
2013-05-01 20:16:05 +00:00
$this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config, $this->plugins);
$this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->pages, true);
2013-04-14 22:41:04 +00:00
$this->text->setLanguage($this->page->get("language"));
$fileName = $this->config->get("templateDir").$this->page->get("template").$this->config->get("systemExtension");
if(!is_file($fileName)) die("Template '".$this->page->get("template")."' does not exist!");
2013-04-07 18:04:09 +00:00
global $yellow;
2013-04-14 22:41:04 +00:00
require($fileName);
2013-04-07 18:04:09 +00:00
}
2013-04-14 22:41:04 +00:00
// Execute a template snippet
function snippet($name, $args = NULL)
2013-04-07 18:04:09 +00:00
{
$this->page->args = func_get_args();
$fileName = $this->config->get("snippetDir").$name.$this->config->get("systemExtension");
if(!is_file($fileName)) die("Snippet '$name' does not exist!");
2013-04-07 18:04:09 +00:00
global $yellow;
require($fileName);
}
2013-04-14 22:41:04 +00:00
// Return template snippet arguments
function getSnippetArgs()
{
return $this->page->args;
}
2013-04-14 22:41:04 +00:00
// Return extra HTML header lines generated from plugins
2013-04-07 18:04:09 +00:00
function getHeaderExtra()
{
2013-04-14 22:41:04 +00:00
$header = "";
2013-04-07 18:04:09 +00:00
foreach($this->plugins->plugins as $key=>$value)
2013-04-14 22:41:04 +00:00
{
2013-04-07 18:04:09 +00:00
if(method_exists($value["obj"], "onHeaderExtra")) $header .= $value["obj"]->onHeaderExtra();
2013-04-14 22:41:04 +00:00
}
return $header;
}
// Return content location for current HTTP request, without base location
function getRelativeLocation($baseLocation)
{
$location = $this->toolbox->getRequestLocation();
$location = $this->toolbox->normaliseLocation($location);
2013-05-01 20:16:05 +00:00
return substru($location, strlenu($baseLocation));
2013-04-14 22:41:04 +00:00
}
2013-04-07 18:04:09 +00:00
// Return content file name from location
function getContentFileName($location)
{
2013-04-14 22:41:04 +00:00
return $this->toolbox->findFileFromLocation($location,
2013-05-01 20:16:05 +00:00
$this->config->get("contentDir"), $this->config->get("contentHomeDir"),
$this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
2013-04-07 18:04:09 +00:00
}
2013-04-14 22:41:04 +00:00
2013-04-07 18:04:09 +00:00
// Return content directory from location
function getContentDirectory($location)
{
2013-04-14 22:41:04 +00:00
return $this->toolbox->findFileFromLocation($location,
2013-05-01 20:16:05 +00:00
$this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", "");
2013-04-07 18:04:09 +00:00
}
2013-04-14 22:41:04 +00:00
// Register plugin
2013-04-07 18:04:09 +00:00
function registerPlugin($name, $class, $version)
{
2013-04-14 22:41:04 +00:00
$this->plugins->register($name, $class, $version);
2013-04-07 18:04:09 +00:00
}
}
2013-05-01 20:16:05 +00:00
2013-04-07 18:04:09 +00:00
// Yellow page data
class Yellow_Page
{
2013-05-01 20:16:05 +00:00
var $baseLocation; //base location
var $location; //page location
var $fileName; //content file name
var $parser; //content parser
var $metaData; //meta data of page
var $rawData; //raw data of page (unparsed)
var $rawTextOffsetBytes; //raw text of page (unparsed)
var $args; //arguments for template snippet
2013-05-01 20:16:05 +00:00
var $pages; //access to file system
var $active; //page is active?
var $hidden; //page is hidden in navigation?
function __construct($baseLocation, $location, $fileName, $rawData, $pages, $parseContent = false)
2013-04-14 22:41:04 +00:00
{
$this->baseLocation = $baseLocation;
$this->location = $location;
$this->fileName = $fileName;
2013-05-01 20:16:05 +00:00
$this->setRawData($rawData, $pages->toolbox, $pages->config);
$this->pages = $pages;
$this->active = $pages->toolbox->isActiveLocation($baseLocation, $location);
$this->hidden = $pages->toolbox->isHiddenLocation($baseLocation, $location, $fileName, $pages->config->get("contentDir"));
if($parseContent) $this->parseContent();
2013-04-14 22:41:04 +00:00
}
// Set page raw data
2013-04-07 18:04:09 +00:00
function setRawData($rawData, $toolbox, $config)
{
2013-04-14 22:41:04 +00:00
$this->metaData = array();
$this->rawData = $rawData;
2013-05-01 20:16:05 +00:00
$this->rawTextOffsetBytes = 0;
2013-04-14 22:41:04 +00:00
$this->set("title", $toolbox->createTextTitle($this->location));
2013-04-07 18:04:09 +00:00
$this->set("author", $config->get("author"));
2013-04-14 22:41:04 +00:00
$this->set("language", $config->get("language"));
2013-04-07 18:04:09 +00:00
$this->set("parser", $config->get("parser"));
$this->set("template", $config->get("template"));
2013-04-14 22:41:04 +00:00
2013-04-07 18:04:09 +00:00
if(preg_match("/^(\-\-\-[\r\n]+)(.+?)([\r\n]+\-\-\-[\r\n]+)/s", $rawData, $parsed))
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$this->rawTextOffsetBytes = strlenb($parsed[0]);
2013-04-14 22:41:04 +00:00
preg_match_all("/([^\:\r\n]+)\s*\:\s*([^\r\n]+)/s", $parsed[2], $matches, PREG_SET_ORDER);
2013-05-01 20:16:05 +00:00
foreach($matches as $match) $this->set(strtoloweru($match[1]), $match[2]);
2013-04-14 22:41:04 +00:00
} else if(preg_match("/^([^\r\n]+)([\r\n]+=+[\r\n]+)/", $rawData, $parsed)) {
2013-05-01 20:16:05 +00:00
$this->rawTextOffsetBytes = strlenb($parsed[0]);
2013-04-14 22:41:04 +00:00
$this->set("title", $parsed[1]);
}
2013-04-07 18:04:09 +00:00
}
2013-05-01 20:16:05 +00:00
// Parse page content on demand
function parseContent()
{
if(empty($this->parser->html))
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Page::parseContent location:".$this->location."<br/>\n";
$text = $this->getContentRawText();
foreach($this->pages->plugins->plugins as $key=>$value)
{
if(method_exists($value["obj"], "onParseBefore")) $text = $value["obj"]->onParseBefore($text, $statusCode);
}
if(!$this->pages->plugins->isExisting($this->get("parser"))) die("Parser '".$this->get("parser")."' does not exist!");
$this->parser = $this->pages->plugins->plugins[$this->get("parser")]["obj"];
$text = $this->parser->parse($text);
foreach($this->pages->plugins->plugins as $key=>$value)
{
if(method_exists($value["obj"], "onParseAfter")) $text = $value["obj"]->onParseAfter($text, $statusCode);
}
$this->setContent($text);
if(!$this->isExisting("description"))
{
$this->set("description", $this->pages->toolbox->createTextDescription($this->getContent(), 150));
}
if(!$this->isExisting("keywords"))
{
$this->set("keywords", $this->pages->toolbox->createTextKeywords($this->get("title"), 10));
}
}
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Set page meta data
2013-04-07 18:04:09 +00:00
function set($key, $value)
{
$this->metaData[$key] = $value;
}
2013-04-14 22:41:04 +00:00
// Return page meta data
2013-04-07 18:04:09 +00:00
function get($key)
{
2013-04-14 22:41:04 +00:00
return $this->IsExisting($key) ? $this->metaData[$key] : "";
2013-04-07 18:04:09 +00:00
}
2013-04-14 22:41:04 +00:00
// Return page meta data, HTML encoded
2013-04-07 18:04:09 +00:00
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
2013-04-14 22:41:04 +00:00
// Return page title, HTML encoded
function getTitle()
{
return $this->getHtml("title");
}
// Set page content, HTML encoded
function setContent($html)
{
$this->parser->html = $html;
}
// Return page content, HTML encoded
function getContent()
{
2013-05-01 20:16:05 +00:00
$this->parseContent();
2013-04-14 22:41:04 +00:00
return $this->parser->html;
}
// Return page content, raw text
function getContentRawText()
{
2013-05-01 20:16:05 +00:00
return substrb($this->rawData, $this->rawTextOffsetBytes);
2013-04-14 22:41:04 +00:00
}
// Return absolut page location
function getLocation()
{
return $this->baseLocation.$this->location;
}
2013-05-01 20:16:05 +00:00
// Return page modification time (Unix time UTC)
function getModified()
{
return filemtime($this->fileName);
}
// Return child pages relative to current page
function getChildren($hidden = false)
{
return $this->pages->findChildren($this->location, $hidden);
}
// Return pages on the same level as current page
function getSiblings($hidden = false)
{
$parentLocation = $this->pages->getParentLocation($this->location);
return $this->pages->findChildren($parentLocation, $hidden);
}
// Return parent page relative to current page
function getParent()
{
$parentLocation = $this->pages->getParentLocation($this->location);
return $this->pages->findPage($parentLocation);
}
2013-04-14 22:41:04 +00:00
// Check if meta data exists
function isExisting($key)
{
return !is_null($this->metaData[$key]);
}
2013-05-01 20:16:05 +00:00
// Check if page is within current HTTP request
2013-04-14 22:41:04 +00:00
function isActive()
{
return $this->active;
}
2013-05-01 20:16:05 +00:00
// Check if page is hidden in navigation
2013-04-14 22:41:04 +00:00
function isHidden()
{
return $this->hidden;
}
2013-04-07 18:04:09 +00:00
}
2013-05-01 20:16:05 +00:00
// Yellow page collection as array
class Yellow_PageCollection extends ArrayObject
2013-04-07 18:04:09 +00:00
{
2013-05-01 20:16:05 +00:00
var $baseLocation; //base location
var $location; //collection location
var $paginationPage; //current page number in pagination
var $paginationCount; //highest page number in pagination
var $toolbox; //access to toolbox
2013-04-14 22:41:04 +00:00
2013-05-01 20:16:05 +00:00
function __construct($input, $baseLocation, $location, $toolbox)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
parent::__construct($input);
$this->baseLocation = $baseLocation;
$this->location = $location;
$this->toolbox = $toolbox;
}
2013-04-14 22:41:04 +00:00
2013-05-01 20:16:05 +00:00
// Filter page collection by meta data
function filter($key, $value, $exactMatch = true)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if(!empty($key))
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$array = array();
$value = strtoloweru($value);
$valueLength = strlenu($value);
foreach($this->getArrayCopy() as $page)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if($page->isExisting($key))
{
foreach(preg_split("/,\s*/", strtoloweru($page->get($key))) as $valuePage)
{
$length = $exactMatch ? strlenu($valuePage) : $valueLength;
if($value == substru($valuePage, 0, $length)) array_push($array, $page);
}
}
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
$this->exchangeArray($array);
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
return $this;
}
// Reverse page collection
function reverse($entriesMax = 0)
{
$this->exchangeArray(array_reverse($this->getArrayCopy()));
return $this;
}
// Paginate page collection
function pagination($limit, $reverse = true)
{
$array = $this->getArrayCopy();
if($reverse) $array = array_reverse($array);
$this->paginationPage = 1;
$this->paginationCount = ceil($this->count() / $limit);
if($limit < $this->count() && isset($_REQUEST["page"])) $this->paginationPage = max(1, $_REQUEST["page"]);
$this->exchangeArray(array_slice($array, ($this->paginationPage - 1) * $limit, $limit));
return $this;
}
// Return current page number in pagination
function getPaginationPage()
{
return $this->$paginationPage;
}
// Return highest page number in pagination
function getPaginationCount()
{
return $this->paginationCount;
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
// Return absolut location for a page in pagination
function getLocationPage($pageNumber)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if($pageNumber>=1 && $pageNumber<=$this->paginationCount)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$locationArgs = $this->toolbox->getRequestLocationArgs($pageNumber>1 ? "page:$pageNumber" : "page:");
$location = $this->baseLocation.$this->location.$locationArgs;
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
return $location;
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
// Return absolut location for previous page in pagination
function getLocationPrevious()
{
$pageNumber = $this->paginationPage;
$pageNumber = ($pageNumber>1 && $pageNumber<=$this->paginationCount) ? $pageNumber-1 : 0;
return $this->getLocationPage($pageNumber);
}
// Return absolut location for next page in pagination
function getLocationNext()
{
$pageNumber = $this->paginationPage;
$pageNumber = ($pageNumber>=1 && $pageNumber<$this->paginationCount) ? $pageNumber+1 : 0;
return $this->getLocationPage($pageNumber);
}
// Check if there is an active pagination
function isPagination()
{
return $this->paginationCount > 1;
}
}
// Yellow page tree from file system
class Yellow_Pages
2013-04-07 18:04:09 +00:00
{
2013-05-01 20:16:05 +00:00
var $baseLocation; //base location
var $pages; //scanned pages
var $toolbox; //access to toolbox
var $config; //access to configuration
var $plugins; //access to plugins
function __construct($baseLocation, $toolbox, $config, $plugins)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$this->baseLocation = $baseLocation;
$this->pages = array();
$this->toolbox = $toolbox;
$this->config = $config;
$this->plugins = $plugins;
}
// Return top-level navigation pages
function root($hidden = false)
{
return $this->findChildren("", $hidden);
}
// Return child pages for a location
function findChildren($location, $hidden = false)
{
$pages = new Yellow_PageCollection(array(), $this->baseLocation, $location, $this->toolbox);
$this->scanChildren($location);
foreach($this->pages[$location] as $page)
{
if($hidden || !$page->isHidden()) $pages->append($page);
}
return $pages;
2013-04-14 22:41:04 +00:00
}
2013-04-07 18:04:09 +00:00
2013-05-01 20:16:05 +00:00
// Return page for a location, false if not found
function findPage($location)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$parentLocation = $this->getParentLocation($location);
$this->scanChildren($parentLocation);
foreach($this->pages[$parentLocation] as $page)
{
if($this->baseLocation.$location == $page->getLocation()) return $page;
}
return false;
}
// Scan child pages on demand
function scanChildren($location)
{
if(is_null($this->pages[$location]))
{
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Pages::scanChildren location:$location<br/>\n";
$this->pages[$location] = array();
$path = $this->config->get("contentDir");
if(!empty($location))
{
$path = $this->toolbox->findFileFromLocation($location,
$this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", "");
}
$fileNames = array();
foreach($this->toolbox->getDirectoryEntries($path, "/.*/", true) as $entry)
{
array_push($fileNames, $path.$entry."/".$this->config->get("contentDefaultFile"));
}
$fileRegex = "/.*\\".$this->config->get("contentExtension")."/";
foreach($this->toolbox->getDirectoryEntries($path, $fileRegex, true, false) as $entry)
{
if($entry == $this->config->get("contentDefaultFile")) continue;
array_push($fileNames, $path.$entry);
}
foreach($fileNames as $fileName)
{
$childLocation = $this->toolbox->findLocationFromFile($fileName,
$this->config->get("contentDir"), $this->config->get("contentHomeDir"),
$this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
$fileHandle = @fopen($fileName, "r");
if($fileHandle)
{
$fileData = fread($fileHandle, 4096);
fclose($fileHandle);
} else {
$fileData = "";
}
$page = new Yellow_Page($this->baseLocation, $childLocation, $fileName, $fileData, $this);
array_push($this->pages[$location], $page);
}
}
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
// Return parent navigation location
function getParentLocation($location)
{
$parentLocation = "";
if(preg_match("/^(.*\/)(.+?)$/", $location, $matches))
{
$parentLocation = $matches[1]!="/" ? $matches[1] : "";
}
return $parentLocation;
}
}
// Yellow toolbox with helpers
class Yellow_Toolbox
{
// Return base location from current HTTP request
2013-04-14 22:41:04 +00:00
static function getBaseLocation()
{
$baseLocation = "/";
if(preg_match("/^(.*)\//", $_SERVER["SCRIPT_NAME"], $matches)) $baseLocation = $matches[1];
return $baseLocation;
}
2013-05-01 20:16:05 +00:00
// Return location from current HTTP request
static function getRequestLocation()
{
$uri = $_SERVER["REQUEST_URI"];
return ($pos = strposu($uri, '?')) ? substru($uri, 0, $pos) : $uri;
}
// Return arguments from current HTTP request
static function getRequestLocationArgs($arg = "", $encodeArgs = true)
{
preg_match("/^(.*?):(.*)$/", $arg, $args);
if(preg_match("/^(.*?\/)(\w+:.*)$/", rawurldecode(self::getRequestLocation()), $matches))
{
foreach(explode('/', $matches[2]) as $token)
{
preg_match("/^(.*?):(.*)$/", $token, $matches);
if($matches[1] == $args[1]) { $matches[2] = $args[2]; $found = true; }
if(!empty($matches[1]) && !empty($matches[2]))
{
if(!empty($locationArgs)) $locationArgs .= '/';
$locationArgs .= "$matches[1]:$matches[2]";
}
}
}
if(!$found && !empty($args[1]) && !empty($args[2]))
{
if(!empty($locationArgs)) $locationArgs .= '/';
$locationArgs .= "$args[1]:$args[2]";
}
if($encodeArgs)
{
$locationArgs = rawurlencode($locationArgs);
$locationArgs = strreplaceu(array('%3A','%2F'), array(':','/'), $locationArgs);
}
return $locationArgs;
}
// Normalise location and remove unwanted path tokens
static function normaliseLocation($location, $removeArgs = true)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$string = strreplaceu('\\', '/', rawurldecode($location));
$location = ($string[0]=='/') ? '' : '/';
for($pos=0; $pos<strlenb($string); ++$pos)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if($string[$pos] == '/')
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if($string[$pos+1] == '/') continue;
if($string[$pos+1] == '.')
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$posNew = $pos+1; while($string[$posNew] == '.') ++$posNew;
if($string[$posNew]=='/' || $string[$posNew]=='')
2013-04-14 22:41:04 +00:00
{
$pos = $posNew-1;
continue;
}
}
}
2013-05-01 20:16:05 +00:00
$location .= $string[$pos];
}
if($removeArgs && preg_match("/^(.*?\/)(\w+:.*)$/", $location, $matches))
{
$location = $matches[1];
foreach(explode('/', $matches[2]) as $token)
{
preg_match("/^(.*?):(.*)$/", $token, $matches);
if(!empty($matches[1]) && !empty($matches[2])) $_REQUEST[$matches[1]] = $matches[2];
}
2013-04-14 22:41:04 +00:00
}
return $location;
}
// Check if location is specifying file or directory
static function isFileLocation($location)
{
2013-05-01 20:16:05 +00:00
return substru($location, -1, 1) != "/";
2013-04-14 22:41:04 +00:00
}
// Check if location is within current HTTP request
static function isActiveLocation($baseLocation, $location)
{
2013-05-01 20:16:05 +00:00
$currentLocation = substru(self::getRequestLocation(), strlenu($baseLocation));
2013-04-14 22:41:04 +00:00
if($location != "/")
{
2013-05-01 20:16:05 +00:00
$active = substru($currentLocation, 0, strlenu($location))==$location;
2013-04-14 22:41:04 +00:00
} else {
$active = $currentLocation==$location;
}
return $active;
}
2013-05-01 20:16:05 +00:00
// Check if location is hidden in navigation
2013-04-14 22:41:04 +00:00
static function isHiddenLocation($baseLocation, $location, $fileName, $pathBase)
{
$hidden = false;
2013-05-01 20:16:05 +00:00
if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) $fileName = substru($fileName, strlenu($pathBase));
2013-04-14 22:41:04 +00:00
$tokens = explode('/', $fileName);
for($i=0; $i<count($tokens)-1; ++$i)
{
if(!preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i]))
{
$hidden = true;
break;
}
}
return $hidden;
}
// Find file path from location
static function findFileFromLocation($location, $pathBase, $pathHome, $fileDefault, $fileExtension)
{
$path = $pathBase;
2013-05-01 20:16:05 +00:00
$tokens = explode('/', $location);
if(count($tokens) > 2)
2013-04-14 22:41:04 +00:00
{
for($i=1; $i<count($tokens)-1; ++$i)
{
2013-05-01 20:16:05 +00:00
if(preg_match("/^[\d\-\.]+/", $tokens[$i])) $duplicate = true;
2013-04-14 22:41:04 +00:00
$entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i]."$/");
2013-05-01 20:16:05 +00:00
$path .= empty($entries) ? "$tokens[$i]/" : "$entries[0]/";
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
if($path == $pathBase.$pathHome) $duplicate = true;
2013-04-14 22:41:04 +00:00
} else {
2013-05-01 20:16:05 +00:00
$i = 1;
$path .= $pathHome;
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
if($tokens[$i] != "")
{
if(preg_match("/^[\d\-\.]+/", $tokens[$i])) $duplicate = true;
$entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i].$fileExtension."$/", false, false);
$path .= empty($entries) ? $tokens[$i].$fileExtension : $entries[0];
} else {
$path .= $fileDefault;
}
return $duplicate ? "" : $path;
2013-04-14 22:41:04 +00:00
}
// Find location from file path
static function findLocationFromFile($fileName, $pathBase, $pathHome, $fileDefault, $fileExtension)
{
$location = "/";
2013-05-01 20:16:05 +00:00
if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) $fileName = substru($fileName, strlenu($pathBase));
if(substru($fileName, 0, strlenu($pathHome)) == $pathHome) $fileName = substru($fileName, strlenu($pathHome));
$tokens = explode('/', $fileName);
for($i=0; $i<count($tokens)-1; ++$i)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1];
$location .= "$tokens[$i]/";
}
if($tokens[$i] != $fileDefault)
{
if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1];
$location .= substru($tokens[$i], 0, -strlenu($fileExtension));
2013-04-14 22:41:04 +00:00
}
return $location;
}
// Return human readable HTTP server status
static function getHttpStatusFormated($statusCode)
{
switch($statusCode)
{
case 301: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Moved permanently"; break;
case 302: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Moved temporarily"; break;
2013-05-01 20:16:05 +00:00
case 303: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Reload please"; break;
2013-04-14 22:41:04 +00:00
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 424: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Does not exist"; break;
default: die("Unknown HTTP status $statusCode!");
}
return $text;
}
// Return files and directories
static function getDirectoryEntries($path, $regex = "/.*/", $sort = false, $directories = true)
{
$entries = array();
$dirHandle = @opendir($path);
if($dirHandle)
{
while(($entry = readdir($dirHandle)) !== false)
{
2013-05-01 20:16:05 +00:00
if(substru($entry, 0, 1) == ".") continue;
2013-04-14 22:41:04 +00:00
if(preg_match($regex, $entry))
{
if($directories)
{
if(is_dir("$path/$entry")) array_push($entries, $entry);
} else {
if(is_file("$path/$entry")) array_push($entries, $entry);
}
}
}
if($sort) natsort($entries);
closedir($dirHandle);
}
return $entries;
}
2013-04-07 18:04:09 +00:00
2013-05-01 20:16:05 +00:00
// Create description from text string
static function createTextDescription($text, $lengthMax, $removeHtml = true)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
if(preg_match("/<h1>.*<\/h1>(.*)/si", $text, $matches)) $text = $matches[1];
if($removeHtml)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
while(true)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$elementFound = preg_match("/<\s*?(\/?\w*).*?\>/s", $text, $matches, PREG_OFFSET_CAPTURE, $offsetBytes);
$element = $matches[0][0];
$elementName = $matches[1][0];
$elementOffsetBytes = $elementFound ? $matches[0][1] : strlenb($text);
$string = html_entity_decode(substrb($text, $offsetBytes, $elementOffsetBytes - $offsetBytes), ENT_QUOTES, "UTF-8");
if(preg_match("/^(blockquote|br|div|h\d|hr|li|ol|p|pre|ul)/i", $elementName)) $string .= ' ';
$string = preg_replace("/\s+/s", " ", $string);
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;
if($lengthMax<=0 || !$elementFound) break;
$offsetBytes = $elementOffsetBytes + strlenb($element);
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
$output = rtrim($output);
if($lengthMax <= 0) $output .= '…';
} else {
$elementsOpen = array();
while(true)
2013-04-14 22:41:04 +00:00
{
2013-05-01 20:16:05 +00:00
$elementFound = preg_match("/&.*?\;|<\s*?(\/?\w*)\s*?(.*?)\s*?\>/s", $text, $matches, PREG_OFFSET_CAPTURE, $offsetBytes);
$element = $matches[0][0];
$elementName = $matches[1][0];
$elementOffsetBytes = $elementFound ? $matches[0][1] : strlenb($text);
$string = substrb($text, $offsetBytes, $elementOffsetBytes - $offsetBytes);
$length = strlenu($string);
$output .= substru($string, 0, $length < $lengthMax ? $length : $lengthMax-1);
$lengthMax -= $length + ($element[0]=='&' ? 1 : 0);
if($lengthMax<=0 || !$elementFound) break;
if(!empty($elementName))
{
if(!preg_match("/^(\/|area|br|col|hr|img|input|col|param)/i", $elementName))
{
if(substru($matches[2][0], -1) != '/') array_push($elementsOpen, $elementName);
} else {
array_pop($elementsOpen);
}
}
$output .= $element;
$offsetBytes = $elementOffsetBytes + strlenb($element);
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
$output = rtrim($output);
if($lengthMax <= 0) $output .= '…';
for($t=count($elementsOpen)-1; $t>=0; --$t) $output .= "</".$elementsOpen[$t].">";
2013-04-14 22:41:04 +00:00
}
2013-05-01 20:16:05 +00:00
return $output;
2013-04-14 22:41:04 +00:00
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Create keywords from text string
static function createTextKeywords($text, $keywordsMax)
{
2013-05-01 20:16:05 +00:00
$tokens = preg_split("/[,\s\(\)]/", strtoloweru($text));
foreach($tokens as $key=>$value) if(strlenu($value) < 3) unset($tokens[$key]);
2013-04-14 22:41:04 +00:00
return implode(", ", array_slice(array_unique($tokens), 0, $keywordsMax));
}
// Create title from text string
static function createTextTitle($text)
{
if(preg_match("/^.*\/(\w*)/", $text, $matches)) $text = ucfirst($matches[1]);
return $text;
}
// Detect web browser language
2013-05-01 20:16:05 +00:00
static function detectBrowserLanguage($languagesAllowed, $languageDefault)
2013-04-14 22:41:04 +00:00
{
$language = $languageDefault;
if(isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
{
foreach(preg_split("/,\s*/", $_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $string)
{
2013-05-01 20:16:05 +00:00
$tokens = explode(';', $string, 2);
2013-04-14 22:41:04 +00:00
if(in_array($tokens[0], $languagesAllowed))
{
$language = $tokens[0];
break;
}
}
}
return $language;
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Detect PNG and JPG image dimensions
static function detectImageDimensions($fileName)
{
$width = $height = 0;
$fileHandle = @fopen($fileName, "rb");
if($fileHandle)
{
2013-05-01 20:16:05 +00:00
if(substru($fileName, -3) == "png")
2013-04-14 22:41:04 +00:00
{
$dataSignature = fread($fileHandle, 8);
$dataHeader = fread($fileHandle, 25);
if(!feof($fileHandle) && $dataSignature=="\x89PNG\r\n\x1a\n")
{
$width = (ord($dataHeader[10])<<8) + ord($dataHeader[11]);
$height = (ord($dataHeader[14])<<8) + ord($dataHeader[15]);
}
2013-05-01 20:16:05 +00:00
} else if(substru($fileName, -3) == "jpg") {
2013-04-14 22:41:04 +00:00
$dataSignature = fread($fileHandle, 11);
$dataHeader = fread($fileHandle, 147);
$dataHeader = fread($fileHandle, 16);
if(!feof($fileHandle) && $dataSignature=="\xff\xd8\xff\xe0\x00\x10JFIF\0")
{
$width = (ord($dataHeader[7])<<8) + ord($dataHeader[8]);
$height = (ord($dataHeader[5])<<8) + ord($dataHeader[6]);
}
}
fclose($fileHandle);
}
return array($width, $height);
}
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
// Start timer
static function timerStart(&$time)
{
$time = microtime(true);
}
// Stop timer and calcuate elapsed time (milliseconds)
static function timerStop(&$time)
{
$time = intval((microtime(true)-$time) * 1000);
}
2013-04-07 18:04:09 +00:00
}
// Yellow configuration
class Yellow_Config
{
2013-04-14 22:41:04 +00:00
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);
2013-05-01 20:16:05 +00:00
if(!empty($matches[1]) && !empty($matches[2]))
2013-04-14 22:41:04 +00:00
{
$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($filterEnd == "")
{
$config = $this->config;
} else {
foreach($this->config as $key=>$value)
{
2013-05-01 20:16:05 +00:00
if(substru($key, -strlenu($filterEnd)) == $filterEnd) $config[$key] = $value;
2013-04-14 22:41:04 +00:00
}
}
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);
2013-05-01 20:16:05 +00:00
if($matches[1]=="language" && !empty($matches[2])) { $language = $matches[2]; break; }
2013-04-14 22:41:04 +00:00
}
foreach($fileData as $line)
{
if(preg_match("/^\//", $line)) continue;
preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
2013-05-01 20:16:05 +00:00
if(!empty($language) && !empty($matches[1]) && !empty($matches[2]))
2013-04-14 22:41:04 +00:00
{
$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
function setLanguageText($language, $key, $value)
{
if(is_null($this->text[$language])) $this->text[$language] = array();
$this->text[$language][$key] = $value;
}
// 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
function getData($language, $filterStart = "")
{
$text = array();
if(!is_null($this->text[$language]))
{
if($filterStart == "")
{
$text = $this->text[$language];
} else {
foreach($this->text[$language] as $key=>$value)
{
2013-05-01 20:16:05 +00:00
if(substru($key, 0, strlenu("language")) == "language") $text[$key] = $value;
if(substru($key, 0, strlenu($filterStart)) == $filterStart) $text[$key] = $value;
2013-04-14 22:41:04 +00:00
}
}
}
return $text;
}
// Check if text string exists
function isExisting($key)
{
return !is_null($this->text[$this->language]) && !is_null($this->text[$this->language][$key]);
}
2013-04-07 18:04:09 +00:00
}
// Yellow plugins
class Yellow_Plugins
{
2013-04-14 22:41:04 +00:00
var $plugins; //registered plugins
2013-04-07 18:04:09 +00:00
2013-04-14 22:41:04 +00:00
function __construct()
{
$this->plugins = array();
}
// Load plugins
function load()
2013-04-07 18:04:09 +00:00
{
global $yellow;
2013-04-14 22:41:04 +00:00
require_once("core_markdown.php");
require_once("core_rawhtml.php");
require_once("core_webinterface.php");
foreach($yellow->toolbox->getDirectoryEntries($yellow->config->get("pluginDir"), "/.*\.php/", true, false) as $entry)
2013-04-07 18:04:09 +00:00
{
2013-04-14 22:41:04 +00:00
$fileName = $yellow->config->get("pluginDir")."/$entry";
require_once($fileName);
}
foreach($this->plugins as $key=>$value)
{
$this->plugins[$key]["obj"] = new $value["class"];
if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Plugins::load class:$value[class] $value[version]<br/>\n";
if(method_exists($this->plugins[$key]["obj"], "initPlugin"))
{
$this->plugins[$key]["obj"]->initPlugin($yellow);
}
2013-04-07 18:04:09 +00:00
}
}
2013-04-14 22:41:04 +00:00
// Register plugin
2013-04-07 18:04:09 +00:00
function register($name, $class, $version)
{
2013-04-14 22:41:04 +00:00
if(!$this->isExisting($name))
{
$this->plugins[$name] = array();
$this->plugins[$name]["class"] = $class;
$this->plugins[$name]["version"] = $version;
}
}
// Check if plugin exists
function isExisting($name)
{
return !is_null($this->plugins[$name]);
2013-04-07 18:04:09 +00:00
}
}
2013-05-01 20:16:05 +00:00
// Unicode support for PHP 5
mb_internal_encoding("UTF-8");
function strlenu() { return call_user_func_array("mb_strlen", func_get_args()); }
function strposu() { return call_user_func_array("mb_strpos", func_get_args()); }
function strreplaceu() { return call_user_func_array("str_replace", func_get_args()); }
function strtoloweru() { return call_user_func_array("mb_strtolower", func_get_args()); }
function strtoupperu() { return call_user_func_array("mb_strtoupper", func_get_args()); }
function substru() { return call_user_func_array("mb_substr", func_get_args()); }
function strlenb() { return call_user_func_array("strlen", func_get_args()); }
function strposb() { return call_user_func_array("strpos", func_get_args()); }
function substrb() { return call_user_func_array("substr", func_get_args()); }
2013-04-07 18:04:09 +00:00
?>