1
0
mirror of https://github.com/vrana/adminer.git synced 2025-08-30 01:30:12 +02:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Peter Knut
0797cb6a10 Release 4.9.4 2024-10-09 22:09:31 +02:00
Peter Knut
dd122a1056 Clean up the code for PHP < 5.6 2024-10-09 22:00:13 +02:00
Peter Knut
96c0177422 Editor: Fix building links with array parameters
This solves a situation when enum data type has a foreign key to another table.
2024-10-09 09:19:37 +02:00
Peter Knut
7d6c7998d8 Editor: Fix array conversion to string (issue #3) 2024-10-08 22:59:57 +02:00
Peter Knut
3df88d4a24 Refactor opening adminer.sql[.gz] file 2024-10-07 23:58:10 +02:00
Peter Knut
2d4b73653b Refactor generating of private key and random strings
Generating of private key is atomic now.
More secure random strings on PHP 7+.
2024-10-07 23:38:33 +02:00
Peter Knut
a63fadd503 Refactor working with a locked file 2024-10-07 22:20:32 +02:00
Peter Knut
a494827dc5 Remove suppressing errors while reading local files with file_get_contents (issue #1) 2024-10-07 13:32:24 +02:00
Peter Knut
8ac486a57c Firefox: Fix opening a database to the new browser's tab with Ctrl+click 2024-10-06 00:44:02 +02:00
Peter Knut
bfcc6d8297 Better default value for object definition (*.*) while creating new database user 2024-10-04 10:03:00 +02:00
Peter Knut
29fd200ef5 Unify displaying of 'New item' action based on privileges 2024-10-04 00:44:39 +02:00
Peter Knut
b6058368d3 Fix the width of inline edit field 2024-10-03 23:33:34 +02:00
Peter Knut
fd38c4261a Bump version to 4.9.4-dev 2024-10-03 23:33:34 +02:00
21 changed files with 242 additions and 157 deletions

View File

@@ -432,7 +432,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
function error() {
global $connection;
return nl_br(h(preg_replace('~^(\[[^]]*])+~m', '', $connection->error)));
return nl2br(h(preg_replace('~^(\[[^]]*])+~m', '', $connection->error)));
}
function create_database($db, $collation) {

View File

@@ -14,7 +14,7 @@ if (!defined("DRIVER")) {
function connect($server = "", $username = "", $password = "", $database = null, $port = null, $socket = null) {
global $adminer;
mysqli_report(MYSQLI_REPORT_OFF); // stays between requests, not required since PHP 5.3.4
mysqli_report(MYSQLI_REPORT_OFF);
list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
$ssl = $adminer->connectSsl();
@@ -34,7 +34,7 @@ if (!defined("DRIVER")) {
$database,
(is_numeric($port) ? $port : ini_get("mysqli.default_port")),
(!is_numeric($port) ? $port : $socket),
($ssl ? 64 : 0) // 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16)
($ssl ? MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT : 0)
);
$this->options(MYSQLI_OPT_LOCAL_INFILE, false);
return $return;
@@ -262,7 +262,7 @@ if (!defined("DRIVER")) {
}
function set_charset($charset) {
$this->query("SET NAMES $charset"); // charset in DSN is ignored before PHP 5.3.6
$this->query("SET NAMES $charset");
}
function select_db($database) {
@@ -375,7 +375,7 @@ if (!defined("DRIVER")) {
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
$connection->set_charset(charset($connection)); // available in MySQLi since PHP 5.0.5
$connection->set_charset(charset($connection));
$connection->query("SET sql_quote_show_create = 1, autocommit = 1");
if (min_version('5.7.8', 10.2, $connection)) {
$structured_types[lang('Strings')][] = "json";

View File

@@ -488,7 +488,7 @@ ORDER BY connamespace, conname") as $row) {
if (preg_match('~^(.*\n)?([^\n]*)\n( *)\^(\n.*)?$~s', $return, $match)) {
$return = $match[1] . preg_replace('~((?:[^&]|&[^;]*;){' . strlen($match[3]) . '})(.*)~', '\1<b>\2</b>', $match[2]) . $match[4];
}
return nl_br($return);
return nl2br($return);
}
function create_database($db, $collation) {

View File

@@ -25,12 +25,16 @@ class Adminer {
function connectSsl() {
}
/** Get key used for permanent login
* @param bool
* @return string cryptic string which gets combined with password or false in case of an error
*/
/**
* Gets a private key used for permanent login.
*
* @param bool $create
*
* @return string|false Cryptic string which gets combined with password or false in case of an error.
* @throws \Random\RandomException
*/
function permanentLogin($create = false) {
return password_file($create);
return get_private_key($create);
}
/** Return key used to group brute force attacks; behind a reverse proxy, you want to return the last part of X-Forwarded-For
@@ -937,9 +941,11 @@ class Adminer {
return $ext;
}
/** Set the path of the file for webserver load
* @return string path of the sql dump file
*/
/**
* Gets the path of the file for webserver load.
*
* @return string Path of the sql import file.
*/
function importServerPath() {
return "adminer.sql";
}

View File

@@ -1,4 +1,5 @@
<?php
$connection = '';
$has_token = $_SESSION["token"];
@@ -82,11 +83,11 @@ function build_http_url($server, $username, $password, $defaultServer, $defaultP
function add_invalid_login() {
global $adminer;
$fp = file_open_lock(get_temp_dir() . "/adminer.invalid");
if (!$fp) {
$file = open_file_with_lock(get_temp_dir() . "/adminer.invalid");
if (!$file) {
return;
}
$invalids = unserialize(stream_get_contents($fp));
$invalids = unserialize(stream_get_contents($file));
$time = time();
if ($invalids) {
foreach ($invalids as $ip => $val) {
@@ -100,13 +101,16 @@ function add_invalid_login() {
$invalid = array($time + 30*60, 0); // active for 30 minutes
}
$invalid[1]++;
file_write_unlock($fp, serialize($invalids));
write_and_unlock_file($file, serialize($invalids));
}
function check_invalid_login() {
global $adminer;
$invalids = unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
$invalid = ($invalids ? $invalids[$adminer->bruteForceKey()] : array());
$filename = get_temp_dir() . "/adminer.invalid";
$invalids = file_exists($filename) ? unserialize(file_get_contents($filename)) : [];
$invalid = ($invalids ? $invalids[$adminer->bruteForceKey()] : []);
$next_attempt = ($invalid[1] > 29 ? $invalid[0] - time() : 0); // allow 30 invalid attempts
if ($next_attempt > 0) { //! do the same with permanent login
auth_error(lang('Too many unsuccessful logins, try again in %d minute(s).', ceil($next_attempt / 60)));
@@ -168,9 +172,10 @@ function unset_permanent() {
}
/** Renders an error message and a login form
* @param string plain text
* @return null exits
*/
* @param string plain text
* @return null exits
* @throws \Random\RandomException
*/
function auth_error($error) {
global $adminer, $has_token;
$session_name = session_name();
@@ -195,7 +200,7 @@ function auth_error($error) {
$error = lang('Session support must be enabled.');
}
$params = session_get_cookie_params();
cookie("adminer_key", ($_COOKIE["adminer_key"] ? $_COOKIE["adminer_key"] : rand_string()), $params["lifetime"]);
cookie("adminer_key", ($_COOKIE["adminer_key"] ?: get_random_string()), $params["lifetime"]);
page_header(lang('Login'), $error, null);
echo "<form action='' method='post'>\n";
echo "<div>";

View File

@@ -32,9 +32,9 @@ if (isset($_GET["file"])) {
}
if ($_GET["script"] == "version") {
$fp = file_open_lock(get_temp_dir() . "/adminer.version");
if ($fp) {
file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
$file = open_file_with_lock(get_temp_dir() . "/adminer.version");
if ($file) {
write_and_unlock_file($file, serialize(["signature" => $_POST["signature"], "version" => $_POST["version"]]));
}
exit;
}

View File

@@ -142,14 +142,20 @@ function csp() {
);
}
/** Get a CSP nonce
* @return string Base64 value
*/
function get_nonce() {
/**
* Gets a CSP nonce.
*
* @return string Base64 value.
* @throws \Random\RandomException
*/
function get_nonce()
{
static $nonce;
if (!$nonce) {
$nonce = base64_encode(rand_string());
$nonce = base64_encode(get_random_string(true));
}
return $nonce;
}

View File

@@ -1,4 +1,5 @@
<?php
/** Get database connection
* @return Min_DB
*/
@@ -157,14 +158,6 @@ function h($string) {
return str_replace("\0", "&#0;", htmlspecialchars($string, ENT_QUOTES, 'utf-8'));
}
/** Convert \n to <br>
* @param string
* @return string
*/
function nl_br($string) {
return str_replace("\n", "<br>", $string); // nl2br() uses XHTML before PHP 5.3
}
/** Generate HTML checkbox
* @param string
* @param string
@@ -955,7 +948,7 @@ function input($field, $value, $function) {
if (version_compare(PHP_VERSION, 5.4) >= 0) {
$args[] = JSON_PRETTY_PRINT;
}
$value = call_user_func_array('json_encode', $args); //! requires PHP 5.2
$value = call_user_func_array('json_encode', $args);
$function = "json";
}
$reset = ($jush == "mssql" && $field["auto_increment"]);
@@ -1215,60 +1208,98 @@ function get_temp_dir() {
return $return;
}
/** Open and exclusively lock a file
* @param string
* @return resource or null for error
*/
function file_open_lock($filename) {
$fp = @fopen($filename, "r+"); // @ - may not exist
if (!$fp) { // c+ is available since PHP 5.2.6
$fp = @fopen($filename, "w"); // @ - may not be writable
if (!$fp) {
return;
}
chmod($filename, 0660);
/**
* Opens and exclusively lock a file.
*
* @param string $filename
* @return resource|null
*/
function open_file_with_lock($filename)
{
$file = fopen($filename, "c+");
if (!$file) {
return null;
}
flock($fp, LOCK_EX);
return $fp;
chmod($filename, 0660);
if (!flock($file, LOCK_EX)) {
fclose($file);
return null;
}
return $file;
}
/** Write and unlock a file
* @param resource
* @param string
*/
function file_write_unlock($fp, $data) {
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, strlen($data));
flock($fp, LOCK_UN);
fclose($fp);
/**
* Writes and unlocks a file.
*
* @param resource $file
* @param string $data
*/
function write_and_unlock_file($file, $data)
{
rewind($file);
fwrite($file, $data);
ftruncate($file, strlen($data));
unlock_file($file);
}
/** Read password from file adminer.key in temporary directory or create one
* @param bool
* @return string or false if the file can not be created
*/
function password_file($create) {
/**
* Unlocks and closes the file.
*
* @param resource $file
*/
function unlock_file($file)
{
flock($file, LOCK_UN);
fclose($file);
}
/**
* Reads password from file adminer.key in temporary directory or create one.
*
* @param $create bool
* @return string|false Returns false if the file can not be created.
* @throws \Random\RandomException
*/
function get_private_key($create)
{
$filename = get_temp_dir() . "/adminer.key";
$return = @file_get_contents($filename); // @ - may not exist
if ($return || !$create) {
return $return;
if (!$create && !file_exists($filename)) {
return false;
}
$fp = @fopen($filename, "w"); // @ - can have insufficient rights //! is not atomic
if ($fp) {
chmod($filename, 0660);
$return = rand_string();
fwrite($fp, $return);
fclose($fp);
$file = open_file_with_lock($filename);
if (!$file) {
return false;
}
return $return;
$key = stream_get_contents($file);
if (!$key) {
$key = get_random_string();
write_and_unlock_file($file, $key);
} else {
unlock_file($file);
}
return $key;
}
/** Get a random string
* @return string 32 hexadecimal characters
*/
function rand_string() {
return md5(uniqid(mt_rand(), true));
/**
* Returns a random 32 characters long string.
*
* @param $binary bool
* @return string
* @throws \Random\RandomException
*/
function get_random_string($binary = false)
{
$bytes = function_exists('random_bytes') ? random_bytes(32) : uniqid(mt_rand(), true);
return $binary ? $bytes : md5($bytes);
}
/** Format value to use in select

View File

@@ -1,2 +1,2 @@
<?php
$VERSION = "4.9.3";
$VERSION = "4.9.4";

View File

@@ -232,14 +232,16 @@ if (is_ajax()) {
$set = null;
if (isset($rights["insert"]) || !support("table")) {
$set = "";
$params = [];
foreach ((array) $_GET["where"] as $val) {
if ($foreign_keys[$val["col"]] && count($foreign_keys[$val["col"]]) == 1 && ($val["op"] == "="
|| (!$val["op"] && !preg_match('~[_%]~', $val["val"])) // LIKE in Editor
if (isset($foreign_keys[$val["col"]]) && count($foreign_keys[$val["col"]]) == 1
&& ($val["op"] == "=" || (!$val["op"] && (is_array($val["val"]) || !preg_match('~[_%]~', $val["val"]))) // LIKE in Editor
)) {
$set .= "&set" . urlencode("[" . bracket_escape($val["col"]) . "]") . "=" . urlencode($val["val"]);
$params["set" . "[" . bracket_escape($val["col"]) . "]"] = $val["val"];
}
}
$set = $params ? "&" . http_build_query($params) : "";
}
$adminer->selectLinks($table_status, $set);
@@ -446,7 +448,7 @@ if (!$columns && support("table")) {
$link .= where_link($i++, $k, $v);
}
}
$val = select_value($val, $link, $field, $text_length);
$id = h("val[$unique_idf][" . bracket_escape($key) . "]");
$value = $_POST["val"][$unique_idf][bracket_escape($key)];
@@ -507,7 +509,7 @@ if (!$columns && support("table")) {
echo "\n";
}
}
echo "<div class='footer'><div>\n";
if ($rows || $page) {
if ($pagination) {
@@ -539,7 +541,7 @@ if (!$columns && support("table")) {
}
echo "</fieldset>\n";
}
echo "<fieldset>";
echo "<legend>" . lang('Whole result') . "</legend>";
$display_rows = ($exact_count ? "" : "~ ") . $found_rows;

View File

@@ -21,12 +21,18 @@ if (!$error && $_POST) {
if (!isset($_GET["import"])) {
$query = $_POST["query"];
} elseif ($_POST["webfile"]) {
$sql_file_path = $adminer->importServerPath();
$fp = @fopen((file_exists($sql_file_path)
? $sql_file_path
: "compress.zlib://$sql_file_path.gz"
), "rb");
$query = ($fp ? fread($fp, 1e6) : false);
$import_file_path = $adminer->importServerPath();
if (!$import_file_path) {
$fp = false;
} elseif (file_exists($import_file_path)) {
$fp = fopen($import_file_path, "rb");
} elseif (file_exists("$import_file_path.gz")) {
$fp = fopen("compress.zlib://$import_file_path.gz", "rb");
} else {
$fp = false;
}
$query = $fp ? fread($fp, 1e6) : false;
} else {
$query = get_file("sql_file", true);
}
@@ -249,10 +255,10 @@ if (!isset($_GET["import"])) {
: lang('File uploads are disabled.')
);
echo "</div></fieldset>\n";
$importServerPath = $adminer->importServerPath();
if ($importServerPath) {
$import_file_path = $adminer->importServerPath();
if ($import_file_path) {
echo "<fieldset><legend>" . lang('From server') . "</legend><div>";
echo lang('Webserver file %s', "<code>" . h($importServerPath) . "$gz</code>");
echo lang('Webserver file %s', "<code>" . h($import_file_path) . "$gz</code>");
echo ' <input type="submit" name="webfile" value="' . lang('Run file') . '">';
echo "</div></fieldset>\n";
}

View File

@@ -25,6 +25,7 @@ pre { margin: 1em 0 0; }
pre code { display: block; font-size: 100%; }
pre, textarea { font: 110%/1.25 monospace; }
pre.jush { background: #fff; }
input, textarea { box-sizing: border-box; }
input, select { vertical-align: middle; }
input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; }

View File

@@ -103,6 +103,11 @@ var dbPrevious = {};
* @this HTMLSelectElement
*/
function dbMouseDown(event) {
// Firefox: mouse-down event does not contain pressed key information for OPTION.
// Chrome: mouse-down event has inherited key information from SELECT.
// So we ignore the event for OPTION to work Ctrl+click correctly everywhere.
if (event.target.tagName === "OPTION") return;
dbCtrl = isCtrl(event);
if (dbPrevious[this.name] === undefined) {
dbPrevious[this.name] = this.value;

View File

@@ -716,9 +716,13 @@ function selectClick(event, text, warning) {
td.innerHTML = original;
}
};
var pos = event.rangeOffset;
var value = (td.firstChild && td.firstChild.alt) || td.textContent || td.innerText;
input.style.width = Math.max(td.clientWidth - 14, 20) + 'px'; // 14 = 2 * (td.border + td.padding + input.border)
let pos = event.rangeOffset;
let value = (td.firstChild && td.firstChild.alt) || td.textContent || td.innerText;
const tdStyle = window.getComputedStyle(td, null);
input.style.width = Math.max(td.clientWidth - parseFloat(tdStyle.paddingLeft) - parseFloat(tdStyle.paddingRight), 20) + 'px';
if (text) {
var rows = 1;
value.replace(/\n/g, function () {

View File

@@ -7,9 +7,19 @@ if (!$fields) {
$table_status = table_status1($TABLE, true);
$name = $adminer->tableName($table_status);
$rights = [];
foreach ($fields as $key => $field) {
$rights += $field["privileges"];
}
page_header(($fields && is_view($table_status) ? $table_status['Engine'] == 'materialized view' ? lang('Materialized view') : lang('View') : lang('Table')) . ": " . ($name != "" ? $name : h($TABLE)), $error);
$adminer->selectLinks($table_status);
$set = null;
if (isset($rights["insert"]) || !support("table")) {
$set = "";
}
$adminer->selectLinks($table_status, $set);
$comment = $table_status["Comment"];
if ($comment != "") {
echo "<p class='nowrap'>" . lang('Comment') . ": " . h($comment) . "\n";
@@ -28,7 +38,7 @@ if (!is_view($table_status)) {
}
echo '<p class="links"><a href="' . h(ME) . 'indexes=' . urlencode($TABLE) . '">' . lang('Alter indexes') . "</a>\n";
}
if (fk_support($table_status)) {
echo "<h3 id='foreign-keys'>" . lang('Foreign keys') . "</h3>\n";
$foreign_keys = foreign_keys($TABLE);

View File

@@ -126,7 +126,14 @@ if ($_POST) {
if ($old_pass != "") {
$row["hashed"] = true;
}
$grants[(DB == "" || $grants ? "" : idf_escape(addcslashes(DB, "%_\\"))) . ".*"] = array();
if ($grants) {
$grants[".*"] = [];
} elseif (DB != "") {
$grants[idf_escape(addcslashes(DB, "%_\\")) . ".*"] = [];
} else {
$grants["*.* "] = []; // Space is added to force editing mode.
}
}
?>
@@ -142,13 +149,21 @@ if ($_POST) {
<?php
//! MAX_* limits, REQUIRE
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th colspan='2'>" . lang('Privileges') . doc_link(array('sql' => "grant.html#priv_level"));
echo "<thead><tr><th colspan='2'>" . lang('Privileges') . doc_link(array('sql' => "grant.html#priv_level")) . "</th>";
$i = 0;
foreach ($grants as $object => $grant) {
echo '<th>' . ($object != "*.*" ? "<input name='objects[$i]' value='" . h($object) . "' size='10' autocapitalize='off'>" : "<input type='hidden' name='objects[$i]' value='*.*' size='10'>*.*"); //! separate db, table, columns, PROCEDURE|FUNCTION, routine
echo "<th>";
//! separate db, table, columns, PROCEDURE|FUNCTION, routine
if ($object == "*.*") {
echo "<input type='hidden' name='objects[$i]' value='*.*' size='10'>*.*";
} else {
echo "<input name='objects[$i]' value='" . h(trim($object)) . "' size='10' autocapitalize='off'>";
}
echo "</th>";
$i++;
}
echo "</thead>\n";
echo "</tr></thead>\n";
foreach ([
"" => "",

View File

@@ -1,3 +1,14 @@
Adminer 4.9.4 (released 2024-10-09):
- Fix the width of inline edit field.
- Unify displaying of 'New item' action based on privileges.
- Better default value for object definition (*.*) while creating new database user.
- Firefox: Fix opening a database to the new browser's tab with Ctrl+click.
- Remove suppressing errors while reading local files.
- More secure random strings on PHP 7+.
- Editor: Fix array conversion to string (issue #3).
- Editor: Fix building links with array parameters.
- Clean up the code for PHP < 5.6.
Adminer 4.9.3 (released 2024-10-02):
- MySQL, PostgreSQL: Fix queries splitting and string constants.
- MySQL: Fix where clause for JSON column.

View File

@@ -16,8 +16,11 @@ class Adminer {
function connectSsl() {
}
/**
* @throws \Random\RandomException
*/
function permanentLogin($create = false) {
return password_file($create);
return get_private_key($create);
}
function bruteForceKey() {
@@ -350,10 +353,10 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5
$op = $where["op"];
$val = $where["val"];
if (($key < 0 ? "" : $col) . $val != "") {
$conds = array();
if (($key >= 0 && $col != "") || $val != "") {
$conds = [];
foreach (($col != "" ? array($col => $fields[$col]) : $fields) as $name => $field) {
foreach (($col != "" ? [$col => $fields[$col]] : $fields) as $name => $field) {
if ($col != "" || is_numeric($val) || !preg_match(number_type(), $field["type"])) {
$name = idf_escape($name);
@@ -579,6 +582,7 @@ qsl('div').onclick = whisperClick;", "")
}
function importServerPath() {
return null;
}
function homepage() {

View File

@@ -17,7 +17,7 @@ function email_header($header) {
* @return bool
*/
function send_mail($email, $subject, $message, $from = "", $files = array()) {
$eol = (DIRECTORY_SEPARATOR == "/" ? "\n" : "\r\n"); // PHP_EOL available since PHP 5.0.2
$eol = "\r\n";
$message = str_replace("\n", $eol, wordwrap(str_replace("\r", "", "$message\n")));
$boundary = uniqid("boundary");
$attachments = "";

View File

@@ -272,7 +272,7 @@ if (isset($_GET["simpledb"])) {
function rollback() {
return false;
}
function slowQuery($query, $timeout) {
$this->_conn->timeout = $timeout;
return $query;
@@ -437,22 +437,6 @@ if (isset($_GET["simpledb"])) {
function last_id() {
}
function hmac($algo, $data, $key, $raw_output = false) {
// can use hash_hmac() since PHP 5.1.2
$blocksize = 64;
if (strlen($key) > $blocksize) {
$key = pack("H*", $algo($key));
}
$key = str_pad($key, $blocksize, "\0");
$k_ipad = $key ^ str_repeat("\x36", $blocksize);
$k_opad = $key ^ str_repeat("\x5C", $blocksize);
$return = $algo($k_opad . pack("H*", $algo($k_ipad . $data)));
if ($raw_output) {
$return = pack("H*", $return);
}
return $return;
}
function sdb_request($action, $params = array()) {
global $adminer, $connection;
list($host, $params['AWSAccessKeyId'], $secret) = $adminer->credentials();
@@ -467,7 +451,7 @@ if (isset($_GET["simpledb"])) {
$query .= '&' . rawurlencode($key) . '=' . rawurlencode($val);
}
$query = str_replace('%7E', '~', substr($query, 1));
$query .= "&Signature=" . urlencode(base64_encode(hmac('sha1', "POST\n" . preg_replace('~^https?://~', '', $host) . "\n/\n$query", $secret, true)));
$query .= "&Signature=" . urlencode(base64_encode(hash_hmac('sha1', "POST\n" . preg_replace('~^https?://~', '', $host) . "\n/\n$query", $secret, true)));
@ini_set('track_errors', 1); // @ - may be disabled
$file = @file_get_contents($connection->_url, false, stream_context_create(array('http' => array(

View File

@@ -7,36 +7,31 @@
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerPlugin extends Adminer {
/** @access protected */
var $plugins;
function _findRootClass($class) { // is_subclass_of(string, string) is available since PHP 5.0.3
do {
$return = $class;
} while ($class = get_parent_class($class));
return $return;
}
/** Register plugins
* @param array object instances or null to register all classes starting by 'Adminer'
*/
function __construct($plugins) {
protected $plugins;
/**
* Registers plugins.
* @param array $plugins Object instances or null to register all classes starting by 'Adminer'.
*/
function __construct(array $plugins = null)
{
if ($plugins === null) {
$plugins = array();
$plugins = [];
foreach (get_declared_classes() as $class) {
if (preg_match('~^Adminer.~i', $class) && strcasecmp($this->_findRootClass($class), 'Adminer')) { //! can use interface
if (preg_match('~^Adminer.~i', $class) && !is_subclass_of($class, 'Adminer')) { //! can use interface
$plugins[$class] = new $class;
}
}
}
$this->plugins = $plugins;
//! it is possible to use ReflectionObject to find out which plugins defines which methods at once
}
function _callParent($function, $args) {
return call_user_func_array(array('parent', $function), $args);
}
function _applyPlugin($function, $args) {
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
@@ -57,7 +52,7 @@ class AdminerPlugin extends Adminer {
}
return $this->_callParent($function, $args);
}
function _appendPlugin($function, $args) {
$return = $this->_callParent($function, $args);
foreach ($this->plugins as $plugin) {
@@ -70,14 +65,14 @@ class AdminerPlugin extends Adminer {
}
return $return;
}
// appendPlugin
function dumpFormat() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
function dumpOutput() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
@@ -94,7 +89,7 @@ class AdminerPlugin extends Adminer {
}
// applyPlugin
function name() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);