Hello web interface
This commit is contained in:
parent
9355317b5e
commit
2474166d27
16 changed files with 1471 additions and 641 deletions
12
.htaccess
12
.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>
|
||||
|
|
12
README.md
12
README.md
|
@ -2,3 +2,15 @@ Yellow
|
|||
======
|
||||
|
||||
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).
|
|
@ -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).
|
||||
Visit [Yellow on Github](https://github.com/markseu/yellowcms).
|
|
@ -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
|
||||
errorPageFile = error(.*).txt
|
||||
textStringFile = text_(.*).ini
|
4
system/config/error401.txt
Normal file
4
system/config/error401.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Title: Unauthorised
|
||||
---
|
||||
You are not authorised on this server. Please log in.
|
4
system/config/error424.txt
Normal file
4
system/config/error424.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Title: Page does not exist
|
||||
---
|
||||
You can [create this page](javascript:showPane('cmspaneeditor');).
|
19
system/config/text_english.ini
Normal file
19
system/config/text_english.ini
Normal file
|
@ -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
|
4
system/config/user.ini
Normal file
4
system/config/user.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Yellow user accounts
|
||||
// Format: Email, password (sha256 with email prefix as salt), name, language
|
||||
|
||||
// user@user.com,e1e2f704225259e91c44fb259c7db595e6cfd1a2e85a2b56508ab5aa9217d265,User,en
|
|
@ -5,23 +5,26 @@
|
|||
// Yellow main class
|
||||
class Yellow
|
||||
{
|
||||
const Version = "0.0.0"; //Hello world!
|
||||
|
||||
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->config = new Yellow_Config();
|
||||
$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("yellowVersion", Yellow::Version);
|
||||
$this->config->setDefault("baseLocation", $this->toolbox->getBaseLocation());
|
||||
$this->config->setDefault("stylesLocation", "/media/styles/");
|
||||
$this->config->setDefault("imagesLocation", "/media/images/");
|
||||
|
@ -33,17 +36,18 @@ 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("systemExtension", ".php");
|
||||
$this->config->setDefault("configFile", "config.ini");
|
||||
$this->config->setDefault("yellowVersion", Yellow::Version);
|
||||
$this->config->setDefault("errorPageFile", "error(.*).txt");
|
||||
$this->config->setDefault("textStringFile", "text_(.*).ini");
|
||||
$this->config->load($this->config->get("configDir").$this->config->get("configFile"));
|
||||
$this->plugins = new Yellow_Plugins();
|
||||
$this->text->load($this->config->get("configDir").$this->config->get("textStringFile"), $this->toolbox);
|
||||
}
|
||||
|
||||
// Start CMS and handle request
|
||||
// Start and handle request
|
||||
function request()
|
||||
{
|
||||
$this->toolbox->timerStart($time);
|
||||
|
@ -69,7 +73,7 @@ class Yellow
|
|||
}
|
||||
}
|
||||
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(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequest status:$statusCode location:$location<br>\n";
|
||||
}
|
||||
|
||||
// Process request for a file
|
||||
|
@ -118,7 +122,7 @@ class Yellow
|
|||
{
|
||||
header($this->toolbox->getHttpStatusFormated($statusCode));
|
||||
header("Content-Type: text/html; charset=UTF-8");
|
||||
$fileName = $this->config->get("configDir").sprintf("error%d.txt", $statusCode);
|
||||
$fileName = str_replace("(.*)", $statusCode, $this->config->get("configDir").$this->config->get("errorPageFile"));
|
||||
$fileHandle = @fopen($fileName, "r");
|
||||
if($fileHandle)
|
||||
{
|
||||
|
@ -129,7 +133,7 @@ class Yellow
|
|||
}
|
||||
}
|
||||
if($fileData != "") $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode);
|
||||
if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequestFile base:$baseLocation, file:$fileName<br>\n";
|
||||
if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequestFile base:$baseLocation file:$fileName<br>\n";
|
||||
return $statusCode;
|
||||
}
|
||||
|
||||
|
@ -145,6 +149,7 @@ class Yellow
|
|||
{
|
||||
$this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config);
|
||||
$this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->toolbox, $this->config);
|
||||
$this->text->setLanguage($this->page->get("language"));
|
||||
|
||||
$text = $this->page->getContentRawText();
|
||||
foreach($this->plugins->plugins as $key=>$value)
|
||||
|
@ -154,7 +159,7 @@ class Yellow
|
|||
$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)
|
||||
|
@ -243,6 +248,7 @@ class Yellow_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)
|
||||
{
|
||||
|
@ -251,6 +257,7 @@ class Yellow_Page
|
|||
$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
|
||||
|
@ -288,7 +295,7 @@ class Yellow_Page
|
|||
// 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
|
||||
|
@ -338,6 +345,12 @@ class Yellow_Page
|
|||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
// Check if page is active
|
||||
function isHidden()
|
||||
{
|
||||
return $this->hidden;
|
||||
}
|
||||
}
|
||||
|
||||
// Yellow page tree from file system
|
||||
|
@ -354,9 +367,9 @@ class Yellow_Pages
|
|||
function scan($baseLocation, $toolbox, $config)
|
||||
{
|
||||
$this->pages = array();
|
||||
foreach($toolbox->getDirectoryEntries($config->get("contentDir"), "/^[\d\-\.]+(.*)$/", true) as $entry)
|
||||
foreach($toolbox->getDirectoryEntries($config->get("contentDir"), "/.*/", true) as $entry)
|
||||
{
|
||||
$fileName = $config->get("contentDir").$entry."/".$config->get("contentDefaultFile").$config->get("contentExtension");
|
||||
$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");
|
||||
|
@ -373,9 +386,14 @@ class Yellow_Pages
|
|||
}
|
||||
|
||||
// Return top-level pages
|
||||
function root()
|
||||
function root($showHidden = false)
|
||||
{
|
||||
return $this->pages;
|
||||
$pages = array();
|
||||
foreach($this->pages as $page)
|
||||
{
|
||||
if($showHidden || !$page->isHidden()) array_push($pages, $page);
|
||||
}
|
||||
return $pages;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,6 +466,23 @@ class Yellow_Toolbox
|
|||
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)
|
||||
{
|
||||
|
@ -465,10 +500,10 @@ class Yellow_Toolbox
|
|||
{
|
||||
$path .= $tokens[$i].$fileExtension;
|
||||
} else {
|
||||
$path .= $fileDefault.$fileExtension;
|
||||
$path .= $fileDefault;
|
||||
}
|
||||
} else {
|
||||
$path .= $pathHome.$fileDefault.$fileExtension;
|
||||
$path .= $pathHome.$fileDefault;
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
@ -486,12 +521,12 @@ class Yellow_Toolbox
|
|||
if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1];
|
||||
$location .= "$tokens[$i]/";
|
||||
}
|
||||
if($tokens[$i] != $fileDefault.$fileExtension)
|
||||
if($tokens[$i] != $fileDefault)
|
||||
{
|
||||
$location .= substr($tokens[$i], 0, -strlen($fileExtension)-1);
|
||||
}
|
||||
} else {
|
||||
if($fileName != $pathHome.$fileDefault.$fileExtension)
|
||||
if($fileName != $pathHome.$fileDefault)
|
||||
{
|
||||
$location .= substr($fileName, $pathHome, -strlen($fileExtension)-1);
|
||||
}
|
||||
|
@ -504,18 +539,19 @@ class Yellow_Toolbox
|
|||
{
|
||||
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;
|
||||
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)
|
||||
static function getDirectoryEntries($path, $regex = "/.*/", $sort = false, $directories = true)
|
||||
{
|
||||
$entries = array();
|
||||
$dirHandle = @opendir($path);
|
||||
|
@ -580,6 +616,25 @@ class Yellow_Toolbox
|
|||
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)
|
||||
{
|
||||
|
@ -642,6 +697,7 @@ class Yellow_Config
|
|||
$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;
|
||||
|
@ -670,7 +726,7 @@ class Yellow_Config
|
|||
// Return configuration
|
||||
function get($key)
|
||||
{
|
||||
return is_null($this->config[$key]) ? $this->configDefaults[$key] : $this->config[$key];
|
||||
return $this->isExisting($key) ? $this->config[$key] : $this->configDefaults[$key];
|
||||
}
|
||||
|
||||
// Return configuration, HTML encoded
|
||||
|
@ -679,6 +735,22 @@ class Yellow_Config
|
|||
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)
|
||||
{
|
||||
|
@ -686,6 +758,100 @@ class Yellow_Config
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
|
@ -702,10 +868,11 @@ class Yellow_Plugins
|
|||
global $yellow;
|
||||
require_once("core_markdown.php");
|
||||
require_once("core_rawhtml.php");
|
||||
foreach($yellow->toolbox->getDirectoryEntries($yellow->config->get("pluginDir")) as $entry)
|
||||
require_once("core_webinterface.php");
|
||||
foreach($yellow->toolbox->getDirectoryEntries($yellow->config->get("pluginDir"), "/.*\.php/", true, false) as $entry)
|
||||
{
|
||||
$fileName = "$entry/plugin_$entry.php";
|
||||
if(is_file($fileName)) require_once($fileName);
|
||||
$fileName = $yellow->config->get("pluginDir")."/$entry";
|
||||
require_once($fileName);
|
||||
}
|
||||
foreach($this->plugins as $key=>$value)
|
||||
{
|
||||
|
@ -721,12 +888,18 @@ class Yellow_Plugins
|
|||
// Register plugin
|
||||
function register($name, $class, $version)
|
||||
{
|
||||
if(is_null($this->plugins[$name]))
|
||||
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]);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -5,6 +5,7 @@
|
|||
// Markdown parser core plugin
|
||||
class Yellow_Markdown
|
||||
{
|
||||
const Version = "0.1.1";
|
||||
var $markdown; //markdown parser
|
||||
var $html; //generated HTML
|
||||
|
||||
|
@ -32,6 +33,14 @@ class Yellow_MarkdownExtraParser extends MarkdownExtra_Parser
|
|||
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)
|
||||
{
|
||||
|
@ -39,7 +48,7 @@ class Yellow_MarkdownExtraParser extends MarkdownExtra_Parser
|
|||
$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\"";
|
||||
|
@ -51,5 +60,5 @@ class Yellow_MarkdownExtraParser extends MarkdownExtra_Parser
|
|||
}
|
||||
}
|
||||
|
||||
$yellow->registerPlugin("markdown", "Yellow_Markdown", "0.1.0");
|
||||
$yellow->registerPlugin("markdown", "Yellow_Markdown", Yellow_Markdown::Version);
|
||||
?>
|
|
@ -5,6 +5,7 @@
|
|||
// Raw HTML parser core plugin
|
||||
class Yellow_RawHtml
|
||||
{
|
||||
const Version = "0.1.1";
|
||||
var $html; //generated HTML
|
||||
|
||||
// Parse text, dummy transformation
|
||||
|
@ -14,5 +15,5 @@ class Yellow_RawHtml
|
|||
}
|
||||
}
|
||||
|
||||
$yellow->registerPlugin("rawhtml", "Yellow_RawHtml", "0.1.0");
|
||||
$yellow->registerPlugin("rawhtml", "Yellow_RawHtml", Yellow_RawHtml::Version);
|
||||
?>
|
25
system/core/core_webinterface.css
Normal file
25
system/core/core_webinterface.css
Normal file
|
@ -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; }
|
243
system/core/core_webinterface.js
Normal file
243
system/core/core_webinterface.js
Normal file
|
@ -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();
|
317
system/core/core_webinterface.php
Executable file
317
system/core/core_webinterface.php
Executable file
|
@ -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);
|
||||
?>
|
BIN
system/core/core_webinterface.png
Normal file
BIN
system/core/core_webinterface.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
14
system/plugins/example.php
Executable file
14
system/plugins/example.php
Executable file
|
@ -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);
|
||||
?>
|
Loading…
Add table
Reference in a new issue