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', '
' . lang('System') . '', html_select("auth[driver]", SqlDriver::$drivers, DRIVER, "loginDriver(this);")); echo adminer()->loginFormField('server', '
' . lang('Server') . '', ''); // this is matched by compile.php echo adminer()->loginFormField('username', '
' . lang('Username') . '', '' . script("const authDriver = qs('#username').form['auth[driver]']; authDriver && authDriver.onchange();")); echo adminer()->loginFormField('password', '
' . lang('Password') . '', ''); echo adminer()->loginFormField('db', '
' . lang('Database') . '', ''); echo "
\n"; echo "

\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 '

\n"; // required for IE9 inline edit if (!$failed && ($warnings = driver()->warnings())) { $id = "warnings"; $return = ", " . lang('Warnings') . "" . script("qsl('a').onclick = partial(toggle, '$id');", "") . "$return\n" ; } 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 "

\n"; echo "\n"; echo "\n"; $structured_types = driver()->structuredTypes(); foreach ($fields as $field) { echo "
" . lang('Column') . "" . lang('Type') . (support("comment") ? "" . lang('Comment') : "") . "
" . h($field["field"]); $type = h($field["full_type"]); $collation = h($field["collation"]); echo "" . (in_array($type, (array) $structured_types[lang('User types')]) ? "$type" : $type . ($collation && isset($tableStatus["Collation"]) && $collation != $tableStatus["Collation"] ? " $collation" : "")) . "" ; echo ($field["null"] ? " NULL" : ""); echo ($field["auto_increment"] ? " " . lang('Auto Increment') . "" : ""); $default = h($field["default"]); echo (isset($field["default"]) ? " [" . ($field["generated"] ? "$default" : $default) . "]" : ""); echo (support("comment") ? "" . h($field["comment"]) : ""); echo "\n"; } echo "
\n"; echo "
\n"; } /** Print list of indexes on table in tabular format * @param Index[] $indexes * @param TableStatus $tableStatus */ function tableIndexesPrint(array $indexes, array $tableStatus): void { $partial = false; foreach ($indexes as $name => $index) { $partial |= !!$index["partial"]; } echo "\n"; $default_algorithm = first(driver()->indexAlgorithms($tableStatus)); foreach ($indexes as $name => $index) { ksort($index["columns"]); // enforce correct columns order $print = array(); foreach ($index["columns"] as $key => $val) { $print[] = "" . h($val) . "" . ($index["lengths"][$key] ? "(" . $index["lengths"][$key] . ")" : "") . ($index["descs"][$key] ? " DESC" : "") ; } echo ""; echo "
$index[type]" . ($default_algorithm && $index['algorithm'] != $default_algorithm ? " ($index[algorithm])" : ""); echo "" . implode(", ", $print); if ($partial) { echo "" . ($index['partial'] ? "WHERE " . h($index['partial']) : ""); } echo "\n"; } echo "
\n"; } /** Print columns box in select * @param list $select result of selectColumnsProcess()[0] * @param string[] $columns selectable columns */ function selectColumnsPrint(array $select, array $columns): void { print_fieldset("select", lang('Select'), $select); $i = 0; $select[""] = array(); foreach ($select as $key => $val) { $val = idx($_GET["columns"], $key, array()); $column = select_input( " name='columns[$i][col]'", $columns, $val["col"], ($key !== "" ? "selectFieldChange" : "selectAddRow") ); echo "
" . (driver()->functions || driver()->grouping ? html_select("columns[$i][fun]", array(-1 => "") + array_filter(array(lang('Functions') => driver()->functions, lang('Aggregation') => driver()->grouping)), $val["fun"]) . on_help("event.target.value && event.target.value.replace(/ |\$/, '(') + ')'", 1) . script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "") . "($column)" : $column) . "
\n"; $i++; } echo "\n"; } /** Print search box in select * @param list $where result of selectSearchProcess() * @param string[] $columns selectable columns * @param Index[] $indexes */ function selectSearchPrint(array $where, array $columns, array $indexes): void { print_fieldset("search", lang('Search'), $where); foreach ($indexes as $i => $index) { if ($index["type"] == "FULLTEXT") { echo "
(" . implode(", ", array_map('Adminer\h', $index["columns"])) . ") AGAINST"; echo " "; echo script("qsl('input').oninput = selectFieldChange;", ""); echo checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL"); echo "
\n"; } } $change_next = "this.parentNode.firstChild.onchange();"; foreach (array_merge((array) $_GET["where"], array(array())) as $i => $val) { if (!$val || ("$val[col]$val[val]" != "" && in_array($val["op"], adminer()->operators()))) { echo "
" . select_input( " name='where[$i][col]'", $columns, $val["col"], ($val ? "selectFieldChange" : "selectAddRow"), "(" . lang('anywhere') . ")" ); echo html_select("where[$i][op]", adminer()->operators(), $val["op"], $change_next); echo ""; echo script("mixin(qsl('input'), {oninput: function () { $change_next }, onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", ""); echo "
\n"; } } echo "\n"; } /** Print order box in select * @param list $order result of selectOrderProcess() * @param string[] $columns selectable columns * @param Index[] $indexes */ function selectOrderPrint(array $order, array $columns, array $indexes): void { print_fieldset("sort", lang('Sort'), $order); $i = 0; foreach ((array) $_GET["order"] as $key => $val) { if ($val != "") { echo "
" . select_input(" name='order[$i]'", $columns, $val, "selectFieldChange"); echo checkbox("desc[$i]", 1, isset($_GET["desc"][$key]), lang('descending')) . "
\n"; $i++; } } echo "
" . select_input(" name='order[$i]'", $columns, "", "selectAddRow"); echo checkbox("desc[$i]", 1, false, lang('descending')) . "
\n"; echo "\n"; } /** Print limit box in select */ function selectLimitPrint(int $limit): void { echo "
" . lang('Limit') . "
"; //
for easy styling echo ""; echo script("qsl('input').oninput = selectFieldChange;", ""); echo "
\n"; } /** Print text length box in select * @param numeric-string $text_length result of selectLengthProcess() */ function selectLengthPrint(string $text_length): void { if ($text_length !== null) { echo "
" . lang('Text length') . "
"; echo ""; echo "
\n"; } } /** Print action box in select * @param Index[] $indexes */ function selectActionPrint(array $indexes): void { echo "
" . lang('Action') . "
"; echo ""; echo " "; echo "\n"; echo "const indexColumns = "; $columns = array(); foreach ($indexes as $index) { $current_key = reset($index["columns"]); if ($index["type"] != "FULLTEXT" && $current_key) { $columns[$current_key] = 1; } } $columns[""] = 1; foreach ($columns as $key => $val) { json_row($key); } echo ";\n"; echo "selectFieldChange.call(qs('#form')['select']);\n"; echo "\n"; echo "
\n"; } /** Print command box in select * @return bool whether to print default commands */ function selectCommandPrint(): bool { return !information_schema(DB); } /** Print import box in select * @return bool whether to print default import */ function selectImportPrint(): bool { return !information_schema(DB); } /** Print extra text in the end of a select form * @param string[] $emailFields fields holding e-mails * @param string[] $columns selectable columns */ function selectEmailPrint(array $emailFields, array $columns): void { } /** Process columns box in select * @param string[] $columns selectable columns * @param Index[] $indexes * @return list> [[select_expressions], [group_expressions]] */ function selectColumnsProcess(array $columns, array $indexes): array { $select = array(); // select expressions, empty for * $group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used foreach ((array) $_GET["columns"] as $key => $val) { if ($val["fun"] == "count" || ($val["col"] != "" && (!$val["fun"] || in_array($val["fun"], driver()->functions) || in_array($val["fun"], driver()->grouping)))) { $select[$key] = apply_sql_function($val["fun"], ($val["col"] != "" ? idf_escape($val["col"]) : "*")); if (!in_array($val["fun"], driver()->grouping)) { $group[] = $select[$key]; } } } return array($select, $group); } /** Process search box in select * @param Field[] $fields * @param Index[] $indexes * @return list expressions to join by AND */ function selectSearchProcess(array $fields, array $indexes): array { $return = array(); foreach ($indexes as $i => $index) { if ($index["type"] == "FULLTEXT" && idx($_GET["fulltext"], $i) != "") { $return[] = "MATCH (" . implode(", ", array_map('Adminer\idf_escape', $index["columns"])) . ") AGAINST (" . q($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")"; } } foreach ((array) $_GET["where"] as $key => $val) { $col = $val["col"]; if ("$col$val[val]" != "" && in_array($val["op"], adminer()->operators())) { $conds = array(); foreach (($col != "" ? array($col => $fields[$col]) : $fields) as $name => $field) { $prefix = ""; $cond = " $val[op]"; if (preg_match('~IN$~', $val["op"])) { $in = process_length($val["val"]); $cond .= " " . ($in != "" ? $in : "(NULL)"); } elseif ($val["op"] == "SQL") { $cond = " $val[val]"; // SQL injection } elseif (preg_match('~^(I?LIKE) %%$~', $val["op"], $match)) { $cond = " $match[1] " . adminer()->processInput($field, "%$val[val]%"); } elseif ($val["op"] == "FIND_IN_SET") { $prefix = "$val[op](" . q($val["val"]) . ", "; $cond = ")"; } elseif (!preg_match('~NULL$~', $val["op"])) { $cond .= " " . adminer()->processInput($field, $val["val"]); } if ($col != "" || ( // find anywhere isset($field["privileges"]["where"]) && (preg_match('~^[-\d.' . (preg_match('~IN$~', $val["op"]) ? ',' : '') . ']+$~', $val["val"]) || !preg_match('~' . number_type() . '|bit~', $field["type"])) && (!preg_match("~[\x80-\xFF]~", $val["val"]) || preg_match('~char|text|enum|set~', $field["type"])) && (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val["val"])) )) { $conds[] = $prefix . driver()->convertSearch(idf_escape($name), $val, $field) . $cond; } } $return[] = (count($conds) == 1 ? $conds[0] : ($conds ? "(" . implode(" OR ", $conds) . ")" : "1 = 0" )); } } return $return; } /** Process order box in select * @param Field[] $fields * @param Index[] $indexes * @return list expressions to join by comma */ function selectOrderProcess(array $fields, array $indexes): array { $return = array(); foreach ((array) $_GET["order"] as $key => $val) { if ($val != "") { $return[] = (preg_match('~^((COUNT\(DISTINCT |[A-Z0-9_]+\()(`(?:[^`]|``)+`|"(?:[^"]|"")+")\)|COUNT\(\*\))$~', $val) ? $val : idf_escape($val)) //! MS SQL uses [] . (isset($_GET["desc"][$key]) ? " DESC" : "") ; } } return $return; } /** Process limit box in select */ function selectLimitProcess(): int { return (isset($_GET["limit"]) ? intval($_GET["limit"]) : 50); } /** Process length box in select * @return numeric-string number of characters to shorten texts, will be escaped, empty string means unlimited */ function selectLengthProcess(): string { return (isset($_GET["text_length"]) ? "$_GET[text_length]" : "100"); } /** Process extras in select form * @param string[] $where AND conditions * @param list[] $foreignKeys * @return bool true if processed, false to process other parts of form */ function selectEmailProcess(array $where, array $foreignKeys): bool { return false; } /** Build SQL query used in select * @param list $select result of selectColumnsProcess()[0] * @param list $where result of selectSearchProcess() * @param list $group result of selectColumnsProcess()[1] * @param list $order result of selectOrderProcess() * @param int $limit result of selectLimitProcess() * @param int $page index of page starting at zero * @return string empty string to use default query */ function selectQueryBuild(array $select, array $where, array $group, array $order, int $limit, ?int $page): string { return ""; } /** Query printed after execution in the message * @param string $query executed query * @param string $time elapsed time */ function messageQuery(string $query, string $time, bool $failed = false): string { restart_session(); $history = &get_session("queries"); if (!idx($history, $_GET["db"])) { $history[$_GET["db"]] = array(); } if (strlen($query) > 1e6) { $query = preg_replace('~[\x80-\xFF]+$~', '', substr($query, 0, 1e6)) . "\n…"; // [\x80-\xFF] - valid UTF-8, \n - can end by one-line comment } $history[$_GET["db"]][] = array($query, time(), $time); // not DB - $_GET["db"] is changed in database.inc.php //! respect $_GET["ns"] $sql_id = "sql-" . count($history[$_GET["db"]]); $return = "" . lang('SQL command') . "\n"; if (!$failed && ($warnings = driver()->warnings())) { $id = "warnings-" . count($history[$_GET["db"]]); $return = "" . lang('Warnings') . ", $return\n"; } return " " . @date("H:i:s") . "" // @ - time zone may be not set . " $return' ; } /** Print before edit form * @param Field[] $fields * @param mixed $row */ function editRowPrint(string $table, array $fields, $row, ?bool $update): void { } /** Functions displayed in edit form * @param Field|array{null:bool} $field * @return string[] */ function editFunctions(array $field): array { $return = ($field["null"] ? "NULL/" : ""); $update = isset($_GET["select"]) || where($_GET); foreach (array(driver()->insertFunctions, driver()->editFunctions) as $key => $functions) { if (!$key || (!isset($_GET["call"]) && $update)) { // relative functions foreach ($functions as $pattern => $val) { if (!$pattern || preg_match("~$pattern~", $field["type"])) { $return .= "/$val"; } } } if ($key && $functions && !preg_match('~set|blob|bytea|raw|file|bool~', $field["type"])) { $return .= "/SQL"; } } if ($field["auto_increment"] && !$update) { $return = lang('Auto Increment'); } return explode("/", $return); } /** Get options to display edit field * @param ?string $table null in call.inc.php * @param Field $field * @param string $attrs attributes to use inside the tag * @return string custom input field or empty string for default */ function editInput(?string $table, array $field, string $attrs, ?string $value): string { if ($field["type"] == "enum") { return (isset($_GET["select"]) ? " " : "") . ($field["null"] ? " " : "") . enum_input("radio", $attrs, $field, $value, $value === 0 ? 0 : null) // 0 - empty value ; } return ""; } /** Get hint for edit field * @param ?string $table null in call.inc.php * @param Field $field */ function editHint(?string $table, array $field, ?string $value): string { return ""; } /** Process sent input * @param Field $field * @return string expression to use in a query */ function processInput(array $field, string $value, ?string $function = ""): string { if ($function == "SQL") { return $value; // SQL injection } $name = $field["field"]; $return = q($value); if (preg_match('~^(now|getdate|uuid)$~', $function)) { $return = "$function()"; } elseif (preg_match('~^current_(date|timestamp)$~', $function)) { $return = $function; } elseif (preg_match('~^([+-]|\|\|)$~', $function)) { $return = idf_escape($name) . " $function $return"; } elseif (preg_match('~^[+-] interval$~', $function)) { $return = idf_escape($name) . " $function " . (preg_match("~^(\\d+|'[0-9.: -]') [A-Z_]+\$~i", $value) && JUSH != "pgsql" ? $value : $return); } elseif (preg_match('~^(addtime|subtime|concat)$~', $function)) { $return = "$function(" . idf_escape($name) . ", $return)"; } elseif (preg_match('~^(md5|sha1|password|encrypt)$~', $function)) { $return = "$function($return)"; } return unconvert_field($field, $return); } /** Return export output options * @return string[] */ function dumpOutput(): array { $return = array('text' => lang('open'), 'file' => lang('save')); if (function_exists('gzencode')) { $return['gz'] = 'gzip'; } return $return; } /** Return export format options * @return string[] empty to disable export */ function dumpFormat(): array { return (support("dump") ? array('sql' => 'SQL') : array()) + array('csv' => 'CSV,', 'csv;' => 'CSV;', 'tsv' => 'TSV'); } /** Export database structure * @return void prints data */ function dumpDatabase(string $db): void { } /** Export table structure * @param int $is_view 0 table, 1 view, 2 temporary view table * @return void prints data */ function dumpTable(string $table, string $style, int $is_view = 0): void { if ($_POST["format"] != "sql") { echo "\xef\xbb\xbf"; // UTF-8 byte order mark if ($style) { dump_csv(array_keys(fields($table))); } } else { if ($is_view == 2) { $fields = array(); foreach (fields($table) as $name => $field) { $fields[] = idf_escape($name) . " $field[full_type]"; } $create = "CREATE TABLE " . table($table) . " (" . implode(", ", $fields) . ")"; } else { $create = create_sql($table, $_POST["auto_increment"], $style); } set_utf8mb4($create); if ($style && $create) { if ($style == "DROP+CREATE" || $is_view == 1) { echo "DROP " . ($is_view == 2 ? "VIEW" : "TABLE") . " IF EXISTS " . table($table) . ";\n"; } if ($is_view == 1) { $create = remove_definer($create); } echo "$create;\n\n"; } } } /** Export table data * @return void prints data */ function dumpData(string $table, string $style, string $query): void { if ($style) { $max_packet = (JUSH == "sqlite" ? 0 : 1048576); // default, minimum is 1024 $fields = array(); $identity_insert = false; if ($_POST["format"] == "sql") { if ($style == "TRUNCATE+INSERT") { echo truncate_sql($table) . ";\n"; } $fields = fields($table); if (JUSH == "mssql") { foreach ($fields as $field) { if ($field["auto_increment"]) { echo "SET IDENTITY_INSERT " . table($table) . " ON;\n"; $identity_insert = true; break; } } } } $result = connection()->query($query, 1); // 1 - MYSQLI_USE_RESULT //! enum and set as numbers if ($result) { $insert = ""; $buffer = ""; $keys = array(); $generated = array(); $suffix = ""; $fetch_function = ($table != '' ? 'fetch_assoc' : 'fetch_row'); $count = 0; while ($row = $result->$fetch_function()) { if (!$keys) { $values = array(); foreach ($row as $val) { $field = $result->fetch_field(); if (idx($fields[$field->name], 'generated')) { $generated[$field->name] = true; continue; } $keys[] = $field->name; $key = idf_escape($field->name); $values[] = "$key = VALUES($key)"; } $suffix = ($style == "INSERT+UPDATE" ? "\nON DUPLICATE KEY UPDATE " . implode(", ", $values) : "") . ";\n"; } if ($_POST["format"] != "sql") { if ($style == "table") { dump_csv($keys); $style = "INSERT"; } dump_csv($row); } else { if (!$insert) { $insert = "INSERT INTO " . table($table) . " (" . implode(", ", array_map('Adminer\idf_escape', $keys)) . ") VALUES"; } foreach ($row as $key => $val) { if ($generated[$key]) { unset($row[$key]); continue; } $field = $fields[$key]; $row[$key] = ($val !== null ? unconvert_field($field, preg_match(number_type(), $field["type"]) && !preg_match('~\[~', $field["full_type"]) && is_numeric($val) ? $val : q(($val === false ? 0 : $val))) : "NULL" ); } $s = ($max_packet ? "\n" : " ") . "(" . implode(",\t", $row) . ")"; if (!$buffer) { $buffer = $insert . $s; } elseif (JUSH == 'mssql' ? $count % 1000 != 0 // https://learn.microsoft.com/en-us/sql/t-sql/queries/table-value-constructor-transact-sql#limitations-and-restrictions : strlen($buffer) + 4 + strlen($s) + strlen($suffix) < $max_packet // 4 - length specification ) { $buffer .= ",$s"; } else { echo $buffer . $suffix; $buffer = $insert . $s; } } $count++; } if ($buffer) { echo $buffer . $suffix; } } elseif ($_POST["format"] == "sql") { echo "-- " . str_replace("\n", " ", connection()->error) . "\n"; } if ($identity_insert) { echo "SET IDENTITY_INSERT " . table($table) . " OFF;\n"; } } } /** Set export filename * @return string filename without extension */ function dumpFilename(string $identifier): string { return friendly_url($identifier != "" ? $identifier : (SERVER != "" ? SERVER : "localhost")); } /** Send headers for export * @return string extension */ function dumpHeaders(string $identifier, bool $multi_table = false): string { $output = $_POST["output"]; $ext = (preg_match('~sql~', $_POST["format"]) ? "sql" : ($multi_table ? "tar" : "csv")); // multiple CSV packed to TAR header("Content-Type: " . ($output == "gz" ? "application/x-gzip" : ($ext == "tar" ? "application/x-tar" : ($ext == "sql" || $output != "file" ? "text/plain" : "text/csv") . "; charset=utf-8" ))); if ($output == "gz") { ob_start(function ($string) { // ob_start() callback receives an optional parameter $phase but gzencode() accepts optional parameter $level return gzencode($string); }, 1e6); } return $ext; } /** Print text after export * @return void prints data */ function dumpFooter(): void { if ($_POST["format"] == "sql") { echo "-- " . gmdate("Y-m-d H:i:s e") . "\n"; } } /** Set the path of the file for webserver load * @return string path of the sql dump file */ function importServerPath(): string { return "adminer.sql"; } /** Print homepage * @return bool whether to print default homepage */ function homepage(): bool { echo '

" . adminer()->name() . " " . VERSION; $new_version = $_COOKIE["adminer_version"]; echo " " . (version_compare(VERSION, $new_version) < 0 ? h($new_version) : "") . ""; echo "

\n"; // this is matched by compile.php switch_lang(); if ($missing == "auth") { $output = ""; foreach ((array) $_SESSION["pwds"] as $vendor => $servers) { foreach ($servers as $server => $usernames) { $name = h(get_setting("vendor-$vendor-$server") ?: get_driver($vendor)); foreach ($usernames as $username => $password) { if ($password !== null) { $dbs = $_SESSION["db"][$vendor][$server][$username]; foreach (($dbs ? array_keys($dbs) : array("")) as $db) { $output .= "
  • ($name) " . h("$username@" . ($server != "" ? adminer()->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "\n"; } } } } } if ($output) { echo "
      \n$output
    \n" . script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});"); } } else { $tables = array(); if ($_GET["ns"] !== "" && !$missing && DB != "") { connection()->select_db(DB); $tables = table_status('', true); } adminer()->syntaxHighlighting($tables); adminer()->databasesPrint($missing); $actions = array(); if (DB == "" || !$missing) { if (support("sql")) { $actions[] = "" . lang('SQL command') . ""; $actions[] = "" . lang('Import') . ""; } $actions[] = "" . lang('Export') . ""; } $in_db = $_GET["ns"] !== "" && !$missing && DB != ""; if ($in_db) { $actions[] = '" . lang('Create table') . ""; } echo ($actions ? "

    " . lang('No tables.') . "

    \n"; } } } } /** Set up syntax highlight for code and