f() instead of $this->f() to give chance to other plugins */
class Adminer {
/** @var Adminer|Plugins */ static $instance;
/** @visibility protected(set) */ public string $error = ''; // HTML
/** Name in title and navigation
* @return string HTML code
*/
function name(): string {
return "Adminer";
}
/** Connection parameters
* @return array{string, string, string}
*/
function credentials(): array {
return array(SERVER, $_GET["username"], get_password());
}
/** Get SSL connection options
* @return string[]|void
*/
function connectSsl() {
}
/** Get key used for permanent login
* @return string cryptic string which gets combined with password or '' in case of an error
*/
function permanentLogin(bool $create = false): string {
return password_file($create);
}
/** Return key used to group brute force attacks; behind a reverse proxy, you want to return the last part of X-Forwarded-For */
function bruteForceKey(): string {
return $_SERVER["REMOTE_ADDR"];
}
/** Get server name displayed in breadcrumbs
* @return string HTML code or null
*/
function serverName(?string $server): string {
return h($server);
}
/** Identifier of selected database */
function database(): ?string {
// should be used everywhere instead of DB
return DB;
}
/** Get cached list of databases
* @return list
*/
function databases(bool $flush = true): array {
return get_databases($flush);
}
/** Print links after list of plugins */
function pluginsLinks(): void {
}
/** Operators used in select
* @return list operators
*/
function operators(): array {
return driver()->operators;
}
/** Get list of schemas
* @return list
*/
function schemas(): array {
return schemas();
}
/** Specify limit for waiting on some slow queries like DB list
* @return float number of seconds
*/
function queryTimeout(): float {
return 2;
}
/** Called after connecting and selecting a database */
function afterConnect(): void {
}
/** Headers to send before HTML output */
function headers(): void {
}
/** Get Content Security Policy headers
* @param list $csp of arrays with directive name in key, allowed sources in value
* @return list same as $csp
*/
function csp(array $csp): array {
return $csp;
}
/** Print HTML code inside
* @param bool $dark dark CSS: false to disable, true to force, null to base on user preferences
* @return bool true to link favicon.ico
*/
function head(?bool $dark = null): bool {
// this is matched by compile.php
echo "\n";
echo ($dark !== false ? "\n" : "");
return true;
}
/** Print extra classes in ; must start with a space */
function bodyClass(): void {
echo " adminer";
}
/** Get URLs of the CSS files
* @return string[] key is URL, value is either 'light' (supports only light color scheme), 'dark' or '' (both)
*/
function css(): array {
$return = array();
foreach (array("", "-dark") as $mode) {
$filename = "adminer$mode.css";
if (file_exists($filename)) {
$file = file_get_contents($filename);
$return["$filename?v=" . crc32($file)] = ($mode
? "dark"
: (preg_match('~prefers-color-scheme:\s*dark~', $file) ? '' : 'light')
);
}
}
return $return;
}
/** Print login form */
function loginForm(): void {
echo "
\n";
// this is matched by compile.php
echo adminer()->loginFormField('driver', '
\n";
echo checkbox("auth[permanent]", 1, $_COOKIE["adminer_permanent"], lang('Permanent login')) . "\n";
}
/** Get login form field
* @param string $heading HTML
* @param string $value HTML
*/
function loginFormField(string $name, string $heading, string $value): string {
return $heading . $value . "\n";
}
/** Authorize the user
* @return mixed true for success, string for error message, false for unknown error
*/
function login(string $login, string $password) {
if ($password == "") {
return lang('Adminer does not support accessing a database without a password, more information.', target_blank());
}
return true;
}
/** Table caption used in navigation and headings
* @param TableStatus $tableStatus
* @return string HTML code, "" to ignore table
*/
function tableName(array $tableStatus): string {
return h($tableStatus["Name"]);
}
/** Field caption used in select and edit
* @param Field|RoutineField $field
* @param int $order order of column in select
* @return string HTML code, "" to ignore field
*/
function fieldName(array $field, int $order = 0): string {
$type = $field["full_type"];
$comment = $field["comment"];
return '' . h($field["field"]) . '';
}
/** Print links after select heading
* @param TableStatus $tableStatus
* @param ?string $set new item options, NULL for no new item
*/
function selectLinks(array $tableStatus, ?string $set = ""): void {
$name = $tableStatus["Name"];
echo '
';
$links = array("select" => lang('Select data'));
if (support("table") || support("indexes")) {
$links["table"] = lang('Show structure');
}
$is_view = false;
if (support("table")) {
$is_view = is_view($tableStatus);
if (!$is_view) {
$links["create"] = lang('Alter table');
} elseif (support("view")) {
$links["view"] = lang('Alter view');
}
}
if ($set !== null) {
$links["edit"] = lang('New item');
}
foreach ($links as $key => $val) {
echo " $val";
}
echo doc_link(array(JUSH => driver()->tableHelp($name, $is_view)), "?");
echo "\n";
}
/** Get foreign keys for table
* @return ForeignKey[] same format as foreign_keys()
*/
function foreignKeys(string $table): array {
return foreign_keys($table);
}
/** Find backward keys for table
* @return BackwardKey[]
*/
function backwardKeys(string $table, string $tableName): array {
return array();
}
/** Print backward keys for row
* @param BackwardKey[] $backwardKeys
* @param string[] $row
*/
function backwardKeysPrint(array $backwardKeys, array $row): void {
}
/** Query printed in select before execution
* @param string $query query to be executed
* @param float $start start time of the query
*/
function selectQuery(string $query, float $start, bool $failed = false): string {
$return = "
" . h(str_replace("\n", " ", $query)) . "(" . format_time($start) . ")"
. (support("sql") ? " " . lang('Edit') . "" : "")
. $return
;
}
/** Query printed in SQL command before execution
* @param string $query query to be executed
* @return string escaped query to be printed
*/
function sqlCommandQuery(string $query): string {
return shorten_utf8(trim($query), 1000);
}
/** Print HTML code just before the Execute button in SQL command */
function sqlPrintAfter(): void {
}
/** Description of a row in a table
* @return string SQL expression, empty string for no description
*/
function rowDescription(string $table): string {
return "";
}
/** Get descriptions of selected data
* @param list $rows all data to print
* @param list[] $foreignKeys
* @return list
*/
function rowDescriptions(array $rows, array $foreignKeys): array {
return $rows;
}
/** Get a link to use in select table
* @param string $val raw value of the field
* @param Field $field
* @return string|void null to create the default link
*/
function selectLink(?string $val, array $field) {
}
/** Value printed in select table
* @param ?string $val HTML-escaped value to print
* @param ?string $link link to foreign key
* @param Field $field
* @param string $original original value before applying editVal() and escaping
*/
function selectVal(?string $val, ?string $link, array $field, ?string $original): string {
$return = ($val === null ? "NULL"
: (preg_match("~char|binary|boolean~", $field["type"]) && !preg_match("~var~", $field["type"]) ? "$val"
: (preg_match('~json~', $field["type"]) ? "$val"
: $val)
));
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && !is_utf8($val)) {
$return = "" . lang('%d byte(s)', strlen($original)) . "";
}
return ($link ? "$return" : $return);
}
/** Value conversion used in select and edit
* @param Field $field
*/
function editVal(?string $val, array $field): ?string {
return $val;
}
/** Get configuration options for AdminerConfig
* @return string[] key is config description, value is HTML
*/
function config(): array {
return array();
}
/** Print table structure in tabular format
* @param Field[] $fields
* @param TableStatus $tableStatus
*/
function tableStructurePrint(array $fields, ?array $tableStatus = null): void {
echo "