mikuli.cz

:)
git clone https://git.sr.ht/~ashymad/mikuli.cz
Log | Files | Refs

commit 8079b6eab8c5443a15c12d060d7c49306b8227ab
parent 58093305a2e81b71ed7082be111b1c628144ed4d
Author: markseu <mark2011@mayberg.se>
Date:   Sat, 20 Feb 2016 18:34:06 +0100

System update (file system support)

Diffstat:
MREADME.md | 2+-
Msystem/plugins/commandline.php | 23++++++-----------------
Msystem/plugins/core.php | 257+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msystem/plugins/markdown.php | 30+++++++++++++-----------------
Msystem/plugins/webinterface.php | 125+++++++++++++++++++++++++++++++++++++++++++------------------------------------
5 files changed, 220 insertions(+), 217 deletions(-)

diff --git a/README.md b/README.md @@ -1,4 +1,4 @@ -Yellow 0.6.2 +Yellow 0.6.3 ============ [![Yellow](https://raw.githubusercontent.com/wiki/datenstrom/yellow/images/yellow.jpg)](http://datenstrom.se/yellow) diff --git a/system/plugins/commandline.php b/system/plugins/commandline.php @@ -5,7 +5,7 @@ // Command line plugin class YellowCommandline { - const Version = "0.6.5"; + const Version = "0.6.6"; var $yellow; //access to API var $files; //number of files var $errors; //number of errors @@ -88,19 +88,14 @@ class YellowCommandline list($dummy, $command, $path, $location) = $args; if(empty($location) || $location[0]=='/') { - if($this->checkStaticConfig() && $this->checkStaticFilesystem()) + if($this->checkStaticConfig()) { $statusCode = $this->buildStatic($path, $location); } else { $statusCode = 500; $this->files = 0; $this->errors = 1; - if(!$this->checkStaticFilesystem()) - { - echo "ERROR building files: Static website not supported on Windows file system!\n"; - } else { - $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile"); - echo "ERROR building files: Please configure ServerScheme, ServerName, ServerBase, ServerTime in file '$fileName'!\n"; - } + $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile"); + echo "ERROR building files: Please configure ServerScheme, ServerName, ServerBase, ServerTime in file '$fileName'!\n"; } echo "Yellow $command: $this->files file".($this->files!=1 ? 's' : ''); echo ", $this->errors error".($this->errors!=1 ? 's' : ''); @@ -132,7 +127,7 @@ class YellowCommandline } foreach($this->locationsArgsPagination as $location) { - if(substru($location, -1) != ':') + if(substru($location, -1) != $this->yellow->toolbox->getLocationArgsSeparator()) { $statusCode = max($statusCode, $this->buildStaticFile($path, $location, false, true)); } @@ -225,7 +220,7 @@ class YellowCommandline $serverName = $this->yellow->config->get("serverName"); $serverBase = $this->yellow->config->get("serverBase"); $pagination = $this->yellow->config->get("contentPagination"); - preg_match_all("/<a(.*?)href=\"([^\"]+)\"(.*?)>/i", $text, $matches); + preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $text, $matches); foreach($matches[2] as $match) { if(preg_match("/^(.*?)#(.*)$/", $match, $tokens)) $match = $tokens[1]; @@ -344,12 +339,6 @@ class YellowCommandline $this->yellow->lookup->isValidLocation($serverBase) && $serverBase!="/"; } - // Check static filesystem - function checkStaticFilesystem() - { - return strtoupperu(substru(PHP_OS, 0, 3)) != "WIN"; - } - // Check static directory function checkStaticDirectory($path) { diff --git a/system/plugins/core.php b/system/plugins/core.php @@ -5,7 +5,7 @@ // Yellow core class YellowCore { - const Version = "0.6.2"; + const Version = "0.6.3"; var $page; //current page var $pages; //pages from file system var $files; //files from file system @@ -84,6 +84,21 @@ class YellowCore $this->config->set("contentHomeDir", $pathHome); } + // Handle command + function command($name, $args = NULL) + { + $statusCode = 0; + if($this->plugins->isExisting($name)) + { + $plugin = $this->plugins->plugins[$name]; + if(method_exists($plugin["obj"], "onCommand")) $statusCode = $plugin["obj"]->onCommand(func_get_args()); + } else { + $statusCode = 500; + $this->page->error($statusCode, "Plugin '$name' does not exist!"); + } + return $statusCode; + } + // Handle request function request() { @@ -124,8 +139,8 @@ class YellowCore if($this->toolbox->isRequestCleanUrl($location)) { $statusCode = 303; - $locationArgs = $this->toolbox->getLocationArgsCleanUrl($this->config->get("contentPagination")); - $location = $this->lookup->normaliseUrl($serverScheme, $serverName, $base, $location.$locationArgs); + $location = $location.$this->getRequestLocationArgsClean(); + $location = $this->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); $this->sendStatus($statusCode, $location); } } else { @@ -184,7 +199,7 @@ class YellowCore } $this->page = new YellowPage($this); $this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); - $this->page->parseData($this->toolbox->getFileData($fileName), $cacheable, $statusCode, $pageError); + $this->page->parseData($this->toolbox->readFile($fileName), $cacheable, $statusCode, $pageError); $this->text->setLanguage($this->page->get("language")); $this->page->parseContent(); return $fileName; @@ -229,7 +244,7 @@ class YellowCore if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate"); @header("Content-Type: ".$this->toolbox->getMimeContentType($fileName)); @header("Last-Modified: ".$lastModifiedFormatted); - echo $this->toolbox->getFileData($fileName); + echo $this->toolbox->readFile($fileName); } return $statusCode; } @@ -246,13 +261,20 @@ class YellowCore } } + // Parse snippet + function snippet($name, $args = NULL) + { + $this->pages->snippetArgs = func_get_args(); + $this->page->parseSnippet($name); + } + // Return request information function getRequestInformation($serverScheme = "", $serverName = "", $base = "") { $serverScheme = empty($serverScheme) ? $this->config->get("serverScheme") : $serverScheme; $serverName = empty($serverName) ? $this->config->get("serverName") : $serverName; $base = empty($base) ? $this->config->get("serverBase") : $base; - $location = $this->toolbox->getLocationClean(); + $location = $this->toolbox->getLocation(); $location = substru($location, strlenu($base)); if(preg_match("/\.(css|js|jpg|png|txt|woff)$/", $location)) { @@ -270,6 +292,12 @@ class YellowCore return array($serverScheme, $serverName, $base, $location, $fileName); } + // Return request location + function getRequestLocationArgsClean() + { + return $this->toolbox->getLocationArgsClean($this->config->get("contentPagination")); + } + // Return request language function getRequestLanguage() { @@ -291,7 +319,7 @@ class YellowCore // Return static file from cache if available function getStaticFileFromCache($location, $fileName, $cacheable, $statusCode) { - if(PHP_SAPI != "cli" && $cacheable) + if(PHP_SAPI!="cli" && $cacheable) { if($statusCode == 200) { @@ -328,28 +356,6 @@ class YellowCore } return $ok; } - - // Execute command - function command($name, $args = NULL) - { - $statusCode = 0; - if($this->plugins->isExisting($name)) - { - $plugin = $this->plugins->plugins[$name]; - if(method_exists($plugin["obj"], "onCommand")) $statusCode = $plugin["obj"]->onCommand(func_get_args()); - } else { - $statusCode = 500; - $this->page->error($statusCode, "Plugin '$name' does not exist!"); - } - return $statusCode; - } - - // Execute snippet - function snippet($name, $args = NULL) - { - $this->pages->snippetArgs = func_get_args(); - $this->page->parseSnippet($name); - } } // Yellow page @@ -418,14 +424,9 @@ class YellowPage { if($this->statusCode == 0) { - $fileHandle = @fopen($this->fileName, "r"); - if($fileHandle) - { - $this->statusCode = 200; - $this->rawData = fread($fileHandle, filesize($this->fileName)); - fclose($fileHandle); - $this->parseMeta(); - } + $this->rawData = $this->yellow->toolbox->readFile($this->fileName); + $this->statusCode = 200; + $this->parseMeta(); } } @@ -502,7 +503,11 @@ class YellowPage if(method_exists($plugin["obj"], "onParseContentRaw")) { $this->parser = $plugin["obj"]; - $this->parserData = $this->parser->onParseContentRaw($this, $this->getContent(true)); + $this->parserData = $this->getContent(true); + $this->parserData = preg_replace("/@pageRead/i", $this->get("pageRead"), $this->parserData); + $this->parserData = preg_replace("/@pageEdit/i", $this->get("pageEdit"), $this->parserData); + $this->parserData = preg_replace("/@pageError/i", $this->get("pageError"), $this->parserData); + $this->parserData = $this->parser->onParseContentRaw($this, $this->parserData); foreach($this->yellow->plugins->plugins as $key=>$value) { if(method_exists($value["obj"], "onParseContentText")) @@ -1210,20 +1215,11 @@ class YellowPages $fileNames = $this->yellow->lookup->findChildrenFromLocation($location); foreach($fileNames as $fileName) { - $fileHandle = @fopen($fileName, "r"); - if($fileHandle) - { - $fileData = fread($fileHandle, 4096); - $statusCode = filesize($fileName) <= 4096 ? 200 : 0; - fclose($fileHandle); - } else { - $fileData = ""; - $statusCode = 0; - } $page = new YellowPage($this->yellow); $page->setRequestInformation($serverScheme, $serverName, $base, $this->yellow->lookup->findLocationFromFile($fileName), $fileName); - $page->parseData($fileData, false, $statusCode); + $page->parseData($this->yellow->toolbox->readFile($fileName, 4096), false, 0); + if(strlenb($page->rawData) < 4096) $page->statusCode = 200; array_push($this->pages[$location], $page); } } @@ -1299,7 +1295,7 @@ class YellowPages return new YellowPageCollection($this->yellow); } - // Return available languages + // Return languages in multi language mode function getLanguages($showInvisible = false) { $languages = array(); @@ -1612,20 +1608,17 @@ class YellowConfig // Load configuration from file function load($fileName) { - $fileData = @file($fileName); - if($fileData) + if(defined("DEBUG") && DEBUG>=2) echo "YellowConfig::load file:$fileName<br/>\n"; + $this->modified = filemtime($fileName); + $fileData = $this->yellow->toolbox->readFile($fileName); + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) { - if(defined("DEBUG") && DEBUG>=2) echo "YellowConfig::load file:$fileName<br/>\n"; - $this->modified = filemtime($fileName); - foreach($fileData as $line) + if(preg_match("/^\#/", $line)) continue; + preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && !strempty($matches[2])) { - if(preg_match("/^\#/", $line)) continue; - preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); - if(!empty($matches[1]) && !strempty($matches[2])) - { - $this->set(lcfirst($matches[1]), $matches[2]); - if(defined("DEBUG") && DEBUG>=3) echo "YellowConfig::load ".lcfirst($matches[1]).":$matches[2]<br/>\n"; - } + $this->set(lcfirst($matches[1]), $matches[2]); + if(defined("DEBUG") && DEBUG>=3) echo "YellowConfig::load ".lcfirst($matches[1]).":$matches[2]<br/>\n"; } } } @@ -1712,26 +1705,22 @@ class YellowText $regex = "/^".basename($fileName)."$/"; foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false) as $entry) { - $fileData = @file($entry); - if($fileData) + if(defined("DEBUG") && DEBUG>=2) echo "YellowText::load file:$entry<br/>\n"; + $language = ""; + $this->modified = max($this->modified, filemtime($entry)); + $fileData = $this->yellow->toolbox->readFile($entry); + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) { - if(defined("DEBUG") && DEBUG>=2) echo "YellowText::load file:$entry<br/>\n"; - $this->modified = max($this->modified, filemtime($entry)); - $language = ""; - foreach($fileData as $line) + if(preg_match("/^\#/", $line)) continue; + preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); + if(empty($language)) { - preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); - if(lcfirst($matches[1])=="language" && !strempty($matches[2])) { $language = $matches[2]; break; } + if(lcfirst($matches[1])=="language" && !strempty($matches[2])) $language = $matches[2]; } - foreach($fileData as $line) + if(!empty($language) && !empty($matches[1]) && !strempty($matches[2])) { - if(preg_match("/^\#/", $line)) continue; - preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); - if(!empty($language) && !empty($matches[1]) && !strempty($matches[2])) - { - $this->setText(lcfirst($matches[1]), $matches[2], $language); - if(defined("DEBUG") && DEBUG>=3) echo "YellowText::load ".lcfirst($matches[1]).":$matches[2]<br/>\n"; - } + $this->setText(lcfirst($matches[1]), $matches[2], $language); + if(defined("DEBUG") && DEBUG>=3) echo "YellowText::load ".lcfirst($matches[1]).":$matches[2]<br/>\n"; } } } @@ -1787,7 +1776,6 @@ class YellowText } else { foreach($this->text[$language] as $key=>$value) { - if(substru($key, 0, strlenu("language")) == "language") $text[$key] = $value; if(substru($key, 0, strlenu($filterStart)) == $filterStart) $text[$key] = $value; } } @@ -1809,6 +1797,14 @@ class YellowText return date($format, $timestamp); } + // Return languages + function getLanguages() + { + $languages = array(); + foreach($this->text as $key=>$value) array_push($languages, $key); + return $languages; + } + // Return text modification date, Unix time or HTTP format function getModified($httpFormat = false) { @@ -2125,6 +2121,7 @@ class YellowLookup } else if(!preg_match("#^$pageBase#", $location)) { $location = $pageBase.$location; } + $location = strreplaceu(':', $this->yellow->toolbox->getLocationArgsSeparator(), $location); } } else { if($filterStrict && !preg_match("/^(http|https|ftp|mailto):/", $location)) $location = "error-xss-filter"; @@ -2280,52 +2277,52 @@ class YellowToolbox } // Return location from current HTTP request - function getLocation() - { - $uri = $_SERVER["REQUEST_URI"]; - return rawurldecode(($pos = strposu($uri, '?')) ? substru($uri, 0, $pos) : $uri); - } - - // Return location from current HTTP request, remove unwanted path tokens - function getLocationClean() + function getLocation($filterStrict = true) { - $string = $this->getLocation(); - $location = ($string[0]=='/') ? '' : '/'; - for($pos=0; $pos<strlenb($string); ++$pos) + $location = $_SERVER["REQUEST_URI"]; + $location = rawurldecode(($pos = strposu($location, '?')) ? substru($location, 0, $pos) : $location); + if($filterStrict) { - if($string[$pos] == '/') + $locationFiltered = ""; + if($location[0] != '/') $location = '/'.$location; + for($pos=0; $pos<strlenb($location); ++$pos) { - if($string[$pos+1] == '/') continue; - if($string[$pos+1] == '.') + if($location[$pos] == '/') { - $posNew = $pos+1; while($string[$posNew] == '.') ++$posNew; - if($string[$posNew]=='/' || $string[$posNew]=='') + if($location[$pos+1] == '/') continue; + if($location[$pos+1] == '.') { - $pos = $posNew-1; - continue; + $posNew = $pos+1; while($location[$posNew] == '.') ++$posNew; + if($location[$posNew]=='/' || $location[$posNew]=='') + { + $pos = $posNew-1; + continue; + } } } + $locationFiltered .= $location[$pos]; } - $location .= $string[$pos]; - } - if(preg_match("/^(.*?\/)([^\/]+:.*)$/", $location, $matches)) - { - $_SERVER["LOCATION"] = $location = $matches[1]; - $_SERVER["LOCATION_ARGS"] = $matches[2]; - foreach(explode('/', $matches[2]) as $token) + $location = $locationFiltered; + $separator = $this->getLocationArgsSeparator(); + if(preg_match("/^(.*?\/)([^\/]+$separator.*)$/", $location, $matches)) { - preg_match("/^(.*?):(.*)$/", $token, $matches); - if(!empty($matches[1]) && !strempty($matches[2])) + $_SERVER["LOCATION"] = $location = $matches[1]; + $_SERVER["LOCATION_ARGS"] = $matches[2]; + foreach(explode('/', $matches[2]) as $token) { - $matches[1] = strreplaceu(array("\x1c", "\x1d"), array('/', ':'), $matches[1]); - $matches[2] = strreplaceu(array("\x1c", "\x1d"), array('/', ':'), $matches[2]); - $_REQUEST[$matches[1]] = $matches[2]; + preg_match("/^(.*?)$separator(.*)$/", $token, $matches); + if(!empty($matches[1]) && !strempty($matches[2])) + { + $matches[1] = strreplaceu(array("\x1c", "\x1d", "\x1e"), array('/', ':', '='), $matches[1]); + $matches[2] = strreplaceu(array("\x1c", "\x1d", "\x1e"), array('/', ':', '='), $matches[2]); + $_REQUEST[$matches[1]] = $matches[2]; + } } + } else { + $_SERVER["LOCATION"] = $location; + $_SERVER["LOCATION_ARGS"] = ""; } - } else { - $_SERVER["LOCATION"] = $location; - $_SERVER["LOCATION_ARGS"] = ""; - } + } return $location; } @@ -2335,13 +2332,14 @@ class YellowToolbox return $_SERVER["LOCATION_ARGS"]; } - // Return location arguments from current HTTP request, modify an argument + // Return location arguments from current HTTP request, modify existing arguments function getLocationArgsNew($arg, $pagination) { + $separator = $this->getLocationArgsSeparator(); preg_match("/^(.*?):(.*)$/", $arg, $args); foreach(explode('/', $_SERVER["LOCATION_ARGS"]) as $token) { - preg_match("/^(.*?):(.*)$/", $token, $matches); + preg_match("/^(.*?)$separator(.*)$/", $token, $matches); if($matches[1] == $args[1]) { $matches[2] = $args[2]; $found = true; } if(!empty($matches[1]) && !strempty($matches[2])) { @@ -2356,43 +2354,51 @@ class YellowToolbox } if(!empty($locationArgs)) { - if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; $locationArgs = $this->normaliseArgs($locationArgs, false, false); + if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; } return $locationArgs; } - // Return location arguments from current HTTP request, convert form into clean URL - function getLocationArgsCleanUrl($pagination) + // Return location arguments from current HTTP request, convert form parameters + function getLocationArgsClean($pagination) { foreach(array_merge($_GET, $_POST) as $key=>$value) { if(!empty($key) && !strempty($value)) { if(!empty($locationArgs)) $locationArgs .= '/'; - $key = strreplaceu(array('/', ':'), array("\x1c", "\x1d"), $key); - $value = strreplaceu(array('/', ':'), array("\x1c", "\x1d"), $value); + $key = strreplaceu(array('/', ':', '='), array("\x1c", "\x1d", "\x1e"), $key); + $value = strreplaceu(array('/', ':', '='), array("\x1c", "\x1d", "\x1e"), $value); $locationArgs .= "$key:$value"; } } if(!empty($locationArgs)) { - if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; $locationArgs = $this->normaliseArgs($locationArgs, false, false); + if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; } return $locationArgs; } + + // Return location arguments separator + function getLocationArgsSeparator() + { + return (strtoupperu(substru(PHP_OS, 0, 3)) != "WIN") ? ':' : '='; + } // Check if location contains location arguments function isLocationArgs($location) { - return preg_match("/[^\/]+:.*$/", $location); + $separator = $this->getLocationArgsSeparator(); + return preg_match("/[^\/]+$separator.*$/", $location); } // Check if location contains pagination arguments function isLocationArgsPagination($location, $pagination) { - return preg_match("/^(.*\/)?$pagination:.*$/", $location); + $separator = $this->getLocationArgsSeparator(); + return preg_match("/^(.*\/)?$pagination$separator.*$/", $location); } // Check if script location is requested @@ -2429,7 +2435,8 @@ class YellowToolbox { if($appendSlash) $text .= '/'; if($filterStrict) $text = strreplaceu(' ', '-', strtoloweru($text)); - return strreplaceu(array('%3A','%2F'), array(':','/'), rawurlencode($text)); + $text = strreplaceu(':', $this->getLocationArgsSeparator(), $text); + return strreplaceu(array('%2F','%3A','%3D'), array('/',':','='), rawurlencode($text)); } // Normalise text into UTF-8 NFC @@ -2610,7 +2617,7 @@ class YellowToolbox $path = dirname($fileName); if(!empty($path) && !is_dir($path)) @mkdir($path, 0777, true); } - $fileHandle = @fopen($fileName, "w"); + $fileHandle = @fopen($fileName, "wb"); if($fileHandle) { fwrite($fileHandle, $fileData); diff --git a/system/plugins/markdown.php b/system/plugins/markdown.php @@ -1,11 +1,11 @@ <?php -// Copyright (c) 2013-2015 Datenstrom, http://datenstrom.se +// Copyright (c) 2013-2016 Datenstrom, http://datenstrom.se // This file may be used and distributed under the terms of the public license. // Markdown plugin class YellowMarkdown { - const Version = "0.6.1"; + const Version = "0.6.2"; var $yellow; //access to API // Handle initialisation @@ -43,16 +43,6 @@ class YellowMarkdownParser extends MarkdownExtraParser }; parent::__construct(); } - - // Transform text - function transform($text) - { - $text = preg_replace("/@pageRead/i", $this->page->get("pageRead"), $text); - $text = preg_replace("/@pageEdit/i", $this->page->get("pageEdit"), $text); - $text = preg_replace("/@pageError/i", $this->page->get("pageError"), $text); - $text = preg_replace("/@pageFile/i", $this->page->get("pageFile"), $text); - return parent::transform($text); - } // Return unique id attribute function getIdAttribute($text) @@ -209,7 +199,7 @@ class MarkdownParser { ### Version ### - const MARKDOWNLIB_VERSION = "1.5.0"; + const MARKDOWNLIB_VERSION = "1.6.0"; ### Simple Function Interface ### @@ -1818,6 +1808,11 @@ class MarkdownExtraParser extends MarkdownParser { public $fn_link_class = "footnote-ref"; public $fn_backlink_class = "footnote-backref"; + # Content to be displayed within footnote backlinks. The default is '↩'; + # the U+FE0E on the end is a Unicode variant selector used to prevent iOS + # from displaying the arrow character as an emoji. + public $fn_backlink_html = '&#8617;&#xFE0E;'; + # Class name for table cell alignment (%% replaced left/center/right) # For instance: 'go-%%' becomes 'go-left' or 'go-right' or 'go-center' # If empty, the align attribute is used instead of a class name. @@ -1917,9 +1912,9 @@ class MarkdownExtraParser extends MarkdownParser { ### Extra Attribute Parser ### # Expression to use to catch attributes (includes the braces) - protected $id_class_attr_catch_re = '\{((?:[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,})[ ]*\}'; + protected $id_class_attr_catch_re = '\{((?>[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,})[ ]*\}'; # Expression to use when parsing in a context when no capture is desired - protected $id_class_attr_nocatch_re = '\{(?:[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,}[ ]*\}'; + protected $id_class_attr_nocatch_re = '\{(?>[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,}[ ]*\}'; protected function doExtraAttributes($tag_name, $attr, $defaultIdValue = null, $classes = array()) { # @@ -3261,6 +3256,7 @@ class MarkdownExtraParser extends MarkdownParser { $title = $this->encodeAttribute($title); $attr .= " title=\"$title\""; } + $backlink_text = $this->fn_backlink_html; $num = 0; while (!empty($this->footnotes_ordered)) { @@ -3280,9 +3276,9 @@ class MarkdownExtraParser extends MarkdownParser { $note_id = $this->encodeAttribute($note_id); # Prepare backlink, multiple backlinks if multiple references - $backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>"; + $backlink = "<a href=\"#fnref:$note_id\"$attr>$backlink_text</a>"; for ($ref_num = 2; $ref_num <= $ref_count; ++$ref_num) { - $backlink .= " <a href=\"#fnref$ref_num:$note_id\"$attr>&#8617;</a>"; + $backlink .= " <a href=\"#fnref$ref_num:$note_id\"$attr>$backlink_text</a>"; } # Add backlink to last paragraph; create new paragraph if needed. if (preg_match('{</p>$}', $footnote)) { diff --git a/system/plugins/webinterface.php b/system/plugins/webinterface.php @@ -1,11 +1,11 @@ <?php -// Copyright (c) 2013-2015 Datenstrom, http://datenstrom.se +// Copyright (c) 2013-2016 Datenstrom, http://datenstrom.se // This file may be used and distributed under the terms of the public license. // Web interface plugin class YellowWebinterface { - const Version = "0.6.3"; + const Version = "0.6.4"; var $yellow; //access to API var $active; //web interface is active? (boolean) var $userLoginFailed; //web interface login failed? (boolean) @@ -21,9 +21,9 @@ class YellowWebinterface $this->yellow = $yellow; $this->users = new YellowUsers($yellow); $this->merge = new YellowMerge($yellow); - $this->yellow->config->setDefault("webinterfaceLocation", "/edit/"); $this->yellow->config->setDefault("webinterfaceServerScheme", $this->yellow->config->get("serverScheme")); $this->yellow->config->setDefault("webinterfaceServerName", $this->yellow->config->get("serverName")); + $this->yellow->config->setDefault("webinterfaceLocation", "/edit/"); $this->yellow->config->setDefault("webinterfaceUserHashAlgorithm", "bcrypt"); $this->yellow->config->setDefault("webinterfaceUserHashCost", "10"); $this->yellow->config->setDefault("webinterfaceUserHome", "/"); @@ -67,7 +67,7 @@ class YellowWebinterface if($page->statusCode == 424) { $title = $this->yellow->toolbox->createTextTitle($page->location); - $this->rawDataEdit = $this->getDataNew($title); + $this->rawDataEdit = $this->getRawDataNew($title); } } } @@ -99,21 +99,9 @@ class YellowWebinterface $output .= "<script type=\"text/javascript\" src=\"".htmlspecialchars($location).".js\"></script>\n"; $output .= "<script type=\"text/javascript\">\n"; $output .= "// <![CDATA[\n"; - if($this->isUser()) - { - $output .= "yellow.page.title = ".json_encode($this->getDataTitle($this->rawDataEdit)).";\n"; - $output .= "yellow.page.rawDataSource = ".json_encode($this->rawDataSource).";\n"; - $output .= "yellow.page.rawDataEdit = ".json_encode($this->rawDataEdit).";\n"; - $output .= "yellow.page.rawDataNew = ".json_encode($this->getDataNew()).";\n"; - $output .= "yellow.page.pageFile = ".json_encode($this->yellow->page->get("pageFile")).";\n"; - $output .= "yellow.page.userPermission = ".json_encode($this->userPermission).";\n"; - $output .= "yellow.page.parserSafeMode = ".json_encode($this->yellow->page->parserSafeMode).";\n"; - $output .= "yellow.page.statusCode = ".json_encode($this->yellow->page->statusCode).";\n"; - } - $output .= "yellow.config = ".json_encode($this->getDataConfig()).";\n"; - $language = $this->isUser() ? $this->users->getLanguage() : $this->yellow->page->get("language"); - if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language"); - $output .= "yellow.text = ".json_encode($this->yellow->text->getData("webinterface", $language)).";\n"; + $output .= "yellow.page = ".json_encode($this->getPageData()).";\n"; + $output .= "yellow.config = ".json_encode($this->getConfigData()).";\n"; + $output .= "yellow.text = ".json_encode($this->getTextData()).";\n"; if(defined("DEBUG") && DEBUG>=1) $output .= "yellow.debug = ".json_encode(DEBUG).";\n"; $output .= "// ]]>\n"; $output .= "</script>\n"; @@ -260,7 +248,7 @@ class YellowWebinterface $this->rawDataSource = rawurldecode($_POST["rawdatasource"]); $this->rawDataEdit = rawurldecode($_POST["rawdataedit"]); $page = $this->getPageUpdate($serverScheme, $serverName, $base, $location, $fileName, - $this->rawDataSource, $this->rawDataEdit, $this->yellow->toolbox->getFileData($fileName)); + $this->rawDataSource, $this->rawDataEdit, $this->yellow->toolbox->readFile($fileName)); if(!$page->isError()) { if($this->yellow->toolbox->renameFile($fileName, $page->fileName) && @@ -511,14 +499,14 @@ class YellowWebinterface return $page; } - // Return content data for new page - function getDataNew($title = "") + // Return raw data for new page + function getRawDataNew($title = "") { $fileName = $this->yellow->lookup->findFileFromLocation($this->yellow->page->location); $fileName = $this->yellow->lookup->findFileNew($fileName, $this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("configDir"), $this->yellow->config->get("template")); - $fileData = $this->yellow->toolbox->getFileData($fileName); + $fileData = $this->yellow->toolbox->readFile($fileName); $fileData = preg_replace("/@datetime/i", date("Y-m-d H:i:s"), $fileData); $fileData = preg_replace("/@date/i", date("Y-m-d"), $fileData); $fileData = preg_replace("/@username/i", $this->users->getName(), $fileData); @@ -527,8 +515,26 @@ class YellowWebinterface return $fileData; } - // Return configuration data including information of current user - function getDataConfig() + // Return page data including webinterface information + function getPageData() + { + $data = array(); + if($this->isUser()) + { + $data["title"] = $this->getDataTitle($this->rawDataEdit); + $data["rawDataSource"] = $this->rawDataSource; + $data["rawDataEdit"] = $this->rawDataEdit; + $data["rawDataNew"] = $this->getRawDataNew(); + $data["userPermission"] = $this->userPermission; + $data["pageFile"] = $this->yellow->page->get("pageFile"); + $data["parserSafeMode"] = $this->yellow->page->parserSafeMode; + $data["statusCode"] = $this->yellow->page->statusCode; + } + return $data; + } + + // Return configuration data including user information + function getConfigData() { $data = $this->yellow->config->getData("", "Location"); if($this->isUser()) @@ -541,6 +547,8 @@ class YellowWebinterface $data["serverScheme"] = $this->yellow->config->get("serverScheme"); $data["serverName"] = $this->yellow->config->get("serverName"); $data["serverBase"] = $this->yellow->config->get("serverBase"); + $data["serverTime"] = $this->yellow->config->get("serverTime"); + $data["serverLanguages"] = $this->yellow->text->getLanguages(); } else { $data["login"] = $this->yellow->page->statusCode==200; $data["loginEmail"] = $this->yellow->config->get("loginEmail"); @@ -549,6 +557,17 @@ class YellowWebinterface return $data; } + // Return text strings + function getTextData() + { + $language = $this->isUser() ? $this->users->getLanguage() : $this->yellow->page->get("language"); + if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language"); + $textLanguage = array_merge($this->yellow->text->getData("language", $language)); + $textWebinterface = array_merge($this->yellow->text->getData("webinterface", $language)); + $textYellow = array_merge($this->yellow->text->getData("yellow", $language)); + return array_merge($textLanguage, $textWebinterface, $textYellow); + } + // Check if web interface request function isActive() { @@ -576,22 +595,19 @@ class YellowUsers } // Load users from file - function load($fileName) + function load($fileName) { - $fileData = @file($fileName); - if($fileData) + if(defined("DEBUG") && DEBUG>=2) echo "YellowUsers::load file:$fileName<br/>\n"; + $fileData = $this->yellow->toolbox->readFile($fileName); + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) { - if(defined("DEBUG") && DEBUG>=2) echo "YellowUsers::load file:$fileName<br/>\n"; - foreach($fileData as $line) + if(preg_match("/^\#/", $line)) continue; + preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]) && + !empty($matches[5]) && !empty($matches[6])) { - if(preg_match("/^\#/", $line)) continue; - preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); - if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]) && - !empty($matches[5]) && !empty($matches[6])) - { - $this->set($matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]); - if(defined("DEBUG") && DEBUG>=3) echo "YellowUsers::load email:$matches[1]<br/>\n"; - } + $this->set($matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]); + if(defined("DEBUG") && DEBUG>=3) echo "YellowUsers::load email:$matches[1]<br/>\n"; } } } @@ -613,28 +629,25 @@ class YellowUsers { $email = strreplaceu(',', '-', $email); $hash = strreplaceu(',', '-', $hash); - $fileData = @file($fileName); - if($fileData) + $fileData = $this->yellow->toolbox->readFile($fileName); + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) { - foreach($fileData as $line) + preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]) && + !empty($matches[5]) && !empty($matches[6])) { - preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); - if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]) && - !empty($matches[5]) && !empty($matches[6])) + if($matches[1] == $email) { - if($matches[1] == $email) - { - $name = strreplaceu(',', '-', empty($name) ? $matches[3] : $name); - $language = strreplaceu(',', '-', empty($language) ? $matches[4] : $language); - $status = strreplaceu(',', '-', empty($status) ? $matches[5] : $status); - $home = strreplaceu(',', '-', empty($home) ? $matches[6] : $home); - $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; - $found = true; - continue; - } + $name = strreplaceu(',', '-', empty($name) ? $matches[3] : $name); + $language = strreplaceu(',', '-', empty($language) ? $matches[4] : $language); + $status = strreplaceu(',', '-', empty($status) ? $matches[5] : $status); + $home = strreplaceu(',', '-', empty($home) ? $matches[6] : $home); + $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; + $found = true; + continue; } - $fileDataNew .= $line; } + $fileDataNew .= $line; } if(!$found) { @@ -661,7 +674,6 @@ class YellowUsers if($this->isExisting($email)) { $serverScheme = $this->yellow->config->get("webinterfaceServerScheme"); - $serverName = $this->yellow->config->get("webinterfaceServerName"); $location = $this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"); $session = $this->yellow->toolbox->createHash($this->users[$email]["hash"], "sha256"); if(empty($session)) $session = "error-hash-algorithm-sha256"; @@ -673,7 +685,6 @@ class YellowUsers function destroyCookie($cookieName) { $serverScheme = $this->yellow->config->get("webinterfaceServerScheme"); - $serverName = $this->yellow->config->get("webinterfaceServerName"); $location = $this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"); setcookie($cookieName, "", time()-3600, $location, "", $serverScheme=="https"); }