From 6a8d4f817d2e9ecda61183142c71b44e83d15eb3 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 19 Apr 2017 11:24:58 +0200 Subject: [inc/Database] Support expanding nested arrays In parametrized queries, you can now pass an array as an argument. This will result in the arguments being expanded to :a1,:a2,:a3 which is suitable for "IN (:slist)" constructs. --- inc/database.inc.php | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'inc') diff --git a/inc/database.inc.php b/inc/database.inc.php index ff98f5ee..f3a90fe7 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -100,6 +100,8 @@ class Database public static function simpleQuery($query, $args = array(), $ignoreError = false) { self::init(); + // Support passing nested arrays for IN statements, automagically refactor + self::handleArrayArgument($query, $args); try { if (!isset(self::$statements[$query])) { self::$statements[$query] = self::$dbh->prepare($query); @@ -122,6 +124,46 @@ class Database return false; } + /** + * Convert nested array argument to multiple arguments. + * If you have: + * $query = 'SELECT * FROM tbl WHERE bcol = :bool AND col IN (:list) + * $args = ( 'bool' => 1, 'list' => ('foo', 'bar') ) + * it results in: + * $query = '...WHERE bcol = :bool AND col IN (:list_0, :list_1) + * $args = ( 'bool' => 1, 'list_0' => 'foo', 'list_1' => 'bar' ) + * + * @param string $query sql query string + * @param array $args query arguments + */ + private static function handleArrayArgument(&$query, &$args) + { + foreach (array_keys($args) as $key) { + if (is_numeric($key) || $key === '?') + continue; + if (is_array($args[$key])) { + if (empty($args[$key])) { + // Empty list - what to do? We try to generate a query string that will not yield any result + $args[$key] = 'asdf' . mt_rand(0,PHP_INT_MAX) . mt_rand(0,PHP_INT_MAX) + . mt_rand(0,PHP_INT_MAX) . '@' . microtime(true); + continue; + } + $newkey = $key; + if ($newkey{0} !== ':') { + $newkey = ":$newkey"; + } + $new = array(); + foreach ($args[$key] as $subIndex => $sub) { + $new[] = $newkey . '_' . $subIndex; + $args[$newkey . '_' . $subIndex] = $sub; + } + unset($args[$key]); + $new = implode(',', $new); + $query = preg_replace('/' . $newkey . '\b/', $new, $query); + } + } + } + /** * Simply calls PDO::prepare and returns the PDOStatement. * You must call PDOStatement::execute manually on it. -- cgit v1.2.3-55-g7522 From ede3dc1d10f0ab1b901734a76c4c2cbccc2b202f Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 19 Apr 2017 23:49:27 +0200 Subject: [inc/Dictionary] Add $returnTagOnMissing to :translateFile() --- inc/dictionary.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'inc') diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php index 634b1c3c..ca2811ff 100644 --- a/inc/dictionary.inc.php +++ b/inc/dictionary.inc.php @@ -81,11 +81,11 @@ class Dictionary return $strings[$tag]; } - public static function translateFile($path, $tag) + public static function translateFile($path, $tag, $returnTagOnMissing = false) { if (!class_exists('Page') || Page::getModule() === false) return false; // We have no page - return false for now, as we're most likely running in api or install mode - return self::translateFileModule(Page::getModule()->getIdentifier(), $path, $tag); + return self::translateFileModule(Page::getModule()->getIdentifier(), $path, $tag, $returnTagOnMissing); } public static function translate($tag, $returnTagOnMissing = false) -- cgit v1.2.3-55-g7522 From b68ef6e73547be686355e4c26037206c97162d51 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 24 Apr 2017 15:46:01 +0200 Subject: [inc/Database] Add ::queryAll() --- inc/database.inc.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'inc') diff --git a/inc/database.inc.php b/inc/database.inc.php index f3a90fe7..9153c688 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -53,6 +53,20 @@ class Database return $res->fetch(PDO::FETCH_ASSOC); } + /** + * If you need all rows for a query as plain array you can use this. + * Don't use this if you want to do further processing of the data, to save some + * memory. + * + * @return array|bool List of associative arrays representing rows, or false on error + */ + public static function queryAll($query, $args = array(), $ignoreError = false) + { + $res = self::simpleQuery($query, $args, $ignoreError); + if ($res === false) + return false; + return $res->fetchAll(PDO::FETCH_ASSOC); + } /** * Execute the given query and return the number of rows affected. -- cgit v1.2.3-55-g7522 From f7900fa08276d2668221a1b4ce7462d68e6f2893 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 5 May 2017 13:04:19 +0200 Subject: [webinterface] Log user out when disabling HTTPS to prevent lockout --- inc/session.inc.php | 9 +++++++-- index.php | 2 +- modules-available/webinterface/page.inc.php | 14 ++++++++------ 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'inc') diff --git a/inc/session.inc.php b/inc/session.inc.php index 26effa3f..24bf6ac0 100644 --- a/inc/session.inc.php +++ b/inc/session.inc.php @@ -74,10 +74,15 @@ class Session { if (self::$sid === false) return; @unlink(self::getSessionFile()); - @setcookie('sid', '', time() - 8640000, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + self::deleteCookie(); self::$sid = false; self::$data = false; } + + public static function deleteCookie() + { + setcookie('sid', '', time() - 8640000, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + } private static function getSessionFile() { @@ -104,7 +109,7 @@ class Session $sessionfile = self::getSessionFile(); $ret = @file_put_contents($sessionfile, @serialize(self::$data)); if (!$ret) Util::traceError('Storing session data in ' . $sessionfile . ' failed.'); - $ret = @setcookie('sid', self::$sid, time() + CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + $ret = setcookie('sid', self::$sid, time() + CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); if (!$ret) Util::traceError('Error: Could not set Cookie for Client (headers already sent)'); } } diff --git a/index.php b/index.php index 7cbb3b40..a3f45ff3 100644 --- a/index.php +++ b/index.php @@ -116,7 +116,7 @@ if (defined('CONFIG_DEBUG') && CONFIG_DEBUG) { // Set HSTS Header if client is using HTTPS if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { - if (Request::any('hsts') === 'off' || Property::get('webinterface.https-hsts', 'False') !== 'True') { + if (Property::get('webinterface.https-hsts', 'False') !== 'True') { Header('Strict-Transport-Security: max-age=0', true); } else { Header('Strict-Transport-Security: max-age=15768000', true); diff --git a/modules-available/webinterface/page.inc.php b/modules-available/webinterface/page.inc.php index 5207420a..ae9a94fd 100644 --- a/modules-available/webinterface/page.inc.php +++ b/modules-available/webinterface/page.inc.php @@ -26,12 +26,10 @@ class Page_WebInterface extends Page private function actionConfigureHttps() { - $task = false; - $off = ''; - switch (Request::post('mode')) { + $mode = Request::post('mode'); + switch ($mode) { case 'off': $task = $this->setHttpsOff(); - $off = '&hsts=off'; break; case 'random': $task = $this->setHttpsRandomCert(); @@ -43,10 +41,12 @@ class Page_WebInterface extends Page $task = $this->setRedirectMode(); break; } - Property::set(self::PROP_HSTS, Request::post('usehsts', false, 'string') === 'on' ? 'True' : 'False'); + if ($mode !== 'off') { + Property::set(self::PROP_HSTS, Request::post('usehsts', false, 'string') === 'on' ? 'True' : 'False'); + } if (isset($task['id'])) { Session::set('https-id', $task['id']); - Util::redirect('?do=WebInterface&show=httpsupdate' . $off); + Util::redirect('?do=WebInterface&show=httpsupdate'); } Util::redirect('?do=WebInterface'); } @@ -123,7 +123,9 @@ class Page_WebInterface extends Page private function setHttpsOff() { Property::set(self::PROP_TYPE, 'off'); + Property::set(self::PROP_HSTS, 'off'); Header('Strict-Transport-Security: max-age=0', true); + Session::deleteCookie(); return Taskmanager::submit('LighttpdHttps', array()); } -- cgit v1.2.3-55-g7522 From 16dc9cfeea4bc060982f0b364ddaac98095ef654 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 9 May 2017 14:30:30 +0200 Subject: [webinterface] Allow customizing page title prefix and logo bgcolor --- inc/render.inc.php | 19 +++++++++++++- modules-available/main/templates/main-menu.html | 1 + modules-available/webinterface/page.inc.php | 30 ++++++++++++++++++++++ .../webinterface/templates/customization.html | 30 ++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 modules-available/webinterface/templates/customization.html (limited to 'inc') diff --git a/inc/render.inc.php b/inc/render.inc.php index 5515c659..c34c285a 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -40,6 +40,11 @@ class Render self::$mustache = new Mustache_Engine($options); } + private static function cssEsc($str) + { + return str_replace(array('"', '&', '<', '>'), array('\\000022', '\\000026', '\\00003c', '\\00003e'), $str); + } + /** * Output the buffered, generated page */ @@ -47,12 +52,24 @@ class Render { Header('Content-Type: text/html; charset=utf-8'); $modules = array_reverse(Module::getActivated()); + $title = Property::get('page-title-prefix', ''); + $bgcolor = Property::get('logo-background', ''); + if (!empty($bgcolor) || !empty($title)) { + self::$header .= '"; + } ob_start('ob_gzhandler'); echo ' - ', self::$title, RENDER_DEFAULT_TITLE, ' + ', $title, self::$title, RENDER_DEFAULT_TITLE, ' diff --git a/modules-available/main/templates/main-menu.html b/modules-available/main/templates/main-menu.html index 2ede4f87..55b19833 100644 --- a/modules-available/main/templates/main-menu.html +++ b/modules-available/main/templates/main-menu.html @@ -20,6 +20,7 @@ OpenSLX +