From ff49a0beb7ca2d2ae71a3723680ed5cbe41eb92a Mon Sep 17 00:00:00 2001 From: Stricted Date: Wed, 23 Dec 2015 20:15:10 +0100 Subject: [PATCH] add current dev version (WIP) --- cache/.gitignore | 1 + config.inc.php.example | 14 +- database.sql | 1 + index.php | 3 +- js/default/functions.js | 14 +- lib/api/page/ServerPage.class.php | 31 +- lib/page/LoginPage.class.php | 2 +- lib/system/DNS.class.php | 13 +- lib/system/RequestHandler.class.php | 97 +++- lib/system/SingletonFactory.class.php | 74 +++ lib/system/SystemException.class.php | 510 +++++++++--------- lib/system/User.class.php | 7 +- lib/system/api/smarty | 2 +- lib/system/cache/CacheHandler.class.php | 140 +++++ .../builder/AbstractCacheBuilder.class.php | 77 +++ .../builder/ControllerCacheBuilder.class.php | 34 ++ .../builder/DNSApiCacheBuilder.class.php | 49 ++ .../cache/builder/ICacheBuilder.class.php | 38 ++ .../cache/source/DiskCacheSource.class.php | 152 ++++++ .../cache/source/ICacheSource.class.php | 45 ++ lib/system/template/plugins/block.link.php | 40 ++ .../template/plugins/function.pages.php | 2 +- .../template/plugins/prefilter.hascontent.php | 2 +- templates/default/apiManagement.tpl | 4 +- templates/default/domainAdd.tpl | 6 +- templates/default/error.tpl | 2 +- templates/default/header.tpl | 10 +- templates/default/index.tpl | 14 +- templates/default/login.tpl | 2 +- templates/default/recordAdd.tpl | 8 +- templates/default/recordEdit.tpl | 8 +- templates/default/recordList.tpl | 20 +- templates/default/secAdd.tpl | 8 +- templates/default/secList.tpl | 4 +- 34 files changed, 1060 insertions(+), 374 deletions(-) create mode 100644 cache/.gitignore create mode 100644 lib/system/SingletonFactory.class.php create mode 100644 lib/system/cache/CacheHandler.class.php create mode 100644 lib/system/cache/builder/AbstractCacheBuilder.class.php create mode 100644 lib/system/cache/builder/ControllerCacheBuilder.class.php create mode 100644 lib/system/cache/builder/DNSApiCacheBuilder.class.php create mode 100644 lib/system/cache/builder/ICacheBuilder.class.php create mode 100644 lib/system/cache/source/DiskCacheSource.class.php create mode 100644 lib/system/cache/source/ICacheSource.class.php create mode 100644 lib/system/template/plugins/block.link.php diff --git a/cache/.gitignore b/cache/.gitignore new file mode 100644 index 0000000..66ca35b --- /dev/null +++ b/cache/.gitignore @@ -0,0 +1 @@ +*.php \ No newline at end of file diff --git a/config.inc.php.example b/config.inc.php.example index 1169b31..178a25f 100644 --- a/config.inc.php.example +++ b/config.inc.php.example @@ -1,8 +1,8 @@ - diff --git a/js/default/functions.js b/js/default/functions.js index f87f682..9432361 100644 --- a/js/default/functions.js +++ b/js/default/functions.js @@ -43,7 +43,7 @@ $(document).ready(function(){ } $.ajax({ - url: 'index.php?page=action', + url: 'index.php?Action', data: { action: action, dataID: deleteID @@ -76,7 +76,7 @@ $(document).ready(function(){ $('#requestApiKey').unbind('click'); $("#requestApiKey").on('click', function(e){ $.ajax({ - url: 'index.php?page=action', + url: 'index.php?Action', data: { action: 'requestApiKey', dataID: 1 @@ -121,7 +121,7 @@ $(document).ready(function(){ } $.ajax({ - url: 'index.php?page=action', + url: 'index.php?Action', data: { action: action, dataID: dataID @@ -239,7 +239,7 @@ $(document).ready(function(){ var t = $(this); var dataID = t.attr('export-id'); $.ajax({ - url: 'index.php?page=action', + url: 'index.php?Action', data: { action: 'export', dataID: dataID @@ -316,7 +316,7 @@ $(document).ready(function(){ var origin = $('#importModal').find('.modal-body').find('#importOrigin').val(); var zone = $('#importModal').find('.modal-body').find('#importTextarea').val(); $.ajax({ - url: 'index.php?page=action', + url: 'index.php?Action', data: { action: 'import', dataID: dataID ? dataID : 0, /* 0 for new zone otherwise soaID for existing zone*/ @@ -332,11 +332,11 @@ $(document).ready(function(){ else { if (!dataID) { // redirect to main page on success - $(location).attr('href','index.php?page=DomainList'); + $(location).attr('href','index.php?DomainList'); } else { // redirect to record list on success - $(location).attr('href','index.php?page=RecordList&id=' + dataID); + $(location).attr('href','index.php?RecordList/' + dataID); } } } diff --git a/lib/api/page/ServerPage.class.php b/lib/api/page/ServerPage.class.php index e0386ba..4554fc9 100644 --- a/lib/api/page/ServerPage.class.php +++ b/lib/api/page/ServerPage.class.php @@ -1,6 +1,7 @@ query($sql, array(1)); - - while ($zone = DNS::getDB()->fetch_array($statement)) { - $data[$zone['origin']] = array(); - $data[$zone['origin']]['soa'] = $zone; - $data[$zone['origin']]['rr'] = array(); - $data[$zone['origin']]['sec'] = array(); - - /* resource records */ - $sql2 = "SELECT * FROM dns_rr where zone = ? and active = ?"; - $statement2 = DNS::getDB()->query($sql2, array($zone['id'], 1)); - while ($rr = DNS::getDB()->fetch_array($statement2)) { - $data[$zone['origin']]['rr'][] = $rr; - } - - if (ENABLE_DNSSEC) { - /* dnssec keys */ - $sql3 = "SELECT * FROM dns_sec where zone = ? and active = ?"; - $statement3 = DNS::getDB()->query($sql3, array($zone['id'], 1)); - while ($sec = DNS::getDB()->fetch_array($statement3)) { - $data[$zone['origin']]['sec'][] = $sec; - } - } - } + $data = DNSApiCacheBuilder::getInstance()->getData(); header('Content-Type: application/json'); echo json_encode($data, JSON_PRETTY_PRINT); diff --git a/lib/page/LoginPage.class.php b/lib/page/LoginPage.class.php index e2da1c8..283ce7a 100644 --- a/lib/page/LoginPage.class.php +++ b/lib/page/LoginPage.class.php @@ -20,7 +20,7 @@ class LoginPage extends AbstractPage { } User::login(trim($_POST['username']), trim($_POST['password']), $remember); - header("Location: ?page=index"); + header("Location: index.php?index"); } } } diff --git a/lib/system/DNS.class.php b/lib/system/DNS.class.php index 87edc9d..1b1dc51 100644 --- a/lib/system/DNS.class.php +++ b/lib/system/DNS.class.php @@ -138,9 +138,11 @@ class DNS { if (error_reporting() != 0) { $type = 'error'; switch ($errorNo) { - case 2: $type = 'warning'; + case 2: + $type = 'warning'; break; - case 8: $type = 'notice'; + case 8: + $type = 'notice'; break; } @@ -285,7 +287,12 @@ class DNS { require_once(DNS_DIR.'/lib/system/api/smarty/libs/Smarty.class.php'); self::$tplObj = new \Smarty; - self::getTPL()->setTemplateDir(DNS_DIR.(empty(self::$module) ? '' : '/'.self::$module)."/templates/".$tpl); + if (!empty(self::$module)) { + // try first to load the template from module then from core + self::getTPL()->addTemplateDir(DNS_DIR.'/'.self::$module."/templates/".$tpl); + } + + self::getTPL()->addTemplateDir(DNS_DIR."/templates/".$tpl); self::getTPL()->setCompileDir(DNS_DIR.(empty(self::$module) ? '' : '/'.self::$module)."/templates/compiled/".$tpl); self::getTPL()->setPluginsDir(array( DNS_DIR."/lib/system/api/smarty/libs/plugins", diff --git a/lib/system/RequestHandler.class.php b/lib/system/RequestHandler.class.php index bf61611..89e9441 100644 --- a/lib/system/RequestHandler.class.php +++ b/lib/system/RequestHandler.class.php @@ -1,5 +1,6 @@ pattern = '~/?(?:(?P[A-Za-z0-9\-]+)(?:/(?P\d+)(?:-(?P[^/]+))?)?)?~x'; + $this->getControllers($module); + + if (DNS::getSession()->username !== null) { + DNS::getTPL()->assign(array("username" => DNS::getSession()->username)); } else { - $className = '\\dns'.(empty($module) ? '' : '\\'.$module).'\\page\\IndexPage'; + DNS::getTPL()->assign(array("username" => '')); } - if (!User::isLoggedIn() && $className != '\dns\page\LoginPage' && $className != '\dns\page\ApiPage') { - DNS::getTPL()->display('login.tpl'); - exit; + $className = ""; + if (!empty($_SERVER['QUERY_STRING'])) { + $this->matches($_SERVER['QUERY_STRING']); + $this->registerRouteData(); + } + else { + $className = '\\dns'.(empty($module) ? '' : '\\'.$module).'\\page\\IndexPage'; } - if (DNS::getSession()->username !== null) { - DNS::getTPL()->assign(array("username" => DNS::getSession()->username)); + if (isset($this->routeData['controller']) && !empty($this->routeData['controller'])) { + $controller = strtolower($this->routeData['controller']); + if (isset($this->controllers[$controller]) && !empty($this->controllers[$controller])) { + $className = $this->controllers[$controller]; + } + else { + @header('HTTP/1.0 404 Not Found'); + DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => 'The link you are trying to reach is no longer available or invalid.')); + DNS::getTPL()->display('error.tpl'); + exit; + } } - if (empty($className)) { - @header('HTTP/1.0 404 Not Found'); - DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => 'The link you are trying to reach is no longer available or invalid.')); - DNS::getTPL()->display('error.tpl'); + if (!User::isLoggedIn() && $className != '\dns\page\LoginPage' && $className != '\dns\page\ApiPage') { + DNS::getTPL()->display('login.tpl'); exit; } @@ -80,4 +86,45 @@ class RequestHandler { exit; } } + + /** + * Registers route data within $_GET and $_REQUEST. + */ + protected function registerRouteData() { + foreach ($this->routeData as $key => $value) { + $_GET[$key] = $value; + $_REQUEST[$key] = $value; + } + } + + public function getControllers ($module) { + + $this->controllers = ControllerCacheBuilder::getInstance()->getData(array('module' => $module)); + /* + $pages = glob(DNS_DIR.'/lib/'.(empty($module) ? '' : $module.'/').'page/*Page.class.php'); + + foreach ($pages as $page) { + $page = str_replace('Page.class.php', '', basename($page)); + + $class = "\\dns".(empty($module) ? '' : "\\".$module)."\\page\\".$page."Page"; + if (class_exists($class) && is_subclass_of($class, '\\dns\\page\\AbstractPage')) { + $this->controllers[strtolower($page)] = $class; + } + } + */ + } + + public function matches($requestURL) { + if (preg_match($this->pattern, $requestURL, $matches)) { + foreach ($matches as $key => $value) { + if (!is_numeric($key)) { + $this->routeData[$key] = $value; + } + } + + return true; + } + + return false; + } } diff --git a/lib/system/SingletonFactory.class.php b/lib/system/SingletonFactory.class.php new file mode 100644 index 0000000..c5fee78 --- /dev/null +++ b/lib/system/SingletonFactory.class.php @@ -0,0 +1,74 @@ +<?php +namespace dns\system; + +/** + * Basis class for singleton classes. + * + * @author Alexander Ebert + * @copyright 2001-2014 WoltLab GmbH + * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> + * @package com.woltlab.wcf + * @subpackage system + * @category Community Framework + */ +abstract class SingletonFactory { + /** + * list of singletons + * @var array<SingletonFactory> + */ + protected static $__singletonObjects = array(); + + /** + * Singletons do not support a public constructor. Override init() if + * your class needs to initialize components on creation. + */ + protected final function __construct() { + $this->init(); + } + + /** + * Called within __construct(), override if neccessary. + */ + protected function init() { } + + /** + * Object cloning is disallowed. + */ + protected final function __clone() { } + + /** + * Object serializing is disallowed. + */ + public final function __sleep() { + throw new \Exception('Serializing of Singletons is not allowed'); + } + + /** + * Returns an unique instance of current child class. + * + * @return \dns\system\SingletonFactory + */ + public static final function getInstance() { + $className = get_called_class(); + if (!array_key_exists($className, self::$__singletonObjects)) { + self::$__singletonObjects[$className] = null; + self::$__singletonObjects[$className] = new $className(); + } + else if (self::$__singletonObjects[$className] === null) { + throw new \Exception("Infinite loop detected while trying to retrieve object for '".$className."'"); + } + + return self::$__singletonObjects[$className]; + } + + /** + * Returns whether this singleton is already initialized. + * + * @return boolean + */ + public static final function isInitialized() { + $className = get_called_class(); + + return isset(self::$__singletonObjects[$className]); + } +} diff --git a/lib/system/SystemException.class.php b/lib/system/SystemException.class.php index e616371..03ea54e 100644 --- a/lib/system/SystemException.class.php +++ b/lib/system/SystemException.class.php @@ -1,255 +1,255 @@ -<?php -namespace dns\system; - -/** - * A SystemException is thrown when an unexpected error occurs. - * - * @author Marcel Werk - * @copyright 2001-2015 WoltLab GmbH - * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> - * @package com.woltlab.wcf - * @subpackage system.exception - * @category Community Framework - */ -// @codingStandardsIgnoreFile -class SystemException extends \Exception { - /** - * error description - * @var string - */ - protected $description = null; - - /** - * additional information - * @var string - */ - protected $information = ''; - - /** - * additional information - * @var string - */ - protected $functions = ''; - - /** - * exception id - * @var string - */ - protected $exceptionID = ''; - - /** - * Creates a new SystemException. - * - * @param string $message error message - * @param integer $code error code - * @param string $description description of the error - * @param \Exception $previous repacked Exception - */ - public function __construct($message = '', $code = 0, $description = '', \Exception $previous = null) { - parent::__construct((string) $message, (int) $code, $previous); - $this->description = $description; - } - - /** - * Removes database password from stack trace. - * @see \Exception::getTraceAsString() - */ - public function __getTraceAsString() { - $e = ($this->getPrevious() ?: $this); - $string = $e->getTraceAsString(); - $string = preg_replace('/PDO->__construct\(.*\)/', 'PDO->__construct(...)', $string); - $string = preg_replace('/DB->__construct\(.*\)/', 'DB->__construct(...)', $string); - return $string; - } - - /** - * @see \Exception::getMessage() - */ - public function _getMessage() { - $e = ($this->getPrevious() ?: $this); - return $e->getMessage(); - } - - /** - * Returns the description of this exception. - * - * @return string - */ - public function getDescription() { - return $this->description; - } - - /** - * Returns exception id - * - * @return string - */ - public function getExceptionID() { - if (empty($this->exceptionID)) { - $this->logError(); - } - - return $this->exceptionID; - } - - /** - * Writes an error to log file. - */ - protected function logError() { - if (!empty($this->exceptionID)) { - return; - } - - $logFile = DNS_DIR . '/log/' . gmdate('Y-m-d', time()) . '.txt'; - - // try to create file - @touch($logFile); - - // validate if file exists and is accessible for us - if (!file_exists($logFile) || !is_writable($logFile)) { - /* - We cannot recover if we reached this point, the server admin - is urged to fix his pretty much broken configuration. - - GLaDOS: Look at you, sailing through the air majestically, like an eagle... piloting a blimp. - */ - return; - } - - $e = ($this->getPrevious() ?: $this); - - // don't forget to update ExceptionLogViewPage, when changing the log file format - $message = gmdate('r', time())."\n". - 'Message: '.$e->getMessage()."\n". - 'File: '.$e->getFile().' ('.$e->getLine().")\n". - 'PHP version: '.phpversion()."\n". - 'DNS version: '.DNS_VERSION."\n". - 'Request URI: '.(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '')."\n". - 'Referrer: '.(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')."\n". - 'User-Agent: '.(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')."\n". - 'Information: '.json_encode($this->information)."\n". - "Stacktrace: \n ".implode("\n ", explode("\n", $this->__getTraceAsString()))."\n"; - - // calculate Exception-ID - $this->exceptionID = sha1($message); - $message = "<<<<<<<<".$this->exceptionID."<<<<\n".$message."<<<<\n\n"; - - // append - @file_put_contents($logFile, $message, FILE_APPEND); - } - - /** - * @see \wcf\system\exception\IPrintableException::show() - */ - public function show() { - // send status code - @header('HTTP/1.1 503 Service Unavailable'); - - // print report - $e = ($this->getPrevious() ?: $this); - ?><!DOCTYPE html> - <html> - <head> - <title>Fatal error: <?php echo htmlspecialchars($this->_getMessage(), ENT_COMPAT, 'UTF-8'); ?> - - - - -
-

Fatal error: getExceptionID()) { ?>Unable to write log file, please make "/log/" writable!_getMessage(), ENT_COMPAT, 'UTF-8'); } ?>

- - -
- getDescription()) { ?>


getDescription(); ?>

- -

Information:

-

- error message: _getMessage(), ENT_COMPAT, 'UTF-8'); ?>
- error code: getCode()); ?>
- information; ?> - file: getFile(), ENT_COMPAT, 'UTF-8'); ?> (getLine(); ?>)
- php version:
- dns version:
- date:
- request:
- referer:
-

- -

Stacktrace:

-
__getTraceAsString(), ENT_COMPAT, 'UTF-8'); ?>
-
- -
-

Information:

-

- getExceptionID()) { ?> - Unable to write log file, please make "/log/" writable! - - ID: getExceptionID(); ?>
- Please send the ID above to the site administrator. - -

-
- - functions; ?> -
- - - - + * @package com.woltlab.wcf + * @subpackage system.exception + * @category Community Framework + */ +// @codingStandardsIgnoreFile +class SystemException extends \Exception { + /** + * error description + * @var string + */ + protected $description = null; + + /** + * additional information + * @var string + */ + protected $information = ''; + + /** + * additional information + * @var string + */ + protected $functions = ''; + + /** + * exception id + * @var string + */ + protected $exceptionID = ''; + + /** + * Creates a new SystemException. + * + * @param string $message error message + * @param integer $code error code + * @param string $description description of the error + * @param \Exception $previous repacked Exception + */ + public function __construct($message = '', $code = 0, $description = '', \Exception $previous = null) { + parent::__construct((string) $message, (int) $code, $previous); + $this->description = $description; + } + + /** + * Removes database password from stack trace. + * @see \Exception::getTraceAsString() + */ + public function __getTraceAsString() { + $e = ($this->getPrevious() ?: $this); + $string = $e->getTraceAsString(); + $string = preg_replace('/PDO->__construct\(.*\)/', 'PDO->__construct(...)', $string); + $string = preg_replace('/DB->__construct\(.*\)/', 'DB->__construct(...)', $string); + return $string; + } + + /** + * @see \Exception::getMessage() + */ + public function _getMessage() { + $e = ($this->getPrevious() ?: $this); + return $e->getMessage(); + } + + /** + * Returns the description of this exception. + * + * @return string + */ + public function getDescription() { + return $this->description; + } + + /** + * Returns exception id + * + * @return string + */ + public function getExceptionID() { + if (empty($this->exceptionID)) { + $this->logError(); + } + + return $this->exceptionID; + } + + /** + * Writes an error to log file. + */ + protected function logError() { + if (!empty($this->exceptionID)) { + return; + } + + $logFile = DNS_DIR . '/log/' . gmdate('Y-m-d', time()) . '.txt'; + + // try to create file + @touch($logFile); + + // validate if file exists and is accessible for us + if (!file_exists($logFile) || !is_writable($logFile)) { + /* + We cannot recover if we reached this point, the server admin + is urged to fix his pretty much broken configuration. + + GLaDOS: Look at you, sailing through the air majestically, like an eagle... piloting a blimp. + */ + return; + } + + $e = ($this->getPrevious() ?: $this); + + // don't forget to update ExceptionLogViewPage, when changing the log file format + $message = gmdate('r', time())."\n". + 'Message: '.$e->getMessage()."\n". + 'File: '.$e->getFile().' ('.$e->getLine().")\n". + 'PHP version: '.phpversion()."\n". + 'DNS version: '.DNS_VERSION."\n". + 'Request URI: '.(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '')."\n". + 'Referrer: '.(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')."\n". + 'User-Agent: '.(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')."\n". + 'Information: '.json_encode($this->information)."\n". + "Stacktrace: \n ".implode("\n ", explode("\n", $this->__getTraceAsString()))."\n"; + + // calculate Exception-ID + $this->exceptionID = sha1($message); + $message = "<<<<<<<<".$this->exceptionID."<<<<\n".$message."<<<<\n\n"; + + // append + @file_put_contents($logFile, $message, FILE_APPEND); + } + + /** + * @see \wcf\system\exception\IPrintableException::show() + */ + public function show() { + // send status code + @header('HTTP/1.1 503 Service Unavailable'); + + // print report + $e = ($this->getPrevious() ?: $this); + ?> + + + Fatal error: <?php echo htmlspecialchars($this->_getMessage(), ENT_COMPAT, 'UTF-8'); ?> + + + + +
+

Fatal error: getExceptionID()) { ?>Unable to write log file, please make "/log/" writable!_getMessage(), ENT_COMPAT, 'UTF-8'); } ?>

+ + +
+ getDescription()) { ?>


getDescription(); ?>

+ +

Information:

+

+ error message: _getMessage(), ENT_COMPAT, 'UTF-8'); ?>
+ error code: getCode()); ?>
+ information; ?> + file: getFile(), ENT_COMPAT, 'UTF-8'); ?> (getLine(); ?>)
+ php version:
+ dns version:
+ date:
+ request:
+ referer:
+

+ +

Stacktrace:

+
__getTraceAsString(), ENT_COMPAT, 'UTF-8'); ?>
+
+ +
+

Information:

+

+ getExceptionID()) { ?> + Unable to write log file, please make "/log/" writable! + + ID: getExceptionID(); ?>
+ Please send the ID above to the site administrator. + +

+
+ + functions; ?> +
+ + + + register('username', $row["username"]); DNS::getSession()->register('userID', $row["userID"]); DNS::getSession()->register('status', intval($row["status"])); - + DNS::getSession()->register('csrf_token', DNS::generateRandomID()); return true; } } @@ -81,6 +81,10 @@ class User { return false; } + public static function getSecurityToken () { + return DNS::getSession()->csrf_token; + } + /** * login the user * @@ -98,6 +102,7 @@ class User { DNS::getSession()->register('username', $row["username"]); DNS::getSession()->register('userID', $row["userID"]); DNS::getSession()->register('status', intval($row["status"])); + DNS::getSession()->register('csrf_token', DNS::generateRandomID()); if ($remember === true) { $sha1UserID = sha1($row["userID"]); diff --git a/lib/system/api/smarty b/lib/system/api/smarty index 4537d8a..35480f1 160000 --- a/lib/system/api/smarty +++ b/lib/system/api/smarty @@ -1 +1 @@ -Subproject commit 4537d8aae6c4a26f5439bc3a05d3437d25c2c4d2 +Subproject commit 35480f10e7ce9b0fdaf23d3799d7b79463919b1e diff --git a/lib/system/cache/CacheHandler.class.php b/lib/system/cache/CacheHandler.class.php new file mode 100644 index 0000000..88b861a --- /dev/null +++ b/lib/system/cache/CacheHandler.class.php @@ -0,0 +1,140 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache + * @category Community Framework + */ +class CacheHandler extends SingletonFactory { + /** + * cache source object + * @var \dns\system\cache\source\ICacheSource + */ + protected $cacheSource = null; + + /** + * Creates a new CacheHandler object. + */ + protected function init() { + // init cache source object + try { + $className = 'dns\system\cache\source\\'.ucfirst(CACHE_SOURCE_TYPE).'CacheSource'; + if (class_exists($className)) { + $this->cacheSource = new $className(); + } + else { + // fallback to disk cache + $this->cacheSource = new DiskCacheSource(); + } + } + catch (\Exception $e) { + if (CACHE_SOURCE_TYPE != 'disk') { + // fallback to disk cache + $this->cacheSource = new DiskCacheSource(); + } + else { + throw $e; + } + } + } + + /** + * Flush cache for given resource. + * + * @param \dns\system\cache\builder\ICacheBuilder $cacheBuilder + * @param array $parameters + */ + public function flush(ICacheBuilder $cacheBuilder, array $parameters) { + $this->getCacheSource()->flush($this->getCacheName($cacheBuilder, $parameters), empty($parameters)); + } + + /** + * Flushes the entire cache. + */ + public function flushAll() { + $this->getCacheSource()->flushAll(); + } + + /** + * Returns cached value for given resource, false if no cache exists. + * + * @param \dns\system\cache\builder\ICacheBuilder $cacheBuilder + * @param array $parameters + * @return mixed + */ + public function get(ICacheBuilder $cacheBuilder, array $parameters) { + return $this->getCacheSource()->get($this->getCacheName($cacheBuilder, $parameters), $cacheBuilder->getMaxLifetime()); + } + + /** + * Caches a value for given resource, + * + * @param \dns\system\cache\builder\ICacheBuilder $cacheBuilder + * @param array $parameters + * @param array $data + */ + public function set(ICacheBuilder $cacheBuilder, array $parameters, array $data) { + $this->getCacheSource()->set($this->getCacheName($cacheBuilder, $parameters), $data, $cacheBuilder->getMaxLifetime()); + } + + /** + * Returns cache index hash. + * + * @param array $parameters + * @return string + */ + public function getCacheIndex(array $parameters) { + return sha1(serialize($this->orderParameters($parameters))); + } + + /** + * Builds cache name. + * + * @param \dns\system\cache\builder\ICacheBuilder $cacheBuilder + * @param array $parameters + * @return string + */ + protected function getCacheName(ICacheBuilder $cacheBuilder, array $parameters = array()) { + $className = explode('\\', get_class($cacheBuilder)); + $cacheName = str_replace('CacheBuilder', '', array_pop($className)); + if (!empty($parameters)) { + $cacheName .= '-' . $this->getCacheIndex($parameters); + } + + return ucfirst($cacheName); + } + + /** + * Returns the cache source object. + * + * @return \dns\system\cache\source\ICacheSource + */ + public function getCacheSource() { + return $this->cacheSource; + } + + /** + * Unifys parameter order, numeric indizes will be discarded. + * + * @param array $parameters + * @return array + */ + protected function orderParameters($parameters) { + if (!empty($parameters)) { + array_multisort($parameters); + } + + return $parameters; + } +} diff --git a/lib/system/cache/builder/AbstractCacheBuilder.class.php b/lib/system/cache/builder/AbstractCacheBuilder.class.php new file mode 100644 index 0000000..d2ffe24 --- /dev/null +++ b/lib/system/cache/builder/AbstractCacheBuilder.class.php @@ -0,0 +1,77 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache.builder + * @category Community Framework + */ +abstract class AbstractCacheBuilder extends SingletonFactory implements ICacheBuilder { + /** + * list of cache resources by index + * @var array + */ + protected $cache = array(); + + /** + * maximum cache lifetime in seconds, '0' equals infinite + * @var integer + */ + protected $maxLifetime = 0; + + /** + * @see \dns\system\cache\builder\ICacheBuilder::getData() + */ + public function getData(array $parameters = array(), $arrayIndex = '') { + $index = CacheHandler::getInstance()->getCacheIndex($parameters); + + if (!isset($this->cache[$index])) { + // fetch cache or rebuild if missing + $this->cache[$index] = CacheHandler::getInstance()->get($this, $parameters); + if ($this->cache[$index] === null) { + $this->cache[$index] = $this->rebuild($parameters); + + // update cache + CacheHandler::getInstance()->set($this, $parameters, $this->cache[$index]); + } + } + + if (!empty($arrayIndex)) { + if (!isset($this->cache[$index][$arrayIndex])) { + throw new \Exception("array index '".$arrayIndex."' does not exist in cache resource"); + } + + return $this->cache[$index][$arrayIndex]; + } + + return $this->cache[$index]; + } + + /** + * @see \dns\system\cache\builder\ICacheBuilder::getMaxLifetime() + */ + public function getMaxLifetime() { + return $this->maxLifetime; + } + + /** + * @see \dns\system\cache\builder\ICacheBuilder::reset() + */ + public function reset(array $parameters = array()) { + CacheHandler::getInstance()->flush($this, $parameters); + } + + /** + * Rebuilds cache for current resource. + * + * @param array $parameters + */ + abstract protected function rebuild(array $parameters); +} diff --git a/lib/system/cache/builder/ControllerCacheBuilder.class.php b/lib/system/cache/builder/ControllerCacheBuilder.class.php new file mode 100644 index 0000000..0e1b128 --- /dev/null +++ b/lib/system/cache/builder/ControllerCacheBuilder.class.php @@ -0,0 +1,34 @@ +query($sql, array(1)); + + while ($zone = DNS::getDB()->fetch_array($statement)) { + $data[$zone['origin']] = array(); + $data[$zone['origin']]['soa'] = $zone; + $data[$zone['origin']]['rr'] = array(); + $data[$zone['origin']]['sec'] = array(); + + /* resource records */ + $sql2 = "SELECT * FROM dns_rr where zone = ? and active = ?"; + $statement2 = DNS::getDB()->query($sql2, array($zone['id'], 1)); + while ($rr = DNS::getDB()->fetch_array($statement2)) { + $data[$zone['origin']]['rr'][] = $rr; + } + + if (ENABLE_DNSSEC) { + /* dnssec keys */ + $sql3 = "SELECT * FROM dns_sec where zone = ? and active = ?"; + $statement3 = DNS::getDB()->query($sql3, array($zone['id'], 1)); + while ($sec = DNS::getDB()->fetch_array($statement3)) { + $data[$zone['origin']]['sec'][] = $sec; + } + } + } + + return $data; + } +} diff --git a/lib/system/cache/builder/ICacheBuilder.class.php b/lib/system/cache/builder/ICacheBuilder.class.php new file mode 100644 index 0000000..608e05b --- /dev/null +++ b/lib/system/cache/builder/ICacheBuilder.class.php @@ -0,0 +1,38 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache.builder + * @category Community Framework + */ +interface ICacheBuilder { + /** + * Returns the data that ought to be cached. + * + * @param array $parameters + * @param string $arrayIndex + * @return array + */ + public function getData(array $parameters = array(), $arrayIndex = ''); + + /** + * Returns maximum lifetime for cache resource. + * + * @return integer + */ + public function getMaxLifetime(); + + /** + * Flushes cache. If no parameters are given, all caches starting with + * the same cache name will be flushed too. + * + * @param array $parameters + */ + public function reset(array $parameters = array()); +} diff --git a/lib/system/cache/source/DiskCacheSource.class.php b/lib/system/cache/source/DiskCacheSource.class.php new file mode 100644 index 0000000..162522f --- /dev/null +++ b/lib/system/cache/source/DiskCacheSource.class.php @@ -0,0 +1,152 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache.source + * @category Community Framework + */ +class DiskCacheSource implements ICacheSource { + /** + * @see \dns\system\cache\source\ICacheSource::flush() + */ + public function flush($cacheName, $useWildcard) { + if ($useWildcard) { + $this->removeFiles('cache.'.$cacheName.'*.php'); + } + else { + $this->removeFiles('cache.'.$cacheName.'.php'); + } + } + + /** + * @see \dns\system\cache\source\ICacheSource::flushAll() + */ + public function flushAll() { + $this->removeFiles('cache.*.php'); + } + + /** + * @see \dns\system\cache\source\ICacheSource::get() + */ + public function get($cacheName, $maxLifetime) { + $filename = $this->getFilename($cacheName); + if ($this->needRebuild($filename, $maxLifetime)) { + return null; + } + + // load cache + try { + return $this->readCache($cacheName, $filename); + } + catch (\Exception $e) { + return null; + } + } + + /** + * @see \dns\system\cache\source\ICacheSource::set() + */ + public function set($cacheName, $value, $maxLifetime) { + $filename = $this->getFilename($cacheName); + $content = "\n"; + $content .= serialize($value); + + if (!file_exists($filename)) { + @touch($filename); + } + + $handler = fOpen($filename, "a+"); + fWrite($handler, $content); + fClose($handler); + } + + /** + * Returns cache filename. + * + * @param string $cacheName + * @return string + */ + protected function getFilename($cacheName) { + return DNS_DIR.'/cache/cache.'.$cacheName.'.php'; + } + + /** + * Removes files matching given pattern. + * + * @param string $pattern + */ + protected function removeFiles($pattern) { + $directory = DNS_DIR.'cache/'; + + foreach (glob($directory.$pattern) as $filename) { + @unlink($filename); + } + } + + /** + * Determines wheater the cache needs to be rebuild or not. + * + * @param string $filename + * @param integer $maxLifetime + * @return boolean + */ + protected function needRebuild($filename, $maxLifetime) { + // cache does not exist + if (!file_exists($filename)) { + return true; + } + + // cache is empty + if (!@filesize($filename)) { + return true; + } + + // cache resource was marked as obsolete + if (($mtime = filemtime($filename)) <= 1) { + return true; + } + + // maxlifetime expired + if ($maxLifetime > 0 && (time() - $mtime) > $maxLifetime) { + return true; + } + + // do not rebuild cache + return false; + } + + /** + * Loads the file of a cached resource. + * + * @param string $cacheName + * @param string $filename + * @return mixed + */ + protected function readCache($cacheName, $filename) { + // get file contents + $contents = file_get_contents($filename); + + // find first newline + $position = strpos($contents, "\n"); + if ($position === false) { + throw new \Exception("Unable to load cache resource '".$cacheName."'"); + } + + // cut contents + $contents = substr($contents, $position + 1); + + // unserialize + $value = @unserialize($contents); + if ($value === false) { + throw new \Exception("Unable to load cache resource '".$cacheName."'"); + } + + return $value; + } +} diff --git a/lib/system/cache/source/ICacheSource.class.php b/lib/system/cache/source/ICacheSource.class.php new file mode 100644 index 0000000..95237fb --- /dev/null +++ b/lib/system/cache/source/ICacheSource.class.php @@ -0,0 +1,45 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache.source + * @category Community Framework + */ +interface ICacheSource { + /** + * Flushes a specific cache, optionally removing caches which share the same name. + * + * @param string $cacheName + * @param boolean $useWildcard + */ + public function flush($cacheName, $useWildcard); + + /** + * Clears the cache completely. + */ + public function flushAll(); + + /** + * Returns a cached variable. + * + * @param string $cacheName + * @param integer $maxLifetime + * @return mixed + */ + public function get($cacheName, $maxLifetime); + + /** + * Stores a variable in the cache. + * + * @param string $cacheName + * @param mixed $value + * @param integer $maxLifetime + */ + public function set($cacheName, $value, $maxLifetime); +} diff --git a/lib/system/template/plugins/block.link.php b/lib/system/template/plugins/block.link.php new file mode 100644 index 0000000..c976980 --- /dev/null +++ b/lib/system/template/plugins/block.link.php @@ -0,0 +1,40 @@ + 1) { - $link = "index.php?page=".$tagArgs['controller'].(isset($tagArgs['id']) ? "&id=".$tagArgs['id'] : ""); + $link = "index.php?".$tagArgs['controller'].(isset($tagArgs['id']) ? "/".$tagArgs['id'] : ""); if (!isset($tagArgs['pageNo'])) { if (($tagArgs['pageNo'] = $tplObj->smarty->getTemplateVars('pageNo')) === null) { diff --git a/lib/system/template/plugins/prefilter.hascontent.php b/lib/system/template/plugins/prefilter.hascontent.php index 3049954..addd485 100644 --- a/lib/system/template/plugins/prefilter.hascontent.php +++ b/lib/system/template/plugins/prefilter.hascontent.php @@ -22,7 +22,7 @@ * @category Community Framework */ -function smarty_prefilter_hascontent($source, &$smarty) { +function smarty_prefilter_hascontent($source, $smarty) { $ldq = preg_quote($smarty->left_delimiter, '~'); $rdq = preg_quote($smarty->right_delimiter, '~'); diff --git a/templates/default/apiManagement.tpl b/templates/default/apiManagement.tpl index 1d3cccc..d6d7b69 100644 --- a/templates/default/apiManagement.tpl +++ b/templates/default/apiManagement.tpl @@ -2,8 +2,8 @@ diff --git a/templates/default/domainAdd.tpl b/templates/default/domainAdd.tpl index 201024f..cd1bf68 100644 --- a/templates/default/domainAdd.tpl +++ b/templates/default/domainAdd.tpl @@ -2,8 +2,8 @@ @@ -12,7 +12,7 @@ Domain erfolgreich hinzugefügt. {/if} -
+
diff --git a/templates/default/error.tpl b/templates/default/error.tpl index 278fb81..b102eaa 100644 --- a/templates/default/error.tpl +++ b/templates/default/error.tpl @@ -2,7 +2,7 @@ diff --git a/templates/default/header.tpl b/templates/default/header.tpl index acf6af3..fb61f6b 100644 --- a/templates/default/header.tpl +++ b/templates/default/header.tpl @@ -29,7 +29,7 @@ - Domain Control Panel + Domain Control Panel
@@ -49,14 +49,14 @@ Domains Settings diff --git a/templates/default/index.tpl b/templates/default/index.tpl index 77f407d..1c79aa9 100644 --- a/templates/default/index.tpl +++ b/templates/default/index.tpl @@ -2,7 +2,7 @@ @@ -10,7 +10,7 @@ @@ -26,9 +26,9 @@ - - - + + + {if $isReseller === true || $smarty.const.ENABLE_DNSSEC}{/if} @@ -39,12 +39,12 @@ {foreach from=$domains item=domain} - + diff --git a/templates/default/login.tpl b/templates/default/login.tpl index 1a5e67b..c735610 100644 --- a/templates/default/login.tpl +++ b/templates/default/login.tpl @@ -25,7 +25,7 @@

Please Sign In

- +
diff --git a/templates/default/recordAdd.tpl b/templates/default/recordAdd.tpl index f7b396c..345e449 100644 --- a/templates/default/recordAdd.tpl +++ b/templates/default/recordAdd.tpl @@ -2,15 +2,15 @@ @@ -19,7 +19,7 @@ Record erfolgreich hinzugefügt.
{/if} - +
diff --git a/templates/default/recordEdit.tpl b/templates/default/recordEdit.tpl index 197ecf5..7f33ba4 100644 --- a/templates/default/recordEdit.tpl +++ b/templates/default/recordEdit.tpl @@ -2,15 +2,15 @@ @@ -19,7 +19,7 @@ Record erfolgreich bearbeitet.
{/if} - +
diff --git a/templates/default/recordList.tpl b/templates/default/recordList.tpl index c5c0e8e..52f5217 100644 --- a/templates/default/recordList.tpl +++ b/templates/default/recordList.tpl @@ -2,16 +2,16 @@
IDNameSerialIDNameSerial RecordsManage
{$domain['id']}{if $domain['active'] != 1}{lang}domain.disabled{/lang} {/if}{$domain['origin']}{if $domain['active'] != 1}{lang}domain.disabled{/lang} {/if}{$domain['origin']} {$domain['serial']} {$domain['rrc']} {if $isReseller === true} {/if} - {if $smarty.const.ENABLE_DNSSEC} {/if} + {if $smarty.const.ENABLE_DNSSEC} {/if} {if $isReseller === true}{/if}
- - - - + + + + - + @@ -47,7 +47,7 @@ diff --git a/templates/default/secAdd.tpl b/templates/default/secAdd.tpl index ec434bd..bb1993d 100644 --- a/templates/default/secAdd.tpl +++ b/templates/default/secAdd.tpl @@ -1,14 +1,14 @@ {include file="header.tpl"} @@ -17,7 +17,7 @@ Record erfolgreich hinzugefügt. {/if} - +
diff --git a/templates/default/secList.tpl b/templates/default/secList.tpl index 4bf967d..d63eb28 100644 --- a/templates/default/secList.tpl +++ b/templates/default/secList.tpl @@ -1,8 +1,8 @@ {include file="header.tpl"} {if !empty($ds)} -- 2.20.1
IDHostTTLTypeIDHostTTLType PrioDataData Manage
{$record['aux']} {if $record['data']|strlen > 40}{$record['data']|substr:0:40}…{else}{$record['data']}{/if} - +