From 8ed117ca50aa743f9b029594c3817d3dd454357e Mon Sep 17 00:00:00 2001 From: Roy-Orbison Date: Mon, 7 Aug 2023 17:22:55 +0930 Subject: [PATCH 1/5] Allow selection of SQL files to import instead of only accepting the very non-descriptive adminer.sql[.gz], and make it possible to use a source directory other than Adminer's own. --- plugins/import-from-dir.php | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 plugins/import-from-dir.php diff --git a/plugins/import-from-dir.php b/plugins/import-from-dir.php new file mode 100644 index 00000000..7d65d301 --- /dev/null +++ b/plugins/import-from-dir.php @@ -0,0 +1,85 @@ +dir = $dir; + } + + protected function _readFiles($gz = false) { + $mapped = array(); + $glob = "$this->dir*.[Ss][Qq][Ll]"; + if ($gz) { + $suffix = '.gz'; # lowercase only because of core + $glob .= $suffix; + $suffix_cut = -3; + } + if ($files = glob($glob)) { + $from = strlen($this->dir); + foreach ($files as $file) { + if ($from) { + $file = substr($file, $from); # do not expose server paths in output + } + if ($gz) { + $mapped[substr($file, 0, $suffix_cut)] = $file; + } + else { + $mapped[$file] = $file; + } + } + } + return $mapped; + } + + function importServerPath() { + static $posted = null; + + $files = $this->_readFiles(); + if (extension_loaded('zlib')) { + $files += $this->_readFiles(true); # core prioritises files without .gz + } + if (count($files) > 1) { + ksort($files); + } + + if ($posted !== null || !isset($_POST['webfile'])) { + # use existing translation strings + echo "
" . lang('From server') . "
"; + echo lang('Webserver file %s', ''); + echo ' '; + echo "
\n"; + $posted = null; + return false; # skip core UI + } + + if ( + empty($_POST['webfilename']) + || !is_string($_POST['webfilename']) + || !array_key_exists($_POST['webfilename'], $files) + ) { + $posted = ''; + return 'SELECTED_FILE_DOES_NOT_EXIST'; # can't return empty string because of core file_exists() check + } + + $posted = $_POST['webfilename']; + return $this->dir . $posted; + } +} From 5a625a5f5e4bbb6f827e9ef85477c97c4acde93f Mon Sep 17 00:00:00 2001 From: Roy-Orbison Date: Mon, 7 Aug 2023 15:58:38 +0930 Subject: [PATCH 2/5] Plugin for using external login system or for allowing unrestricted access. --- plugins/login-external.php | 138 +++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 plugins/login-external.php diff --git a/plugins/login-external.php b/plugins/login-external.php new file mode 100644 index 00000000..20926bb5 --- /dev/null +++ b/plugins/login-external.php @@ -0,0 +1,138 @@ +driver)) { + $externals->driver = 'server'; + } + if (isset($_POST['auth'])) { + $_POST['auth']['driver'] = $externals->driver; + $_POST['auth']['server'] = $_POST['auth']['username'] = $_POST['auth']['password'] = ''; + } + $this->externals = $externals; + } + + function name() { + return empty($this->externals->app_name) ? null : $this->externals->app_name; + } + + function credentials() { + if (empty($this->externals->authenticated)) { + # always check external stat rather than relying on adminer's session login + auth_error( + empty($this->externals->expired_html) ? + 'External authentication expired.' : + $this->externals->expired_html + ); + return false; + } + return [ + $this->externals->server, + $this->externals->username, + $this->externals->password, + ]; + } + + function database() { + return empty($this->externals->database) ? null : $this->externals->database; + } + + function loginForm() { + if (empty($this->externals->authenticated)) { + if (empty($this->externals->failure_html)) { + echo '

You must first log in to the system that grants access to this tool.

