Hello world
This commit is contained in:
parent
f42d94c9f4
commit
9355317b5e
20 changed files with 3967 additions and 3 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
13
.htaccess
Normal file
13
.htaccess
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Yellow .htaccess
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
|
||||
# RewriteBase /yellow
|
||||
|
||||
RewriteRule ^content/(.*) error [R=301,L]
|
||||
RewriteRule ^system/(.*) error [R=301,L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.+) index.php [L]
|
||||
</IfModule>
|
|
@ -1,4 +1,4 @@
|
|||
yellowcms
|
||||
=========
|
||||
Yellow
|
||||
======
|
||||
|
||||
CMS for people, web-based and flat-file
|
||||
Yellow is a CMS for people, it's web-based and flat-file.
|
7
content/1-home/page.txt
Executable file
7
content/1-home/page.txt
Executable file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
Title: Home
|
||||
---
|
||||
Yes, it works! Your Yellow installation was successful.
|
||||
You can now [edit this page](wiki/) or use your favorite text editor.
|
||||
|
||||
[Visit Yellow on Github](https://github.com/markseu/yellowcms).
|
4
content/2-services/page.txt
Executable file
4
content/2-services/page.txt
Executable file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Title: Services
|
||||
---
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna pizza. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
4
content/3-about/page.txt
Executable file
4
content/3-about/page.txt
Executable file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Title: About
|
||||
---
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna pizza. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
5
index.php
Normal file
5
index.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
require_once("system/core/core.php");
|
||||
$yellow = new Yellow();
|
||||
$yellow->request();
|
||||
?>
|
BIN
media/images/default_icon.png
Normal file
BIN
media/images/default_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
14
media/styles/default_style.css
Normal file
14
media/styles/default_style.css
Normal file
|
@ -0,0 +1,14 @@
|
|||
html, body { margin:0px; padding:0px; }
|
||||
body { width:600px; margin:50px auto; font-family:"Helvetica Neue",Helvetica,sans-serif; background:#fff; color:#777; }
|
||||
a { text-decoration:none; color:#05d; }
|
||||
a:hover { text-decoration:none; color:#f00; }
|
||||
h1, h2, h3, h4, h5, h6 { font-weight:normal; color:#111; }
|
||||
h1 { font-size:1.5em; }
|
||||
p, ul { line-height:1.5; }
|
||||
img { vertical-align:top; }
|
||||
.header a { font-size:2.0em; color:#111; }
|
||||
.navigation { margin-top:1em; margin-bottom:1em; padding-bottom:1em; border-bottom:solid 2px #ec0; font-size:1.2em; font-weight:bold; }
|
||||
.navigation ul { list-style:none; margin:0px; padding:0px; }
|
||||
.navigation li { display:inline; margin-right:1em; }
|
||||
.navigation li a.active { color: red; }
|
||||
.footer { margin-top:2em; padding-top:1em; border-top:solid 2px #ec0; }
|
2
media/styles/print_style.css
Normal file
2
media/styles/print_style.css
Normal file
|
@ -0,0 +1,2 @@
|
|||
body, h1, h2, h3, h4, h5, h6 { background:white; color:black; }
|
||||
.navigation, .footer { display:none !important; }
|
24
system/config/config.ini
Normal file
24
system/config/config.ini
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Yellow CMS configuration
|
||||
// All directories and locations have to end with a slash
|
||||
|
||||
sitename = Website
|
||||
author = Website
|
||||
language = en
|
||||
|
||||
parser = markdown
|
||||
template = default
|
||||
stylesLocation = /media/styles/
|
||||
imagesLocation = /media/images/
|
||||
pluginsLocation = /media/plugins/
|
||||
|
||||
systemDir = system/
|
||||
configDir = system/config/
|
||||
pluginDir = system/plugins/
|
||||
snippetDir = system/snippets/
|
||||
templateDir = system/templates/
|
||||
contentDir = content/
|
||||
contentHomeDir = 1-home/
|
||||
contentDefaultFile = page
|
||||
contentExtension = .txt
|
||||
configExtension = .ini
|
||||
systemExtension = .php
|
4
system/config/error404.txt
Normal file
4
system/config/error404.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Title: File not found
|
||||
---
|
||||
The requested file was not found. Oh no...
|
732
system/core/core.php
Executable file
732
system/core/core.php
Executable file
|
@ -0,0 +1,732 @@
|
|||
<?php
|
||||
// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
|
||||
// This file may be used and distributed under the terms of the public license.
|
||||
|
||||
// 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
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$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->config->setDefault("parser", "markdown");
|
||||
$this->config->setDefault("template", "default");
|
||||
$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("systemDir", "system/");
|
||||
$this->config->setDefault("configDir", "system/config/");
|
||||
$this->config->setDefault("pluginDir", "system/plugins/");
|
||||
$this->config->setDefault("snippetDir", "system/snippets/");
|
||||
$this->config->setDefault("templateDir", "system/templates/");
|
||||
$this->config->setDefault("contentDir", "content/");
|
||||
$this->config->setDefault("contentHomeDir", "1-home/");
|
||||
$this->config->setDefault("contentDefaultFile", "page");
|
||||
$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->load($this->config->get("configDir").$this->config->get("configFile"));
|
||||
$this->plugins = new Yellow_Plugins();
|
||||
}
|
||||
|
||||
// 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";
|
||||
}
|
||||
|
||||
// Process request
|
||||
function processRequest()
|
||||
{
|
||||
$statusCode = 0;
|
||||
$baseLocation = $this->config->get("baseLocation");
|
||||
$location = $this->getRelativeLocation($baseLocation);
|
||||
$fileName = $this->getContentFileName($location);
|
||||
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";
|
||||
}
|
||||
|
||||
// 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);
|
||||
$this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->toolbox, $this->config);
|
||||
|
||||
$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!");
|
||||
$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);
|
||||
|
||||
if(!$this->page->isExisting("description"))
|
||||
{
|
||||
$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));
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
// 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!");
|
||||
global $yellow;
|
||||
require($fileName);
|
||||
}
|
||||
|
||||
// Return extra HTML header lines generated from plugins
|
||||
function getHeaderExtra()
|
||||
{
|
||||
$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 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 content directory from location
|
||||
function getContentDirectory($location)
|
||||
{
|
||||
return $this->toolbox->findFileFromLocation($location,
|
||||
$this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", "");
|
||||
}
|
||||
|
||||
// Register plugin
|
||||
function registerPlugin($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?
|
||||
|
||||
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 setRawData($rawData, $toolbox, $config)
|
||||
{
|
||||
$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("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]);
|
||||
}
|
||||
}
|
||||
|
||||
// Set page meta data
|
||||
function set($key, $value)
|
||||
{
|
||||
$this->metaData[$key] = $value;
|
||||
}
|
||||
|
||||
// Return page meta data
|
||||
function get($key)
|
||||
{
|
||||
return is_null($this->metaData[$key]) ? "" : $this->metaData[$key];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
// Yellow plugins
|
||||
class Yellow_Plugins
|
||||
{
|
||||
var $plugins; //registered plugins
|
||||
|
||||
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)
|
||||
{
|
||||
$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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
55
system/core/core_markdown.php
Executable file
55
system/core/core_markdown.php
Executable file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
|
||||
// This file may be used and distributed under the terms of the public license.
|
||||
|
||||
// Markdown parser core plugin
|
||||
class Yellow_Markdown
|
||||
{
|
||||
var $markdown; //markdown parser
|
||||
var $html; //generated HTML
|
||||
|
||||
// Initialise plugin
|
||||
function initPlugin($yellow)
|
||||
{
|
||||
$this->markdown = new Yellow_MarkdownExtraParser($yellow);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
function __construct($yellow)
|
||||
{
|
||||
$this->yellow = $yellow;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// 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);
|
||||
$alt = $matches[2];
|
||||
$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(isset($title)) $result .= " title=\"".$this->encodeAttribute($title)."\"";
|
||||
$result .= $this->empty_element_suffix;
|
||||
|
||||
return $this->hashPart($result);
|
||||
}
|
||||
}
|
||||
|
||||
$yellow->registerPlugin("markdown", "Yellow_Markdown", "0.1.0");
|
||||
?>
|
18
system/core/core_rawhtml.php
Executable file
18
system/core/core_rawhtml.php
Executable file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
// Copyright (c) 2013 Datenstrom, http://www.datenstrom.se
|
||||
// This file may be used and distributed under the terms of the public license.
|
||||
|
||||
// Raw HTML parser core plugin
|
||||
class Yellow_RawHtml
|
||||
{
|
||||
var $html; //generated HTML
|
||||
|
||||
// Parse text, dummy transformation
|
||||
function parse($text)
|
||||
{
|
||||
return $this->html = $text;
|
||||
}
|
||||
}
|
||||
|
||||
$yellow->registerPlugin("rawhtml", "Yellow_RawHtml", "0.1.0");
|
||||
?>
|
3050
system/core/markdown.php
Executable file
3050
system/core/markdown.php
Executable file
File diff suppressed because it is too large
Load diff
3
system/snippets/footer.php
Executable file
3
system/snippets/footer.php
Executable file
|
@ -0,0 +1,3 @@
|
|||
<div class="footer">© 2013 <?php echo $yellow->config->getHtml("sitename") ?></div>
|
||||
</body>
|
||||
</html>
|
14
system/snippets/header.php
Executable file
14
system/snippets/header.php
Executable file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" lang="<?php echo $yellow->page->getHtml("language") ?>">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="<?php echo $yellow->page->getHtml("description") ?>" />
|
||||
<meta name="keywords" content="<?php echo $yellow->page->getHtml("keywords") ?>" />
|
||||
<meta name="author" content="<?php echo $yellow->page->getHtml("author") ?>" />
|
||||
<title><?php echo $yellow->config->getHtml("sitename")." - ".$yellow->page->getHtml("title") ?></title>
|
||||
<link rel="shortcut icon" href="<?php echo $yellow->config->get("baseLocation").$yellow->config->get("imagesLocation")."default_icon.png" ?>" />
|
||||
<link href="<?php echo $yellow->config->get("baseLocation").$yellow->config->get("stylesLocation")."default_style.css" ?>" rel="styleSheet" media="all" type="text/css" />
|
||||
<link href="<?php echo $yellow->config->get("baseLocation").$yellow->config->get("stylesLocation")."print_style.css" ?>" rel="styleSheet" media="print" type="text/css" />
|
||||
<?php echo $yellow->getHeaderExtra() ?>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><a href="<?php echo $yellow->config->get("baseLocation")."/" ?>"><?php echo $yellow->config->getHtml("sitename") ?></a></div>
|
7
system/snippets/navigation.php
Executable file
7
system/snippets/navigation.php
Executable file
|
@ -0,0 +1,7 @@
|
|||
<div class="navigation">
|
||||
<ul>
|
||||
<?php foreach($yellow->pages->root() as $page): ?>
|
||||
<li><a<?php echo $page->isActive() ? " class=\"active\"" : "" ?> href="<?php echo $page->getLocation() ?>"><?php echo $page->getTitle() ?></a></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
7
system/templates/default.php
Executable file
7
system/templates/default.php
Executable file
|
@ -0,0 +1,7 @@
|
|||
<?php $yellow->snippet("header") ?>
|
||||
<?php $yellow->snippet("navigation") ?>
|
||||
<div class="content">
|
||||
<h1><?php echo $yellow->page->getTitle() ?></h1>
|
||||
<?php echo $yellow->page->getContent() ?>
|
||||
</div>
|
||||
<?php $yellow->snippet("footer") ?>
|
Loading…
Reference in a new issue