commit 2474166d27df9da05345fb285ec26ed3c7d90d86
parent 9355317b5efdf5f5b3ff6a07f687854acab1f3c9
Author: markseu <mark2011@mayberg.se>
Date: Mon, 15 Apr 2013 00:41:04 +0200
Hello web interface
Diffstat:
16 files changed, 1478 insertions(+), 641 deletions(-)
diff --git a/.htaccess b/.htaccess
@@ -4,10 +4,14 @@ RewriteEngine on
# RewriteBase /yellow
-RewriteRule ^content/(.*) error [R=301,L]
-RewriteRule ^system/(.*) error [R=301,L]
+RewriteCond %{ENV:REDIRECT_STATUS} ^$
+RewriteRule ^(content|system)/ error404 [L]
+RewriteCond %{REQUEST_URI} \.(css|js|png)$
+RewriteRule ^media/plugins/(core_.+) system/core/$1 [L]
+RewriteCond %{REQUEST_URI} \.(css|js|png)$
+RewriteRule ^media/plugins/(.+) system/plugins/$1 [L]
-RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.+) index.php [L]
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^ index.php [L]
</IfModule>
diff --git a/README.md b/README.md
@@ -1,4 +1,16 @@
Yellow
======
-Yellow is a CMS for people, it's web-based and flat-file.
-\ No newline at end of file
+Yellow is a CMS for people, it's web-based and flat-file.
+
+How do I install this?
+----------------------
+[Download Yellow](https://github.com/markseu/yellowcms/archive/master.zip) and unzip it.
+Copy all files to your web server hosting.
+Open your website in a browser, that's it!
+
+Installation requirements are Apache, mod_rewrite and PHP 5.3.
+
+Need help? Have a question?
+---------------------------
+Visit [Yellow on Reddit](http://www.reddit.com/r/yellowcms/), follow [Yellow on Twitter](https://twitter.com/yellowcms).
+\ No newline at end of file
diff --git a/content/1-home/page.txt b/content/1-home/page.txt
@@ -2,6 +2,6 @@
Title: Home
---
Yes, it works! Your Yellow installation was successful.
-You can now [edit this page](wiki/) or use your favorite text editor.
+You can now [edit this page](@baselocation/wiki/) or use your favorite text editor.
-[Visit Yellow on Github](https://github.com/markseu/yellowcms).
-\ No newline at end of file
+Visit [Yellow on Github](https://github.com/markseu/yellowcms).
+\ No newline at end of file
diff --git a/system/config/config.ini b/system/config/config.ini
@@ -1,5 +1,5 @@
-// Yellow CMS configuration
-// All directories and locations have to end with a slash
+// Yellow site configuration
+// All locations and directories have to end with a slash
sitename = Website
author = Website
@@ -10,7 +10,6 @@ template = default
stylesLocation = /media/styles/
imagesLocation = /media/images/
pluginsLocation = /media/plugins/
-
systemDir = system/
configDir = system/config/
pluginDir = system/plugins/
@@ -18,7 +17,9 @@ snippetDir = system/snippets/
templateDir = system/templates/
contentDir = content/
contentHomeDir = 1-home/
-contentDefaultFile = page
+contentDefaultFile = page.txt
contentExtension = .txt
configExtension = .ini
-systemExtension = .php
-\ No newline at end of file
+systemExtension = .php
+errorPageFile = error(.*).txt
+textStringFile = text_(.*).ini
+\ No newline at end of file
diff --git a/system/config/error401.txt b/system/config/error401.txt
@@ -0,0 +1,4 @@
+---
+Title: Unauthorised
+---
+You are not authorised on this server. Please log in.
+\ No newline at end of file
diff --git a/system/config/error424.txt b/system/config/error424.txt
@@ -0,0 +1,4 @@
+---
+Title: Page does not exist
+---
+You can [create this page](javascript:showPane('cmspaneeditor');).
+\ No newline at end of file
diff --git a/system/config/text_english.ini b/system/config/text_english.ini
@@ -0,0 +1,19 @@
+// Yellow text strings
+// Format: key = text string
+
+language = en
+languageDescription = English
+languageAuthor = Mark Seuffert
+
+webinterfaceLoginText = Yellow login
+webinterfaceLoginEmail = Email:
+webinterfaceLoginPassword = Password:
+webinterfaceLoginButton = Login
+webinterfaceSaveButton = Save
+webinterfaceCancelButton = Cancel
+webinterfaceEdit = Edit
+webinterfaceShow = Show
+webinterfaceUser = User
+webinterfaceUserLogout = Logout
+webinterface424Title = New page
+webinterface424Text = Write text here
+\ No newline at end of file
diff --git a/system/config/user.ini b/system/config/user.ini
@@ -0,0 +1,4 @@
+// Yellow user accounts
+// Format: Email, password (sha256 with email prefix as salt), name, language
+
+// user@user.com,e1e2f704225259e91c44fb259c7db595e6cfd1a2e85a2b56508ab5aa9217d265,User,en
diff --git a/system/core/core.php b/system/core/core.php
@@ -5,27 +5,30 @@
// Yellow main class
class Yellow
{
- const Version = "0.0.0"; //Hello world!
-
- var $page; //current page data
- var $pages; //current page tree, top level
- var $toolbox; //toolbox with helpers
- var $config; //site configuration
- var $plugins; //site plugins
+ const Version = "0.1.0";
+ var $page; //current page data
+ var $pages; //current page tree, top level
+ var $toolbox; //toolbox with helpers
+ var $config; //site configuration
+ var $text; //site text strings
+ var $plugins; //site plugins
function __construct()
{
- $this->toolbox = new Yellow_Toolbox();
+ $this->toolbox = new Yellow_Toolbox();
$this->config = new Yellow_Config();
- $this->config->setDefault("sitename", "Yellow");
- $this->config->setDefault("author", "Yellow");
- $this->config->setDefault("language", "en");
+ $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");
$this->config->setDefault("parser", "markdown");
$this->config->setDefault("template", "default");
- $this->config->setDefault("baseLocation", $this->toolbox->getBaseLocation());
+ $this->config->setDefault("yellowVersion", Yellow::Version);
+ $this->config->setDefault("baseLocation", $this->toolbox->getBaseLocation());
$this->config->setDefault("stylesLocation", "/media/styles/");
$this->config->setDefault("imagesLocation", "/media/images/");
- $this->config->setDefault("pluginsLocation", "media/plugins/");
+ $this->config->setDefault("pluginsLocation", "media/plugins/");
$this->config->setDefault("systemDir", "system/");
$this->config->setDefault("configDir", "system/config/");
$this->config->setDefault("pluginDir", "system/plugins/");
@@ -33,700 +36,870 @@ class Yellow
$this->config->setDefault("templateDir", "system/templates/");
$this->config->setDefault("contentDir", "content/");
$this->config->setDefault("contentHomeDir", "1-home/");
- $this->config->setDefault("contentDefaultFile", "page");
+ $this->config->setDefault("contentDefaultFile", "page.txt");
$this->config->setDefault("contentExtension", ".txt");
- $this->config->setDefault("configExtension", ".ini");
+ $this->config->setDefault("configExtension", ".ini");
$this->config->setDefault("systemExtension", ".php");
$this->config->setDefault("configFile", "config.ini");
- $this->config->setDefault("yellowVersion", Yellow::Version);
- $this->config->load($this->config->get("configDir").$this->config->get("configFile"));
- $this->plugins = new Yellow_Plugins();
- }
+ $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);
+ }
- // Start CMS 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";
- }
+ // 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";
+ }
- // Process request
+ // Process request
function processRequest()
{
- $statusCode = 0;
- $baseLocation = $this->config->get("baseLocation");
- $location = $this->getRelativeLocation($baseLocation);
+ $statusCode = 0;
+ $baseLocation = $this->config->get("baseLocation");
+ $location = $this->getRelativeLocation($baseLocation);
$fileName = $this->getContentFileName($location);
- foreach($this->plugins->plugins as $key=>$value)
- {
+ foreach($this->plugins->plugins as $key=>$value)
+ {
if(method_exists($value["obj"], "onRequest"))
- {
+ {
$statusCode = $value["obj"]->onRequest($baseLocation, $location, $fileName);
if($statusCode) break;
- }
- }
- if($statusCode == 0) $statusCode = $this->processRequestFile($baseLocation, $location, $fileName, $statusCode);
- if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequest status:$statusCode, location:$location<br>\n";
- }
+ }
+ }
+ if($statusCode == 0) $statusCode = $this->processRequestFile($baseLocation, $location, $fileName, $statusCode);
+ if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequest status:$statusCode location:$location<br>\n";
+ }
- // 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");
- $fileName = $this->config->get("configDir").sprintf("error%d.txt", $statusCode);
- $fileHandle = @fopen($fileName, "r");
- if($fileHandle)
- {
- $fileData = fread($fileHandle, filesize($fileName));
- fclose($fileHandle);
- } else {
- die("Configuration problem: Can't open file '$fileName'!");
- }
- }
- if($fileData != "") $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode);
- 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));
- if($text != "") header($text);
- }
-
- // Send page response
- function sendPage($baseLocation, $location, $fileName, $fileData, $statusCode)
- {
- $this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config);
+ // 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");
+ $fileName = str_replace("(.*)", $statusCode, $this->config->get("configDir").$this->config->get("errorPageFile"));
+ $fileHandle = @fopen($fileName, "r");
+ if($fileHandle)
+ {
+ $fileData = fread($fileHandle, filesize($fileName));
+ fclose($fileHandle);
+ } else {
+ die("Configuration problem: Can't open file '$fileName'!");
+ }
+ }
+ if($fileData != "") $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode);
+ 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));
+ if($text != "") header($text);
+ }
+
+ // Send page response
+ function sendPage($baseLocation, $location, $fileName, $fileData, $statusCode)
+ {
+ $this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config);
$this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->toolbox, $this->config);
-
- $text = $this->page->getContentRawText();
+ $this->text->setLanguage($this->page->get("language"));
+
+ $text = $this->page->getContentRawText();
foreach($this->plugins->plugins as $key=>$value)
- {
+ {
if(method_exists($value["obj"], "onParseBefore"))
- {
+ {
$text = $value["obj"]->onParseBefore($text, $statusCode);
- }
- }
- if(is_null($this->plugins->plugins[$this->page->get("parser")])) die("Parser '".$this->page->get("parser")."' does not exist!");
+ }
+ }
+ if(!$this->plugins->isExisting($this->page->get("parser"))) die("Parser '".$this->page->get("parser")."' does not exist!");
$this->page->parser = $this->plugins->plugins[$this->page->get("parser")]["obj"];
$text = $this->page->parser->parse($text);
foreach($this->plugins->plugins as $key=>$value)
- {
+ {
if(method_exists($value["obj"], "onParseAfter"))
- {
+ {
$text = $value["obj"]->onParseAfter($text, $statusCode);
- }
- }
- $this->page->setContent($text);
+ }
+ }
+ $this->page->setContent($text);
if(!$this->page->isExisting("description"))
- {
- $this->page->set("description", $this->toolbox->createTextDescription($this->page->getContent(), 150));
+ {
+ $this->page->set("description", $this->toolbox->createTextDescription($this->page->getContent(), 150));
+ }
+ if(!$this->page->isExisting("keywords"))
+ {
+ $this->page->set("keywords", $this->toolbox->createTextKeywords($this->page->get("title"), 10));
}
- if(!$this->page->isExisting("keywords"))
- {
- $this->page->set("keywords", $this->toolbox->createTextKeywords($this->page->get("title"), 10));
- }
-
- $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!");
+
+ $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!");
global $yellow;
- require($fileName);
+ require($fileName);
}
- // Execute a template snippet
+ // Execute a template snippet
function snippet($snippet)
{
- $fileName = $this->config->get("snippetDir").$snippet.$this->config->get("systemExtension");
- if(!is_file($fileName)) die("Snippet '$snippet' does not exist!");
+ $fileName = $this->config->get("snippetDir").$snippet.$this->config->get("systemExtension");
+ if(!is_file($fileName)) die("Snippet '$snippet' does not exist!");
global $yellow;
require($fileName);
}
-
- // Return extra HTML header lines generated from plugins
+
+ // Return extra HTML header lines generated from plugins
function getHeaderExtra()
{
- $header = "";
+ $header = "";
foreach($this->plugins->plugins as $key=>$value)
- {
+ {
if(method_exists($value["obj"], "onHeaderExtra")) $header .= $value["obj"]->onHeaderExtra();
- }
- return $header;
- }
-
- // Return content location for current HTTP request, without base location
- function getRelativeLocation($baseLocation)
- {
- $location = $this->toolbox->getRequestLocation();
- $location = $this->toolbox->normaliseLocation($location);
- $position = strlen($baseLocation);
- return substr($location, $position);
- }
+ }
+ return $header;
+ }
+
+ // Return content location for current HTTP request, without base location
+ function getRelativeLocation($baseLocation)
+ {
+ $location = $this->toolbox->getRequestLocation();
+ $location = $this->toolbox->normaliseLocation($location);
+ $position = strlen($baseLocation);
+ return substr($location, $position);
+ }
// Return content file name from location
function getContentFileName($location)
{
- return $this->toolbox->findFileFromLocation($location,
- $this->config->get("contentDir"), $this->config->get("contentHomeDir"),
- $this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
+ return $this->toolbox->findFileFromLocation($location,
+ $this->config->get("contentDir"), $this->config->get("contentHomeDir"),
+ $this->config->get("contentDefaultFile"), $this->config->get("contentExtension"));
}
-
+
// Return content directory from location
function getContentDirectory($location)
{
- return $this->toolbox->findFileFromLocation($location,
- $this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", "");
+ return $this->toolbox->findFileFromLocation($location,
+ $this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", "");
}
-
- // Register plugin
+
+ // Register plugin
function registerPlugin($name, $class, $version)
{
- $this->plugins->register($name, $class, $version);
+ $this->plugins->register($name, $class, $version);
}
}
// Yellow page data
class Yellow_Page
{
- 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 $rawTextPos; //raw text of page (unparsed)
- var $active; //page is active?
+ 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 $rawTextPos; //raw text of page (unparsed)
+ var $active; //page is active?
+ var $hidden; //page is hidden?
- function __construct($baseLocation, $location, $fileName, $rawData, $toolbox, $config)
- {
- $this->baseLocation = $baseLocation;
- $this->location = $location;
- $this->fileName = $fileName;
- $this->setRawData($rawData, $toolbox, $config);
- $this->active = $toolbox->isActiveLocation($baseLocation, $location);
- }
-
- // Set page raw data
+ function __construct($baseLocation, $location, $fileName, $rawData, $toolbox, $config)
+ {
+ $this->baseLocation = $baseLocation;
+ $this->location = $location;
+ $this->fileName = $fileName;
+ $this->setRawData($rawData, $toolbox, $config);
+ $this->active = $toolbox->isActiveLocation($baseLocation, $location);
+ $this->hidden = $toolbox->isHiddenLocation($baseLocation, $location, $fileName, $config->get("contentDir"));
+ }
+
+ // Set page raw data
function setRawData($rawData, $toolbox, $config)
{
- $this->metaData = array();
- $this->rawData = $rawData;
- $this->rawTextPos = 0;
- $this->set("title", $toolbox->createTextTitle($this->location));
+ $this->metaData = array();
+ $this->rawData = $rawData;
+ $this->rawTextPos = 0;
+ $this->set("title", $toolbox->createTextTitle($this->location));
$this->set("author", $config->get("author"));
- $this->set("language", $config->get("language"));
+ $this->set("language", $config->get("language"));
$this->set("parser", $config->get("parser"));
$this->set("template", $config->get("template"));
-
+
if(preg_match("/^(\-\-\-[\r\n]+)(.+?)([\r\n]+\-\-\-[\r\n]+)/s", $rawData, $parsed))
- {
- $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]) + strlen($parsed[3]);
- preg_match_all("/([^\:\r\n]+)\s*\:\s*([^\r\n]+)/s", $parsed[2], $matches, PREG_SET_ORDER);
- foreach($matches as $match)
- {
- $this->set(strtolower($match[1]), $match[2]);
- }
- } else if(preg_match("/^([^\r\n]+)([\r\n]+=+[\r\n]+)/", $rawData, $parsed)) {
- $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]);
- $this->set("title", $parsed[1]);
- }
+ {
+ $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]) + strlen($parsed[3]);
+ preg_match_all("/([^\:\r\n]+)\s*\:\s*([^\r\n]+)/s", $parsed[2], $matches, PREG_SET_ORDER);
+ foreach($matches as $match)
+ {
+ $this->set(strtolower($match[1]), $match[2]);
+ }
+ } else if(preg_match("/^([^\r\n]+)([\r\n]+=+[\r\n]+)/", $rawData, $parsed)) {
+ $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]);
+ $this->set("title", $parsed[1]);
+ }
}
- // Set page meta data
+ // Set page meta data
function set($key, $value)
{
$this->metaData[$key] = $value;
}
- // Return page meta data
+ // Return page meta data
function get($key)
{
- return is_null($this->metaData[$key]) ? "" : $this->metaData[$key];
+ return $this->IsExisting($key) ? $this->metaData[$key] : "";
}
- // Return page meta data, HTML encoded
+ // Return page meta data, HTML encoded
function getHtml($key)
{
return htmlspecialchars($this->get($key));
}
- // 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()
- {
- return $this->parser->html;
- }
-
- // Return page content, raw text
- function getContentRawText()
- {
- return substr($this->rawData, $this->rawTextPos);
- }
-
- // Return absolut page location
- function getLocation()
- {
- return $this->baseLocation.$this->location;
- }
-
- // Check if meta data exists
- function isExisting($key)
- {
- return !is_null($this->metaData[$key]);
- }
-
- // Check if page is active
- function isActive()
- {
- return $this->active;
- }
+ // 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()
+ {
+ return $this->parser->html;
+ }
+
+ // Return page content, raw text
+ function getContentRawText()
+ {
+ return substr($this->rawData, $this->rawTextPos);
+ }
+
+ // Return absolut page location
+ function getLocation()
+ {
+ return $this->baseLocation.$this->location;
+ }
+
+ // Check if meta data exists
+ function isExisting($key)
+ {
+ return !is_null($this->metaData[$key]);
+ }
+
+ // Check if page is active
+ function isActive()
+ {
+ return $this->active;
+ }
+
+ // Check if page is active
+ function isHidden()
+ {
+ return $this->hidden;
+ }
}
// Yellow page tree from file system
class Yellow_Pages
{
- var $pages; //scanned pages
-
- function __construct($baseLocation, $toolbox, $config)
- {
- $this->scan($baseLocation, $toolbox, $config);
- }
-
- // Scan top-level pages
- function scan($baseLocation, $toolbox, $config)
- {
- $this->pages = array();
- foreach($toolbox->getDirectoryEntries($config->get("contentDir"), "/^[\d\-\.]+(.*)$/", true) as $entry)
- {
- $fileName = $config->get("contentDir").$entry."/".$config->get("contentDefaultFile").$config->get("contentExtension");
- $location = $toolbox->findLocationFromFile($fileName, $config->get("contentDir"), $config->get("contentHomeDir"),
- $config->get("contentDefaultFile"), $config->get("contentExtension"));
- $fileHandle = @fopen($fileName, "r");
- if($fileHandle)
- {
- $fileData = fread($fileHandle, 4096);
- fclose($fileHandle);
- } else {
- $fileData = "";
- }
- $page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $toolbox, $config);
- array_push($this->pages, $page);
- }
- }
-
- // Return top-level pages
- function root()
- {
- return $this->pages;
- }
+ var $pages; //scanned pages
+
+ function __construct($baseLocation, $toolbox, $config)
+ {
+ $this->scan($baseLocation, $toolbox, $config);
+ }
+
+ // Scan top-level pages
+ function scan($baseLocation, $toolbox, $config)
+ {
+ $this->pages = array();
+ foreach($toolbox->getDirectoryEntries($config->get("contentDir"), "/.*/", true) as $entry)
+ {
+ $fileName = $config->get("contentDir").$entry."/".$config->get("contentDefaultFile");
+ $location = $toolbox->findLocationFromFile($fileName, $config->get("contentDir"), $config->get("contentHomeDir"),
+ $config->get("contentDefaultFile"), $config->get("contentExtension"));
+ $fileHandle = @fopen($fileName, "r");
+ if($fileHandle)
+ {
+ $fileData = fread($fileHandle, 4096);
+ fclose($fileHandle);
+ } else {
+ $fileData = "";
+ }
+ $page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $toolbox, $config);
+ array_push($this->pages, $page);
+ }
+ }
+
+ // Return top-level pages
+ function root($showHidden = false)
+ {
+ $pages = array();
+ foreach($this->pages as $page)
+ {
+ if($showHidden || !$page->isHidden()) array_push($pages, $page);
+ }
+ return $pages;
+ }
}
-
+
// Yellow toolbox with helpers
class Yellow_Toolbox
{
- // Return location from current HTTP request
- static function getRequestLocation()
- {
- $uri = $_SERVER["REQUEST_URI"];
- return ($pos = strpos($uri, '?')) ? substr($uri, 0, $pos) : $uri;
- }
+ // Return location from current HTTP request
+ static function getRequestLocation()
+ {
+ $uri = $_SERVER["REQUEST_URI"];
+ return ($pos = strpos($uri, '?')) ? substr($uri, 0, $pos) : $uri;
+ }
- // Return arguments from current HTTP request
- static function getRequestLocationArguments()
- {
- $uri = $_SERVER["REQUEST_URI"];
- return ($pos = strpos($uri, '?')) ? substr($uri, $pos+1) : "";
- }
-
- // Return base location
- static function getBaseLocation()
- {
- $baseLocation = "/";
- if(preg_match("/^(.*)\//", $_SERVER["SCRIPT_NAME"], $matches)) $baseLocation = $matches[1];
- return $baseLocation;
- }
-
- // Normalise location and remove incorrect path tokens
- static function normaliseLocation($location)
- {
- $str = str_replace('\\', '/', rawurldecode($location));
- $location = ($str[0]=='/') ? '' : '/';
- for($pos=0; $pos<strlen($str); ++$pos)
- {
- if($str[$pos] == '/')
- {
- if($str[$pos+1] == '/') continue;
- if($str[$pos+1] == '.')
- {
- $posNew = $pos+1; while($str[$posNew] == '.') ++$posNew;
- if($str[$posNew]=='/' || $str[$posNew]=='')
- {
- $pos = $posNew-1;
- continue;
- }
- }
- }
- $location .= $str[$pos];
- }
- return $location;
- }
-
- // Check if location is specifying file or directory
- static function isFileLocation($location)
- {
- return substr($location,-1,1) != "/";
- }
-
- // Check if location is within current HTTP request
- static function isActiveLocation($baseLocation, $location)
- {
- $currentLocation = substr(self::getRequestLocation(), strlen($baseLocation));
- if($location != "/")
- {
- $active = substr($currentLocation, 0, strlen($location))==$location;
- } else {
- $active = $currentLocation==$location;
- }
- return $active;
- }
-
- // Find file path from location
- static function findFileFromLocation($location, $pathBase, $pathHome, $fileDefault, $fileExtension)
- {
- $path = $pathBase;
- if($location != "/")
- {
- $tokens = explode('/', $location);
- for($i=1; $i<count($tokens)-1; ++$i)
- {
- $entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i]."$/");
- if(!empty($entries)) $tokens[$i] = $entries[0];
- $path .= "$tokens[$i]/";
- }
- if($tokens[$i] != "")
- {
- $path .= $tokens[$i].$fileExtension;
- } else {
- $path .= $fileDefault.$fileExtension;
- }
- } else {
- $path .= $pathHome.$fileDefault.$fileExtension;
- }
- return $path;
- }
-
- // Find location from file path
- static function findLocationFromFile($fileName, $pathBase, $pathHome, $fileDefault, $fileExtension)
- {
- $location = "/";
- if(substr($fileName, 0, strlen($pathBase)) == $pathBase) $fileName = substr($fileName, strlen($pathBase));
- if(substr($fileName, 0, strlen($pathHome)) != $pathHome)
- {
- $tokens = explode('/', $fileName);
- for($i=0; $i<count($tokens)-1; ++$i)
- {
- if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1];
- $location .= "$tokens[$i]/";
- }
- if($tokens[$i] != $fileDefault.$fileExtension)
- {
- $location .= substr($tokens[$i], 0, -strlen($fileExtension)-1);
- }
- } else {
- if($fileName != $pathHome.$fileDefault.$fileExtension)
- {
- $location .= substr($fileName, $pathHome, -strlen($fileExtension)-1);
- }
- }
- return $location;
- }
-
- // Return human readable HTTP server status
- static function getHttpStatusFormated($statusCode)
- {
- switch($statusCode)
- {
- case 301: $text = "$_SERVER[SERVER_PROTOCOL] 301 Moved permanently"; break;
- case 302: $text = "$_SERVER[SERVER_PROTOCOL] 302 Moved temporarily"; break;
- case 304: $text = "$_SERVER[SERVER_PROTOCOL] 304 Not modified"; break;
- case 404: $text = "$_SERVER[SERVER_PROTOCOL] 404 Not found"; break;
- case 424: $text = "$_SERVER[SERVER_PROTOCOL] 424 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)
- {
- if(substr($entry, 0, 1) == ".") continue;
- 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;
- }
+ // Return arguments from current HTTP request
+ static function getRequestLocationArguments()
+ {
+ $uri = $_SERVER["REQUEST_URI"];
+ return ($pos = strpos($uri, '?')) ? substr($uri, $pos+1) : "";
+ }
+
+ // Return base location
+ static function getBaseLocation()
+ {
+ $baseLocation = "/";
+ if(preg_match("/^(.*)\//", $_SERVER["SCRIPT_NAME"], $matches)) $baseLocation = $matches[1];
+ return $baseLocation;
+ }
+
+ // Normalise location and remove incorrect path tokens
+ static function normaliseLocation($location)
+ {
+ $str = str_replace('\\', '/', rawurldecode($location));
+ $location = ($str[0]=='/') ? '' : '/';
+ for($pos=0; $pos<strlen($str); ++$pos)
+ {
+ if($str[$pos] == '/')
+ {
+ if($str[$pos+1] == '/') continue;
+ if($str[$pos+1] == '.')
+ {
+ $posNew = $pos+1; while($str[$posNew] == '.') ++$posNew;
+ if($str[$posNew]=='/' || $str[$posNew]=='')
+ {
+ $pos = $posNew-1;
+ continue;
+ }
+ }
+ }
+ $location .= $str[$pos];
+ }
+ return $location;
+ }
+
+ // Check if location is specifying file or directory
+ static function isFileLocation($location)
+ {
+ return substr($location,-1,1) != "/";
+ }
+
+ // Check if location is within current HTTP request
+ static function isActiveLocation($baseLocation, $location)
+ {
+ $currentLocation = substr(self::getRequestLocation(), strlen($baseLocation));
+ if($location != "/")
+ {
+ $active = substr($currentLocation, 0, strlen($location))==$location;
+ } else {
+ $active = $currentLocation==$location;
+ }
+ return $active;
+ }
+
+ // Check if location is within visible collection
+ static function isHiddenLocation($baseLocation, $location, $fileName, $pathBase)
+ {
+ $hidden = false;
+ if(substr($fileName, 0, strlen($pathBase)) == $pathBase) $fileName = substr($fileName, strlen($pathBase));
+ $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;
+ if($location != "/")
+ {
+ $tokens = explode('/', $location);
+ for($i=1; $i<count($tokens)-1; ++$i)
+ {
+ $entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i]."$/");
+ if(!empty($entries)) $tokens[$i] = $entries[0];
+ $path .= "$tokens[$i]/";
+ }
+ if($tokens[$i] != "")
+ {
+ $path .= $tokens[$i].$fileExtension;
+ } else {
+ $path .= $fileDefault;
+ }
+ } else {
+ $path .= $pathHome.$fileDefault;
+ }
+ return $path;
+ }
+
+ // Find location from file path
+ static function findLocationFromFile($fileName, $pathBase, $pathHome, $fileDefault, $fileExtension)
+ {
+ $location = "/";
+ if(substr($fileName, 0, strlen($pathBase)) == $pathBase) $fileName = substr($fileName, strlen($pathBase));
+ if(substr($fileName, 0, strlen($pathHome)) != $pathHome)
+ {
+ $tokens = explode('/', $fileName);
+ for($i=0; $i<count($tokens)-1; ++$i)
+ {
+ if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1];
+ $location .= "$tokens[$i]/";
+ }
+ if($tokens[$i] != $fileDefault)
+ {
+ $location .= substr($tokens[$i], 0, -strlen($fileExtension)-1);
+ }
+ } else {
+ if($fileName != $pathHome.$fileDefault)
+ {
+ $location .= substr($fileName, $pathHome, -strlen($fileExtension)-1);
+ }
+ }
+ 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;
+ 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)
+ {
+ if(substr($entry, 0, 1) == ".") continue;
+ 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;
+ }
- // Create description from text
- static function createTextDescription($text, $lengthMax)
- {
- $description = "";
- preg_match_all("/\<p\>(.+?\<\/p\>)/s", $text, $parsedDescription, PREG_SET_ORDER);
- foreach($parsedDescription as $matches)
- {
- preg_match_all("/([^\<]*)[^\>]+./s", $matches[1], $parsedUndoTag, PREG_SET_ORDER);
- if(count($parsedUndoTag) > 0)
- {
- if(!empty($description)) $description .= " ";
- foreach($parsedUndoTag as $matchTag)
- {
- $description .= preg_replace("/[\\x00-\\x1f]+/s", " ", $matchTag[1]);
- }
- }
- if(strlen($description) > $lengthMax)
- {
- $description = substr($description, 0, $lengthMax-3)."...";
- break;
- }
- }
- return $description;
- }
+ // Create description from text
+ static function createTextDescription($text, $lengthMax)
+ {
+ $description = "";
+ preg_match_all("/\<p\>(.+?\<\/p\>)/s", $text, $parsedDescription, PREG_SET_ORDER);
+ foreach($parsedDescription as $matches)
+ {
+ preg_match_all("/([^\<]*)[^\>]+./s", $matches[1], $parsedUndoTag, PREG_SET_ORDER);
+ if(count($parsedUndoTag) > 0)
+ {
+ if(!empty($description)) $description .= " ";
+ foreach($parsedUndoTag as $matchTag)
+ {
+ $description .= preg_replace("/[\\x00-\\x1f]+/s", " ", $matchTag[1]);
+ }
+ }
+ if(strlen($description) > $lengthMax)
+ {
+ $description = substr($description, 0, $lengthMax-3)."...";
+ break;
+ }
+ }
+ return $description;
+ }
- // Create keywords from text string
- static function createTextKeywords($text, $keywordsMax)
- {
- $tokens = preg_split("/[,\s\(\)]/", strtolower($text));
- foreach($tokens as $key => $value) if(strlen($value) < 3) unset($tokens[$key]);
- 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;
- }
+ // Create keywords from text string
+ static function createTextKeywords($text, $keywordsMax)
+ {
+ $tokens = preg_split("/[,\s\(\)]/", strtolower($text));
+ foreach($tokens as $key => $value) if(strlen($value) < 3) unset($tokens[$key]);
+ 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
+ function detectBrowserLanguage($languagesAllowed, $languageDefault)
+ {
+ $language = $languageDefault;
+ if(isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
+ {
+ foreach(preg_split("/,\s*/", $_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $string)
+ {
+ $tokens = split(";", $string, 2);
+ if(in_array($tokens[0], $languagesAllowed))
+ {
+ $language = $tokens[0];
+ break;
+ }
+ }
+ }
+ return $language;
+ }
- // Detect PNG and JPG image dimensions
- static function detectImageDimensions($fileName)
- {
- $width = $height = 0;
- $fileHandle = @fopen($fileName, "rb");
- if($fileHandle)
- {
- if(substr($fileName, -3) == "png")
- {
- $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]);
- }
- } else if(substr($fileName, -3) == "jpg") {
- $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);
- }
+ // Detect PNG and JPG image dimensions
+ static function detectImageDimensions($fileName)
+ {
+ $width = $height = 0;
+ $fileHandle = @fopen($fileName, "rb");
+ if($fileHandle)
+ {
+ if(substr($fileName, -3) == "png")
+ {
+ $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]);
+ }
+ } else if(substr($fileName, -3) == "jpg") {
+ $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);
+ }
- // 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);
- }
+ // 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);
+ }
}
// 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)
- {
- foreach($fileData as $line)
- {
- if(preg_match("/^\//", $line)) continue;
- preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
- if($matches[1]!="" && $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 is_null($this->config[$key]) ? $this->configDefaults[$key] : $this->config[$key];
- }
-
- // Return configuration, HTML encoded
- function getHtml($key)
- {
- return htmlspecialchars($this->get($key));
- }
-
- // Check if configuration exists
- function isExisting($key)
- {
- return !is_null($this->config[$key]);
- }
+ 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($matches[1]!="" && $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($filterEnd == "")
+ {
+ $config = $this->config;
+ } else {
+ foreach($this->config as $key=>$value)
+ {
+ if(substr($key, -strlen($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" && $matches[2]!="") { $language = $matches[2]; break; }
+ }
+ foreach($fileData as $line)
+ {
+ if(preg_match("/^\//", $line)) continue;
+ preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches);
+ if($language!="" && $matches[1]!="" && $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
+ 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)
+ {
+ if(substr($key, 0, strlen("language")) == "language") $text[$key] = $value;
+ if(substr($key, 0, strlen($filterStart)) == $filterStart) $text[$key] = $value;
+ }
+ }
+ }
+ return $text;
+ }
+
+ // 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
{
- var $plugins; //registered plugins
+ var $plugins; //registered plugins
- function __construct()
- {
- $this->plugins = array();
- }
-
- // Load plugins
- function load()
+ function __construct()
+ {
+ $this->plugins = array();
+ }
+
+ // Load plugins
+ function load()
{
global $yellow;
- require_once("core_markdown.php");
- require_once("core_rawhtml.php");
- foreach($yellow->toolbox->getDirectoryEntries($yellow->config->get("pluginDir")) as $entry)
- {
- $fileName = "$entry/plugin_$entry.php";
- if(is_file($fileName)) require_once($fileName);
- }
- foreach($this->plugins as $key=>$value)
+ 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)
{
- $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);
- }
+ $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);
+ }
}
}
-
- // Register plugin
+
+ // Register plugin
function register($name, $class, $version)
{
- if(is_null($this->plugins[$name]))
- {
- $this->plugins[$name] = array();
- $this->plugins[$name]["class"] = $class;
- $this->plugins[$name]["version"] = $version;
- }
+ 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]);
}
}
?>
\ No newline at end of file
diff --git a/system/core/core_markdown.php b/system/core/core_markdown.php
@@ -5,51 +5,60 @@
// Markdown parser core plugin
class Yellow_Markdown
{
- var $markdown; //markdown parser
- var $html; //generated HTML
-
- // Initialise plugin
+ const Version = "0.1.1";
+ var $markdown; //markdown parser
+ var $html; //generated HTML
+
+ // Initialise plugin
function initPlugin($yellow)
{
$this->markdown = new Yellow_MarkdownExtraParser($yellow);
}
-
- // Parse text
+
+ // Parse text
function parse($text)
{
return $this->html = $this->markdown->transform($text);
}
}
-
+
require("markdown.php");
class Yellow_MarkdownExtraParser extends MarkdownExtra_Parser
{
- var $yellow; //access to API
+ var $yellow; //access to API
- function __construct($yellow)
- {
- $this->yellow = $yellow;
- parent::__construct();
- }
-
- // Handle images
+ function __construct($yellow)
+ {
+ $this->yellow = $yellow;
+ parent::__construct();
+ }
+
+ // Transform text
+ function transform($text)
+ {
+ $baseLocation = $this->yellow->config->get("baseLocation");
+ $text = preg_replace("/@baseLocation/i", $baseLocation, $text);
+ return parent::transform($text);
+ }
+
+ // Handle images
function _doImages_inline_callback($matches)
- {
+ {
$path = $matches[3]=="" ? $matches[4] : $matches[3];
- $src = $this->yellow->config->get("baseLocation").$this->yellow->config->get("imagesLocation").$path;
- list($width, $height) = $this->yellow->toolbox->detectImageDimensions(".".$this->yellow->config->get("imagesLocation").$path);
+ $src = $this->yellow->config->get("baseLocation").$this->yellow->config->get("imagesLocation").$path;
+ list($width, $height) = $this->yellow->toolbox->detectImageDimensions(".".$this->yellow->config->get("imagesLocation").$path);
$alt = $matches[2];
- $title =& $matches[7];
-
+ $title = $matches[7];
+
$result = "<img src=\"".$this->encodeAttribute($src)."\"";
- if($width && $height) $result .= " width=\"$width\" height=\"$height\"";
- if(isset($alt)) $result .= " alt=\"".$this->encodeAttribute($alt)."\"";
+ if($width && $height) $result .= " width=\"$width\" height=\"$height\"";
+ if(isset($alt)) $result .= " alt=\"".$this->encodeAttribute($alt)."\"";
if(isset($title)) $result .= " title=\"".$this->encodeAttribute($title)."\"";
$result .= $this->empty_element_suffix;
-
+
return $this->hashPart($result);
}
}
-$yellow->registerPlugin("markdown", "Yellow_Markdown", "0.1.0");
+$yellow->registerPlugin("markdown", "Yellow_Markdown", Yellow_Markdown::Version);
?>
\ No newline at end of file
diff --git a/system/core/core_rawhtml.php b/system/core/core_rawhtml.php
@@ -5,14 +5,15 @@
// Raw HTML parser core plugin
class Yellow_RawHtml
{
- var $html; //generated HTML
+ const Version = "0.1.1";
+ var $html; //generated HTML
- // Parse text, dummy transformation
+ // Parse text, dummy transformation
function parse($text)
{
return $this->html = $text;
}
}
-$yellow->registerPlugin("rawhtml", "Yellow_RawHtml", "0.1.0");
+$yellow->registerPlugin("rawhtml", "Yellow_RawHtml", Yellow_RawHtml::Version);
?>
\ No newline at end of file
diff --git a/system/core/core_webinterface.css b/system/core/core_webinterface.css
@@ -0,0 +1,25 @@
+.yellowlogin { width:600px; position:absolute; top:5px; padding:30px; border:1px solid #ccc; background:#fff; color:#000; }
+.yellowlogin h1 { margin:0px; padding:0px; }
+.yellowlogin p { margin:0.5em; text-align:right; }
+
+.yellowbar { width:600px; position:absolute; top:1px; background:#fff; color:#000; }
+.yellowbar img { vertical-align:top; }
+.yellowbar button { color:#05d; padding-left:0.5em; padding-right:0.5em; }
+.yellowbar button:hover { color:#f00; }
+.yellowbarleft { margin-left:0px; display:block; float:left; height:100%; }
+.yellowbarright { margin-right:0px; display:block; float:right; height:100%; }
+.yellowbarlink { cursor:pointer; font:inherit; background:none; border:none; margin:0px padding:0px; }
+.yellowbubble { -webkit-border-radius:4px; -moz-border-radius:4px; border-radius:4px; }
+
+.yellowpane { position:absolute; display:none; margin:0px; padding:5px; border:solid 1px #ccc; background:#fff; color:#000; z-index:10; }
+.yellowpane a { text-decoration:none; color:#000; }
+.yellowpane a:hover { text-decoration:none; color:#f00; }
+.yellowpane p { margin:0.5em; }
+.yellowpane ul { list-style:none; margin:0em 0.5em; padding:0px; }
+
+#yellowpaneedit { }
+#yellowpaneshow { min-width:250px; overflow:auto; }
+#yellowpaneuser { }
+#yellowedittext { margin:0px; margin-bottom:5px; padding:5px; border:solid 1px #ccc; resize:none; font-size:0.9em }
+#yelloweditbuttons { margin-bottom:5px; width:100%; }
+#yelloweditbuttons input { margin-left:5px; }
+\ No newline at end of file
diff --git a/system/core/core_webinterface.js b/system/core/core_webinterface.js
@@ -0,0 +1,243 @@
+// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Yellow main API
+var yellow =
+{
+ version: "0.0.0", //Hello web interface!
+ onClick: function(e) { yellow.webinterface.hidePanesOnClick(e); },
+ onShow: function(id) { yellow.webinterface.showPane(id); },
+ onReset: function(id) { yellow.webinterface.resetPane(id); },
+ onResize: function() { yellow.webinterface.resizePanes(); },
+ webinterface:{}, page:{}, pages:{}, toolbox:{}, config:{}, text:{}
+}
+
+// Yellow web interface
+yellow.webinterface =
+{
+ created: false, //interface created? (boolean)
+ timerId: 0, //interface timer ID
+ heightOld: 0, //height of big panes
+
+ // Initialise web interface
+ init: function()
+ {
+ this.intervalId = window.setInterval("yellow.webinterface.create()", 1);
+ window.onresize = yellow.onResize;
+ window.onclick = yellow.onClick;
+ },
+
+ // Create action bar and panes
+ create: function()
+ {
+ var body = document.getElementsByTagName("body")[0];
+ if(!body || !body.firstChild || this.created) return;
+ if(yellow.debug) console.log("yellow.webinterface.create email:"+yellow.config.userEmail+" "+yellow.config.userName);
+ if(yellow.config.userEmail)
+ {
+ var location = yellow.config.baseLocation+yellow.config.pluginsLocation;
+ var element = document.createElement("div");
+ element.className = "yellowbar";
+ element.setAttribute("id", "yellowbar");
+ element.innerHTML =
+ "<div class=\"yellowbarleft\">"+
+ "<img src=\""+location+"core_webinterface.png\" width=\"16\" height=\"16\"> Yellow"+
+ "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneedit');\">"+this.getText("Edit")+"</button>"+
+ "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneshow');\">"+this.getText("Show")+"</button>"+
+ "</div>"+
+ "<div class=\"yellowbarright\">"+
+ "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneuser');\" id=\"yellowusername\">"+this.getText("User")+"</button>"+
+ "</div>";
+ body.insertBefore(element, body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellowpaneedit"), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellowpaneshow", yellow.pages), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellowpaneuser"), body.firstChild);
+ yellow.toolbox.setText(document.getElementById("yellowusername"), yellow.config.userName+" ↓");
+ yellow.toolbox.setText(document.getElementById("yellowedittext"), yellow.page.rawData);
+ } else {
+ var element = document.createElement("div");
+ element.className = "yellowlogin yellowbubble";
+ element.setAttribute("id", "yellowlogin");
+ element.innerHTML =
+ "<form method=\"post\" name=\"formlogin\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"login\"/>"+
+ "<h1>"+this.getText("LoginText")+"</h1>"+
+ "<p>"+this.getText("LoginEmail")+" <input name=\"email\" maxlength=\"64\" /></p>"+
+ "<p>"+this.getText("LoginPassword")+" <input type=\"password\" name=\"password\" maxlength=\"64\" /></p>"+
+ "<p><input type=\"submit\" value=\""+this.getText("LoginButton")+"\"/></p>"+
+ "</form>";
+ body.insertBefore(element, body.firstChild);
+ }
+ window.clearInterval(this.intervalId);
+ this.created = true;
+ this.resizePanes(true);
+ },
+
+ // Create pane
+ createPane: function (id, data)
+ {
+ if(yellow.debug) console.log("yellow.webinterface.createPane id:"+id);
+ var outDiv = document.createElement("div");
+ if(id == "yellowpaneedit")
+ {
+ outDiv.innerHTML =
+ "<p>Editing page...</p>"+
+ "<form method=\"post\" name=\"formeditor\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"edit\"/>"+
+ "<textarea id=\"yellowedittext\" name=\"rawdata\"></textarea>"+
+ "<div id=\"yelloweditbuttons\">"+
+ "<input type=\"submit\" value=\""+this.getText("SaveButton")+"\"/>"+
+ "<input type=\"button\" value=\""+this.getText("CancelButton")+"\" onclick=\"yellow.onReset('yellowpaneedit');\"/>"+
+ "</div>"+
+ "</form>";
+ } else if(id == "yellowpaneshow") {
+ outDiv.innerHTML = "<p>Showing files...</p>";
+ for(var n in data)
+ {
+ var outUl = document.createElement("ul");
+ var outLi = document.createElement("li");
+ var outA = document.createElement("a");
+ outA.setAttribute("href", data[n]["location"]);
+ yellow.toolbox.setText(outA, data[n]["title"]);
+ outLi.appendChild(outA);
+ outUl.appendChild(outLi);
+ outDiv.appendChild(outUl);
+ }
+ } else if(id == "yellowpaneuser") {
+ outDiv.innerHTML =
+ "<p>"+yellow.config.userEmail+"</p>"+
+ "<form method=\"post\" name=\"formlogout\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"logout\"/>"+
+ "<p><a href=\"javascript:document.formlogout.submit();\">"+this.getText("UserLogout")+"</a></p> "+
+ "</form>";
+ }
+ var element = document.createElement("div");
+ element.className = "yellowpane yellowbubble";
+ element.setAttribute("id", id);
+ element.appendChild(outDiv);
+ return element;
+ },
+
+ // Reset pane
+ resetPane: function(id)
+ {
+ if(id == "yellowpaneedit")
+ {
+ document.formeditor.reset();
+ yellow.toolbox.setText(document.getElementById("yellowedittext"), yellow.page.rawData);
+ this.hidePane(id);
+ }
+ },
+
+ // Show pane
+ showPane: function(id)
+ {
+ if(document.getElementById(id).style.display == "block")
+ {
+ this.hidePanes();
+ } else {
+ this.hidePanes();
+ if(yellow.debug) console.log("yellow.webinterface.showPane id:"+id);
+ document.getElementById(id).style.display = "block";
+ this.resizePanes(true);
+ }
+ },
+
+ // Hide pane
+ hidePane: function(id)
+ {
+ if(document.getElementById(id)) document.getElementById(id).style.display = "none";
+ },
+
+ // Hide all panes
+ hidePanes: function ()
+ {
+ for(var element=document.getElementById("yellowbar"); element; element=element.nextSibling)
+ {
+ if(element.className && element.className.indexOf("yellowpane")>=0)
+ {
+ this.hidePane(element.getAttribute("id"));
+ }
+ }
+ },
+
+ // Hide all panes on mouse click
+ hidePanesOnClick: function(e)
+ {
+ var element = e.target || e.srcElement;
+ while(element = element.parentNode)
+ {
+ if(element.className)
+ {
+ if(element.className.indexOf("yellowpane")>=0 || element.className.indexOf("yellowbar")>=0) return;
+ }
+ }
+ this.hidePanes();
+ },
+
+ // Resize panes, recalculate height and width where needed
+ resizePanes: function(force)
+ {
+ var interfaceHeight = Number(window.innerHeight);
+ if((interfaceHeight!=this.heightOld || force) && document.getElementById("yellowbar"))
+ {
+ this.heightOld = interfaceHeight;
+ var elementBar = document.getElementById("yellowbar");
+ var borderRadius = 6;
+ var panePadding = 5;
+ var editPadding = 5;
+ var interfaceTop = elementBar.offsetHeight + 1;
+ interfaceHeight -= interfaceTop + borderRadius*2;
+ if(yellow.debug) console.log("yellow.webinterface.resizePanes windowY:"+interfaceHeight+" actionbarY:"+document.getElementById("yellowbar").offsetHeight+" buttonsY:"+document.getElementById("yelloweditbuttons").offsetHeight+" editorX:"+document.getElementById("yellowpaneedit").offsetWidth);
+
+ this.setPaneHeight(document.getElementById("yellowpaneedit"), interfaceHeight, null, interfaceTop);
+ this.setPaneHeight(document.getElementById("yellowpaneshow"), null, interfaceHeight, interfaceTop);
+ this.setPaneHeight(document.getElementById("yellowpaneuser"), null, null, interfaceTop);
+
+ var editTextHeight = interfaceHeight - panePadding*2 - editPadding*2 - 10
+ - (document.getElementById("yellowedittext").offsetTop-document.getElementById("yellowpaneedit").getElementsByTagName("p")[0].offsetTop)
+ - document.getElementById("yelloweditbuttons").offsetHeight;
+ document.getElementById("yellowpaneedit").style.width = (elementBar.offsetWidth - panePadding*2).toString()+"px";
+ document.getElementById("yellowedittext").style.height = editTextHeight.toString()+"px";
+ document.getElementById("yellowedittext").style.width = (document.getElementById("yellowpaneedit").offsetWidth - 2 - panePadding*2 - editPadding*2).toString()+"px";
+ document.getElementById("yellowpaneuser").style.marginLeft = (elementBar.offsetWidth - document.getElementById("yellowpaneuser").offsetWidth).toString()+"px";
+ }
+ },
+
+ // Set pane height
+ setPaneHeight: function(element, height, maxHeight, top)
+ {
+ if(maxHeight)
+ {
+ element.style.maxHeight = maxHeight.toString()+"px";
+ } else if(height) {
+ element.style.height = height.toString()+"px";
+ }
+ element.style.top = top+"px";
+ },
+
+ // Return text string
+ getText: function(key)
+ {
+ return ("webinterface"+key in yellow.text) ? yellow.text["webinterface"+key] : "[webinterface"+key+"]";
+ }
+}
+
+// Yellow toolbox with helpers
+yellow.toolbox =
+{
+ // Set element text
+ setText: function(element, text)
+ {
+ while(element.firstChild!==null) element.removeChild(element.firstChild);
+ element.appendChild(document.createTextNode(text));
+ },
+
+ // Insert element after element
+ insertAfter: function(newElement, referenceElement)
+ {
+ referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
+ }
+}
+
+yellow.webinterface.init();
+\ No newline at end of file
diff --git a/system/core/core_webinterface.php b/system/core/core_webinterface.php
@@ -0,0 +1,317 @@
+<?php
+// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Web interface core plugin
+class Yellow_Webinterface
+{
+ const Version = "0.0.0"; //Hello web interface!
+ var $yellow; //access to API
+ var $users; //web interface users
+ var $activeLocation; //web interface location? (boolean)
+ var $activeUserFail; //web interface login failed (boolean)
+ var $activeUserEmail; //web interface user currently logged in
+
+ // Initialise plugin
+ function initPlugin($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->yellow->config->setDefault("webinterfaceLocation", "/wiki/");
+ $this->yellow->config->setDefault("webinterfaceUserFile", "user.ini");
+ $this->users = new Yellow_WebinterfaceUsers();
+ $this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"));
+ }
+
+ // Handle web interface location
+ function onRequest($baseLocation, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($this->checkWebinterfaceLocation($location))
+ {
+ $baseLocation .= rtrim($this->yellow->config->get("webinterfaceLocation"), '/');
+ $location = $this->yellow->getRelativeLocation($baseLocation);
+ $fileName = $this->yellow->getContentFileName($location);
+ if($this->checkUser()) $statusCode = $this->processRequestAction($baseLocation, $location, $fileName);
+ if($statusCode == 0) $statusCode = $this->yellow->processRequestFile($baseLocation, $location, $fileName,
+ $this->activeUserFail ? 401 : 0, false);
+ } else {
+ if($this->yellow->config->get("webinterfaceLocation") == "$location/")
+ {
+ $statusCode = 301;
+ $this->yellow->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$baseLocation$location/");
+ }
+ }
+ return $statusCode;
+ }
+
+ // Handle extra HTML header lines
+ function onHeaderExtra()
+ {
+ $header = "";
+ if($this->isWebinterfaceLocation())
+ {
+ $location = $this->yellow->config->getHtml("baseLocation").$this->yellow->config->getHtml("pluginsLocation");
+ $language = $this->isUser() ? $this->users->getLanguage($this->activeUserEmail) : $this->yellow->page->get("language");
+ $header .= "<link href=\"{$location}core_webinterface.css\" rel=\"styleSheet\" media=\"all\" type=\"text/css\" />\n";
+ $header .= "<script type=\"text/javascript\" src=\"{$location}core_webinterface.js\"></script>\n";
+ $header .= "<script type=\"text/javascript\">\n";
+ $header .= "// <![CDATA[\n";
+ if($this->isUser())
+ {
+ $header .= "yellow.page.rawData = ".json_encode($this->yellow->page->rawData).";\n";
+ $header .= "yellow.pages = ".json_encode($this->getPagesData()).";\n";
+ $header .= "yellow.config = ".json_encode($this->getConfigData($this->activeUserEmail)).";\n";
+ }
+ $header .= "yellow.text = ".json_encode($this->yellow->text->getData($language, "webinterface")).";\n";
+ if(defined("DEBUG")) $header .= "yellow.debug = ".json_encode(DEBUG).";\n";
+ $header .= "// ]]>\n";
+ $header .= "</script>\n";
+ }
+ return $header;
+ }
+
+ // Handle page before parser
+ function onParseBefore($text, $statusCode)
+ {
+ if($this->isWebinterfaceLocation() && $this->isUser())
+ {
+ if($statusCode == 424)
+ {
+ $this->yellow->page->rawData = "---\r\n";
+ $this->yellow->page->rawData .= "Title: ".$this->yellow->text->get("webinterface424Title")."\r\n";
+ $this->yellow->page->rawData .= "Author: ".$this->users->getName($this->activeUserEmail)."\r\n";
+ $this->yellow->page->rawData .= "---\r\n";
+ $this->yellow->page->rawData .= $this->yellow->text->get("webinterface424Text");
+ }
+ }
+ return $text;
+ }
+
+ // Handle page after parser
+ function onParseAfter($text, $statusCode)
+ {
+ if($this->isWebinterfaceLocation() && $this->isUser())
+ {
+ $this->yellow->toolbox->timerStart($time);
+ $baseLocation = $this->yellow->config->get("baseLocation");
+ $webinterfaceLocation = rtrim($this->yellow->config->get("webinterfaceLocation"), '/');
+ $text = preg_replace("#<a(.*?)href=\"$baseLocation(?!$webinterfaceLocation)(.*?)\"(.*?)>#",
+ "<a$1href=\"$baseLocation$webinterfaceLocation$2\"$3>", $text);
+ }
+ return $text;
+ }
+
+ // Process request for an action
+ function processRequestAction($baseLocation, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($_POST["action"] == "edit")
+ {
+ if(strlen($_POST["rawdata"]))
+ {
+ $fileHandle = @fopen($fileName, "w");
+ if($fileHandle)
+ {
+ fwrite($fileHandle, $_POST["rawdata"]);
+ fclose($fileHandle);
+ } else {
+ die("Configuration problem: Can't write page '$fileName'!");
+ }
+ }
+ } else if($_POST["action"]== "logout") {
+ $this->users->destroyCookie("login");
+ $this->activeUserEmail = "";
+ $statusCode = 302;
+ $newLocation = $this->yellow->config->getHtml("baseLocation").$location;
+ $this->yellow->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$newLocation");
+ } else {
+ if(!is_readable($fileName))
+ {
+ if($this->yellow->toolbox->isFileLocation($location) && is_dir($this->yellow->getContentDirectory("$location/")))
+ {
+ $statusCode = 301;
+ $this->yellow->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$baseLocation$location/");
+ } else {
+ $statusCode = $this->checkUserPermissions($location, $fileName) ? 424 : 404;
+ $this->yellow->processRequestFile($baseLocation, $location, $fileName, $statusCode, false);
+ }
+ }
+ }
+ return $statusCode;
+ }
+
+ // Check web interface location
+ function checkWebinterfaceLocation($location)
+ {
+ $locationLength = strlen($this->yellow->config->get("webinterfaceLocation"));
+ $this->activeLocation = substr($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation");
+ return $this->isWebinterfaceLocation();
+ }
+
+ // Check user login
+ function checkUser()
+ {
+ if($_POST["action"] == "login")
+ {
+ $email = $_POST["email"];
+ $password = $_POST["password"];
+ if($this->users->checkUser($email, $password))
+ {
+ $this->users->createCookie("login", $email);
+ $this->activeUserEmail = $email;
+ } else {
+ $this->activeUserFail = true;
+ }
+ } else if(isset($_COOKIE["login"])) {
+ $cookie = $_COOKIE["login"];
+ if($this->users->checkCookie($cookie))
+ {
+ $this->activeUserEmail = $this->users->getCookieEmail($cookie);
+ } else {
+ $this->activeUserFail = true;
+ }
+ }
+ return $this->isUser();
+ }
+
+ // Check users permissions for creating new page
+ function checkUserPermissions($location, $fileName)
+ {
+ $path = dirname($fileName);
+ return is_dir($path);
+ }
+
+ // Check if web interface location
+ function isWebinterfaceLocation()
+ {
+ return $this->activeLocation;
+ }
+
+ // Check if user is logged in
+ function isUser()
+ {
+ return !empty($this->activeUserEmail);
+ }
+
+ // Return page tree with content/media information
+ function getPagesData()
+ {
+ $data = array();
+ foreach($this->yellow->pages->root(true) as $page)
+ {
+ $data[$page->fileName] = array();
+ $data[$page->fileName]["location"] = $page->getLocation();
+ $data[$page->fileName]["title"] = $page->getTitle();
+ }
+ return $data;
+ }
+
+ // Return configuration data including user information
+ function getConfigData($email)
+ {
+ $data = array("userEmail" => $email,
+ "userName" => $this->users->getName($email),
+ "userLanguage" => $this->users->getLanguage($email),
+ "baseLocation" => $this->yellow->config->get("baseLocation"));
+ return array_merge($data, $this->yellow->config->getData("Location"));
+ }
+}
+
+// Yellow web interface users
+class Yellow_WebinterfaceUsers
+{
+ var $users; //registered users
+
+ function __construct()
+ {
+ $this->users = array();
+ }
+
+ // Load users from file
+ function load($fileName)
+ {
+ $fileData = @file($fileName);
+ if($fileData)
+ {
+ foreach($fileData as $line)
+ {
+ if(preg_match("/^\//", $line)) continue;
+ preg_match("/^(.*?)\s*,(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches);
+ if($matches[1]!="" && $matches[2]!="" && $matches[3]!="" && $matches[4]!="")
+ {
+ $this->setUser($matches[1], $matches[2], $matches[3], $matches[4]);
+ if(defined("DEBUG") && DEBUG>=3) echo "Yellow_WebinterfaceUsers::load email:$matches[1] $matches[3]<br/>\n";
+ }
+ }
+ }
+ }
+
+ // Set user data
+ function setUser($email, $password, $name, $language)
+ {
+ $this->users[$email] = array();
+ $this->users[$email]["email"] = $email;
+ $this->users[$email]["password"] = $password;
+ $this->users[$email]["name"] = $name;
+ $this->users[$email]["language"] = $language;
+ $this->users[$email]["session"] = hash("sha256", $email.$password.strrev($email.$password));
+ }
+
+ // Check user login
+ function checkUser($email, $password)
+ {
+ return $this->isExisting($email) && hash("sha256", $email.$password)==$this->users[$email]["password"];
+ }
+
+ // Create browser cookie
+ function createCookie($cookieName, $email)
+ {
+ if($this->isExisting($email))
+ {
+ $salt = hash("sha256", uniqid(mt_rand(), true));
+ $text = $email.";".$salt.";".hash("sha256", $salt.$this->users[$email]["session"]);
+ setcookie($cookieName, $text, time()+60*60*24*30*365*10, "/") || die("Server problem: Can't create '$cookieName' cookie!");
+ }
+ }
+
+ // Destroy browser cookie
+ function destroyCookie($cookieName)
+ {
+ setcookie($cookieName, "", time()-3600, "/");
+ }
+
+ // Check user login from browser cookie
+ function checkCookie($cookie)
+ {
+ list($email, $salt, $session) = explode(";", $cookie);
+ return $this->isExisting($email) && hash("sha256", $salt.$this->users[$email]["session"])==$session;
+ }
+
+ // Return user email from browser cookie
+ function getCookieEmail($cookie)
+ {
+ list($email, $salt, $session) = explode(";", $cookie);
+ return $email;
+ }
+
+ // Return user name
+ function getName($email)
+ {
+ return $this->isExisting($email) ? $this->users[$email]["name"] : "";
+ }
+
+ // Return user language
+ function getLanguage($email)
+ {
+ return $this->isExisting($email) ? $this->users[$email]["language"] : "";
+ }
+
+ // Check if user exists
+ function isExisting($email)
+ {
+ return !is_null($this->users[$email]);
+ }
+}
+
+$yellow->registerPlugin("webinterface", "Yellow_Webinterface", Yellow_Webinterface::Version);
+?>
+\ No newline at end of file
diff --git a/system/core/core_webinterface.png b/system/core/core_webinterface.png
Binary files differ.
diff --git a/system/plugins/example.php b/system/plugins/example.php
@@ -0,0 +1,14 @@
+<?php
+// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Example plugin
+class Yellow_ExamplePlugin
+{
+ //You can download plugins and extensions from Github.
+ //See https://github.com/markseu/yellowcms-extensions
+ const Version = "0.0.0";
+}
+
+$yellow->registerPlugin("example", "Yellow_ExamplePlugin", Yellow_ExamplePlugin::Version);
+?>
+\ No newline at end of file