'; + } + else { + echo $this->externals->failure_html; + } + return false; + } + + if (empty($this->externals->manual_login)) { + echo script( + <<database()); + return << + +EOHTML; + case 'driver': + if (function_exists('get_driver')) { + $value = h($this->externals->driver); + $driver = h(get_driver($this->externals->driver)) ?: 'Unknown'; + return <<$driver + +EOHTML; + } + $value = ' value="' . h($this->externals->driver) . '"'; + # don't break + case 'server': + case 'username': + case 'password': + return << + +EOHTML; + } + } + + function login($login, $password) { + return !empty($this->externals->authenticated); + } +} From f6c8ab14635a45346cc61e20825808aa27d68284 Mon Sep 17 00:00:00 2001 From: Lionel Laffineur Date: Wed, 9 Aug 2023 19:38:13 +0200 Subject: [PATCH 3/5] Fix JS error if #dbs is not in the page + add fieldset around input and add clear button next to input --- plugins/tables-filter.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/plugins/tables-filter.php b/plugins/tables-filter.php index ab716531..d33d2da1 100644 --- a/plugins/tables-filter.php +++ b/plugins/tables-filter.php @@ -54,16 +54,27 @@ function tablesFilterInput() { } sessionStorage && document.addEventListener('DOMContentLoaded', function () { - var db = qs('#dbs').querySelector('select'); - db = db.options[db.selectedIndex].text; - if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){ - qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter'); - tablesFilter(); + if (qs('#dbs') != null) { + var db = qs('#dbs').querySelector('select'); + db = db.options[db.selectedIndex].text; + if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){ + qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter'); + tablesFilter(); + } + sessionStorage.setItem('adminer_tables_filter_db', db); } - sessionStorage.setItem('adminer_tables_filter_db', db); }); -

+ +

+ +
+ + + +
+
+ Date: Thu, 10 Aug 2023 17:28:12 +0930 Subject: [PATCH 4/5] Filter tables plugin cleanup - Put markup first and consolidate all script into single block - Fix some JS oddities - Put into IIFE no does not pollute the global namespace (prevents conflicts) - Hide when JS disabled --- plugins/tables-filter.php | 85 ++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/plugins/tables-filter.php b/plugins/tables-filter.php index d33d2da1..aaf5dec9 100644 --- a/plugins/tables-filter.php +++ b/plugins/tables-filter.php @@ -6,29 +6,43 @@ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) */ + class AdminerTablesFilter { function tablesPrint($tables) { ?> -> -var tablesFilterTimeout = null; -var tablesFilterValue = ''; +
+ +
+ + +
+
-function tablesFilter(){ - var value = qs('#filter-field').value.toLowerCase(); - if (value == tablesFilterValue) { +> +(function() { + +var timeout; +var lastValue = ''; +var filterField = qs('#filter-field'); + +function filter() { + timeout && (timeout = null); + var value = filterField.value.toLowerCase(); + if (value == lastValue) { return; } - tablesFilterValue = value; + lastValue = value; if (value != '') { - var reg = (value + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1'); + var reg = (value + '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); reg = new RegExp('('+ reg + ')', 'gi'); } - if (sessionStorage) { + if (window.sessionStorage) { sessionStorage.setItem('adminer_tables_filter', value); } var tables = qsa('li', qs('#tables')); + var a; + var text; for (var i = 0; i < tables.length; i++) { - var a = null; - var text = tables[i].getAttribute('data-table-name'); + text = tables[i].getAttribute('data-table-name'); if (text == null) { a = qsa('a', tables[i])[1]; text = a.innerHTML.trim(); @@ -48,33 +62,32 @@ function tablesFilter(){ } } -function tablesFilterInput() { - window.clearTimeout(tablesFilterTimeout); - tablesFilterTimeout = window.setTimeout(tablesFilter, 200); -} - -sessionStorage && document.addEventListener('DOMContentLoaded', function () { - if (qs('#dbs') != null) { - var db = qs('#dbs').querySelector('select'); - db = db.options[db.selectedIndex].text; - if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){ - qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter'); - tablesFilter(); - } - sessionStorage.setItem('adminer_tables_filter_db', db); - } +filterField.addEventListener('input', function input() { + timeout && window.clearTimeout(timeout); + timeout = window.setTimeout(filter, 200); }); + +qs('#filter-field-reset').addEventListener('click', function() { + filterField.value = ''; + filterField.dispatchEvent(new Event('input')); +}); + +window.sessionStorage && document.addEventListener('DOMContentLoaded', function restore() { + var db = qs('#dbs select'); + var value; + db = db.options[db.selectedIndex].text; + if ( + db == sessionStorage.getItem('adminer_tables_filter_db') + && (value = sessionStorage.getItem('adminer_tables_filter')) + ) { + filterField.value = value; + filter(); + } + sessionStorage.setItem('adminer_tables_filter_db', db); +}); + +})(); - -
- -
- - - -
-
- Date: Sun, 13 Aug 2023 14:31:26 +0200 Subject: [PATCH 5/5] Added key shortcut Ctrl+Shift+F to focus filter field and disabled enter key --- plugins/tables-filter.php | 91 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/plugins/tables-filter.php b/plugins/tables-filter.php index aaf5dec9..68b9b809 100644 --- a/plugins/tables-filter.php +++ b/plugins/tables-filter.php @@ -6,43 +6,29 @@ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) */ - class AdminerTablesFilter { function tablesPrint($tables) { ?> -
- -
- - -
-
- > -(function() { +var tablesFilterTimeout = null; +var tablesFilterValue = ''; -var timeout; -var lastValue = ''; -var filterField = qs('#filter-field'); - -function filter() { - timeout && (timeout = null); - var value = filterField.value.toLowerCase(); - if (value == lastValue) { +function tablesFilter(){ + var value = qs('#filter-field').value.toLowerCase(); + if (value == tablesFilterValue) { return; } - lastValue = value; + tablesFilterValue = value; if (value != '') { - var reg = (value + '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + var reg = (value + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1'); reg = new RegExp('('+ reg + ')', 'gi'); } - if (window.sessionStorage) { + if (sessionStorage) { sessionStorage.setItem('adminer_tables_filter', value); } var tables = qsa('li', qs('#tables')); - var a; - var text; for (var i = 0; i < tables.length; i++) { - text = tables[i].getAttribute('data-table-name'); + var a = null; + var text = tables[i].getAttribute('data-table-name'); if (text == null) { a = qsa('a', tables[i])[1]; text = a.innerHTML.trim(); @@ -62,32 +48,45 @@ function filter() { } } -filterField.addEventListener('input', function input() { - timeout && window.clearTimeout(timeout); - timeout = window.setTimeout(filter, 200); -}); +function tablesFilterInput() { + window.clearTimeout(tablesFilterTimeout); + tablesFilterTimeout = window.setTimeout(tablesFilter, 200); +} -qs('#filter-field-reset').addEventListener('click', function() { - filterField.value = ''; - filterField.dispatchEvent(new Event('input')); -}); - -window.sessionStorage && document.addEventListener('DOMContentLoaded', function restore() { - var db = qs('#dbs select'); - var value; - db = db.options[db.selectedIndex].text; - if ( - db == sessionStorage.getItem('adminer_tables_filter_db') - && (value = sessionStorage.getItem('adminer_tables_filter')) - ) { - filterField.value = value; - filter(); +sessionStorage && document.addEventListener('DOMContentLoaded', function () { + if (qs('#dbs') != null) { + var db = qs('#dbs').querySelector('select'); + db = db.options[db.selectedIndex].text; + if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){ + qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter'); + tablesFilter(); + } + sessionStorage.setItem('adminer_tables_filter_db', db); } - sessionStorage.setItem('adminer_tables_filter_db', db); + document.addEventListener('keyup', function(event) { + if (event.ctrlKey && event.shiftKey && event.key == 'F') { + qs('#filter-field').focus(); + return; + } + }); + qs('#filter-field').addEventListener('keydown', function(event) { + if (event.key == 'Enter' || event.keyCode == 13 || event.which == 13) { + event.preventDefault(); + return false; + } + }); }); - -})(); + +
+ +
+ + + +
+
+