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

Compare commits

...

102 Commits

Author SHA1 Message Date
Peter Knut
4112aaf26f Release 4.12 2024-11-21 12:54:30 +01:00
Peter Knut
5fdc9dc427 Update docs 2024-11-21 09:59:57 +01:00
Peter Knut
cc646de4ca Remove funding config 2024-11-19 23:41:47 +01:00
Peter Knut
b6b379a8ce Improve arrays formatting in dump method 2024-11-19 23:11:36 +01:00
Peter Knut
f93db81c0e Update translations 2024-11-19 22:58:20 +01:00
Peter Knut
2cafcd7fc8 Handle the situation when no driver is found
This can happen if Adminer for MySQL with existing login is replaced by Adminer for PostgreSQL.
2024-11-19 22:58:20 +01:00
Peter Knut
53799ff6ab Update Spanish translations
Thanks to isaacpolaino (https://github.com/adminerevo/adminerevo/discussions/21#discussioncomment-11283326)
2024-11-19 22:00:12 +01:00
Peter Knut
638288cc04 Cleanup: Definition of custom PDO statement class 2024-11-19 22:00:12 +01:00
Peter Knut
99f4c22c72 MSSQL: Allow to set Encrypt and TrustServerCertificate with AdminerLoginSsl plugin (issue #5)
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-string-syntax#use-trustservercertificate
2024-11-19 22:00:12 +01:00
Peter Knut
55e0c348b8 MSSQL, MongoDB: Connect to localhost with default port if server is not specified 2024-11-19 22:00:12 +01:00
Peter Knut
379003fc8d MongoDB: Fix parsing WHERE condition from SQL query
Thanks to herobank110 (https://github.com/vrana/adminer/pull/491)
2024-11-19 22:00:12 +01:00
Peter Knut
0933e4e67d MongoDB: Small cleanup 2024-11-19 22:00:12 +01:00
Peter Knut
ee26735ac6 Refactor drivers definition and compilation
- Rename 'server' driver to 'mysql'
- MySQL driver is no longer the required default
- Fix compiled SQLite single-driver Adminer
- Allow to compile only selected drivers
2024-11-19 22:00:11 +01:00
Peter Knut
214d7745a7 Compiler: Refactor languages compilation
- Allow to compile only selected languages
- Fix translations in plugins
2024-11-07 10:52:13 +01:00
Peter Knut
99b7c08e3a Compiler: Add new lines before selected keywords, not after 2024-11-05 22:16:39 +01:00
Peter Knut
b1ecb0649e Improve dumping methods if run from terminal 2024-11-05 15:56:57 +01:00
vukbgit
2430ad2702 MariaDB: Add support for UUID data type
- MariaDB >= 10.7
- UUID string data type
- uuid() function for UUID type on new/edit item form
2024-11-04 14:40:50 +01:00
Peter Knut
9eeeca6b0e Fix highlighting default submit button in indexes form 2024-11-03 22:31:45 +01:00
Peter Knut
d165cd9aec Change logo link to main page (login) 2024-11-03 22:31:45 +01:00
Peter Knut
a0a0d44c7c Update project URL and info 2024-11-03 22:31:45 +01:00
Peter Knut
316754af47 Enhance checking of new version
- Do not verify version on login page
- Do not show error from version checking
- Sync expiration of version cookie with file
- Clean up the code
2024-11-03 22:31:45 +01:00
Peter Knut
47f1f19970 Fix SQL query code direction if RTL language is used 2024-11-03 22:31:45 +01:00
Peter Knut
5c4dc82081 PostgreSQL: Fix layout of stored function parameters 2024-11-03 22:31:45 +01:00
Peter Knut
226d4ad54b MySQL: Print comments of stored procedures and functions 2024-11-03 22:31:45 +01:00
Peter Knut
85c0c8f003 Fix disappearing dragged row 2024-11-03 22:31:45 +01:00
Peter Knut
c815ea875b Fix compiling single language version 2024-11-03 22:31:45 +01:00
Peter Knut
872991fa14 Docs: Update migration section 2024-11-03 22:31:45 +01:00
Peter Knut
35411d8f4e Bump version to 4.12-dev 2024-11-03 22:31:45 +01:00
Peter Knut
81e337bed1 Release 4.11 2024-10-30 22:14:44 +01:00
Peter Knut
18ddbf1d60 MySQL: Fix highlighting current table in menu on macOS 2024-10-30 22:12:59 +01:00
Peter Knut
e4235d21e5 Clean up JS code 2024-10-30 21:16:39 +01:00
Peter Knut
10dfc54bf4 Show help popup after a short delay, refactoring 2024-10-30 21:16:39 +01:00
Peter Knut
af3c863be3 Fix drag-n-drop moving of function parameters 2024-10-30 21:16:39 +01:00
Peter Knut
6cd5495c1b PostgreSQL: Show list of schemas in database, unify lists of sequences and user types 2024-10-30 21:16:39 +01:00
Peter Knut
78ad8381ab Update CS and SK translations 2024-10-30 21:16:39 +01:00
Peter Knut
87fc82f88e Fix printing error message while validating server URL 2024-10-30 21:16:39 +01:00
Peter Knut
0519a0b985 Devel: Add modification time to CSS and JS links for easier development 2024-10-30 21:16:39 +01:00
Peter Knut
f61cf1ba0c Support drag-n-drop moving on touch screens 2024-10-30 21:16:39 +01:00
HyP3r
fc2e025603 MS SQL: Prefix Unicode strings with 'N' so they are treated correctly 2024-10-30 21:16:39 +01:00
Peter Knut
659e72b692 MariaDB: Fix several links to documentation pages 2024-10-30 21:16:39 +01:00
Peter Knut
123373ca82 Switch to custom JUSH library 2024-10-30 21:16:39 +01:00
Peter Knut
e99f2d90cf Update project information 2024-10-30 21:16:39 +01:00
Peter Knut
bdabc5aa13 Small CSS tuning 2024-10-30 21:16:39 +01:00
Peter Knut
92f3e0ca00 Reset the style of sortable row after dragging 2024-10-22 23:29:03 +02:00
Peter Knut
aa1266e4f2 Bump version to 4.10.1-dev 2024-10-22 23:29:03 +02:00
Peter Knut
b7bbd07155 Release 4.10 2024-10-22 17:10:38 +02:00
Peter Knut
1ff6f246e8 Add <div> for page footer, layout changes 2024-10-22 17:10:38 +02:00
Peter Knut
555e2e76b7 Keep backward compatibility with non-official plugins 2024-10-22 17:10:36 +02:00
Peter Knut
7883e0bd99 Update information files 2024-10-22 17:10:17 +02:00
Peter Knut
18e26a3b68 Add drag-n-drop moving of rows in table editing 2024-10-22 17:10:14 +02:00
Peter Knut
25a1ccf75b Refactor table editing, remove option to hide default values 2024-10-22 13:07:49 +02:00
Peter Knut
b9cdf52ec5 Add drag-n-drop moving of rows in table selection filter 2024-10-22 13:07:49 +02:00
Peter Knut
7997331b77 Hide arrow buttons in number input fields 2024-10-22 13:07:49 +02:00
Peter Knut
3bb75dc036 Fix missing SQL statement if warnings are printed
Regression from 4.9.
2024-10-22 13:07:49 +02:00
Adrian Jones
441e7f050c Check new version against GitHub pages 2024-10-22 13:07:49 +02:00
Peter Knut
c41cb51ede Change version layout 2024-10-22 13:07:49 +02:00
Peter Knut
42d92875c5 Print username next to the logout button 2024-10-22 13:07:49 +02:00
Peter Knut
df0e5b59bb Update readme.txt 2024-10-22 13:07:49 +02:00
Peter Knut
de9f572112 Elasticsearch: Add documentation link for regexp 2024-10-22 13:07:49 +02:00
Peter Knut
dd9a4a2b65 Remove deprecated HTML table parameters 2024-10-20 00:09:54 +02:00
Roy-Orbison
91d44f4a9f Plugin to auto-include adminer.js when present 2024-10-20 00:09:54 +02:00
Peter Knut
f993acb538 Do not display empty action links in main menu 2024-10-20 00:09:54 +02:00
Peter Knut
a87b606918 Remove a:visited style 2024-10-20 00:09:54 +02:00
Peter Knut
3e81c3871f Elasticsearch: New condition operators as the combination of query type and match type
- Support for regexp conditions.
- Proper formatting of boolean values.
2024-10-17 00:25:16 +02:00
Peter Knut
13752c0498 Define 'LIKE%%' operator in each driver 2024-10-17 00:25:16 +02:00
Peter Knut
e378f7d817 Update translations for regexp search 2024-10-17 00:25:16 +02:00
Roy-Orbison
6f789eac0a Enable regular expressions when searching data in all tables
Allows use of the database-specific regex operator and pattern syntax when searching multiple tables.
2024-10-17 00:25:16 +02:00
Roy Orbitson
9ed4c859ed Add removal buttons to table data filter 2024-10-17 00:25:16 +02:00
Peter Knut
62246338bf Add 'Home' to breadcrumb navigation 2024-10-17 00:25:16 +02:00
Peter Knut
e5a7f75807 Full width design for database select box 2024-10-17 00:25:16 +02:00
Peter Knut
279337aa65 Integrate tables-filter plugin into the base code 2024-10-17 00:25:16 +02:00
Peter Knut
bf1d16cdb7 Hide edited value if selected function will not use it 2024-10-17 00:25:16 +02:00
Peter Knut
1de9275f11 Show second link for editing a table under the table view, add table head to indexes 2024-10-17 00:25:16 +02:00
Peter Knut
0f2e04730f Show partitioning info in table structure page 2024-10-17 00:25:16 +02:00
Peter Knut
ae629f8ac7 Bump version to 4.10-dev 2024-10-17 00:25:16 +02:00
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
Peter Knut
507f335371 Release 4.9.3 2024-10-02 17:07:09 +02:00
Peter Knut
ea314b8103 Hide invalid edit form if table record is not found 2024-10-02 09:35:59 +02:00
Peter Knut
e250470768 PostgreSQL: Fix editing record that contains a field with GENERATED ALWAYS default value
Fields with GENERATED ALWAYS default values are also disabled.

Thanks to PurpleTape (https://github.com/adminerevo/adminerevo/issues/201).
2024-10-02 00:29:24 +02:00
Peter Knut
2fa42d50eb Fix using undefined Min_DB::info property 2024-10-01 23:37:07 +02:00
Peter Knut
a366b7af09 MySQL: Fix editing user's proxy privilege, refactoring
- Uncheck all other priviledges if 'All privileges' is checked.
- Refactor related functions.
2024-10-01 23:22:26 +02:00
Peter Knut
b039a39e4d Bigger font size for code blocks 2024-10-01 09:07:21 +02:00
SeaEagle
08e48c8641 MySQL: Fix where clause for JSON column
Issue: https://github.com/adminerevo/adminerevo/issues/175
2024-10-01 09:06:20 +02:00
Peter Knut
78c2041cfd Fix background color of <pre> used as edit field 2024-10-01 00:33:47 +02:00
Peter Knut
5d7c5fa268 Do not include unchanged PARTITION BY definition into ALTER TABLE query 2024-09-22 00:33:55 +02:00
Peter Knut
8f1db4cf6f Add helper methods for dumping variable to the output 2024-09-21 22:34:38 +02:00
Peter Knut
9daa88acca MariaDB: Fix comparing CURRENT_TIMESTAMP definition while altering a table 2024-09-21 22:20:08 +02:00
Peter Knut
aa519b78ca MySQL, PostgreSQL: Fix queries splitting and string constants
Thanks to alxivnov (https://github.com/vrana/adminer/pull/490).
2024-09-21 09:28:50 +02:00
Michael Graß
aee800efed Do not limit unlimited memory, fix number conversion warning 2024-09-20 22:28:46 +02:00
Peter Knut
06d0f957d5 Bump version to 4.9.3-dev 2024-09-18 10:57:48 +02:00
113 changed files with 4512 additions and 2525 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +0,0 @@
patreon: jakubvrana
custom: ["https://sourceforge.net/p/adminer/donate/"]

1276
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

8
LICENSE.md Normal file
View File

@@ -0,0 +1,8 @@
Licenses
========
You may use Adminer under the terms of either the Apache License Version 2.0
or the GNU General Public License (GPL) version 2.
- [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)

170
README.md Normal file
View File

@@ -0,0 +1,170 @@
Adminer
=======
**Adminer** is a full-featured database management tool written in PHP. It consists of a single file ready to deploy to
the target server. As a companion, **Adminer Editor** offers data manipulation for end-users.
Supported database drivers:
- MySQL, MariaDB, PostgreSQL, SQLite, MS SQL, Oracle, MongoDB
- With plugin: SimpleDB, Elasticsearch (beta), Firebird (alpha), ClickHouse (alpha)
Requirements
------------
- PHP 5.6+ with enabled sessions.
Migration from original Adminer
-------------------------------
- Remove plugin AdminerTablesFilter (plugins/tables-filter.php).
- If you use complex custom theme, you will probably need to adjust a thing or two.
More information can be found in [Upgrade Guide](docs/upgrade.md).
Please, read also 👉 **[What to expect](#what-to-expect)** section before you decide to switch to this project.
Usage
-----
Download one for the latest [release files](https://github.com/pematon/adminer/releases), upload to the HTTP server
with PHP and enjoy 😉 If you are not satisfied with any combination of the database driver and language, you can
download the source code and compile your own Adminer:
- Download the source code.
- Run `composer install` to install dependencies.
- Run compile.php:
```shell
# Adminer
php compile.php <drivers> <languages>
# Editor
php compile.php editor <drivers> <languages>
```
For example:
```shell
php compile.php pgsql cs
php compile.php mysql,pgsql en,de,cs,sk
```
[Available drivers](https://github.com/pematon/adminer/tree/master/adminer/drivers),
[languages](https://github.com/pematon/adminer/tree/master/adminer/lang).
Security
--------
Adminer does not allow connecting to databases without a password and it rate-limits the connection attempts to protect
against brute-force attacks. Still, it is highly recommended to 🔒 **restrict access to Adminer** 🔒 by whitelisting IP
addresses allowed to connect to it, by password-protecting the access in your web server or by enabling security plugins
(e.g. to require an OTP).
Plugins
-------
* Download plugins you want and place them into the `plugins` folder.
* Create `index.php` file specifying which plugins do you want to use.
File structure will be:
```
- plugins
- drivers
- elastic.php
- dump-xml.php
- tinymce.php
- file-upload.php
- ...
- adminer.php
- index.php
```
Index.php:
```php
<?php
function adminer_object() {
// Required to run any plugin.
include_once "./plugins/plugin.php";
// Autoloader.
foreach (glob("plugins/*.php") as $filename) {
include_once "./$filename";
}
// Enable extra drivers just by including them.
include_once "./plugins/drivers/elastic.php";
// Specify enabled plugins.
$plugins = [
new AdminerDumpXml(),
new AdminerTinymce(),
new AdminerFileUpload("data/"),
// ...
];
// It is possible to combine customization and plugins.
// class AdminerCustomization extends AdminerPlugin {
// }
// return new AdminerCustomization($plugins);
return new AdminerPlugin($plugins);
}
// Include original Adminer or Adminer Editor.
include "./adminer.php";
```
[Available plugins](https://github.com/pematon/adminer/tree/master/plugins).
Main project files
------------------
- adminer/index.php - Run development version of Adminer.
- editor/index.php - Run development version of Adminer Editor.
- editor/example.php - Example customization.
- plugins/readme.txt - Plugins for Adminer and Adminer Editor.
- adminer/plugin.php - Plugin demo.
- adminer/sqlite.php - Development version of Adminer with SQLite allowed.
- editor/sqlite.php - Development version of Editor with SQLite allowed.
- adminer/designs.php - Development version of Adminer with adminer.css switcher.
- compile.php - Create a single file version.
- lang.php - Update translations.
- tests/katalon.html - Katalon Automation Recorder test suite.
Project history
---------------
Adminer was originally developed by Jakub Vrana, and it can be still found on [official pages](https://www.adminer.org/).
Unfortunately, it is not maintained for several years. In the meantime, I (@peterpp) created for my company a set of
custom plugins, modern theme, fixed some bugs and practically rewrote the Elasticsearch driver. I also looked closely
and contributed to the [AdminerEvo](https://www.adminerevo.org/) project that looked promising. However, I finally
decided to continue working on this fork and fulfill my own vision.
What to expect
--------------
Our top priority is fixing the security issues and reported bugs. But we really want to move forward and transform
Adminer to a tool that will keep its simplicity, yet looks much better, is even easier to use and can be configured
without requirement of additional plugins.
### Version 4.x
Original design and backward compatibility is kept. Many issues were fixed, and we introduced several functional and
UI improvements.
### Version 5
Bridges will be burned 🔥🔥🔥. It's in development already, so you [can check](https://github.com/pematon/adminer/tree/version-5)
what's going on. Or you can become the early adopter and help us with testing 😉
Our goals are:
- **Requirements** - Bump minimal PHP to 7.1, maybe even higher.
- **Themes** Modernize the current old-school theme, add new default theme based on our [Adminer theme](https://github.com/pematon/adminer-theme),
support dark mode, configurable color variants for production/devel environment. All current designs will be removed.
- **Plugins** - Integrate several basic plugins, enable them by optional configuration.
- **Codebase** - Prefer code readability before minimalism, use PER coding style, add namespaces.
- **Compilation** - Allow to export selected drivers, themes, languages and plugins into a single adminer.php file.
We are also thinking to change the project's name, so people will clearly distinguish between original Adminer and
other forks. Any suggestions are welcome.

View File

@@ -1,11 +1,13 @@
# Security Policy
Reporting security issues
=========================
## Supported Versions
To report a security issue, please [open a draft security advisory](https://github.com/pematon/adminer/security/advisories).
I support only the last published version and the last development version (last commit).
Security issues are handled with top priority. Once acknowledged, a fix should be available and new version released
as soon as possible. Security advisories will be made public after a fix and new version have been released,
or the advisory has been declined.
## Reporting a Vulnerability
Supported versions
------------------
To report a vulnerability, create a private bug at https://sourceforge.net/p/adminer/bugs-and-features/new/?private=1.
I handle security issues with top priority. If you don't hear from me in a week then please ping the bug. Once I accept the bug, the fix should be available and new version released within days. I will mark the bug as public after releasing a new version or declining the bug.
Only the last published version and the last development version (last commit) are supported.

View File

@@ -1,5 +1,6 @@
<?php
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["call"]);
$PROCEDURE = ($_GET["name"] ?: $_GET["call"]);
page_header(lang('Call') . ": " . h($PROCEDURE), $error);
$routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
@@ -28,13 +29,13 @@ if (!$error && $_POST) {
}
$call[] = (isset($out[$key]) ? "@" . idf_escape($field["field"]) : $val);
}
$query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")";
$start = microtime(true);
$result = $connection->multi_query($query);
$affected = $connection->affected_rows; // getting warnigns overwrites this
echo $adminer->selectQuery($query, $start, !$result);
if (!$result) {
echo "<p class='error'>" . error() . "\n";
} else {
@@ -42,7 +43,7 @@ if (!$error && $_POST) {
if (is_object($connection2)) {
$connection2->select_db(DB);
}
do {
$result = $connection->store_result();
if (is_object($result)) {
@@ -53,16 +54,15 @@ if (!$error && $_POST) {
;
}
} while ($connection->next_result());
if ($out) {
select($connection->query("SELECT " . implode(", ", $out)));
}
}
}
?>
<form action="" method="post">
<?php
echo "<form action='' method='post'>\n";
if ($in) {
echo "<table cellspacing='0' class='layout'>\n";
foreach ($in as $key) {
@@ -83,8 +83,28 @@ if ($in) {
}
echo "</table>\n";
}
?>
<p>
<input type="submit" value="<?php echo lang('Call'); ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
echo "<p>",
"<input type='submit' value='", lang('Call'), "'>",
"<input type='hidden' name='token' value='$token'>",
"</p>\n",
"</form>\n";
$comment = $routine["comment"];
if ($comment !== null && $comment !== "") {
$comment = h(trim($routine["comment"], "\n"));
// Remove indenting of all lines (used in MySQL routines in 'sys' database).
if (preg_match('~^ +~', $comment, $matches)) {
preg_match_all("~^($matches[0]|$)~m", $comment, $linesWithIndent);
if (count($linesWithIndent[0]) == substr_count($comment, "\n")) {
$comment = preg_replace("~^($matches[0])~m", "", $comment);
}
}
// Format common headlines (used in MySQL routines in 'sys' database).
$comment = preg_replace('~(^|[^\n]\n)(Description|Parameters|Example)\n~', "$1\n<strong>$2</strong>\n", $comment);
echo "<pre class='comment'>$comment</pre>\n";
}

View File

@@ -82,20 +82,39 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
}
$partitioning = "";
if ($partition_by[$row["partition_by"]]) {
$partitions = array();
if ($row["partition_by"] == 'RANGE' || $row["partition_by"] == 'LIST') {
foreach (array_filter($row["partition_names"]) as $key => $val) {
$value = $row["partition_values"][$key];
$partitions[] = "\n PARTITION " . idf_escape($val) . " VALUES " . ($row["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
if (support("partitioning")) {
if (isset($partition_by[$row["partition_by"]])) {
$params = array_filter($row, function ($key) {
return preg_match('~^partition~', $key);
}, ARRAY_FILTER_USE_KEY);
foreach ($params["partition_names"] as $key => $name) {
if ($name === "") {
unset($params["partition_names"][$key]);
unset($params["partition_values"][$key]);
}
}
if ($params != get_partitions_info($TABLE)) {
$partitions = [];
if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') {
foreach ($params["partition_names"] as $key => $name) {
$value = $params["partition_values"][$key];
$partitions[] = "\n PARTITION " . idf_escape($name) . " VALUES " . ($params["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
}
}
// $params["partition"] can be expression, not only column
$partitioning .= "\nPARTITION BY {$params["partition_by"]}({$params["partition"]})";
if ($partitions) {
$partitioning .= " (" . implode(",", $partitions) . "\n)";
} elseif ($params["partitions"]) {
$partitioning .= " PARTITIONS " . (int)$params["partitions"];
}
}
} elseif (preg_match("~partitioned~", $table_status["Create_options"])) {
$partitioning .= "\nREMOVE PARTITIONING";
}
$partitioning .= "\nPARTITION BY $row[partition_by]($row[partition])" . ($partitions // $row["partition"] can be expression, not only column
? " (" . implode(",", $partitions) . "\n)"
: ($row["partitions"] ? " PARTITIONS " . (+$row["partitions"]) : "")
);
} elseif (support("partitioning") && preg_match("~partitioned~", $table_status["Create_options"])) {
$partitioning .= "\nREMOVE PARTITIONING";
}
$message = lang('Table has been altered.');
@@ -141,13 +160,9 @@ if (!$_POST) {
}
if (support("partitioning")) {
$from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($TABLE);
$result = $connection->query("SELECT PARTITION_METHOD, PARTITION_ORDINAL_POSITION, PARTITION_EXPRESSION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");
list($row["partition_by"], $row["partitions"], $row["partition"]) = $result->fetch_row();
$partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION");
$partitions[""] = "";
$row["partition_names"] = array_keys($partitions);
$row["partition_values"] = array_values($partitions);
$row += get_partitions_info($TABLE);
$row["partition_names"][] = "";
$row["partition_values"][] = "";
}
}
}
@@ -167,8 +182,8 @@ foreach ($engines as $engine) {
<p>
<?php if (support("columns") || $TABLE == "") { ?>
<?php echo lang('Table name'); ?>: <input name="name" data-maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php if ($TABLE == "" && !$_POST) { echo script("focus(qs('#form')['name']);"); } ?>
<?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?php if ($TABLE == "" && !$_POST) { echo script("focus(gid('form')['name']);"); } ?>
<?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . help_script_command("value", true) : ""); ?>
<?php echo ($collations && !preg_match("~sqlite|mssql~", $jush) ? html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]) : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?>
@@ -184,7 +199,6 @@ edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
</div>
<p>
<?php echo lang('Auto Increment'); ?>: <input type="number" name="Auto_increment" size="6" value="<?php echo h($row["Auto_increment"]); ?>">
<?php echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : adminer_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly"); ?>
<?php
$comments = ($_POST ? $_POST["comments"] : adminer_setting("comments"));
echo (support("comment")
@@ -207,7 +221,7 @@ if (support("partitioning")) {
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
<p>
<?php echo "<select name='partition_by'>" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>" . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); ?>
<?php echo "<select name='partition_by'>" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>" . help_script_command("value.replace(/./, 'PARTITION BY \$&')", true) . script("qsl('select').onchange = partitionByChange;"); ?>
(<input name="partition" value="<?php echo h($row["partition"]); ?>">)
<?php echo lang('Partitions'); ?>: <input type="number" name="partitions" class="size<?php echo ($partition_table || !$row["partition_by"] ? " hidden" : ""); ?>" value="<?php echo h($row["partitions"]); ?>">
<table cellspacing="0" id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>

View File

@@ -66,7 +66,7 @@ echo ($_POST["add_x"] || strpos($name, "\n")
'mariadb' => "supported-character-sets-and-collations/",
'mssql' => "ms187963.aspx",
)) : "");
echo script("focus(qs('#name'));");
echo script("focus(gid('name'));");
?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php

View File

@@ -47,7 +47,28 @@ if ($tables_views && !$error && !$_POST["search"]) {
page_header(($_GET["ns"] == "" ? lang('Database') . ": " . h(DB) : lang('Schema') . ": " . h($_GET["ns"])), $error, true);
if ($adminer->homepage()) {
if ($_GET["ns"] !== "") {
if ($_GET["ns"] === "") {
echo "<h3 id='schemas'>" . lang('Schemas') . "</h3>\n";
$schemas = schemas();
if (!$schemas) {
echo "<p class='message'>" . lang('No schemas.') . "\n";
} else {
// TODO: Checkboxes for batch dropping of schemas.
echo "<div class='scrollable'>\n",
"<table class='nowrap'>\n",
'<thead><tr class="wrap">',
'<th>', lang('Schema'), "</th>",
'</tr></thead>';
foreach ($schemas as $name) {
echo "<tr", odd(), ">",
"<th><a href='", h(ME), "ns=" . urlencode($name), "' title='", lang('Show schema'), "'>" . h($name) . "</a></th>",
"</tr>";
}
echo '</table></div>';
}
} else {
echo "<h3 id='tables-views'>" . lang('Tables and views') . "</h3>\n";
$tables_list = tables_list();
if (!$tables_list) {
@@ -59,9 +80,13 @@ if ($adminer->homepage()) {
echo "<input type='search' name='query' value='" . h($_POST["query"]) . "'>";
echo script("qsl('input').onkeydown = partialArg(bodyKeydown, 'search');", "");
echo " <input type='submit' name='search' value='" . lang('Search') . "'>\n";
if ($adminer->operator_regexp !== null) {
echo "<p><label><input type='checkbox' name='regexp' value='1'" . (empty($_POST['regexp']) ? '' : ' checked') . '>' . lang('as a regular expression') . '</label>';
echo doc_link(['sql' => 'regexp.html', 'pgsql' => 'functions-matching.html#FUNCTIONS-POSIX-REGEXP', 'elastic' => "regexp-syntax.html"]) . "</p>\n";
}
echo "</div></fieldset>\n";
if ($_POST["search"] && $_POST["query"] != "") {
$_GET["where"][0]["op"] = $driver->convertOperator("LIKE %%");
$_GET["where"][0]["op"] = $adminer->operator_regexp !== null && !empty($_POST['regexp']) ? $adminer->operator_regexp : $adminer->operator_like;
search_tables();
}
}
@@ -69,7 +94,7 @@ if ($adminer->homepage()) {
echo "<table cellspacing='0' class='nowrap checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo '<thead><tr class="wrap">';
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("qs('#check-all').onclick = partial(formCheck, /^(tables|views)\[/);", "");
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("gid('check-all').onclick = partial(formCheck, /^(tables|views)\[/);", "");
echo '<th>' . lang('Table');
echo '<td>' . lang('Engine') . doc_link(array('sql' => 'storage-engines.html'));
echo '<td>' . lang('Collation') . doc_link(array('sql' => 'charset-charsets.html', 'mariadb' => 'supported-character-sets-and-collations/'));
@@ -122,17 +147,17 @@ if ($adminer->homepage()) {
echo "</div>\n";
if (!information_schema(DB)) {
echo "<div class='footer'><div>\n";
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . on_help("'VACUUM'");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . on_help($jush == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'");
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . help_script("VACUUM");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . help_script($jush == "sql" ? "OPTIMIZE TABLE" : "VACUUM OPTIMIZE");
echo "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>"
. ($jush == "sqlite" ? $vacuum
: ($jush == "pgsql" ? $vacuum . $optimize
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . on_help("'ANALYZE TABLE'") . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'CHECK TABLE'")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . on_help("'REPAIR TABLE'")
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . help_script("ANALYZE TABLE") . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . help_script("CHECK TABLE")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . help_script("REPAIR TABLE")
: "")))
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . on_help($jush == "sqlite" ? "'DELETE'" : "'TRUNCATE" . ($jush == "pgsql" ? "'" : " TABLE'")) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . on_help("'DROP TABLE'") . confirm() . "\n";
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . help_script($jush == "sqlite" ? "DELETE" : ("TRUNCATE" . ($jush == "pgsql" ? "" : " TABLE"))) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . help_script("DROP TABLE") . confirm() . "\n";
$databases = (support("scheme") ? $adminer->schemas() : $adminer->databases());
if (count($databases) != 1 && $jush != "sqlite") {
$db = (isset($_POST["target"]) ? $_POST["target"] : (support("scheme") ? $_GET["ns"] : DB));
@@ -157,37 +182,59 @@ if ($adminer->homepage()) {
if (support("routine")) {
echo "<h3 id='routines'>" . lang('Routines') . "</h3>\n";
$routines = routines();
if ($routines) {
echo "<table cellspacing='0'>\n";
echo '<thead><tr><th>' . lang('Name') . '<td>' . lang('Type') . '<td>' . lang('Return type') . "<td></thead>\n";
$commentsSupported = $routines[0]["ROUTINE_COMMENT"] !== null;
echo "<table>\n";
echo '<thead><tr>',
'<th>', lang('Name'), '</th><td>', lang('Type'), '</td><td>', lang('Return type'), "</td>";
if ($commentsSupported) {
echo "<td>", lang('Comment'), "</td>";
}
echo "<td></td>",
"</tr></thead>\n";
odd('');
foreach ($routines as $row) {
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"])); // not computed on the pages to be able to print the header first
echo '<tr' . odd() . '>';
echo '<th><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . h($row["ROUTINE_NAME"]) . '</a>';
echo '<td>' . h($row["ROUTINE_TYPE"]);
echo '<td>' . h($row["DTD_IDENTIFIER"]);
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a>";
// not computed on the pages to be able to print the header first
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"]));
echo '<tr', odd(), '>',
'<th><a href="', h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name), '">', h($row["ROUTINE_NAME"]), '</a></th>',
'<td>', h($row["ROUTINE_TYPE"]), '</td>',
'<td>', h($row["DTD_IDENTIFIER"]), '</td>';
if ($commentsSupported) {
echo '<td>', shorten_utf8(preg_replace('~\s{2,}~', " ", trim($row["ROUTINE_COMMENT"])), 50), '</td>';
}
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a></td>";
}
echo "</table>\n";
}
echo '<p class="links">'
. (support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : '')
. '<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n"
;
echo '<p class="links">',
(support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : ''),
'<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n";
}
if (support("sequence")) {
echo "<h3 id='sequences'>" . lang('Sequences') . "</h3>\n";
$sequences = get_vals("SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = current_schema() ORDER BY sequence_name");
if ($sequences) {
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th>" . lang('Name') . "</thead>\n";
echo "<table>\n",
"<thead><tr><th>", lang('Name'), "</th><td></td></tr></thead>\n";
odd('');
foreach ($sequences as $val) {
echo "<tr" . odd() . "><th><a href='" . h(ME) . "sequence=" . urlencode($val) . "'>" . h($val) . "</a>\n";
echo "<tr", odd(), ">",
"<th>", h($val), "</th>",
"<td><a href='", h(ME), "sequence=", urlencode($val), "'>", lang('Alter'), "</a></td>\n";
}
echo "</table>\n";
}
echo "<p class='links'><a href='" . h(ME) . "sequence='>" . lang('Create sequence') . "</a>\n";
@@ -197,12 +244,16 @@ if ($adminer->homepage()) {
echo "<h3 id='user-types'>" . lang('User types') . "</h3>\n";
$user_types = types();
if ($user_types) {
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th>" . lang('Name') . "</thead>\n";
echo "<table>\n",
"<thead><tr><th>", lang('Name'), "</th><td></td></tr></thead>\n";
odd('');
foreach ($user_types as $val) {
echo "<tr" . odd() . "><th><a href='" . h(ME) . "type=" . urlencode($val) . "'>" . h($val) . "</a>\n";
echo "<tr", odd(), ">",
"<th>", h($val), "</th>",
"<td><a href='", h(ME), "type=", urlencode($val), "'>", lang('Alter'), "</a></td>\n";
}
echo "</table>\n";
}
echo "<p class='links'><a href='" . h(ME) . "type='>" . lang('Create type') . "</a>\n";
@@ -212,7 +263,7 @@ if ($adminer->homepage()) {
echo "<h3 id='events'>" . lang('Events') . "</h3>\n";
$rows = get_rows("SHOW EVENTS");
if ($rows) {
echo "<table cellspacing='0'>\n";
echo "<table>\n";
echo "<thead><tr><th>" . lang('Name') . "<td>" . lang('Schedule') . "<td>" . lang('Start') . "<td>" . lang('End') . "<td></thead>\n";
foreach ($rows as $row) {
echo "<tr>";

View File

@@ -24,7 +24,7 @@ if (isset($_GET["mongo"])) {
$this->error = $e->getMessage();
}
}
function query($query) {
return false;
}
@@ -109,7 +109,7 @@ if (isset($_GET["mongo"])) {
class Min_Driver extends Min_SQL {
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$select = ($select == array("*")
? array()
@@ -127,7 +127,7 @@ if (isset($_GET["mongo"])) {
->skip($page * $limit)
);
}
function insert($table, $set) {
try {
$return = $this->_conn->_db->selectCollection($table)->insert($set);
@@ -205,8 +205,6 @@ if (isset($_GET["mongo"])) {
return $connection->_db->selectCollection($_GET["select"])->count($where);
}
$operators = array("=");
} elseif (class_exists('MongoDB\Driver\Manager')) {
class Min_DB {
var $extension = "MongoDB", $server_info = MONGODB_VERSION, $affected_rows, $error, $last_id;
@@ -215,21 +213,20 @@ if (isset($_GET["mongo"])) {
var $_db, $_db_name;
function connect($uri, $options) {
$class = 'MongoDB\Driver\Manager';
$this->_link = new $class($uri, $options);
$this->_link = new MongoDB\Driver\Manager($uri, $options);
$this->executeCommand('admin', array('ping' => 1));
}
function executeCommand($db, $command) {
$class = 'MongoDB\Driver\Command';
try {
return $this->_link->executeCommand($db, new $class($command));
return $this->_link->executeCommand($db, new MongoDB\Driver\Command($command));
} catch (Exception $e) {
$this->error = $e->getMessage();
return array();
}
}
function executeBulkWrite($namespace, $bulk, $counter) {
try {
$results = $this->_link->executeBulkWrite($namespace, $bulk);
@@ -340,9 +337,8 @@ if (isset($_GET["mongo"])) {
}
$limit = min(200, max(1, (int) $limit));
$skip = $page * $limit;
$class = 'MongoDB\Driver\Query';
try {
return new Min_Result($connection->_link->executeQuery("$connection->_db_name.$table", new $class($where, array('projection' => $select, 'limit' => $limit, 'skip' => $skip, 'sort' => $sort))));
return new Min_Result($connection->_link->executeQuery("$connection->_db_name.$table", new MongoDB\Driver\Query($where, array('projection' => $select, 'limit' => $limit, 'skip' => $skip, 'sort' => $sort))));
} catch (Exception $e) {
$connection->error = $e->getMessage();
return false;
@@ -353,8 +349,7 @@ if (isset($_GET["mongo"])) {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
$bulk = new MongoDB\Driver\BulkWrite(array());
if (isset($set['_id'])) {
unset($set['_id']);
}
@@ -377,8 +372,7 @@ if (isset($_GET["mongo"])) {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
$bulk = new MongoDB\Driver\BulkWrite(array());
$bulk->delete($where, array('limit' => $limit));
return $connection->executeBulkWrite("$db.$table", $bulk, 'getDeletedCount');
}
@@ -386,8 +380,7 @@ if (isset($_GET["mongo"])) {
function insert($table, $set) {
global $connection;
$db = $connection->_db_name;
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
$bulk = new MongoDB\Driver\BulkWrite(array());
if ($set['_id'] == '') {
unset($set['_id']);
}
@@ -482,7 +475,11 @@ if (isset($_GET["mongo"])) {
}
function sql_query_where_parser($queryWhere) {
$queryWhere = preg_replace('~^\sWHERE \(?\(?(.+?)\)?\)?$~', '\1', $queryWhere);
$queryWhere = preg_replace('~^\s*WHERE\s*~', "", $queryWhere);
while ($queryWhere[0] == "(") {
$queryWhere = preg_replace('~^\((.*)\)$~', "$1", $queryWhere);
}
$wheres = explode(' AND ', $queryWhere);
$wheresOr = explode(') OR (', $queryWhere);
$where = array();
@@ -516,8 +513,7 @@ if (isset($_GET["mongo"])) {
$op = $match[1];
} elseif (preg_match('~^\(date\)(.+)~', $op, $match)) {
$dateTime = new DateTime($val);
$class = 'MongoDB\BSON\UTCDatetime';
$val = new $class($dateTime->getTimestamp() * 1000);
$val = new MongoDB\BSON\UTCDatetime($dateTime->getTimestamp() * 1000);
$op = $match[1];
}
switch ($op) {
@@ -555,29 +551,6 @@ if (isset($_GET["mongo"])) {
}
return $data;
}
$operators = array(
"=",
"!=",
">",
"<",
">=",
"<=",
"regex",
"(f)=",
"(f)!=",
"(f)>",
"(f)<",
"(f)>=",
"(f)<=",
"(date)=",
"(date)!=",
"(date)>",
"(date)<",
"(date)>=",
"(date)<=",
);
}
function table($idf) {
@@ -627,6 +600,11 @@ if (isset($_GET["mongo"])) {
global $adminer;
$connection = new Min_DB;
list($server, $username, $password) = $adminer->credentials();
if ($server == "") {
$server = "localhost:27017";
}
$options = array();
if ($username . $password != "") {
$options["username"] = $username;
@@ -734,11 +712,44 @@ if (isset($_GET["mongo"])) {
}
function driver_config() {
global $operators;
if (class_exists('MongoDB')) {
$operators = ["="];
$operator_regexp = null;
} elseif (class_exists('MongoDB\Driver\Manager')) {
$operators = [
"=",
"!=",
">",
"<",
">=",
"<=",
"regex",
"(f)=",
"(f)!=",
"(f)>",
"(f)<",
"(f)>=",
"(f)<=",
"(date)=",
"(date)!=",
"(date)>",
"(date)<",
"(date)>=",
"(date)<=",
];
$operator_regexp = 'regex';
} else {
$operators = ["="];
$operator_regexp = null;
}
return array(
'possible_drivers' => array("mongo", "mongodb"),
'jush' => "mongo",
'operators' => $operators,
'operator_like' => "LIKE %%", // TODO: LIKE operator is not listed in operators.
'operator_regexp' => $operator_regexp,
'functions' => array(),
'grouping' => array(),
'edit_functions' => array(array("json")),

View File

@@ -24,11 +24,26 @@ if (isset($_GET["mssql"])) {
function connect($server, $username, $password) {
global $adminer;
$connection_info = [
"UID" => $username,
"PWD" => $password,
"CharacterSet" => "UTF-8",
];
$ssl = $adminer->connectSsl();
if (isset($ssl["Encrypt"])) {
$connection_info["Encrypt"] = $ssl["Encrypt"];
}
if (isset($ssl["TrustServerCertificate"])) {
$connection_info["TrustServerCertificate"] = $ssl["TrustServerCertificate"];
}
$db = $adminer->database();
$connection_info = array("UID" => $username, "PWD" => $password, "CharacterSet" => "UTF-8");
if ($db != "") {
$connection_info["Database"] = $db;
}
$this->_link = @sqlsrv_connect(preg_replace('~:~', ',', $server), $connection_info);
if ($this->_link) {
$info = sqlsrv_server_info($this->_link);
@@ -36,11 +51,13 @@ if (isset($_GET["mssql"])) {
} else {
$this->_get_error();
}
return (bool) $this->_link;
}
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
$unicode = strlen($string) != strlen(utf8_decode($string));
return ($unicode ? "N" : "") . "'" . str_replace("'", "''", $string) . "'";
}
function select_db($database) {
@@ -163,7 +180,8 @@ if (isset($_GET["mssql"])) {
}
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
$unicode = strlen($string) != strlen(utf8_decode($string));
return ($unicode ? "N" : "") . "'" . str_replace("'", "''", $string) . "'";
}
function select_db($database) {
@@ -301,6 +319,11 @@ if (isset($_GET["mssql"])) {
global $adminer;
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($credentials[0] == "") {
$credentials[0] = "localhost:1433";
}
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
return $connection;
}
@@ -432,7 +455,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) {
@@ -637,6 +660,10 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
return false;
}
function is_c_style_escapes() {
return true;
}
function show_status() {
return array();
}
@@ -671,6 +698,7 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"),
'operator_like' => "LIKE %%",
'functions' => array("len", "lower", "round", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(

View File

@@ -1,8 +1,8 @@
<?php
$drivers = array("server" => "MySQL") + $drivers;
$drivers["mysql"] = "MySQL";
if (!defined("DRIVER")) {
define("DRIVER", "server"); // server - backwards compatibility
if (isset($_GET["mysql"])) {
define("DRIVER", "mysql");
// MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
if (extension_loaded("mysqli")) {
class Min_DB extends MySQLi {
@@ -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) {
@@ -371,16 +371,28 @@ if (!defined("DRIVER")) {
* @return mixed Min_DB or string for error
*/
function connect() {
global $adminer, $types, $structured_types;
global $adminer, $types, $structured_types, $edit_functions;
$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)) {
if (min_version('5.7.8', '10.2', $connection)) {
$structured_types[lang('Strings')][] = "json";
$types["json"] = 4294967295;
}
// UUID data type for Mariadb >= 10.7
if (min_version('', '10.7', $connection)) {
$structured_types[lang('Strings')][] = "uuid";
$types["uuid"] = 128;
// insert/update function
$edit_functions[0]['uuid'] = 'uuid';
}
return $connection;
}
$return = $connection->error;
@@ -500,11 +512,14 @@ if (!defined("DRIVER")) {
* @return array array($name => array("Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => )) or only inner array with $name
*/
function table_status($name = "", $fast = false) {
$return = array();
foreach (get_rows($fast && min_version(5)
? "SELECT TABLE_NAME AS Name, ENGINE AS Engine, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name")
: "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "")
) as $row) {
if ($fast && min_version(5)) {
$query = "SELECT TABLE_NAME AS Name, ENGINE AS Engine, CREATE_OPTIONS AS Create_options, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name");
} else {
$query = "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "");
}
$tables = [];
foreach (get_rows($query) as $row) {
if ($row["Engine"] == "InnoDB") {
// ignore internal comment, unnecessary since MySQL 5.1.21
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\1', $row["Comment"]);
@@ -513,11 +528,15 @@ if (!defined("DRIVER")) {
$row["Comment"] = "";
}
if ($name != "") {
// MariaDB: Table name is returned as lowercase on macOS, so we fix it here.
$row["Name"] = $name;
return $row;
}
$return[$row["Name"]] = $row;
$tables[$row["Name"]] = $row;
}
return $return;
return $tables;
}
/** Find out whether the identifier is view
@@ -894,23 +913,30 @@ if (!defined("DRIVER")) {
);
}
/** Get information about stored routine
* @param string
* @param string "FUNCTION" or "PROCEDURE"
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
*/
/**
* Gets information about stored routine.
*
* @param string $name
* @param string $type "FUNCTION" or "PROCEDURE"
*
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
*/
function routine($name, $type) {
global $connection, $enum_length, $inout, $types;
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
$info = get_rows("SELECT ROUTINE_BODY, ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB) . " AND ROUTINE_NAME = " . q($name))[0];
$aliases = ["bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar"];
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum_length)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
$fields = array();
$fields = [];
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
foreach ($matches as $param) {
$fields[] = array(
$fields[] = [
"field" => str_replace("``", "`", $param[2]) . $param[3],
"type" => strtolower($param[5]),
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
@@ -919,24 +945,29 @@ if (!defined("DRIVER")) {
"full_type" => $param[4],
"inout" => strtoupper($param[1]),
"collation" => strtolower($param[9]),
);
];
}
if ($type != "FUNCTION") {
return array("fields" => $fields, "definition" => $match[11]);
}
return array(
return $type == "FUNCTION" ? [
"fields" => $fields,
"returns" => array("type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]),
"returns" => ["type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]],
"definition" => $match[17],
"language" => "SQL", // available in information_schema.ROUTINES.PARAMETER_STYLE
);
"language" => $info["ROUTINE_BODY"],
"comment" => $info["ROUTINE_COMMENT"],
] : [
"fields" => $fields,
"returns" => null,
"definition" => $match[11],
"language" => $info["ROUTINE_BODY"],
"comment" => $info["ROUTINE_COMMENT"],
];
}
/** Get list of routines
* @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => )
*/
function routines() {
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
}
/** Get list of available routine languages
@@ -1074,6 +1105,16 @@ if (!defined("DRIVER")) {
return $strictMode;
}
function is_c_style_escapes() {
static $c_style = null;
if ($c_style === null) {
$c_style = strpos(get_key_vals("SHOW VARIABLES LIKE 'sql_mode'")["sql_mode"], 'NO_BACKSLASH_ESCAPES') === false;
}
return $c_style;
}
/** Get process list
* @return array ($row)
*/
@@ -1178,6 +1219,8 @@ if (!defined("DRIVER")) {
'structured_types' => $structured_types,
'unsigned' => array("unsigned", "zerofill", "unsigned zerofill"), ///< @var array number variants
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"), ///< @var array operators used in select
'operator_like' => "LIKE %%",
'operator_regexp' => 'REGEXP',
'functions' => array("char_length", "date", "from_unixtime", "unix_timestamp", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper"), ///< @var array functions used in select
'grouping' => array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"), ///< @var array grouping functions used in select
'edit_functions' => array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only

View File

@@ -493,6 +493,10 @@ AND c_src.TABLE_NAME = " . q($table);
return false;
}
function is_c_style_escapes() {
return true;
}
function process_list() {
return get_rows('SELECT sess.process AS "process", sess.username AS "user", sess.schemaname AS "schema", sess.status AS "status", sess.wait_class AS "wait_class", sess.seconds_in_wait AS "seconds_in_wait", sql.sql_text AS "sql_text", sess.machine AS "machine", sess.port AS "port"
FROM v$session sess LEFT OUTER JOIN v$sql sql
@@ -537,6 +541,7 @@ ORDER BY PROCESS
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"),
'operator_like' => "LIKE %%",
'functions' => array("length", "lower", "round", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(

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) {
@@ -668,23 +668,29 @@ ORDER BY connamespace, conname") as $row) {
}
function routine($name, $type) {
$rows = get_rows('SELECT routine_definition AS definition, LOWER(external_language) AS language, *
FROM information_schema.routines
WHERE routine_schema = current_schema() AND specific_name = ' . q($name));
$return = $rows[0];
$return["returns"] = array("type" => $return["type_udt_name"]);
$return["fields"] = get_rows('SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, parameter_mode AS inout
FROM information_schema.parameters
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
ORDER BY ordinal_position');
return $return;
$info = get_rows('SELECT routine_definition, external_language, type_udt_name
FROM information_schema.routines
WHERE routine_schema = current_schema() AND specific_name = ' . q($name))[0];
$fields = get_rows('SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, parameter_mode AS inout
FROM information_schema.parameters
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
ORDER BY ordinal_position');
return [
"fields" => $fields,
"returns" => ["type" => $info["type_udt_name"]],
"definition" => $info["routine_definition"],
"language" => strtolower($info["external_language"]),
"comment" => null, // Comments are not supported.
];
}
function routines() {
return get_rows('SELECT specific_name AS "SPECIFIC_NAME", routine_type AS "ROUTINE_TYPE", routine_name AS "ROUTINE_NAME", type_udt_name AS "DTD_IDENTIFIER"
FROM information_schema.routines
WHERE routine_schema = current_schema()
ORDER BY SPECIFIC_NAME');
return get_rows('SELECT specific_name AS "SPECIFIC_NAME", routine_name AS "ROUTINE_NAME", routine_type AS "ROUTINE_TYPE", type_udt_name AS "DTD_IDENTIFIER", null AS ROUTINE_COMMENT
FROM information_schema.routines
WHERE routine_schema = current_schema()
ORDER BY SPECIFIC_NAME');
}
function routine_languages() {
@@ -885,6 +891,16 @@ AND typelem = 0"
return false;
}
function is_c_style_escapes() {
static $c_style = null;
if ($c_style === null) {
$c_style = get_vals("SHOW standard_conforming_strings")[0] == "off";
}
return $c_style;
}
function process_list() {
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid"));
}
@@ -936,7 +952,9 @@ AND typelem = 0"
'types' => $types,
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"), // no "SQL" to avoid CSRF
'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "~*", "!~", "!~*", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"), // no "SQL" to avoid CSRF
'operator_like' => "LIKE %%",
'operator_regexp' => '~*',
'functions' => array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(
@@ -949,6 +967,7 @@ AND typelem = 0"
"char|text" => "||",
)
),
'c_style_escapes' => true,
);
}
}

View File

@@ -771,6 +771,10 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return false;
}
function is_c_style_escapes() {
return true;
}
function show_status() {
$return = array();
foreach (get_vals("PRAGMA compile_options") as $option) {
@@ -800,6 +804,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
'structured_types' => array_keys($types),
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"), // REGEXP can be user defined function
'operator_like' => "LIKE %%",
'functions' => array("hex", "length", "lower", "round", "unixepoch", "upper"),
'grouping' => array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"),
'edit_functions' => array(

View File

@@ -182,8 +182,8 @@ $prefixes = array();
if (DB != "") {
$checked = ($TABLE != "" ? "" : " checked");
echo "<thead><tr>";
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked>" . lang('Tables') . "</label>" . script("qs('#check-tables').onclick = partial(formCheck, /^tables\\[/);", "");
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked></label>" . script("qs('#check-data').onclick = partial(formCheck, /^data\\[/);", "");
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked>" . lang('Tables') . "</label>" . script("gid('check-tables').onclick = partial(formCheck, /^tables\\[/);", "");
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked></label>" . script("gid('check-data').onclick = partial(formCheck, /^data\\[/);", "");
echo "</thead>\n";
$views = "";
@@ -208,7 +208,7 @@ if (DB != "") {
} else {
echo "<thead><tr><th style='text-align: left;'>";
echo "<label class='block'><input type='checkbox' id='check-databases'" . ($TABLE == "" ? " checked" : "") . ">" . lang('Database') . "</label>";
echo script("qs('#check-databases').onclick = partial(formCheck, /^databases\\[/);", "");
echo script("gid('check-databases').onclick = partial(formCheck, /^databases\\[/);", "");
echo "</thead>\n";
$databases = $adminer->databases();
if ($databases) {

View File

@@ -3,13 +3,17 @@
class Adminer {
/** @var array operators used in select, null for all operators */
var $operators;
var $operators = null;
/** @var string operator for LIKE condition */
var $operator_like = null;
/** @var string operator for regular expression condition */
var $operator_regexp = null;
/** Name in title and navigation
* @return string HTML code
*/
function name() {
return "<a href='https://www.adminer.org/'" . target_blank() . " id='h1'>Adminer</a>";
return "<a id='h1' href='" . h(HOME_URL) . "'>Adminer</a>";
}
/** Connection parameters
@@ -25,12 +29,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
@@ -121,7 +129,7 @@ class Adminer {
echo "<table cellspacing='0' class='layout'>\n";
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);") . "\n");
echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">' . "\n");
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(qs('#username')); qs('#username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(gid('username')); gid('username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">' . "\n");
echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">' . "\n");
echo "</table>\n";
@@ -241,7 +249,7 @@ class Adminer {
if (!$failed && ($warnings = $driver->warnings())) {
$id = "warnings";
$result = ($supportSql ? "," : "")
$result .= ($supportSql ? "," : "")
. " <a href='#$id'>" . lang('Warnings') . "</a>" . script("qsl('a').onclick = partial(toggle, '$id');", "")
. "</p>\n"
. "<div id='$id' class='hidden'>\n$warnings</div>\n";
@@ -310,6 +318,11 @@ class Adminer {
* @return string
*/
function editVal($val, $field) {
// Format Elasticsearch boolean value, but do not touch PostgreSQL boolean that use string value 't' or 'f'.
if ($field["type"] == "boolean" && is_bool($val)) {
return $val ? "true" : "false";
}
return $val;
}
@@ -334,15 +347,40 @@ class Adminer {
echo "</div>\n";
}
function tablePartitionsPrint($partition_info) {
$showList = $partition_info["partition_by"] == "RANGE" || $partition_info["partition_by"] == "LIST";
echo "<p>";
echo "<code>{$partition_info["partition_by"]} ({$partition_info["partition"]})</code>";
if (!$showList) {
echo " " . lang('Partitions') . ": " . h($partition_info["partitions"]);
}
echo "</p>";
if ($showList) {
echo "<table>\n";
echo "<thead><tr><th>" . lang('Partition') . "</th><td>" . lang('Values') . "</td></tr></thead>\n";
foreach ($partition_info["partition_names"] as $key => $name) {
echo "<tr><th>" . h($name) . "</th><td>" . h($partition_info["partition_values"][$key]) . "\n";
}
echo "</table>\n";
}
}
/** Print list of indexes on table in tabular format
* @param array data about all indexes on a table
* @return null
*/
function tableIndexesPrint($indexes) {
echo "<table cellspacing='0'>\n";
echo "<table>\n";
echo "<thead><tr><th>" . lang('Type') . "</th><td>" . lang('Column (length)') . "</td></tr></thead>\n";
foreach ($indexes as $name => $index) {
ksort($index["columns"]); // enforce correct columns order
$print = array();
$print = [];
foreach ($index["columns"] as $key => $val) {
$print[] = "<i>" . h($val) . "</i>"
. ($index["lengths"][$key] ? "(" . $index["lengths"][$key] . ")" : "")
@@ -351,92 +389,127 @@ class Adminer {
}
echo "<tr title='" . h($name) . "'><th>$index[type]<td>" . implode(", ", $print) . "\n";
}
echo "</table>\n";
}
/** Print columns box in select
* @param array result of selectColumnsProcess()[0]
* @param array selectable columns
* @return null
*/
/**
* Prints columns box in select filter.
*
* @param array $select result of selectColumnsProcess()[0]
* @param array $columns selectable columns
*/
function selectColumnsPrint($select, $columns) {
global $functions, $grouping;
print_fieldset("select", lang('Select'), $select);
print_fieldset("select", lang('Select'), $select, true);
$_GET["columns"][""] = [];
$i = 0;
$select[""] = array();
foreach ($select as $key => $val) {
$val = $_GET["columns"][$key];
foreach ($_GET["columns"] as $key => $val) {
if ($key != "" && $val["col"] == "") continue;
$column = select_input(
" name='columns[$i][col]'",
"name='columns[$i][col]'",
$columns,
$val["col"],
($key !== "" ? "selectFieldChange" : "selectAddRow")
$key !== "" ? "selectFieldChange" : "selectAddRow"
);
echo "<div>" . ($functions || $grouping ? "<select name='columns[$i][fun]'>"
. optionlist(array(-1 => "") + array_filter(array(lang('Functions') => $functions, lang('Aggregation') => $grouping)), $val["fun"]) . "</select>"
. on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1)
. script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "")
. "($column)" : $column) . "</div>\n";
echo "<div ", ($key != "" ? "" : "class='no-sort'"), ">",
"<span class='jsonly handle'></span>";
if ($functions || $grouping) {
echo "<select name='columns[$i][fun]'>",
optionlist([-1 => ""] + array_filter([lang('Functions') => $functions, lang('Aggregation') => $grouping]), $val["fun"]),
"</select>",
help_script_command("value && value.replace(/ |\$/, '(') + ')'", true),
script("qsl('select').onchange = (event) => { " . ($key !== "" ? "" : " qsl('select, input:not(.remove)', event.target.parentNode).onchange();") . " };", ""),
"($column)";
} else {
echo $column;
}
echo " <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>",
script("qsl('#fieldset-select .remove').onclick = selectRemoveRow;", ""),
"</div>\n";
$i++;
}
echo "</div></fieldset>\n";
echo "</div>", script("initSortable('#fieldset-select');"), "</fieldset>\n";
}
/** Print search box in select
* @param array result of selectSearchProcess()
* @param array selectable columns
* @param array
* @return null
*/
/**
* Prints search box in select.
*
* @param array $where result of selectSearchProcess()
* @param array $columns selectable columns
*/
function selectSearchPrint($where, $columns, $indexes) {
print_fieldset("search", lang('Search'), $where);
foreach ($indexes as $i => $index) {
if ($index["type"] == "FULLTEXT") {
echo "<div>(<i>" . implode("</i>, <i>", array_map('h', $index["columns"])) . "</i>) AGAINST";
echo " <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "'>";
echo script("qsl('input').oninput = selectFieldChange;", "");
echo checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL");
echo "</div>\n";
echo "<div>(<i>" . implode("</i>, <i>", array_map('h', $index["columns"])) . "</i>) AGAINST",
" <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "'>",
script("qsl('input').oninput = selectFieldChange;", ""),
checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL"),
"</div>\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"], $this->operators))) {
echo "<div>" . select_input(
" name='where[$i][col]'",
$columns,
$val["col"],
($val ? "selectFieldChange" : "selectAddRow"),
"(" . lang('anywhere') . ")"
);
echo html_select("where[$i][op]", $this->operators, $val["op"], $change_next);
echo "<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "'>";
echo script("mixin(qsl('input'), {oninput: function () { $change_next }, onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", "");
echo "</div>\n";
echo "<div>",
select_input(
" name='where[$i][col]'",
$columns,
$val["col"],
($val ? "selectFieldChange" : "selectAddRow"),
"(" . lang('anywhere') . ")"
),
html_select("where[$i][op]", $this->operators, $val["op"], $change_next),
"<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "'>",
script("mixin(qsl('input'), {oninput: function () { $change_next }, onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", ""),
" <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>",
script('qsl("#fieldset-search .remove").onclick = selectRemoveRow;', ""),
"</div>\n";
}
}
echo "</div></fieldset>\n";
}
/** Print order box in select
* @param array result of selectOrderProcess()
* @param array selectable columns
* @param array
* @return null
*/
/**
* Prints order box in select filter.
*
* @param array $order result of selectOrderProcess()
* @param array $columns selectable columns
*/
function selectOrderPrint($order, $columns, $indexes) {
print_fieldset("sort", lang('Sort'), $order);
print_fieldset("sort", lang('Sort'), $order, true);
$_GET["order"][""] = "";
$i = 0;
foreach ((array) $_GET["order"] as $key => $val) {
if ($val != "") {
echo "<div>" . select_input(" name='order[$i]'", $columns, $val, "selectFieldChange");
echo checkbox("desc[$i]", 1, isset($_GET["desc"][$key]), lang('descending')) . "</div>\n";
$i++;
}
if ($key != "" && $val == "") continue;
echo "<div ", ($key != "" ? "" : "class='no-sort'"), ">",
"<span class='jsonly handle'></span>",
select_input("name='order[$i]'", $columns, $val, $key !== "" ? "selectFieldChange" : "selectAddRow"),
checkbox("desc[$i]", 1, isset($_GET["desc"][$key]), lang('descending')),
" <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>",
script('qsl("#fieldset-sort .remove").onclick = selectRemoveRow;', ""),
"</div>\n";
$i++;
}
echo "<div>" . select_input(" name='order[$i]'", $columns, "", "selectAddRow");
echo checkbox("desc[$i]", 1, false, lang('descending')) . "</div>\n";
echo "</div></fieldset>\n";
echo "</div>", script("initSortable('#fieldset-sort');"), "</fieldset>\n";
}
/** Print limit box in select
@@ -484,7 +557,7 @@ class Adminer {
json_row($key);
}
echo ";\n";
echo "selectFieldChange.call(qs('#form')['select']);\n";
echo "selectFieldChange.call(gid('form')['select']);\n";
echo "</script>\n";
echo "</div></fieldset>\n";
}
@@ -582,6 +655,8 @@ class Adminer {
&& (preg_match('~^[-\d.' . (preg_match('~IN$~', $op) ? ',' : '') . ']+$~', $val) || !preg_match('~' . number_type() . '|bit~', $field["type"]))
&& (!preg_match("~[\x80-\xFF]~", $val) || preg_match('~char|text|enum|set~', $field["type"]))
&& (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val))
&& (!preg_match('~^elastic~', DRIVER) || $field["type"] != "boolean" || preg_match('~true|false~', $val)) // Elasticsearch needs boolean value properly formatted.
&& (!preg_match('~^elastic~', DRIVER) || strpos($op, "regexp") === false || preg_match('~text|keyword~', $field["type"])) // Elasticsearch can use regexp only on text and keyword fields.
) {
$cols[] = $prefix . $driver->convertSearch(idf_escape($name), $where, $field) . $cond;
}
@@ -721,7 +796,7 @@ class Adminer {
* @param string
* @return string custom input field or empty string for default
*/
function editInput($table, $field, $attrs, $value) {
function editInput($table, $field, $attrs, $value, $function) {
if ($field["type"] == "enum") {
return (isset($_GET["select"]) ? "<label><input type='radio'$attrs value='-1' checked><i>" . lang('original') . "</i></label> " : "")
. ($field["null"] ? "<label><input type='radio'$attrs value=''" . ($value !== null || isset($_GET["select"]) ? "" : " checked") . "><i>NULL</i></label> " : "")
@@ -937,9 +1012,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";
}
@@ -961,14 +1038,26 @@ class Adminer {
*/
function navigation($missing) {
global $VERSION, $jush, $drivers, $connection;
?>
?>
<h1>
<?php echo $this->name(); ?>
<?php if ($missing != "auth"): ?>
<span class="version"><?php echo $VERSION; ?></span>
<a href="https://www.adminer.org/#download"<?php echo target_blank(); ?> id="version"><?php echo (version_compare($VERSION, $_COOKIE["adminer_version"]) < 0 ? h($_COOKIE["adminer_version"]) : ""); ?></a>
<?php echo $this->name(); ?>
<?php if ($missing != "auth"): ?>
<span class="version">
<?php echo $VERSION; ?>
<a href="https://github.com/pematon/adminer/releases"<?php echo target_blank(); ?> id="version">
<?php echo (version_compare($VERSION, $_COOKIE["adminer_version"]) < 0 ? h($_COOKIE["adminer_version"]) : ""); ?>
</a>
</span>
<?php
if (!isset($_COOKIE["adminer_version"])) {
echo script("verifyVersion('" . js_escape(ME) . "', '" . get_token() . "');");
}
?>
<?php endif; ?>
</h1>
<?php
if ($missing == "auth") {
$output = "";
@@ -978,14 +1067,21 @@ class Adminer {
if ($password !== null) {
$dbs = $_SESSION["db"][$vendor][$server][$username];
foreach (($dbs ? array_keys($dbs) : array("")) as $db) {
$output .= "<li><a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>($drivers[$vendor]) " . h($username . ($server != "" ? "@" . $this->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "</a>\n";
$output .= "<li><a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>"
. h($drivers[$vendor])
. ($username != "" || $server != "" ? " - " : "")
. h($username)
. ($username != "" && $server != "" ? "@" : "")
. ($server != "" ? h($this->serverName($server)) : "")
. ($db != "" ? h(" - $db") : "")
. "</a></li>\n";
}
}
}
}
}
if ($output) {
echo "<ul id='logins'>\n$output</ul>\n" . script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='logins'>\n$output</ul>\n" . script("mixin(gid('logins'), {onmouseover: menuOver, onmouseout: menuOut});");
}
} else {
$tables = array();
@@ -1018,84 +1114,128 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
</script>
<?php
}
$this->databasesPrint($missing);
$actions = [];
if (DB == "" || !$missing) {
echo "<p class='links'>" . (support("sql") ? "<a href='" . h(ME) . "sql='" . bold(isset($_GET["sql"]) && !isset($_GET["import"])) . ">" . lang('SQL command') . "</a>\n<a href='" . h(ME) . "import='" . bold(isset($_GET["import"])) . ">" . lang('Import') . "</a>\n" : "") . "";
if (support("sql")) {
$actions[] = "<a href='" . h(ME) . "sql='" . bold(isset($_GET["sql"]) && !isset($_GET["import"])) . ">" . lang('SQL command') . "</a>";
$actions[] = "<a href='" . h(ME) . "import='" . bold(isset($_GET["import"])) . ">" . lang('Import') . "</a>";
}
if (support("dump")) {
echo "<a href='" . h(ME) . "dump=" . urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]) . "' id='dump'" . bold(isset($_GET["dump"])) . ">" . lang('Export') . "</a>\n";
$actions[] = "<a href='" . h(ME) . "dump=" . urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]) . "' id='dump'" . bold(isset($_GET["dump"])) . ">" . lang('Export') . "</a>";
}
}
if ($_GET["ns"] !== "" && !$missing && DB != "") {
echo '<a href="' . h(ME) . 'create="' . bold($_GET["create"] === "") . ">" . lang('Create table') . "</a>\n";
if (!$tables) {
echo "<p class='message'>" . lang('No tables.') . "\n";
} else {
$actions[] = '<a href="' . h(ME) . 'create="' . bold($_GET["create"] === "") . ">" . lang('Create table') . "</a>\n";
}
if ($actions) {
echo "<p class='links'>" . implode("\n", $actions) . "</p>";
}
if ($_GET["ns"] !== "" && !$missing && DB != "") {
if ($tables) {
$this->printTablesFilter();
$this->tablesPrint($tables);
} else {
echo "<p class='message'>" . lang('No tables.') . "</p>\n";
}
}
}
}
/** Prints databases list in menu
* @param string
* @return null
*/
/**
* Prints databases select in menu.
*
* @param $missing string
* @return null
*/
function databasesPrint($missing) {
global $adminer, $connection;
$databases = $this->databases();
if (DB && $databases && !in_array(DB, $databases)) {
array_unshift($databases, DB);
}
?>
<form action="">
<p id="dbs">
<?php
echo "<form action=''><p id='dbs'>";
hidden_fields_get();
$db_events = script("mixin(qsl('select'), {onmousedown: dbMouseDown, onchange: dbChange});");
echo "<span title='" . lang('database') . "'>" . lang('DB') . "</span>: " . ($databases
? "<select name='db'>" . optionlist(array("" => "") + $databases, DB) . "</select>$db_events"
: "<input name='db' value='" . h(DB) . "' autocapitalize='off'>\n"
);
if ($databases) {
echo "<select id='database-select' name='db'>" . optionlist(["" => lang('Database')] + $databases, DB) . "</select>"
. script("mixin(gid('database-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
} else {
echo "<input id='database-select' name='db' value='" . h(DB) . "' autocapitalize='off'>\n";
}
echo "<input type='submit' value='" . lang('Use') . "'" . ($databases ? " class='hidden'" : "") . ">\n";
if (support("scheme")) {
if ($missing != "db" && DB != "" && $connection->select_db(DB)) {
echo "<br>" . lang('Schema') . ": <select name='ns'>" . optionlist(array("" => "") + $adminer->schemas(), $_GET["ns"]) . "</select>$db_events";
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
}
if (support("scheme") && $missing != "db" && DB != "" && $connection->select_db(DB)) {
echo "<br><select id='scheme-select' name='ns'>" . optionlist(["" => lang('Schema')] + $adminer->schemas(), $_GET["ns"]) . "</select>"
. script("mixin(gid('scheme-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
}
}
foreach (array("import", "sql", "schema", "dump", "privileges") as $val) {
foreach (["import", "sql", "schema", "dump", "privileges"] as $val) {
if (isset($_GET[$val])) {
echo "<input type='hidden' name='$val' value=''>";
break;
}
}
echo "</p></form>\n";
return null;
}
/** Prints table list in menu
* @param array result of table_status('', true)
* @return null
*/
function printTablesFilter()
{
global $adminer;
echo "<div class='tables-filter jsonly'>"
. "<input id='tables-filter' autocomplete='off' placeholder='" . lang('Table') . "'>"
. script("initTablesFilter(" . json_encode($adminer->database()) . ");")
. "</div>\n";
}
/**
* Prints table list in menu.
*
* @param array $tables Result of table_status('', true)
* @return null
*/
function tablesPrint($tables) {
echo "<ul id='tables'>" . script("mixin(qs('#tables'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='tables'>" . script("mixin(gid('tables'), {onmouseover: menuOver, onmouseout: menuOut});");
foreach ($tables as $table => $status) {
$name = $this->tableName($status);
if ($name != "") {
$active = $table == $_GET["select"] || $table == $_GET["edit"];
echo '<li><a href="' . h(ME) . 'select=' . urlencode($table) . '"'
. bold($_GET["select"] == $table || $_GET["edit"] == $table, "select")
. " title='" . lang('Select data') . "'>" . lang('select') . "</a> "
;
echo (support("table") || support("indexes")
? '<a href="' . h(ME) . 'table=' . urlencode($table) . '"'
. bold(in_array($table, array($_GET["table"], $_GET["create"], $_GET["indexes"], $_GET["foreign"], $_GET["trigger"])), (is_view($status) ? "view" : "structure"))
. " title='" . lang('Show structure') . "'>$name</a>"
: "<span>$name</span>"
) . "\n";
. bold($active, "select")
. " title='" . lang('Select data') . "'>" . lang('select') . "</a> ";
if (support("table") || support("indexes")) {
$active = in_array($table, [$_GET["table"], $_GET["create"], $_GET["indexes"], $_GET["foreign"], $_GET["trigger"]]);
$class = is_view($status) ? "view" : "structure";
echo '<a href="' . h(ME) . 'table=' . urlencode($table) . '"' . bold($active, $class)
. " title='" . lang('Show structure') . "' data-main='true'>$name</a>";
} else {
echo "<span data-main='true'>$name</span>";
}
echo "</li>\n";
}
}
echo "</ul>\n";
return null;
}
}

View File

@@ -1,4 +1,5 @@
<?php
$connection = '';
$has_token = $_SESSION["token"];
@@ -70,7 +71,7 @@ if (!function_exists('is_server_host_valid')) {
*/
function build_http_url($server, $username, $password, $defaultServer, $defaultPort = null) {
if (!preg_match('~^(https?://)?([^:]*)(:\d+)?$~', rtrim($server, '/'), $matches)) {
$this->error = lang('Invalid server or credentials.');
auth_error(lang('Invalid server or credentials.'));
return false;
}
@@ -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)));
@@ -143,7 +147,7 @@ if ($auth) {
set_session($key, null);
}
unset_permanent();
redirect(substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1), lang('Logout successful.') . ' ' . lang('Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.'));
redirect(HOME_URL, lang('Logout successful.') . ' ' . lang('Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.'));
} elseif ($permanent && !$_SESSION["pwds"]) {
session_regenerate_id();
@@ -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>";
@@ -209,6 +214,12 @@ function auth_error($error) {
exit;
}
if (isset($_GET["username"]) && !DRIVER) {
page_header(lang('No driver'), lang('Database driver not found.'), false);
page_footer("auth");
exit;
}
if (isset($_GET["username"]) && !class_exists("Min_DB")) {
unset($_SESSION["pwds"][DRIVER]);
unset_permanent();

View File

@@ -6,6 +6,7 @@ function adminer_errors($errno, $errstr) {
error_reporting(6135); // errors and warnings
set_error_handler('adminer_errors', E_WARNING);
include "../adminer/include/debug.inc.php";
include "../adminer/include/coverage.inc.php";
// disable filter.default
@@ -31,14 +32,14 @@ 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(["version" => $_POST["version"]]));
}
exit;
}
global $adminer, $connection, $driver, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
global $adminer, $connection, $driver, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $languages, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
$_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"];
@@ -72,34 +73,73 @@ if (function_exists("get_magic_quotes_runtime") && get_magic_quotes_runtime()) {
@ini_set("zend.ze1_compatibility_mode", false); // @ - deprecated
@ini_set("precision", 15); // @ - can be disabled, 15 - internal PHP precision
// Migration for backward compatibility. This will keep MySQL users logged in.
if (isset($_GET["username"])) {
// Old 'server' URL param.
if (isset($_GET["server"])) {
$_GET["mysql"] = $_GET["server"];
unset($_GET["server"]);
}
// No URL param for any driver.
$driver_params = array_filter(["mysql", "pgsql", "sqlite", "sqlite2", "oracle", "mssql", "mongo", "clickhouse", "elastic", "elastic5", "firebird", "simpledb"], function ($driver) {
return isset($_GET[$driver]);
});
if (!$driver_params) {
$_GET["mysql"] = "";
}
// Migrate session data.
if (isset($_SESSION["pwds"]["server"])) {
foreach (["pwds", "db", "dbs", "queries"] as $key) {
if (isset($_SESSION[$key]["server"])) {
$_SESSION[$key]["mysql"] = $_SESSION[$key]["server"];
unset($_SESSION[$key]["server"]);
}
}
}
}
include "../adminer/include/lang.inc.php";
include "../adminer/lang/$LANG.inc.php";
include "../adminer/include/pdo.inc.php";
include "../adminer/include/driver.inc.php";
include "../adminer/drivers/sqlite.inc.php";
include "../adminer/drivers/mysql.inc.php";
include "../adminer/drivers/pgsql.inc.php";
include "../adminer/drivers/sqlite.inc.php";
include "../adminer/drivers/oracle.inc.php";
include "../adminer/drivers/mssql.inc.php";
include "../adminer/drivers/mongo.inc.php";
include "./include/adminer.inc.php";
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
$config = driver_config();
$possible_drivers = $config['possible_drivers'];
$jush = $config['jush'];
$types = $config['types'];
$structured_types = $config['structured_types'];
$unsigned = $config['unsigned'];
$operators = $config['operators'];
$functions = $config['functions'];
$grouping = $config['grouping'];
$edit_functions = $config['edit_functions'];
if ($adminer->operators === null) {
$adminer->operators = $operators;
include "./include/adminer.inc.php";
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer());
if (defined("DRIVER")) {
$config = driver_config();
$possible_drivers = $config['possible_drivers'];
$jush = $config['jush'];
$types = $config['types'];
$structured_types = $config['structured_types'];
$unsigned = $config['unsigned'];
$operators = $config['operators'];
$operator_like = $config['operator_like'];
$operator_regexp = $config['operator_regexp'];
$functions = $config['functions'];
$grouping = $config['grouping'];
$edit_functions = $config['edit_functions'];
if ($adminer->operators === null) {
$adminer->operators = $operators;
$adminer->operator_like = $operator_like;
$adminer->operator_regexp = $operator_regexp;
}
} else {
define("DRIVER", null);
}
define("SERVER", $_GET[DRIVER]); // read from pgsql=localhost
define("SERVER", DRIVER ? $_GET[DRIVER] : null); // read from pgsql=localhost
define("DB", $_GET["db"]); // for the sake of speed and size
define("ME", preg_replace('~\?.*~', '', relative_uri()) . '?'
. (sid() ? SID . '&' : '')
@@ -107,6 +147,7 @@ define("ME", preg_replace('~\?.*~', '', relative_uri()) . '?'
. (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
. (DB != "" ? 'db=' . urlencode(DB) . '&' . (isset($_GET["ns"]) ? "ns=" . urlencode($_GET["ns"]) . "&" : "") : '')
);
define("HOME_URL", substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1) ?: ".");
include "../adminer/include/version.inc.php";
include "../adminer/include/design.inc.php";

View File

@@ -0,0 +1,27 @@
<?php
function dump($value)
{
$cli = PHP_SAPI == 'cli';
if (!$cli) {
echo "<pre>";
}
$export = var_export($value, true);
$export = preg_replace('~=>\s+array\s*~', "=> array", $export);
$export = preg_replace('~\(\s+\)~', "()", $export);
echo $export;
if (!$cli) {
echo "</pre>";
}
echo "\n";
}
function dumpe($value)
{
dump($value);
exit;
}

View File

@@ -6,7 +6,7 @@
* @param string used after colon in title and heading, should be HTML escaped
* @return null
*/
function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
function page_header($title, $error = "", $breadcrumb = [], $title2 = "") {
global $LANG, $VERSION, $adminer, $drivers, $jush;
page_headers();
if (is_ajax() && $error) {
@@ -15,15 +15,24 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
}
$title_all = $title . ($title2 != "" ? ": $title2" : "");
$title_page = strip_tags($title_all . (SERVER != "" && SERVER != "localhost" ? h(" - " . SERVER) : "") . " - " . $adminer->name());
// Load Adminer version from file if cookie is missing.
$filename = get_temp_dir() . "/adminer.version";
if (!$_COOKIE["adminer_version"] && file_exists($filename) && ($lifetime = filemtime($filename) + 86400 - time()) > 0) { // 86400 - 1 day in seconds
$data = unserialize(file_get_contents($filename));
$_COOKIE["adminer_version"] = $data["version"];
cookie("adminer_version", $data["version"], $lifetime); // Sync expiration with the file.
}
?>
<!DOCTYPE html>
<html lang="<?php echo $LANG; ?>" dir="<?php echo lang('ltr'); ?>">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex">
<title><?php echo $title_page; ?></title>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css">
<?php echo script_src("../adminer/static/functions.js"); ?>
<?php echo script_src("static/editing.js"); ?>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css?<?php echo filemtime("../adminer/static/default.css"); ?>">
<?php echo script_src("../adminer/static/functions.js?" . filemtime("../adminer/static/functions.js")); ?>
<?php echo script_src("static/editing.js?" . filemtime("../adminer/static/editing.js")); ?>
<?php if ($adminer->head()) { ?>
<link rel="shortcut icon" type="image/x-icon" href="../adminer/static/favicon.ico">
<link rel="apple-touch-icon" href="../adminer/static/favicon.ico">
@@ -33,66 +42,63 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
<?php } ?>
<body class="<?php echo lang('ltr'); ?> nojs">
<?php
$filename = get_temp_dir() . "/adminer.version";
if (!$_COOKIE["adminer_version"] && function_exists('openssl_verify') && file_exists($filename) && filemtime($filename) + 86400 > time()) { // 86400 - 1 day in seconds
$version = unserialize(file_get_contents($filename));
$public = "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwqWOVuF5uw7/+Z70djoK
RlHIZFZPO0uYRezq90+7Amk+FDNd7KkL5eDve+vHRJBLAszF/7XKXe11xwliIsFs
DFWQlsABVZB3oisKCBEuI71J4kPH8dKGEWR9jDHFw3cWmoH3PmqImX6FISWbG3B8
h7FIx3jEaw5ckVPVTeo5JRm/1DZzJxjyDenXvBQ/6o9DgZKeNDgxwKzH+sw9/YCO
jHnq1cFpOIISzARlrHMa/43YfeNRAm/tsBXjSxembBPo7aQZLAWHmaj5+K19H10B
nCpz9Y++cipkVEiKRGih4ZEvjoFysEOdRLj6WiD/uUNky4xGeA6LaJqh5XpkFkcQ
fQIDAQAB
-----END PUBLIC KEY-----
";
if (openssl_verify($version["version"], base64_decode($version["signature"]), $public) == 1) {
$_COOKIE["adminer_version"] = $version["version"]; // doesn't need to send to the browser
}
}
?>
<script<?php echo nonce(); ?>>
mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick<?php
echo (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '$VERSION', '" . js_escape(ME) . "', '" . get_token() . "')"); // $token may be empty in auth.inc.php
?>});
document.body.className = document.body.className.replace(/ nojs/, ' js');
var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
const body = document.body;
body.onkeydown = bodyKeydown;
body.onclick = bodyClick;
body.classList.remove("nojs");
body.classList.add("js");
var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
</script>
<div id="help" class="jush-<?php echo $jush; ?> jsonly hidden"></div>
<?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?>
<?php echo script("initHelpPopup();"); ?>
<div id="content">
<?php
if ($breadcrumb !== null) {
$link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1);
echo '<p id="breadcrumb"><a href="' . h($link ? $link : ".") . '">' . $drivers[DRIVER] . '</a> &raquo; ';
$link = substr(preg_replace('~\b(db|ns)=[^&]*&~', '', ME), 0, -1);
$server = $adminer->serverName(SERVER);
$server = ($server != "" ? $server : lang('Server'));
echo '<p id="breadcrumb">';
echo '<a href="' . h(HOME_URL) . '">' . lang('Home') . '</a> » ';
$server = "";
if ($breadcrumb === false) {
echo "$server\n";
$server .= h($drivers[DRIVER]) . ": ";
}
$server_name = $adminer->serverName(SERVER);
$server .= $server_name != "" ? h($server_name) : lang('Server');
if ($breadcrumb === false) {
echo h($server), "\n";
} else {
echo "<a href='" . h($link) . "' accesskey='1' title='Alt+Shift+1'>$server</a> &raquo; ";
$link = substr(preg_replace('~\b(db|ns)=[^&]*&~', '', ME), 0, -1);
echo "<a href='" . h($link) . "' accesskey='1' title='Alt+Shift+1'>$server</a> » ";
if ($_GET["ns"] != "" || (DB != "" && is_array($breadcrumb))) {
echo '<a href="' . h($link . "&db=" . urlencode(DB) . (support("scheme") ? "&ns=" : "")) . '">' . h(DB) . '</a> &raquo; ';
echo '<a href="' . h($link . "&db=" . urlencode(DB) . (support("scheme") ? "&ns=" : "")) . '">' . h(DB) . '</a> » ';
}
if (is_array($breadcrumb)) {
if ($_GET["ns"] != "") {
echo '<a href="' . h(substr(ME, 0, -1)) . '">' . h($_GET["ns"]) . '</a> &raquo; ';
echo '<a href="' . h(substr(ME, 0, -1)) . '">' . h($_GET["ns"]) . '</a> » ';
}
foreach ($breadcrumb as $key => $val) {
$desc = (is_array($val) ? $val[1] : h($val));
if ($desc != "") {
echo "<a href='" . h(ME . "$key=") . urlencode(is_array($val) ? $val[0] : $val) . "'>$desc</a> &raquo; ";
echo "<a href='" . h(ME . "$key=") . urlencode(is_array($val) ? $val[0] : $val) . "'>$desc</a> » ";
}
}
}
echo "$title\n";
}
}
echo "<h2>$title_all</h2>\n";
echo "<div id='ajaxstatus' class='jsonly hidden'></div>\n";
restart_session();
@@ -126,30 +132,40 @@ function page_headers() {
$adminer->headers();
}
/** Get Content Security Policy headers
* @return array of arrays with directive name in key, allowed sources in value
*/
/**
* Gets Content Security Policy headers.
*
* @return array of arrays with directive name in key, allowed sources in value
* @throws \Random\RandomException
*/
function csp() {
return array(
array(
"script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'", // 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
"connect-src" => "'self'",
"frame-src" => "https://www.adminer.org",
return [
[
// 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
"script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'",
"connect-src" => "'self' https://api.github.com/repos/pematon/adminer/releases/latest",
"frame-src" => "'self'",
"object-src" => "'none'",
"base-uri" => "'none'",
"form-action" => "'self'",
),
);
],
];
}
/** 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;
}
@@ -169,27 +185,38 @@ function page_messages($error) {
}
}
/** Print HTML footer
* @param string "auth", "db", "ns"
* @return null
*/
function page_footer($missing = "") {
/**
* Prints HTML footer.
*
* @param ?string $missing "auth", "db", "ns"
*/
function page_footer($missing = null)
{
global $adminer, $token;
?>
</div>
<?php switch_lang(); ?>
<?php if ($missing != "auth") { ?>
<form action="" method="post">
<p class="logout">
<input type="submit" name="logout" value="<?php echo lang('Logout'); ?>" id="logout">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</p>
</form>
<?php } ?>
<div id="menu">
<?php $adminer->navigation($missing); ?>
</div>
echo "</div>"; // #content
echo "<div id='footer'>\n";
language_select();
if ($missing != "auth") {
?>
<div class="logout">
<form action="" method="post">
<?php echo h($_GET["username"]); ?>
<input type="submit" name="logout" value="<?php echo lang('Logout'); ?>" id="logout">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
</div>
<?php
}
echo "</div>\n";
echo "<div id='menu'>\n";
$adminer->navigation($missing);
echo "</div>\n";
echo script("setupSubmitHighlight(document);");
}

View File

@@ -151,14 +151,6 @@ function get_driver($id) {
return $idf;
}
/** Convert operator so it can be used in search
* @param string $operator
* @return string
*/
function convertOperator($operator) {
return $operator;
}
/** Convert value returned by database to actual value
* @param string
* @param array

View File

@@ -221,12 +221,17 @@ function process_type($field, $collate = "COLLATE") {
* @return array array("field", "type", "NULL", "DEFAULT", "ON UPDATE", "COMMENT", "AUTO_INCREMENT")
*/
function process_field($field, $type_field) {
// MariaDB exports CURRENT_TIMESTAMP as a function.
if ($field["on_update"]) {
$field["on_update"] = str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", $field["on_update"]);
}
return array(
idf_escape(trim($field["field"])),
process_type($type_field),
($field["null"] ? " NULL" : " NOT NULL"), // NULL for timestamp
default_value($field),
(preg_match('~timestamp|datetime~', $field["type"]) && $field["on_update"] ? " ON UPDATE $field[on_update]" : ""),
(preg_match('~timestamp|datetime~', $field["type"]) && $field["on_update"] ? " ON UPDATE " . $field["on_update"] : ""),
(support("comment") && $field["comment"] != "" ? " COMMENT " . q($field["comment"]) : ""),
($field["auto_increment"] ? auto_increment() : null),
);
@@ -240,10 +245,13 @@ function default_value($field) {
$default = $field["default"];
if ($default === null) return "";
if (preg_match('~^GENERATED ~i', $default)) {
if (stripos($default, "GENERATED ") === 0) {
return " $default";
}
// MariaDB exports CURRENT_TIMESTAMP as a function.
$default = str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", $default);
$quote = preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default);
return " DEFAULT " . ($quote ? q($default) : $default);
@@ -266,65 +274,106 @@ function type_class($type) {
}
}
/** Print table interior for fields editing
* @param array
* @param array
* @param string TABLE or PROCEDURE
* @param array returned by referencable_primary()
* @return null
*/
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
/**
* Prints table interior for fields editing.
*
* @param string $type TABLE, FUNCTION or PROCEDURE
* @param array $foreign_keys returned by referencable_primary()
*/
function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign_keys = []) {
global $inout;
$fields = array_values($fields);
$default_class = (($_POST ? $_POST["defaults"] : adminer_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : " class='hidden'");
$comment_class = ($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : "class='hidden'";
?>
<thead><tr>
<?php if ($type == "PROCEDURE") { ?><td><?php } ?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;"></textarea><?php echo script("qs('#enum-edit').onblur = editingLengthBlur;"); ?>
<td id="label-length"><?php echo lang('Length'); ?>
<td><?php echo lang('Options'); /* no label required, options have their own label */ ?>
<?php if ($type == "TABLE") { ?>
<td id="label-null">NULL
<td><input type="radio" name="auto_increment_col" value=""><abbr id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</abbr><?php echo doc_link(array(
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "ms186775.aspx",
)); ?>
<td id="label-default"<?php echo $default_class; ?>><?php echo lang('Default value'); ?>
<?php echo (support("comment") ? "<td id='label-comment'$comment_class>" . lang('Comment') : ""); ?>
<?php } ?>
<td><?php echo "<input type='image' class='icon' name='add[" . (support("move_col") ? 0 : count($fields)) . "]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>" . script("row_count = " . count($fields) . ";"); ?>
</thead>
<tbody>
<?php
if (support("move_col")) {
echo "<td class='jsonly'></td>";
}
if ($type == "PROCEDURE") {
echo "<td></td>";
}
?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?></th>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;"></textarea><?php echo script("gid('enum-edit').onblur = editingLengthBlur;"); ?></td>
<td id="label-length"><?php echo lang('Length'); ?></td>
<td><?php echo lang('Options'); /* no label required, options have their own label */ ?></td>
<?php if ($type == "TABLE") { ?>
<td id="label-null">NULL</td>
<td><input type="radio" name="auto_increment_col" value=""><abbr id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</abbr><?php echo doc_link([
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "ms186775.aspx",
]); ?>
</td>
<td id="label-default"><?php echo lang('Default value'); ?></td>
<?php echo (support("comment") ? "<td id='label-comment' $comment_class>" . lang('Comment') . "</td>" : ""); ?>
<?php } ?>
<td><?php echo "<input type='image' class='icon' name='add[" . (support("move_col") ? 0 : count($fields)) . "]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>" . script("row_count = " . count($fields) . ";"); ?></td>
</tr></thead>
<?php
echo script("mixin(qsl('tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput});");
echo "<tbody>\n";
foreach ($fields as $i => $field) {
$i++;
$orig = $field[($_POST ? "orig" : "field")];
$display = (isset($_POST["add"][$i-1]) || (isset($field["field"]) && !$_POST["drop_col"][$i])) && (support("drop_col") || $orig == "");
?>
<tr<?php echo ($display ? "" : " style='display: none;'"); ?>>
<?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $inout), $field["inout"]) : ""); ?>
<th><?php if ($display) { ?><input name="fields[<?php echo $i; ?>][field]" value="<?php echo h($field["field"]); ?>" data-maxlength="64" autocapitalize="off" aria-labelledby="label-name"><?php } ?>
<input type="hidden" name="fields[<?php echo $i; ?>][orig]" value="<?php echo h($orig); ?>"><?php edit_type("fields[$i]", $field, $collations, $foreign_keys); ?>
<?php if ($type == "TABLE") { ?>
<td><?php echo checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null"); ?>
<td><label class="block"><input type="radio" name="auto_increment_col" value="<?php echo $i; ?>"<?php if ($field["auto_increment"]) { ?> checked<?php } ?> aria-labelledby="label-ai"></label><td<?php echo $default_class; ?>><?php
echo checkbox("fields[$i][has_default]", 1, $field["has_default"], "", "", "", "label-default"); ?><input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" aria-labelledby="label-default"><?php
echo (support("comment") ? "<td$comment_class><input name='fields[$i][comment]' value='" . h($field["comment"]) . "' data-maxlength='" . (min_version(5.5) ? 1024 : 255) . "' aria-labelledby='label-comment'>" : "");
$style = $display ? "" : "style='display: none;'";
echo "<tr $style>\n";
if (support("move_col")) {
echo "<th class='handle jsonly'></th>";
}
if ($type == "PROCEDURE") {
echo "<td>", html_select("fields[$i][inout]", explode("|", $inout), $field["inout"]), "</td>\n";
}
echo "<th>";
if ($display) {
echo "<input name='fields[$i][field]' value='", h($field["field"]), "' data-maxlength='64' autocapitalize='off' aria-labelledby='label-name'>";
}
echo "<input type='hidden' name='fields[$i][orig]' value='", h($orig), "'>";
edit_type("fields[$i]", $field, $collations, $foreign_keys);
echo "</th>\n";
if ($type == "TABLE") {
echo "<td>", checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null"), "</td>\n";
$checked = $field["auto_increment"] ? "checked" : "";
echo "<td><label class='block'><input type='radio' name='auto_increment_col' value='$i' $checked aria-labelledby='label-ai'></label></td>\n";
echo "<td>",
checkbox("fields[$i][has_default]", 1, $field["has_default"], "", "", "", "label-default"),
"<input name='fields[$i][default]' value='", h($field["default"]), "' aria-labelledby='label-default'>",
"</td>\n";
if (support("comment")) {
$max_length = min_version(5.5) ? 1024 : 255;
echo "<td $comment_class>",
"<input name='fields[$i][comment]' value='", h($field["comment"]), "' data-maxlength='$max_length' aria-labelledby='label-comment'>",
"</td>\n";
}
}
echo "<td>";
echo (support("move_col") ?
"<input type='image' class='icon' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'> "
. "<input type='image' class='icon' name='up[$i]' src='../adminer/static/up.gif' alt='↑' title='" . lang('Move up') . "'> "
. "<input type='image' class='icon' name='down[$i]' src='../adminer/static/down.gif' alt='↓' title='" . lang('Move down') . "'> "
: "");
echo ($orig == "" || support("drop_col") ? "<input type='image' class='icon' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "'>" : "");
if (support("move_col")) {
echo "<input type='image' class='icon' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'> ",
"<input type='image' class='icon hidden' name='up[$i]' src='../adminer/static/up.gif' alt='↑' title='" . lang('Move up') . "'> ",
"<input type='image' class='icon hidden' name='down[$i]' src='../adminer/static/down.gif' alt='↓' title='" . lang('Move down') . "'> ";
}
if ($orig == "" || support("drop_col")) {
echo "<input type='image' class='icon' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "'>";
}
echo "</td>\n</tr>\n";
}
echo "</tbody>";
echo script("mixin(qs('#edit-fields tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput}); initSortable('#edit-fields tbody');");
}
/** Move fields up and down or add field
@@ -376,25 +425,43 @@ function normalize_enum($match) {
return "'" . str_replace("'", "''", addcslashes(stripcslashes(str_replace($match[0][0] . $match[0][0], $match[0][0], substr($match[0], 1, -1))), '\\')) . "'";
}
/** Issue grant or revoke commands
* @param string GRANT or REVOKE
* @param array
* @param string
* @param string
* @return bool
*/
function grant($grant, $privileges, $columns, $on) {
if (!$privileges) {
return true;
/**
* Issue grant or revoke commands.
*
* @param bool $grant
* @param array $privileges
* @param string $columns
* @param string $on
* @param string $user
*
* @return bool
*/
function grant($grant, array $privileges, $columns, $on, $user) {
if (!$privileges) return true;
if ($privileges == ["ALL PRIVILEGES", "GRANT OPTION"]) {
if ($grant) {
return (bool) queries("GRANT ALL PRIVILEGES ON $on TO $user WITH GRANT OPTION");
} else {
return queries("REVOKE ALL PRIVILEGES ON $on FROM $user") &&
queries("REVOKE GRANT OPTION ON $on FROM $user");
}
}
if ($privileges == array("ALL PRIVILEGES", "GRANT OPTION")) {
// can't be granted or revoked together
return ($grant == "GRANT"
? queries("$grant ALL PRIVILEGES$on WITH GRANT OPTION")
: queries("$grant ALL PRIVILEGES$on") && queries("$grant GRANT OPTION$on")
);
if ($privileges == ["GRANT OPTION", "PROXY"]) {
if ($grant) {
return (bool) queries("GRANT PROXY ON $on TO $user WITH GRANT OPTION");
} else {
return (bool) queries("REVOKE PROXY ON $on FROM $user");
}
}
return queries("$grant " . preg_replace('~(GRANT OPTION)\([^)]*\)~', '\1', implode("$columns, ", $privileges) . $columns) . $on);
return (bool) queries(
($grant ? "GRANT " : "REVOKE ") .
preg_replace('~(GRANT OPTION)\([^)]*\)~', '$1', implode("$columns, ", $privileges) . $columns) .
" ON $on " .
($grant ? "TO " : "FROM ") . $user
);
}
/** Drop old object and create a new one
@@ -523,34 +590,46 @@ function tar_file($filename, $tmp_file) {
function ini_bytes($ini) {
$val = ini_get($ini);
switch (strtolower(substr($val, -1))) {
case 'g': $val *= 1024; // no break
case 'm': $val *= 1024; // no break
case 'k': $val *= 1024;
case 'g': $val = (int)$val * 1024; // no break
case 'm': $val = (int)$val * 1024; // no break
case 'k': $val = (int)$val * 1024;
}
return $val;
}
/** Create link to database documentation
* @param array $jush => $path
* @param string HTML code
* @return string HTML code
*/
function doc_link($paths, $text = "<sup>?</sup>") {
/**
* Creates link to database documentation.
*
* @param array $paths $jush => $path
* @param string $text HTML code
*
* @return string HTML code
*/
function doc_link(array $paths, $text = "<sup>?</sup>") {
global $jush, $connection;
$server_info = $connection->server_info;
$version = preg_replace('~^(\d\.?\d).*~s', '\1', $server_info); // two most significant digits
$urls = array(
$urls = [
'sql' => "https://dev.mysql.com/doc/refman/$version/en/",
'sqlite' => "https://www.sqlite.org/",
'pgsql' => "https://www.postgresql.org/docs/$version/",
'mssql' => "https://msdn.microsoft.com/library/",
'oracle' => "https://www.oracle.com/pls/topic/lookup?ctx=db" . preg_replace('~^.* (\d+)\.(\d+)\.\d+\.\d+\.\d+.*~s', '\1\2', $server_info) . "&id=",
);
'elastic' => "https://www.elastic.co/guide/en/elasticsearch/reference/$version/",
];
if (preg_match('~MariaDB~', $server_info)) {
$urls['sql'] = "https://mariadb.com/kb/en/library/";
$urls['sql'] = "https://mariadb.com/kb/en/";
$paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql']));
}
return ($paths[$jush] ? "<a href='" . h($urls[$jush] . $paths[$jush]) . "'" . target_blank() . ">$text</a>" : "");
if (!isset($paths[$jush]) || !$paths[$jush] ) {
return "";
}
return "<a href='" . h($urls[$jush] . $paths[$jush]) . "'" . target_blank() . ">$text</a>";
}
/** Wrap gzencode() for usage in ob_start()

View File

@@ -1,4 +1,5 @@
<?php
/** Get database connection
* @return Min_DB
*/
@@ -107,6 +108,9 @@ function min_version($version, $maria_db = "", $connection2 = null) {
$server_info = $match[1];
$version = $maria_db;
}
if ($version == "") {
return false;
}
return (version_compare($server_info, $version) >= 0);
}
@@ -157,14 +161,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
@@ -242,7 +238,7 @@ function html_select($name, $options, $value = "", $onchange = true, $labelled_b
*/
function select_input($attrs, $options, $value = "", $onchange = "", $placeholder = "") {
$tag = ($options ? "select" : "input");
return "<$tag$attrs" . ($options
return "<$tag $attrs" . ($options
? "><option value=''>$placeholder" . optionlist($options, $value, true) . "</select>"
: " size='10' value='" . h($value) . "' placeholder='$placeholder'>"
) . ($onchange ? script("qsl('$tag').onchange = $onchange;", "") : ""); //! use oninput for input
@@ -257,18 +253,17 @@ function confirm($message = "", $selector = "qsl('input')") {
return script("$selector.onclick = function () { return confirm('" . ($message ? js_escape($message) : lang('Are you sure?')) . "'); };", "");
}
/** Print header for hidden fieldset (close by </div></fieldset>)
* @param string
* @param string
* @param bool
* @return null
*/
function print_fieldset($id, $legend, $visible = false) {
/**
* Prints header for hidden fieldset (close by </div></fieldset>)
* @param $id string
* @param $legend string
*/
function print_fieldset($id, $legend, $visible = false, $sortable = false) {
echo "<fieldset><legend>";
echo "<a href='#fieldset-$id'>$legend</a>";
echo script("qsl('a').onclick = partial(toggle, 'fieldset-$id');", "");
echo "</legend>";
echo "<div id='fieldset-$id'" . ($visible ? "" : " class='hidden'") . ">\n";
echo "<div id='fieldset-$id' class='" . ($visible ? "" : "hidden") . ($sortable ? " sortable" : "") . "'>\n";
}
/** Return class='active' if $bold is true
@@ -477,24 +472,36 @@ function escape_key($key) {
*/
function where($where, $fields = array()) {
global $connection, $jush;
$return = array();
$conditions = [];
foreach ((array) $where["where"] as $key => $val) {
$key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key);
$return[] = $column
. ($jush == "sql" && is_numeric($val) && preg_match('~\.~', $val) ? " LIKE " . q($val) // LIKE because of floats but slow with ints
: ($jush == "mssql" ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text
: " = " . unconvert_field($fields[$key], q($val))
))
; //! enum and set
if ($jush == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
if ($jush == "sql" && $fields[$key]["type"] == "json") {
$conditions[] = "$column = CAST(" . q($val) . " AS JSON)";
} elseif ($jush == "sql" && is_numeric($val) && strpos($val, ".") !== false) {
// LIKE because of floats but slow with ints.
$conditions[] = "$column LIKE " . q($val);
} elseif ($jush == "mssql") {
// LIKE because of text.
$conditions[] = "$column LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val));
} else {
$conditions[] = "$column = " . unconvert_field($fields[$key], q($val));
}
// Not just [a-z] to catch non-ASCII characters.
if ($jush == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) {
$conditions[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
}
}
foreach ((array) $where["null"] as $key) {
$return[] = escape_key($key) . " IS NULL";
$conditions[] = escape_key($key) . " IS NULL";
}
return implode(" AND ", $return);
return implode(" AND ", $conditions);
}
/** Create SQL condition from query string
@@ -607,7 +614,7 @@ function auth_url($vendor, $server, $username, $db = null) {
preg_match('~([^?]*)\??(.*)~', remove_from_uri(implode("|", array_keys($drivers)) . "|username|" . ($db !== null ? "db|" : "") . session_name()), $match);
return "$match[1]?"
. (sid() ? SID . "&" : "")
. ($vendor != "server" || $server != "" ? urlencode($vendor) . "=" . urlencode($server) . "&" : "")
. urlencode($vendor) . "=" . urlencode($server) . "&"
. "username=" . urlencode($username)
. ($db != "" ? "&db=" . urlencode($db) : "")
. ($match[2] ? "&$match[2]" : "")
@@ -826,6 +833,8 @@ function is_utf8($val) {
* @return string escaped string with appended ...
*/
function shorten_utf8($string, $length = 80, $suffix = "") {
if ($string == "") return $suffix;
if (!preg_match("(^(" . repeat_pattern("[\t\r\n -\x{10FFFF}]", $length) . ")($)?)u", $string, $match)) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
preg_match("(^(" . repeat_pattern("[\t\r\n -~]", $length) . ")($)?)", $string, $match);
}
@@ -886,7 +895,7 @@ function hidden_fields_get() {
*/
function table_status1($table, $fast = false) {
$return = table_status($table, $fast);
return ($return ? $return : array("Name" => $table));
return ($return ?: array("Name" => $table));
}
/** Find out foreign keys for each column
@@ -935,14 +944,15 @@ function enum_input($type, $attrs, $field, $value, $empty = null) {
*/
function input($field, $value, $function) {
global $types, $adminer, $jush;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
$args = array($value);
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"]);
@@ -950,18 +960,23 @@ function input($field, $value, $function) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$attrs = " name='fields[$name]'";
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]' $disabled";
echo "<td class='function'>";
if ($field["type"] == "enum") {
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value, $function);
} else {
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]'>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. on_help("getTarget(event).value.replace(/^SQL\$/, '')", 1)
? "<select name='function[$name]' $disabled>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. help_script_command("value.replace(/^SQL\$/, '')", true)
. script("qsl('select').onchange = functionChange;", "")
: h(reset($functions))
) . '<td>';
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value, $function); // usage in call is without a table
if ($input != "") {
echo $input;
} elseif (preg_match('~bool~', $field["type"])) {
@@ -995,7 +1010,8 @@ function input($field, $value, $function) {
// type='date' and type='time' display localized value which may be confusing, type='datetime' uses 'T' as date and time separator
echo "<input"
. ((!$has_function || $function === "") && preg_match('~(?<!o)int(?!er)~', $field["type"]) && !preg_match('~\[\]~', $field["full_type"]) ? " type='number'" : "")
. " value='" . h($value) . "'" . ($maxlength ? " data-maxlength='$maxlength'" : "")
. ($function != "now" ? " value='" . h($value) . "'" : " data-last-value='" . h($value) . "'")
. ($maxlength ? " data-maxlength='$maxlength'" : "")
. (preg_match('~char|binary~', $field["type"]) && $maxlength > 20 ? " size='40'" : "")
. "$attrs>"
;
@@ -1009,9 +1025,7 @@ function input($field, $value, $function) {
}
$first++;
}
if ($first) {
echo script("mixin(qsl('td'), {onchange: partial(skipOriginal, $first), oninput: function () { this.onchange(); }});");
}
echo script("mixin(qsl('td'), {onchange: partial(skipOriginal, $first), oninput: function () { this.onchange(); }});");
}
}
@@ -1021,6 +1035,11 @@ function input($field, $value, $function) {
*/
function process_input($field) {
global $adminer, $driver;
if (stripos($field["default"], "GENERATED ALWAYS AS ") === 0) {
return null;
}
$idf = bracket_escape($field["field"]);
$function = $_POST["function"][$idf];
$value = $_POST["fields"][$idf];
@@ -1111,6 +1130,27 @@ function search_tables() {
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/**
* @param string $table
* @return array
*/
function get_partitions_info($table) {
global $connection;
$from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($table);
$result = $connection->query("SELECT PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_ORDINAL_POSITION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");
$info = [];
list($info["partition_by"], $info["partition"], $info["partitions"]) = $result->fetch_row();
$partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION");
$info["partition_names"] = array_keys($partitions);
$info["partition_values"] = array_values($partitions);
return $info;
}
/** Send headers for export
* @param string
* @param bool
@@ -1171,60 +1211,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
@@ -1244,7 +1322,7 @@ function select_value($val, $link, $field, $text_length) {
. "<td>" . select_value($v, $link, $field, $text_length)
;
}
return "<table cellspacing='0'>$return</table>";
return "<table>$return</table>";
}
if (!$link) {
$link = $adminer->selectLink($val, $field);
@@ -1413,13 +1491,26 @@ function lzw_decompress($binary) {
return $return;
}
/** Return events to display help on mouse over
* @param string JS expression
* @param bool JS expression
* @return string
*/
function on_help($command, $side = 0) {
return script("mixin(qsl('select, input'), {onmouseover: function (event) { helpMouseover.call(this, event, $command, $side) }, onmouseout: helpMouseout});", "");
/**
* @param string $text Help text.
* @param bool $side Side position.
*
* @return string
*/
function help_script($text, $side = false)
{
return script("initHelpFor(qsl('select, input'), '" . h($text) . "', $side);", "");
}
/**
* @param string $command JS expression for returning the help text.
* @param bool $side Side position.
*
* @return string
*/
function help_script_command($command, $side = false)
{
return script("initHelpFor(qsl('select, input'), (value) => { return $command; }, $side);", "");
}
/** Print edit data form
@@ -1441,6 +1532,7 @@ function edit_form($table, $fields, $row, $update) {
$adminer->editRowPrint($table, $fields, $row, $update);
if ($row === false) {
echo "<p class='error'>" . lang('No rows.') . "\n";
return;
}
?>
<form action="" method="post" enctype="multipart/form-data" id="form">
@@ -1486,6 +1578,10 @@ function edit_form($table, $fields, $row, $update) {
$value = "";
$function = "now";
}
if ($field["type"] == "uuid" && $value == "uuid()") {
$value = "";
$function = "uuid";
}
input($field, $value, $function);
echo "\n";
}
@@ -1512,7 +1608,7 @@ function edit_form($table, $fields, $row, $update) {
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[1].firstChild);"))
: ($_POST || !$fields ? "" : script("focus(qsa('td', gid('form'))[1].firstChild);"))
);
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));

View File

@@ -1,7 +1,6 @@
<?php
// not used in a single language version
$langs = array(
$languages = [
'en' => 'English', // Jakub Vrána - https://www.vrana.cz
'ar' => 'العربية', // Y.M Amine - Algeria - nbr7@live.fr
'bg' => 'Български', // Deyan Delchev
@@ -25,8 +24,8 @@ $langs = array(
'ja' => '日本語', // Hitoshi Ozawa - http://sourceforge.jp/projects/oss-ja-jpn/releases/
'ka' => 'ქართული', // Saba Khmaladze skhmaladze@uglt.org
'ko' => '한국어', // dalli - skcha67@gmail.com
'lv' => 'Latviešu', // Kristaps Lediņš - https://krysits.com
'lt' => 'Lietuvių', // Paulius Leščinskas - http://www.lescinskas.lt
'lv' => 'Latviešu', // Kristaps Lediņš - https://krysits.com
'lt' => 'Lietuvių', // Paulius Leščinskas - http://www.lescinskas.lt
'ms' => 'Bahasa Melayu', // Pisyek
'nl' => 'Nederlands', // Maarten Balliauw - http://blog.maartenballiauw.be
'no' => 'Norsk', // Iver Odin Kvello, mupublishing.com
@@ -46,24 +45,59 @@ $langs = array(
'vi' => 'Tiếng Việt', // Giang Manh @ manhgd google mail
'zh' => '简体中文', // Mr. Lodar, vea - urn2.net - vea.urn2@gmail.com
'zh-tw' => '繁體中文', // http://tzangms.com
);
];
/** Get current language
* @return string
*/
function get_lang() {
/**
* Returns the list of available languages.
* In compiled version, only selected languages are returned.
*
* @return array
*/
function get_available_languages()
{
global $languages;
return $languages; // compile: available languages
}
/**
* Converts translation key into the right form.
* In compiled version, string keys used in plugins are dynamically translated to numeric keys.
*
* @param string|int $key
*
* @return string|int
*/
function convert_translation_key($key)
{
return $key; // compile: convert translation key
}
/**
* Returns current language.
*
* @return string
*/
function get_lang()
{
global $LANG;
return $LANG;
}
/** Translate string
* @param string
* @param int
* @return string
*/
function lang($idf, $number = null) {
/**
* Returns translated text.
*
* @param string|int $key Numeric key is used in compiled version.
* @param ?int $number
*
* @return string
*/
function lang($key, $number = null)
{
global $LANG, $translations;
$translation = ($translations[$idf] ? $translations[$idf] : $idf);
$key = convert_translation_key($key);
$translation = $translations[$key] ?: $key;
if (is_array($translation)) {
$pos = ($number == 1 ? 0
: ($LANG == 'cs' || $LANG == 'sk' ? ($number && $number < 5 ? 1 : 2) // different forms for 1, 2-4, other
@@ -74,53 +108,77 @@ function lang($idf, $number = null) {
: ($LANG == 'bs' || $LANG == 'ru' || $LANG == 'sr' || $LANG == 'uk' ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number % 10 > 1 && $number % 10 < 5 && $number / 10 % 10 != 1 ? 1 : 2)) // different forms for 1 except 11, 2-4 except 12-14, other
: 1 // different forms for 1, other
))))))); // http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
$translation = $translation[$pos];
}
$args = func_get_args();
array_shift($args);
$format = str_replace("%d", "%s", $translation);
if ($format != $translation) {
$args[0] = format_number($number);
}
return vsprintf($format, $args);
}
function switch_lang() {
global $LANG, $langs;
echo "<form action='' method='post'>\n<div id='lang'>";
echo lang('Language') . ": " . html_select("lang", $langs, $LANG, "this.form.submit();");
function language_select()
{
global $LANG, $languages;
$available_languages = get_available_languages();
if (count($available_languages) == 1) {
return;
}
$options = [];
foreach ($languages as $language => $title) {
if (isset($available_languages[$language])) {
$options[$language] = $title;
}
}
echo "<div id='lang'><form action='' method='post'>\n";
echo lang('Language') . ": " . html_select("lang", $options, $LANG, "this.form.submit();");
echo " <input type='submit' value='" . lang('Use') . "' class='hidden'>\n";
echo "<input type='hidden' name='token' value='" . get_token() . "'>\n"; // $token may be empty in auth.inc.php
echo "</div>\n</form>\n";
echo "</form></div>\n";
}
if (isset($_POST["lang"]) && verify_token()) { // $error not yet available
cookie("adminer_lang", $_POST["lang"]);
$_SESSION["lang"] = $_POST["lang"]; // cookies may be disabled
$_SESSION["translations"] = array(); // used in compiled version
$_SESSION["translations"] = []; // used in compiled version
redirect(remove_from_uri());
}
$LANG = "en";
if (isset($langs[$_COOKIE["adminer_lang"]])) {
$available_languages = get_available_languages();
$LANG = $available_languages[0];
if (isset($available_languages[$_COOKIE["adminer_lang"]])) {
cookie("adminer_lang", $_COOKIE["adminer_lang"]);
$LANG = $_COOKIE["adminer_lang"];
} elseif (isset($langs[$_SESSION["lang"]])) {
} elseif (isset($available_languages[$_SESSION["lang"]])) {
$LANG = $_SESSION["lang"];
} else {
$accept_language = array();
$accept_language = [];
preg_match_all('~([-a-z]+)(;q=([0-9.]+))?~', str_replace("_", "-", strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"])), $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$accept_language[$match[1]] = (isset($match[3]) ? $match[3] : 1);
}
arsort($accept_language);
foreach ($accept_language as $key => $q) {
if (isset($langs[$key])) {
if (isset($available_languages[$key])) {
$LANG = $key;
break;
}
$key = preg_replace('~-.*~', '', $key);
if (!isset($accept_language[$key]) && isset($langs[$key])) {
if (!isset($accept_language[$key]) && isset($available_languages[$key])) {
$LANG = $key;
break;
}

View File

@@ -3,7 +3,7 @@
if (extension_loaded('pdo')) {
/*abstract*/ class Min_PDO {
var $_result, $server_info, $affected_rows, $errno, $error, $pdo;
function __construct() {
global $adminer;
$pos = array_search("SQL", $adminer->operators);
@@ -11,10 +11,10 @@ if (extension_loaded('pdo')) {
unset($adminer->operators[$pos]);
}
}
function dsn($dsn, $username, $password, $options = array()) {
function dsn($dsn, $username, $password, $options = []) {
$options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT;
$options[PDO::ATTR_STATEMENT_CLASS] = array('Min_PDOStatement');
$options[PDO::ATTR_STATEMENT_CLASS] = [Min_PDOStatement::class];
try {
$this->pdo = new PDO($dsn, $username, $password, $options);
} catch (Exception $ex) {
@@ -22,13 +22,13 @@ if (extension_loaded('pdo')) {
}
$this->server_info = @$this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
}
/*abstract function select_db($database);*/
function quote($string) {
return $this->pdo->quote($string);
}
function query($query, $unbuffered = false) {
$result = $this->pdo->query($query);
$this->error = "";
@@ -42,11 +42,11 @@ if (extension_loaded('pdo')) {
$this->store_result($result);
return $result;
}
function multi_query($query) {
return $this->_result = $this->query($query);
}
function store_result($result = null) {
if (!$result) {
$result = $this->_result;
@@ -61,7 +61,7 @@ if (extension_loaded('pdo')) {
$this->affected_rows = $result->rowCount();
return true;
}
function next_result() {
if (!$this->_result) {
return false;
@@ -69,7 +69,7 @@ if (extension_loaded('pdo')) {
$this->_result->_offset = 0;
return @$this->_result->nextRowset(); // @ - PDO_PgSQL doesn't support it
}
function result($query, $field = 0) {
$result = $this->query($query);
if (!$result) {
@@ -79,18 +79,18 @@ if (extension_loaded('pdo')) {
return $row[$field];
}
}
class Min_PDOStatement extends PDOStatement {
var $_offset = 0, $num_rows;
function fetch_assoc() {
return $this->fetch(PDO::FETCH_ASSOC);
}
function fetch_row() {
return $this->fetch(PDO::FETCH_NUM);
}
function fetch_field() {
$row = (object) $this->getColumnMeta($this->_offset++);
$row->orgtable = $row->table;

View File

@@ -1,2 +1,2 @@
<?php
$VERSION = "4.9.2";
$VERSION = "4.12";

View File

@@ -1,11 +1,14 @@
<?php
/** Adminer - Compact database management
* @link https://www.adminer.org/
* @author Jakub Vrana, https://www.vrana.cz/
* @copyright 2007 Jakub Vrana
* @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)
*/
/**
* Adminer - Database management in a single PHP file
*
* @link https://github.com/pematon/adminer
* @author Jakub Vrana (https://www.vrana.cz/)
* @author Peter Knut
* @copyright 2007-2021 Jakub Vrana, 2024 Peter Knut
* @license Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
* @license GNU General Public License, version 2 (https://www.gnu.org/licenses/gpl-2.0.html)
*/
include "./include/bootstrap.inc.php";
include "./include/tmpfile.inc.php";

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'تسجيل الدخول',
'Logout successful.' => 'تم تسجيل الخروج بنجاح.',
'Invalid server or credentials.' => null,
@@ -30,7 +31,6 @@ $translations = array(
'Create database' => 'إنشاء قاعدة بيانات',
'SQL command' => 'استعلام SQL',
'Logout' => 'تسجيل الخروج',
'database' => 'قاعدة بيانات',
'Use' => 'استعمال',
'No tables.' => 'لا توجد جداول.',
'select' => 'تحديد',
@@ -67,7 +67,6 @@ $translations = array(
'Unable to select the table' => 'يتعذر اختيار الجدول',
'Invalid CSRF token. Send the form again.' => 'رمز CSRF غير صالح. المرجو إرسال الاستمارة مرة أخرى.',
'Comment' => 'تعليق',
'Default values' => 'القيم الافتراضية',
'%d byte(s)' => '%d بايت',
'No commands to execute.' => 'لا توجد أوامر للتنفيذ.',
'Unable to upload a file.' => 'يتعذر رفع ملف ما.',
@@ -188,6 +187,7 @@ $translations = array(
'Clone' => 'نسخ',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'لقد تجاوزت العدد الأقصى للحقول. يرجى الرفع من %s.',
'Partition by' => 'مقسم بواسطة',
'Partition' => null,
'Partitions' => 'التقسيمات',
'Partition name' => 'اسم التقسيم',
'Values' => 'القيم',
@@ -223,6 +223,7 @@ $translations = array(
'Databases have been dropped.' => 'تم حذف قواعد البيانات.',
'Database has been dropped.' => 'تم حذف قاعدة البيانات.',
'Search data in tables' => 'بحث في الجداول',
'as a regular expression' => null,
'Schema' => 'المخطط',
'Alter schema' => 'تعديل المخطط',
'Create schema' => 'إنشاء مخطط',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Система',
'Server' => 'Сървър',
'Username' => 'Потребител',
@@ -16,6 +17,8 @@ $translations = array(
'Language' => 'Език',
'Invalid CSRF token. Send the form again.' => 'Невалиден шифроващ ключ. Попълнете и изпратете формуляра отново.',
'If you did not send this request from Adminer then close this page.' => 'Ако не сте изпратили тази заявка през Adminer, затворете тази страница.',
'No driver' => null,
'Database driver not found.' => null,
'No extension' => 'Няма разширение',
'None of the supported PHP extensions (%s) are available.' => 'Никое от поддържаните PHP разширения (%s) не е налично.',
'Session support must be enabled.' => 'Поддръжката на сесии трябва да е разрешена.',
@@ -78,7 +81,6 @@ $translations = array(
'Data' => 'Данни',
'Database' => 'База данни',
'database' => 'база данни',
'Use' => 'Избор',
'Select database' => 'Избор на база данни',
'Invalid database.' => 'Невалидна база данни.',
@@ -165,7 +167,6 @@ $translations = array(
'Options' => 'Опции',
'Comment' => 'Коментар',
'Default value' => 'Стойност по подразбиране',
'Default values' => 'Стойности по подразбиране',
'Drop' => 'Премахване',
'Are you sure?' => 'Сигурни ли сте?',
'Size' => 'Големина',
@@ -176,6 +177,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Максималния брой полета е превишен. Моля, увеличете %s.',
'Partition by' => 'Разделяне на',
'Partition' => null,
'Partitions' => 'Раздели',
'Partition name' => 'Име на раздела',
'Values' => 'Стойности',
@@ -230,6 +232,7 @@ $translations = array(
'Search' => 'Търсене',
'anywhere' => 'навсякъде',
'Search data in tables' => 'Търсене на данни в таблиците',
'as a regular expression' => null,
'Sort' => 'Сортиране',
'descending' => 'низходящо',
'Limit' => 'Редове',
@@ -311,12 +314,15 @@ $translations = array(
'Please use one of the extensions %s.' => 'Моля, използвайте някое от разширенията %s.',
// PostgreSQL and MS SQL schema support
'Schema' => 'Схема',
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'Alter schema' => 'Промяна на схемата',
'Create schema' => 'Създаване на схема',
'Schema has been dropped.' => 'Схемата беше премахната.',
'Schema has been created.' => 'Схемата беше създадена.',
'Schema has been altered.' => 'Схемата беше променена.',
'Schema' => 'Схема',
'Invalid schema.' => 'Невалидна схема.',
// PostgreSQL sequences support

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'লগইন',
'Logout successful.' => 'সফলভাবে লগআউট হয়েছে।',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'ডাটাবেজ তৈরী করুন',
'SQL command' => 'SQL-কমান্ড',
'Logout' => 'লগআউট',
'database' => 'ডাটাবেজ',
'Use' => 'ব্যবহার',
'No tables.' => 'কোন টেবিল নাই।',
'select' => 'নির্বাচন',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'টেবিল নির্বাচন করতে অক্ষম',
'Invalid CSRF token. Send the form again.' => 'অবৈধ CSRF টোকেন। ফর্মটি আবার পাঠান।',
'Comment' => 'মন্তব্য',
'Default values' => 'ডিফল্ট মান',
'%d byte(s)' => array('%d বাইট', '%d বাইটসমূহ'),
'No commands to execute.' => 'সম্পাদন করার মত কোন নির্দেশ নেই।',
'Unable to upload a file.' => 'ফাইল আপলোড করা সম্ভব হচ্ছে না।',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'ক্লোন',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'অনুমোদিত ফিল্ড এর সর্বাধিক সংখ্যা অতিক্রম করে গেছে। অনুগ্রহপূর্বক %s বৃদ্ধি করুন।',
'Partition by' => 'পার্টিশন যার মাধ্যমে',
'Partition' => null,
'Partitions' => 'পার্টিশন',
'Partition name' => 'পার্টিশনের নাম',
'Values' => 'মানসমূহ',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'স্থায়ী লগইন',
'Databases have been dropped.' => 'ডাটাবেজসমূহ মুছে ফেলা হয়েছে।',
'Search data in tables' => 'টেবিলে তথ্য খুঁজুন',
'as a regular expression' => null,
'Schema' => 'স্কিমা',
'Alter schema' => 'স্কিমা পরিবর্তন করো',
'Create schema' => 'স্কিমা তৈরী করো',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistem',
'Server' => 'Server',
'Username' => 'Korisničko ime',
@@ -73,7 +74,6 @@ $translations = array(
'Data' => 'Podaci',
'Database' => 'Baza podataka',
'database' => 'baza podataka',
'Use' => 'Koristi',
'Select database' => 'Izaberite bazu',
'Invalid database.' => 'Neispravna baza podataka.',
@@ -158,7 +158,6 @@ $translations = array(
'Auto Increment' => 'Auto-priraštaj',
'Options' => 'Opcije',
'Comment' => 'Komentar',
'Default values' => 'Podrazumijevane vrijednosti',
'Drop' => 'Izbriši',
'Are you sure?' => 'Da li ste sigurni?',
'Move up' => 'Pomijeri na gore',
@@ -167,6 +166,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Premašen je maksimalni broj dozvoljenih polja. Molim uvećajte %s.',
'Partition by' => 'Podijeli po',
'Partition' => null,
'Partitions' => 'Podijele',
'Partition name' => 'Ime podijele',
'Values' => 'Vrijednosti',
@@ -221,6 +221,7 @@ $translations = array(
'Search' => 'Pretraga',
'anywhere' => 'bilo gdje',
'Search data in tables' => 'Pretraži podatke u tabelama',
'as a regular expression' => null,
'Sort' => 'Poređaj',
'descending' => 'opadajuće',
'Limit' => 'Granica',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Ne',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Inicia la sessió',
'Logout successful.' => 'Desconnexió correcta.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Crea una base de dades',
'SQL command' => 'Ordre SQL',
'Logout' => 'Desconnecta',
'database' => 'base de dades',
'Use' => 'Utilitza',
'No tables.' => 'No hi ha cap taula.',
'select' => 'registres',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Impossible seleccionar la taula',
'Invalid CSRF token. Send the form again.' => 'Token CSRF invàlid. Torna a enviar el formulari.',
'Comment' => 'Comentari',
'Default values' => 'Valors per defecte',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Cap comanda per executar.',
'Unable to upload a file.' => 'Impossible adjuntar el fitxer.',
@@ -189,6 +188,7 @@ $translations = array(
'Tables have been dropped.' => 'S\'han suprimit les taules.',
'Clone' => 'Clona',
'Partition by' => 'Fes particions segons',
'Partition' => null,
'Partitions' => 'Particions',
'Partition name' => 'Nom de la partició',
'Values' => 'Valors',
@@ -251,6 +251,7 @@ $translations = array(
'Type has been created.' => 'S\'ha creat el tipus.',
'Alter type' => 'Modifica el tipus',
'Search data in tables' => 'Cerca dades en les taules',
'as a regular expression' => null,
'From server' => 'En el servidor',
'empty' => 'buit',
'now' => 'ara',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => 'Domů',
'System' => 'Systém',
'Server' => 'Server',
'Username' => 'Uživatel',
@@ -20,6 +21,8 @@ $translations = array(
'Language' => 'Jazyk',
'Invalid CSRF token. Send the form again.' => 'Neplatný token CSRF. Odešlete formulář znovu.',
'If you did not send this request from Adminer then close this page.' => 'Pokud jste tento požadavek neposlali z Adminera, tak tuto stránku zavřete.',
'No driver' => 'Žádný ovladač',
'Database driver not found.' => 'Databázový ovladač se nenašel.',
'No extension' => 'Žádné rozšíření',
'None of the supported PHP extensions (%s) are available.' => 'Není dostupné žádné z podporovaných PHP rozšíření (%s).',
'Connecting to privileged ports is not allowed.' => 'Připojování k privilegovaným portům není povoleno.',
@@ -88,7 +91,6 @@ $translations = array(
'Data' => 'Data',
'Database' => 'Databáze',
'database' => 'databáze',
'DB' => 'DB',
'Use' => 'Vybrat',
'Select database' => 'Vybrat databázi',
@@ -177,7 +179,6 @@ $translations = array(
'Options' => 'Volby',
'Comment' => 'Komentář',
'Default value' => 'Výchozí hodnota',
'Default values' => 'Výchozí hodnoty',
'Drop' => 'Odstranit',
'Drop %s?' => 'Odstranit %s?',
'Are you sure?' => 'Opravdu?',
@@ -189,6 +190,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Byl překročen maximální povolený počet polí. Zvyšte prosím %s.',
'Partition by' => 'Rozdělit podle',
'Partition' => 'Oddíl',
'Partitions' => 'Oddíly',
'Partition name' => 'Název oddílu',
'Values' => 'Hodnoty',
@@ -243,6 +245,7 @@ $translations = array(
'Search' => 'Vyhledat',
'anywhere' => 'kdekoliv',
'Search data in tables' => 'Vyhledat data v tabulkách',
'as a regular expression' => 'jako regulární výraz',
'Sort' => 'Seřadit',
'descending' => 'sestupně',
'Limit' => 'Limit',
@@ -256,8 +259,8 @@ $translations = array(
'%d row(s)' => array('%d řádek', '%d řádky', '%d řádků'),
'Page' => 'Stránka',
'last' => 'poslední',
'Load more data' => 'Nahrát další data',
'Loading' => 'Nahrává se',
'Load more data' => 'Načíst další data',
'Loading' => 'Načítá se',
'Whole result' => 'Celý výsledek',
'%d byte(s)' => array('%d bajt', '%d bajty', '%d bajtů'),
@@ -324,12 +327,15 @@ $translations = array(
'Please use one of the extensions %s.' => 'Prosím použijte jednu z koncovek %s.',
// PostgreSQL and MS SQL schema support
'Schema' => 'Schéma',
'Schemas' => 'Schémy',
'No schemas.' => 'Žádné schémy.',
'Show schema' => 'Zobrazit schéma',
'Alter schema' => 'Pozměnit schéma',
'Create schema' => 'Vytvořit schéma',
'Schema has been dropped.' => 'Schéma bylo odstraněno.',
'Schema has been created.' => 'Schéma bylo vytvořeno.',
'Schema has been altered.' => 'Schéma bylo změněno.',
'Schema' => 'Schéma',
'Invalid schema.' => 'Nesprávné schéma.',
// PostgreSQL sequences support

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'System' => 'System',
'Server' => 'Server',
'Username' => 'Brugernavn',
@@ -64,7 +65,6 @@ $translations = array(
'Format' => 'Format',
'Data' => 'Data',
'Database' => 'Database',
'database' => 'database',
'Use' => 'Brug',
'Select database' => 'Vælg database',
'Invalid database.' => 'Ugyldig database.',
@@ -143,7 +143,6 @@ $translations = array(
'Auto Increment' => 'Auto Increment',
'Options' => 'Valg',
'Comment' => 'Kommentarer',
'Default values' => 'Standardværdier',
'Drop' => 'Drop',
'Are you sure?' => 'Er du sikker?',
'Move up' => 'Flyt op',
@@ -151,6 +150,7 @@ $translations = array(
'Remove' => 'Fjern',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maksimum antal feltnavne overskredet - øg venligst %s.',
'Partition by' => 'Partition ved',
'Partition' => null,
'Partitions' => 'Partitioner',
'Partition name' => 'Partitionsnavn',
'Values' => 'Værdier',
@@ -199,6 +199,7 @@ $translations = array(
'Search' => 'Søg',
'anywhere' => 'hvorsomhelst',
'Search data in tables' => 'Søg data i tabeller',
'as a regular expression' => null,
'Sort' => 'Sorter',
'descending' => 'faldende',
'Limit' => 'Limit',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Nej',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Login',
'Logout successful.' => 'Abmeldung erfolgreich.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Danke, dass Sie Adminer genutzt haben. <a href="https://www.adminer.org/de/donation/">Spenden willkommen!</a>',
@@ -32,7 +33,6 @@ $translations = array(
'Create database' => 'Datenbank erstellen',
'SQL command' => 'SQL-Kommando',
'Logout' => 'Abmelden',
'database' => 'Datenbank',
'Use' => 'Benutzung',
'No tables.' => 'Keine Tabellen.',
'select' => 'zeigen',
@@ -70,7 +70,6 @@ $translations = array(
'Unable to select the table' => 'Auswahl der Tabelle fehlgeschlagen',
'Invalid CSRF token. Send the form again.' => 'CSRF Token ungültig. Bitte die Formulardaten erneut abschicken.',
'Comment' => 'Kommentar',
'Default values' => 'Vorgabewerte festlegen',
'%d byte(s)' => array('%d Byte', '%d Bytes'),
'No commands to execute.' => 'Kein Kommando vorhanden.',
'Unable to upload a file.' => 'Hochladen von Datei fehlgeschlagen.',
@@ -191,6 +190,7 @@ $translations = array(
'Clone' => 'Klonen',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Die maximal erlaubte Anzahl der Felder ist überschritten. Bitte %s erhöhen.',
'Partition by' => 'Partitionieren um',
'Partition' => 'Partition',
'Partitions' => 'Partitionen',
'Partition name' => 'Name der Partition',
'Values' => 'Werte',
@@ -225,6 +225,7 @@ $translations = array(
'Permanent login' => 'Passwort speichern',
'Databases have been dropped.' => 'Datenbanken wurden entfernt.',
'Search data in tables' => 'Suche in Tabellen',
'as a regular expression' => null,
'Schema' => 'Schema',
'Alter schema' => 'Schema ändern',
'Create schema' => 'Schema erstellen',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Nein',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Σύστημα',
'Server' => 'Διακομιστής',
'Username' => 'Όνομα Χρήστη',
@@ -79,7 +80,6 @@ $translations = array(
'Data' => 'Δεδομένα',
'Database' => 'Β. Δεδομένων',
'database' => 'β. δεδομένων',
'Use' => 'χρήση',
'Select database' => 'Επιλέξτε Β.Δ.',
'Invalid database.' => 'Λανθασμένη Β.Δ.',
@@ -166,7 +166,6 @@ $translations = array(
'Options' => 'Επιλογές',
'Comment' => 'Σχόλιο',
'Default value' => 'Προεπιλεγμένη τιμή',
'Default values' => 'Προεπιλεγμένες τιμές',
'Drop' => 'Διαγραφή',
'Are you sure?' => 'Είστε σίγουρος;',
'Size' => 'Μέγεθος',
@@ -177,6 +176,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Υπέρβαση μέγιστου επιτρεπόμενου αριθμού πεδίων. Παρακαλώ αυξήστε %s.',
'Partition by' => 'Τμηματοποίηση ανά',
'Partition' => null,
'Partitions' => 'Τμήματα',
'Partition name' => 'Όνομα Τμήματος',
'Values' => 'Τιμές',
@@ -231,6 +231,7 @@ $translations = array(
'Search' => 'Αναζήτηση',
'anywhere' => 'παντού',
'Search data in tables' => 'Αναζήτηση δεδομένων στους πίνακες',
'as a regular expression' => null,
'Sort' => 'Ταξινόμηση',
'descending' => 'Φθίνουσα',
'Limit' => 'Όριο',
@@ -355,4 +356,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,8 +1,9 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Login',
'Logout successful.' => 'Sesión finalizada con éxito.',
'Invalid server or credentials.' => null,
'Invalid server or credentials.' => 'Servidor o credenciales no válidos.',
'Server' => 'Servidor',
'Username' => 'Usuario',
'Password' => 'Contraseña',
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Crear Base de datos',
'SQL command' => 'Comando SQL',
'Logout' => 'Cerrar sesión',
'database' => 'base de datos',
'Use' => 'Usar',
'No tables.' => 'No existen tablas.',
'select' => 'registros',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'No es posible seleccionar la tabla',
'Invalid CSRF token. Send the form again.' => 'Token CSRF inválido. Vuelva a enviar los datos del formulario.',
'Comment' => 'Comentario',
'Default values' => 'Valores predeterminados',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'No es posible ejecutar ningún comando.',
'Unable to upload a file.' => 'No es posible importar el archivo.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Excedida la cantidad máxima de campos permitidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
'Partition' => null,
'Partitions' => 'Particiones',
'Partition name' => 'Nombre de partición',
'Values' => 'Valores',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Guardar contraseña',
'Databases have been dropped.' => 'Bases de datos eliminadas.',
'Search data in tables' => 'Buscar datos en tablas',
'as a regular expression' => 'como una expresión regular',
'Schema' => 'Esquema',
'Alter schema' => 'Modificar esquema',
'Create schema' => 'Crear esquema',
@@ -266,42 +267,42 @@ $translations = array(
'Edit all' => 'Editar todos',
'HH:MM:SS' => 'HH:MM:SS',
'Drop %s?' => null,
'Tables have been optimized.' => null,
'Materialized view' => null,
'Vacuum' => null,
'Selected' => null,
'overwrite' => null,
'DB' => null,
'File must be in UTF-8 encoding.' => null,
'Modify' => null,
'Load more data' => null,
'Loading' => null,
'ATTACH queries are not supported.' => null,
'Warnings' => null,
'%d / ' => array(),
'Limit rows' => null,
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => null,
'Default value' => null,
'Drop %s?' => '¿Eliminar %s?',
'Tables have been optimized.' => 'Tablas optimizadas.',
'Materialized view' => 'Vista materializada',
'Vacuum' => 'Vacio',
'Selected' => 'Seleccionado',
'overwrite' => 'sobreescribir',
'DB' => 'DB',
'File must be in UTF-8 encoding.' => 'El archivo debe estar codificado en UTF-8.',
'Modify' => 'Modificar',
'Load more data' => 'Cargar mas datos',
'Loading' => 'Cargando',
'ATTACH queries are not supported.' => 'ATTACH consultas no está soportado.',
'Warnings' => 'Advertencias',
'%d / ' => '%d / ',
'Limit rows' => 'Limitar filas',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Adminer no soporta el acceso a bases de datos sin contraseña, <a href="https://www.adminer.org/en/password/"%s>más informacion</a>.',
'Default value' => 'Valor por defecto',
'Full table scan' => null,
'Too many unsuccessful logins, try again in %d minute(s).' => array(),
'Too many unsuccessful logins, try again in %d minute(s).' => array('Demasiados intentos erroneos, pruebe de nuevo en %d minuto.', 'Demasiados intentos erroneos, pruebe de nuevo en %d minutos.'),
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => null,
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => null,
'The action will be performed after successful login with the same credentials.' => null,
'Connecting to privileged ports is not allowed.' => null,
'There is a space in the input password which might be the cause.' => null,
'If you did not send this request from Adminer then close this page.' => null,
'You can upload a big SQL file via FTP and import it from server.' => null,
'Size' => null,
'Compute' => null,
'You are offline.' => null,
'You have no privileges to update this table.' => null,
'Saving' => null,
'Unknown error.' => null,
'Database does not support password.' => null,
'Disable %s or enable %s or %s extensions.' => null,
'yes' => null,
'no' => null,
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'La contraseña Maestra ha expirado. <a href="https://www.adminer.org/en/extension/"%s>Implementar</a> %s un metodo para hacerla permanente.',
'The action will be performed after successful login with the same credentials.' => 'La acción se realizará tras iniciar sesión de nuevo con las mismas credenciales.',
'Connecting to privileged ports is not allowed.' => 'La conexion a puertos especiales no está permitida.',
'There is a space in the input password which might be the cause.' => 'Hay un espacio en la contraseña introducida, lo que puede ser la causa.',
'If you did not send this request from Adminer then close this page.' => 'Si no mandó ésta solicitud desde Adminer entonces cierre esta página.',
'You can upload a big SQL file via FTP and import it from server.' => 'Puede cargar un fichero SQL grande por FTP e importarlo desde el servidor.',
'Size' => 'Tamaño',
'Compute' => 'Procesar',
'You are offline.' => 'Se encuentra desconectado.',
'You have no privileges to update this table.' => 'No tiene privilegios para actualizar esta tabla.',
'Saving' => 'Guardando',
'Unknown error.' => 'Error desconocido.',
'Database does not support password.' => 'La Base de Datos no soporta el uso de contraseña.',
'Disable %s or enable %s or %s extensions.' => 'Deshabilitar %s o habilitar %s o %s extensiones.',
'yes' => 'si',
'no' => 'no',
'Columns' => null,
'Nullable' => null,
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Logi sisse',
'Logout successful.' => 'Väljalogimine õnnestus.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Loo uus andmebaas',
'SQL command' => 'SQL-Päring',
'Logout' => 'Logi välja',
'database' => 'andmebaas',
'Use' => 'Kasuta',
'No tables.' => 'Tabeleid ei leitud.',
'select' => 'kuva',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Tabeli valimine ebaõnnestus',
'Invalid CSRF token. Send the form again.' => 'Sobimatu CSRF, palun postitage vorm uuesti.',
'Comment' => 'Kommentaar',
'Default values' => 'Vaikimisi väärtused',
'%d byte(s)' => array('%d bait', '%d baiti'),
'No commands to execute.' => 'Käsk puudub.',
'Unable to upload a file.' => 'Faili üleslaadimine pole võimalik.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Kloon',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maksimaalne väljade arv ületatud. Palun suurendage %s.',
'Partition by' => 'Partitsiooni',
'Partition' => null,
'Partitions' => 'Partitsioonid',
'Partition name' => 'Partitsiooni nimi',
'Values' => 'Väärtused',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Jäta mind meelde',
'Databases have been dropped.' => 'Andmebaasid on edukalt kustutatud.',
'Search data in tables' => 'Otsi kogu andmebaasist',
'as a regular expression' => null,
'Schema' => 'Struktuur',
'Alter schema' => 'Muuda struktuuri',
'Create schema' => 'Loo struktuur',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'سیستم',
'Server' => 'سرور',
'Username' => 'نام کاربری',
@@ -77,7 +78,6 @@ $translations = array(
'Data' => 'داده',
'Database' => 'پایگاه داده',
'database' => 'پایگاه داده',
'Use' => 'استفاده',
'Select database' => 'انتخاب پایگاه داده',
'Invalid database.' => 'پایگاه داده نامعتبر.',
@@ -164,7 +164,6 @@ $translations = array(
'Options' => 'اختیارات',
'Comment' => 'توضیح',
'Default value' => 'مقدار پیش فرض',
'Default values' => 'مقادیر پیش فرض',
'Drop' => 'حذف',
'Are you sure?' => 'مطمئن هستید؟',
'Size' => 'حجم',
@@ -175,6 +174,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'حداکثر تعداد فیلدهای مجاز اشباع شد. لطفا %s را افزایش دهید.',
'Partition by' => 'بخشبندی توسط',
'Partition' => null,
'Partitions' => 'بخشبندیها',
'Partition name' => 'نام بخش',
'Values' => 'مقادیر',
@@ -229,6 +229,7 @@ $translations = array(
'Search' => 'جستجو',
'anywhere' => 'هرکجا',
'Search data in tables' => 'جستجوی داده در جدول',
'as a regular expression' => null,
'Sort' => 'مرتب کردن',
'descending' => 'نزولی',
'Limit' => 'محدودیت',
@@ -355,4 +356,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Järjestelmä',
'Server' => 'Palvelin',
'Username' => 'Käyttäjänimi',
@@ -79,7 +80,6 @@ $translations = array(
'Data' => 'Data',
'Database' => 'Tietokanta',
'database' => 'tietokanta',
'Use' => 'Käytä',
'Select database' => 'Valitse tietokanta',
'Invalid database.' => 'Tietokanta ei kelpaa.',
@@ -166,7 +166,6 @@ $translations = array(
'Options' => 'Asetukset',
'Comment' => 'Kommentit',
'Default value' => 'Oletusarvo',
'Default values' => 'Oletusarvot',
'Drop' => 'Poista',
'Are you sure?' => 'Oletko varma?',
'Size' => 'Koko',
@@ -177,6 +176,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Kenttien sallittu enimmäismäärä ylitetty. Kasvata arvoa %s.',
'Partition by' => 'Osioi arvolla',
'Partition' => null,
'Partitions' => 'Osiot',
'Partition name' => 'Osion nimi',
'Values' => 'Arvot',
@@ -231,6 +231,7 @@ $translations = array(
'Search' => 'Hae',
'anywhere' => 'kaikkialta',
'Search data in tables' => 'Hae dataa tauluista',
'as a regular expression' => null,
'Sort' => 'Lajittele',
'descending' => 'alenevasti',
'Limit' => 'Raja',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Ei',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Authentification',
'Logout successful.' => 'Au revoir !',
'Invalid server or credentials.' => null,
@@ -30,7 +31,6 @@ $translations = array(
'Create database' => 'Créer une base de données',
'SQL command' => 'Requête SQL',
'Logout' => 'Déconnexion',
'database' => 'base de données',
'Use' => 'Utiliser',
'No tables.' => 'Aucune table.',
'select' => 'select',
@@ -67,7 +67,6 @@ $translations = array(
'Unable to select the table' => 'Impossible de sélectionner la table',
'Invalid CSRF token. Send the form again.' => 'Token CSRF invalide. Veuillez renvoyer le formulaire.',
'Comment' => 'Commentaire',
'Default values' => 'Valeurs par défaut',
'%d byte(s)' => array('%d octet', '%d octets'),
'No commands to execute.' => 'Aucune commande à exécuter.',
'Unable to upload a file.' => 'Impossible d\'importer le fichier.',
@@ -188,6 +187,7 @@ $translations = array(
'Clone' => 'Cloner',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Le nombre maximum de champs est dépassé. Veuillez augmenter %s.',
'Partition by' => 'Partitionner par',
'Partition' => null,
'Partitions' => 'Partitions',
'Partition name' => 'Nom de la partition',
'Values' => 'Valeurs',
@@ -223,6 +223,7 @@ $translations = array(
'Databases have been dropped.' => 'Les bases de données ont été supprimées.',
'Database has been dropped.' => 'La base de données a été supprimée.',
'Search data in tables' => 'Rechercher dans les tables',
'as a regular expression' => 'sous forme d\'expression régulière',
'Schema' => 'Schéma',
'Alter schema' => 'Modifier le schéma',
'Create schema' => 'Créer un schéma',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Non',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Conectar',
'Logout successful.' => 'Pechouse a sesión con éxito.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Crear Base de datos',
'SQL command' => 'Comando SQL',
'Logout' => 'Pechar sesión',
'database' => 'base de datos',
'Use' => 'Usar',
'No tables.' => 'Nengunha táboa.',
'select' => 'selecciona',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'No é posible seleccionar a táboa',
'Invalid CSRF token. Send the form again.' => 'Token CSRF inválido. Envíe de novo os datos do formulario.',
'Comment' => 'Comentario',
'Default values' => 'Valores predeterminados',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Non hai comandos para executar.',
'Unable to upload a file.' => 'Non é posible importar o ficheiro.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Excedida o número máximo de campos permitidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
'Partition' => null,
'Partitions' => 'Particións',
'Partition name' => 'Nome da Partición',
'Values' => 'Valores',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Permanecer conectado',
'Databases have been dropped.' => 'Elimináronse as bases de datos.',
'Search data in tables' => 'Buscar datos en táboas',
'as a regular expression' => null,
'Schema' => 'Esquema',
'Alter schema' => 'Modificar esquema',
'Create schema' => 'Crear esquema',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Non',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'התחברות',
'Logout successful.' => 'ההתחברות הצליחה',
'Invalid server or credentials.' => null,
@@ -30,7 +31,6 @@ $translations = array(
'Create database' => 'צור מסד נתונים',
'SQL command' => 'שאילתת SQL',
'Logout' => 'התנתק',
'database' => 'מסד נתונים',
'Use' => 'השתמש',
'No tables.' => 'אין טבלאות',
'select' => 'בחר',
@@ -67,7 +67,6 @@ $translations = array(
'Unable to select the table' => 'בחירת הטבלה נכשלה',
'Invalid CSRF token. Send the form again.' => 'כשל באבטחת נתונים, שלח טופס שוב',
'Comment' => 'הערה',
'Default values' => 'ערכי ברירת מחדל',
'%d byte(s)' => '%d בתים',
'No commands to execute.' => 'לא נמצאו פקודות להרצה',
'Unable to upload a file.' => 'העלאת הקובץ נכשלה',
@@ -188,6 +187,7 @@ $translations = array(
'Clone' => 'שכפל',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'הגעת למספר השדות המרבי. בבקשה הגדל את %s',
'Partition by' => 'מחיצות ע"י',
'Partition' => null,
'Partitions' => 'מחיצות',
'Partition name' => 'שם מחיצה',
'Values' => 'ערכים',
@@ -223,6 +223,7 @@ $translations = array(
'Databases have been dropped.' => 'מסד הנתונים הושלך',
'Database has been dropped.' => 'מסד הנתונים הושלך',
'Search data in tables' => 'חפש מידע בטבלאות',
'as a regular expression' => null,
'Schema' => 'סכמה',
'Alter schema' => 'שנה סכמה',
'Create schema' => 'צור סכמה',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Belépés',
'Logout successful.' => 'Sikeres kilépés.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Adatbázis létrehozása',
'SQL command' => 'SQL parancs',
'Logout' => 'Kilépés',
'database' => 'adatbázis',
'Use' => 'Használ',
'No tables.' => 'Nincs tábla.',
'select' => 'kiválasztás',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Nem tudom kiválasztani a táblát',
'Invalid CSRF token. Send the form again.' => 'Érvénytelen CSRF azonosító. Küldd újra az űrlapot.',
'Comment' => 'Megjegyzés',
'Default values' => 'Alapértelmezett értékek',
'%d byte(s)' => array('%d bájt', '%d bájt', '%d bájt'),
'No commands to execute.' => 'Nincs végrehajtható parancs.',
'Unable to upload a file.' => 'Nem tudom feltölteni a fájlt.',
@@ -189,6 +188,7 @@ $translations = array(
'Tables have been dropped.' => 'Táblák eldobva.',
'Clone' => 'Klónoz',
'Partition by' => 'Particionálás ezzel',
'Partition' => null,
'Partitions' => 'Particiók',
'Partition name' => 'Partició neve',
'Values' => 'Értékek',
@@ -250,6 +250,7 @@ $translations = array(
'Type has been created.' => 'Típus létrehozva.',
'Alter type' => 'Típus módosítása',
'Search data in tables' => 'Keresés a táblákban',
'as a regular expression' => null,
'From server' => 'Szerverről',
'empty' => 'üres',
'now' => 'most',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistem',
'Server' => 'Server',
'Username' => 'Pengguna',
@@ -73,7 +74,6 @@ $translations = array(
'Data' => 'Data',
'Database' => 'Basis data',
'database' => 'basis data',
'Use' => 'Gunakan',
'Select database' => 'Pilih basis data',
'Invalid database.' => 'Basis data tidak sah.',
@@ -158,7 +158,6 @@ $translations = array(
'Auto Increment' => 'Inkrementasi Otomatis',
'Options' => 'Opsi',
'Comment' => 'Komentar',
'Default values' => 'Nilai bawaan',
'Drop' => 'Hapus',
'Are you sure?' => 'Anda yakin?',
'Move up' => 'Naik',
@@ -167,6 +166,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Sudah lebih dumlah ruas maksimum yang diizinkan. Harap naikkan %s.',
'Partition by' => 'Partisi menurut',
'Partition' => null,
'Partitions' => 'Partisi',
'Partition name' => 'Nama partisi',
'Values' => 'Nilai',
@@ -220,6 +220,7 @@ $translations = array(
'Search' => 'Cari',
'anywhere' => 'di mana pun',
'Search data in tables' => 'Cari data dalam tabel',
'as a regular expression' => null,
'Sort' => 'Urutkan',
'descending' => 'menurun',
'Limit' => 'Batas',
@@ -355,4 +356,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Autenticazione',
'Logout successful.' => 'Uscita effettuata con successo.',
'Invalid server or credentials.' => 'Server o credenziali non valide.',
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Crea database',
'SQL command' => 'Comando SQL',
'Logout' => 'Esci',
'database' => 'database',
'Use' => 'Usa',
'No tables.' => 'No tabelle.',
'select' => 'seleziona',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Selezione della tabella non riuscita',
'Invalid CSRF token. Send the form again.' => 'Token CSRF non valido. Reinvia la richiesta.',
'Comment' => 'Commento',
'Default values' => 'Valori predefiniti',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Nessun commando da eseguire.',
'Unable to upload a file.' => 'Caricamento del file non riuscito.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Clona',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Troppi campi. Per favore aumentare %s.',
'Partition by' => 'Partiziona per',
'Partition' => null,
'Partitions' => 'Partizioni',
'Partition name' => 'Nome partizione',
'Values' => 'Valori',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Login permanente',
'Databases have been dropped.' => 'Database eliminati.',
'Search data in tables' => 'Cerca nelle tabelle',
'as a regular expression' => 'come espressione regolare',
'Schema' => 'Schema',
'Alter schema' => 'Modifica schema',
'Create schema' => 'Crea schema',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'No',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'ログイン',
'Logout successful.' => 'ログアウト',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'データベースを作成',
'SQL command' => 'SQLコマンド',
'Logout' => 'ログアウト',
'database' => 'データベース',
'Use' => '使用',
'No tables.' => 'テーブルがありません。',
'select' => '選択',
@@ -68,7 +68,6 @@ $translations = array(
'Unable to select the table' => 'テーブルを選択できません',
'Invalid CSRF token. Send the form again.' => '不正なCSRFトークン。再送信してください',
'Comment' => 'コメント',
'Default values' => '規定値',
'%d byte(s)' => '%d バイト',
'No commands to execute.' => '実行するコマンドがありません',
'Unable to upload a file.' => 'ファイルをアップロードできません',
@@ -189,6 +188,7 @@ $translations = array(
'Clone' => 'クローン',
'Maximum number of allowed fields exceeded. Please increase %s.' => '定義可能な最大フィールド数を越えました。%s を増やしてください。',
'Partition by' => 'パーティション',
'Partition' => null,
'Partitions' => 'パーティション',
'Partition name' => 'パーティション名',
'Values' => '値',
@@ -225,6 +225,7 @@ $translations = array(
'Permanent login' => '永続的にログイン',
'Databases have been dropped.' => 'データベースを削除しました',
'Search data in tables' => 'データを検索する',
'as a regular expression' => null,
'Schema' => 'スキーマ',
'Alter schema' => 'スキーマ変更',
'Create schema' => 'スキーマ追加',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'შესვლა',
'Logout successful.' => 'გამოხვედით სისტემიდან.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'ბაზის შექმნა',
'SQL command' => 'SQL-ბრძანება',
'Logout' => 'გასვლა',
'database' => 'ბაზა',
'Use' => 'არჩევა',
'No tables.' => 'ბაზაში ცხრილი არაა.',
'select' => 'არჩევა',
@@ -68,7 +68,6 @@ $translations = array(
'Unable to select the table' => 'ცხრილიდან ინფორმაცია ვერ მოვიპოვე',
'Invalid CSRF token. Send the form again.' => 'უმოქმედო CSRF-ტოკენი. ფორმის კიდევ ერთხელ გაგზავნა.',
'Comment' => 'კომენტარები',
'Default values' => 'სტანდარტული მნიშვნელობა',
'%d byte(s)' => '%d ბაიტი',
'No commands to execute.' => 'შესასრულებელი ბრძანება არაა.',
'Unable to upload a file.' => 'ფაილი არ აიტვირთა სერვერზე.',
@@ -187,6 +186,7 @@ $translations = array(
'Tables have been dropped.' => 'ცხრილები წაიშალა.',
'Clone' => 'კლონირება',
'Partition by' => 'დაყოფა',
'Partition' => null,
'Partitions' => 'დანაყოფები',
'Partition name' => 'დანაყოფის სახელი',
'Values' => 'პარამეტრები',
@@ -220,6 +220,7 @@ $translations = array(
'Permanent login' => 'სისტემაში დარჩენა',
'Databases have been dropped.' => 'ბაზა წაიშალა.',
'Search data in tables' => 'ცხრილებში ძებნა',
'as a regular expression' => null,
'Schema' => 'სქემა',
'Alter schema' => 'სქემის შეცვლა',
'Create schema' => 'ახალი სქემა',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'$1-$3-$5' => '$1-$3-$5',
'%.3f s' => '%.3f 초',
'%d byte(s)' => '%d 바이트',
@@ -71,11 +72,9 @@ $translations = array(
'Database has been dropped.' => '데이터베이스를 삭제했습니다.',
'Database has been renamed.' => '데이터베이스의 이름을 바꾸었습니다.',
'Database schema' => '데이터베이스 구조',
'database' => '데이터베이스',
'Database' => '데이터베이스',
'Databases have been dropped.' => '데이터베이스를 삭제했습니다.',
'Date and time' => '시간',
'Default values' => '기본값',
'Delete' => '삭제',
'descending' => '역순',
'Drop' => '삭제',
@@ -172,6 +171,7 @@ $translations = array(
'Parameter name' => '매개변수 이름',
'Partition by' => '파티션',
'Partition name' => '파티션 이름',
'Partition' => null,
'Partitions' => '파티션',
'Password' => '비밀번호',
'Permanent link' => '영구적으로 링크',
@@ -204,6 +204,7 @@ $translations = array(
'Schema has been dropped.' => '스키마를 삭제했습니다.',
'Schema' => '스키마',
'Search data in tables' => '테이블 내 데이터 검색',
'as a regular expression' => null,
'Search' => '검색',
'Select data' => '데이터를 선택하십시오.',
'Select database' => '데이터베이스를 선택하십시오.',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistema',
'Server' => 'Serveris',
'Username' => 'Vartotojas',
@@ -73,7 +74,6 @@ $translations = array(
'Data' => 'Duomenys',
'Database' => 'Duomenų bazė',
'database' => 'duomenų bazė',
'Use' => 'Naudoti',
'Select database' => 'Pasirinkti duomenų bazę',
'Invalid database.' => 'Neteisinga duomenų bazė.',
@@ -157,7 +157,6 @@ $translations = array(
'Auto Increment' => 'Auto Increment',
'Options' => 'Nustatymai',
'Comment' => 'Komentaras',
'Default values' => 'Reikšmės pagal nutylėjimą',
'Drop' => 'Pašalinti',
'Are you sure?' => 'Tikrai?',
'Move up' => 'Perkelti į viršų',
@@ -166,6 +165,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Viršytas maksimalus leidžiamų stulpelių kiekis. Padidinkite %s.',
'Partition by' => 'Skirstyti pagal',
'Partition' => null,
'Partitions' => 'Skirsniai',
'Partition name' => 'Skirsnio pavadinimas',
'Values' => 'Reikšmės',
@@ -219,6 +219,7 @@ $translations = array(
'Search' => 'Ieškoti',
'anywhere' => 'visur',
'Search data in tables' => 'Ieškoti duomenų lentelėse',
'as a regular expression' => null,
'Sort' => 'Rikiuoti',
'descending' => 'mažėjimo tvarka',
'Limit' => 'Limitas',
@@ -355,4 +356,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Ieiet',
'Logout successful.' => 'Jūs veiksmīgi izgājāt no sistēmas.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Izveidot datubāzi',
'SQL command' => 'SQL pieprasījums',
'Logout' => 'Iziet',
'database' => 'datubāze',
'Use' => 'Lietot',
'No tables.' => 'Datubāzē nav tabulu.',
'select' => 'izvēlēties',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Tabula nav pieejama',
'Invalid CSRF token. Send the form again.' => 'Nederīgs CSRF žetons. Nosūtiet formu vēl vienu reizi.',
'Comment' => 'Komentārs',
'Default values' => 'Noklusētā vērtība',
'%d byte(s)' => array('%d baits', '%d baiti', '%d baiti'),
'No commands to execute.' => 'Nav izpildāmu komandu.',
'Unable to upload a file.' => 'Neizdevās ielādēt failu uz servera.',
@@ -189,6 +188,7 @@ $translations = array(
'Tables have been dropped.' => 'Tabulas dzēstas.',
'Clone' => 'Klonēt',
'Partition by' => 'Sadalīt pēc',
'Partition' => null,
'Partitions' => 'Partīcijas',
'Partition name' => 'Partīcijas nosaukums',
'Values' => 'Vērtības',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Atcerēties mani',
'Databases have been dropped.' => 'Datubāzes dzēstas.',
'Search data in tables' => 'Meklēt tabulās',
'as a regular expression' => null,
'Schema' => 'Shēma',
'Alter schema' => 'Izmainīt shēmu',
'Create schema' => 'Jauna shēma',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Nē',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistem',
'Server' => 'Pelayan',
'Username' => 'Nama pengguna',
@@ -82,7 +83,6 @@ $translations = array(
'Data' => 'Data',
'Database' => 'Pangkalan data',
'database' => 'pangkalan data',
'Use' => 'Guna',
'Select database' => 'Pilih pangkalan data',
'Invalid database.' => 'Pangkalan data tidak sah.',
@@ -169,7 +169,6 @@ $translations = array(
'Options' => 'Pilihan',
'Comment' => 'Komen',
'Default value' => 'Nilai lalai',
'Default values' => 'Nilai lalai',
'Drop' => 'Jatuh',
'Drop %s?' => 'Jatuhkan %s?',
'Are you sure?' => 'Anda pasti?',
@@ -181,6 +180,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Bilangan medan telah melebihi had yang dibenarkan. Sila tingkatkan %s.',
'Partition by' => 'Partition mengikut',
'Partition' => null,
'Partitions' => 'Partition',
'Partition name' => 'Nama partition',
'Values' => 'Nilai',
@@ -235,6 +235,7 @@ $translations = array(
'Search' => 'Cari',
'anywhere' => 'di mana-mana',
'Search data in tables' => 'Cari data dalam jadual',
'as a regular expression' => null,
'Sort' => 'Susun',
'descending' => 'menurun',
'Limit' => 'Had',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Tidak',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Aanmelden',
'Logout successful.' => 'Successvol afgemeld.',
'Invalid server or credentials.' => null,
@@ -32,7 +33,6 @@ $translations = array(
'Create database' => 'Database aanmaken',
'SQL command' => 'SQL opdracht',
'Logout' => 'Afmelden',
'database' => 'database',
'Use' => 'Gebruik',
'No tables.' => 'Geen tabellen.',
'select' => 'kies',
@@ -70,7 +70,6 @@ $translations = array(
'Unable to select the table' => 'Onmogelijk tabel te selecteren',
'Invalid CSRF token. Send the form again.' => 'Ongeldig CSRF token. Verstuur het formulier opnieuw.',
'Comment' => 'Commentaar',
'Default values' => 'Standaard waarden',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Geen opdrachten uit te voeren.',
'Unable to upload a file.' => 'Onmogelijk bestand te uploaden.',
@@ -191,6 +190,7 @@ $translations = array(
'Clone' => 'Dupliceer',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maximum aantal velden bereikt. Verhoog %s.',
'Partition by' => 'Partitioneren op',
'Partition' => null,
'Partitions' => 'Partities',
'Partition name' => 'Partitie naam',
'Values' => 'Waarden',
@@ -224,6 +224,7 @@ $translations = array(
'%d in total' => '%d in totaal',
'Permanent login' => 'Blijf aangemeld',
'Search data in tables' => 'Zoeken in database',
'as a regular expression' => 'als een regular expression',
'Schema' => 'Schema',
'Alter schema' => 'Schema wijzigen',
'Create schema' => 'Schema maken',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Neen',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'System' => 'System',
'Server' => 'Server',
'Username' => 'Brukernavn',
@@ -64,7 +65,6 @@ $translations = array(
'Format' => 'Format',
'Data' => 'Data',
'Database' => 'Database',
'database' => 'database',
'Use' => 'Bruk',
'Select database' => 'Velg database',
'Invalid database.' => 'Ugyldig database.',
@@ -143,7 +143,6 @@ $translations = array(
'Auto Increment' => 'Autoinkrement',
'Options' => 'Valg',
'Comment' => 'Kommentarer',
'Default values' => 'Standardverdier',
'Drop' => 'Dropp',
'Are you sure?' => 'Er du sikker?',
'Move up' => 'Flytt opp',
@@ -151,6 +150,7 @@ $translations = array(
'Remove' => 'Fjern',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maksimum antall feltnavn overskredet - venligst øk %s.',
'Partition by' => 'Partisjoner ved',
'Partition' => null,
'Partitions' => 'Partisjoner',
'Partition name' => 'Partisjonsnavn',
'Values' => 'Verdier',
@@ -199,6 +199,7 @@ $translations = array(
'Search' => 'Søk',
'anywhere' => 'hvorsomhelst',
'Search data in tables' => 'Søk data i tabeller',
'as a regular expression' => null,
'Sort' => 'Sorter',
'descending' => 'minkende',
'Limit' => 'Skranke',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Nei',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Rodzaj bazy',
'Server' => 'Serwer',
'Username' => 'Użytkownik',
@@ -81,7 +82,6 @@ $translations = array(
'Data' => 'Dane',
'Database' => 'Baza danych',
'database' => 'baza danych',
'Use' => 'Wybierz',
'Select database' => 'Wybierz bazę danych',
'Invalid database.' => 'Nie znaleziono bazy danych.',
@@ -168,7 +168,6 @@ $translations = array(
'Options' => 'Opcje',
'Comment' => 'Komentarz',
'Default value' => 'Wartość domyślna',
'Default values' => 'Wartości domyślne',
'Drop' => 'Usuń',
'Drop %s?' => 'Usunąć %s?',
'Are you sure?' => 'Czy jesteś pewien?',
@@ -180,6 +179,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Przekroczono maksymalną liczbę pól. Zwiększ %s.',
'Partition by' => 'Partycjonowanie',
'Partition' => null,
'Partitions' => 'Partycje',
'Partition name' => 'Nazwa partycji',
'Values' => 'Wartości',
@@ -234,6 +234,7 @@ $translations = array(
'Search' => 'Szukaj',
'anywhere' => 'gdziekolwiek',
'Search data in tables' => 'Wyszukaj we wszystkich tabelach',
'as a regular expression' => null,
'Sort' => 'Sortuj',
'descending' => 'malejąco',
'Limit' => 'Limit',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Nie',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Entrar',
'Logout successful.' => 'Saída bem sucedida.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Criar Base de dados',
'SQL command' => 'Comando SQL',
'Logout' => 'Sair',
'database' => 'base de dados',
'Use' => 'Usar',
'No tables.' => 'Não existem tabelas.',
'select' => 'selecionar',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Não é possível selecionar a Tabela',
'Invalid CSRF token. Send the form again.' => 'Token CSRF inválido. Enviar o formulário novamente.',
'Comment' => 'Comentário',
'Default values' => 'Valores padrões',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Nenhum comando para executar.',
'Unable to upload a file.' => 'Não é possível enviar o arquivo.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Quantidade máxima de campos permitidos excedidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
'Partition' => null,
'Partitions' => 'Partições',
'Partition name' => 'Nome da Partição',
'Values' => 'Valores',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Login permanente',
'Databases have been dropped.' => 'A Base de dados foi apagada.',
'Search data in tables' => 'Buscar dados nas Tabelas',
'as a regular expression' => null,
'Schema' => 'Esquema',
'Alter schema' => 'Alterar esquema',
'Create schema' => 'Criar esquema',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Entrar',
'Logout successful.' => 'Sessão terminada com sucesso.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Criar Base de dados',
'SQL command' => 'Comando SQL',
'Logout' => 'Terminar sessão',
'database' => 'base de dados',
'Use' => 'Usar',
'No tables.' => 'Não existem tabelas.',
'select' => 'registos',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Não é possivel selecionar a Tabela',
'Invalid CSRF token. Send the form again.' => 'Token CSRF inválido. Enviar o formulario novamente.',
'Comment' => 'Comentário',
'Default values' => 'Valores predeterminados',
'%d byte(s)' => array('%d byte', '%d bytes'),
'No commands to execute.' => 'Nenhum comando para executar.',
'Unable to upload a file.' => 'Não é possível enviar o ficheiro.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Quantidade máxima de campos permitidos excedidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
'Partition' => null,
'Partitions' => 'Partições',
'Partition name' => 'Nome da Partição',
'Values' => 'Valores',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Memorizar a senha',
'Databases have been dropped.' => 'Bases de dados eliminadas.',
'Search data in tables' => 'Pesquisar dados nas Tabelas',
'as a regular expression' => null,
'Schema' => 'Esquema',
'Alter schema' => 'Modificar esquema',
'Create schema' => 'Criar esquema',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Intră',
'Logout successful.' => 'Ați ieșit cu succes.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Crează baza de date',
'SQL command' => 'SQL query',
'Logout' => 'Ieșire',
'database' => 'baza de date',
'Use' => 'Alege',
'No tables.' => 'În baza de date nu sunt tabele.',
'select' => 'selectează',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Nu am putut selecta date din tabel',
'Invalid CSRF token. Send the form again.' => 'CSRF token imposibil. Retrimite forma.',
'Comment' => 'Comentariu',
'Default values' => 'Valoarea inițială',
'%d byte(s)' => array('%d octet', '%d octeți'),
'No commands to execute.' => 'Nu sunt comenzi de executat.',
'Unable to upload a file.' => 'Nu am putut încărca fișierul pe server.',
@@ -189,6 +188,7 @@ $translations = array(
'Tables have been dropped.' => 'Tabelele au fost șterse.',
'Clone' => 'Clonează',
'Partition by' => 'Împarte',
'Partition' => null,
'Partitions' => 'Secțiuni',
'Partition name' => 'Denumirea secțiunii',
'Values' => 'Parametru',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Logare permanentă',
'Databases have been dropped.' => 'Bazele de date au fost șterse.',
'Search data in tables' => 'Caută în tabele',
'as a regular expression' => null,
'Schema' => 'Schema',
'Alter schema' => 'Modifică schema',
'Create schema' => 'Crează o schemă',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'Войти',
'Logout successful.' => 'Вы успешно покинули систему.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'Создать базу данных',
'SQL command' => 'SQL-запрос',
'Logout' => 'Выйти',
'database' => 'база данных',
'Use' => 'Выбрать',
'No tables.' => 'В базе данных нет таблиц.',
'select' => 'выбрать',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'Не удалось получить данные из таблицы',
'Invalid CSRF token. Send the form again.' => 'Недействительный CSRF-токен. Отправите форму ещё раз.',
'Comment' => 'Комментарий',
'Default values' => 'Значения по умолчанию',
'%d byte(s)' => array('%d байт', '%d байта', '%d байтов'),
'No commands to execute.' => 'Нет команд для выполнения.',
'Unable to upload a file.' => 'Не удалось загрузить файл на сервер.',
@@ -189,6 +188,7 @@ $translations = array(
'Tables have been dropped.' => 'Таблицы были удалены.',
'Clone' => 'Клонировать',
'Partition by' => 'Разделить по',
'Partition' => null,
'Partitions' => 'Разделы',
'Partition name' => 'Название раздела',
'Values' => 'Параметры',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'Оставаться в системе',
'Databases have been dropped.' => 'Базы данных удалены.',
'Search data in tables' => 'Поиск в таблицах',
'as a regular expression' => 'как регулярное выражение',
'Schema' => 'Схема',
'Alter schema' => 'Изменить схему',
'Create schema' => 'Новая схема',
@@ -310,4 +311,10 @@ $translations = array(
'No' => 'Нет',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => 'Domov',
'Login' => 'Prihlásiť sa',
'Logout successful.' => 'Odhlásenie prebehlo v poriadku.',
'Invalid server or credentials.' => 'Neplatný server alebo prihlasovacie údaje.',
@@ -32,7 +33,6 @@ $translations = array(
'Create database' => 'Vytvoriť databázu',
'SQL command' => 'SQL príkaz',
'Logout' => 'Odhlásiť',
'database' => 'databáza',
'Use' => 'Vybrať',
'No tables.' => 'Žiadne tabuľky.',
'select' => 'vypísať',
@@ -70,7 +70,6 @@ $translations = array(
'Unable to select the table' => 'Tabuľku sa nepodarilo vypísať',
'Invalid CSRF token. Send the form again.' => 'Neplatný token CSRF. Odošlite formulár znova.',
'Comment' => 'Komentár',
'Default values' => 'Predvolené hodnoty',
'%d byte(s)' => array('%d bajt', '%d bajty', '%d bajtov'),
'No commands to execute.' => 'Žiadne príkazy na vykonanie.',
'Unable to upload a file.' => 'Súbor sa nepodarilo nahrať.',
@@ -78,6 +77,8 @@ $translations = array(
'File uploads are disabled.' => 'Nahrávánie súborov nie je povolené.',
'Routine has been called, %d row(s) affected.' => array('Procedúra bola zavolaná, bol zmenený %d záznam.', 'Procedúra bola zavolaná, boli zmenené %d záznamy.', 'Procedúra bola zavolaná, bolo zmenených %d záznamov.'),
'Call' => 'Zavolať',
'No driver' => 'Žiadny ovládač',
'Database driver not found.' => 'Databázový ovládač sa nenašiel.',
'No extension' => 'Žiadne rozšírenie',
'None of the supported PHP extensions (%s) are available.' => 'Nie je dostupné žiadne z podporovaných rozšírení (%s).',
'Session support must be enabled.' => 'Session premenné musia byť povolené.',
@@ -190,6 +191,7 @@ $translations = array(
'Whole result' => 'Celý výsledok',
'Clone' => 'Klonovať',
'Partition by' => 'Rozdeliť podľa',
'Partition' => 'Oddiel',
'Partitions' => 'Oddiely',
'Partition name' => 'Názov oddielu',
'Values' => 'Hodnoty',
@@ -224,6 +226,7 @@ $translations = array(
'Permanent login' => 'Trvalé prihlásenie',
'%d in total' => '%d celkom',
'Search data in tables' => 'Vyhľadať dáta v tabuľkách',
'as a regular expression' => 'ako regulárny výraz',
'Alter schema' => 'Pozmeniť schému',
'Create schema' => 'Vytvoriť schému',
'Schema has been dropped.' => 'Schéma bola odstránená.',
@@ -256,7 +259,7 @@ $translations = array(
'%d query(s) executed OK.' => array('Bol vykonaný %d dotaz.', 'Boli vykonané %d dotazy.', 'Bolo vykonaných %d dotazov.'),
'Show only errors' => 'Zobraziť iba chyby',
'Refresh' => 'Obnoviť',
'Invalid schema.' => 'Neplatné schéma.',
'Invalid schema.' => 'Neplatná schéma.',
'Please use one of the extensions %s.' => 'Prosím vyberte jednu z koncoviek %s.',
'now' => 'teraz',
'ltr' => 'ltr',
@@ -274,8 +277,8 @@ $translations = array(
'DB' => 'DB',
'File must be in UTF-8 encoding.' => 'Súbor musí byť v kódovaní UTF-8.',
'Modify' => 'Zmeniť',
'Load more data' => 'Nahráť ďalšie dáta',
'Loading' => 'Nahráva sa',
'Load more data' => 'Načítať ďalšie dáta',
'Loading' => 'Načítava sa',
'ATTACH queries are not supported.' => 'Dotazy ATTACH nie sú podporované.',
'Warnings' => 'Varovania',
'%d / ' => '%d / ',
@@ -308,4 +311,7 @@ $translations = array(
'Default' => 'Predvolené',
'One Time Password' => 'Jednorázové heslo',
'Invalid OTP code.' => 'Neplatný kód OTP.',
'Schemas' => 'Schémy',
'No schemas.' => 'Žiadne schémy.',
'Show schema' => 'Zobraziť schému',
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistem',
'Server' => 'Strežnik',
'Username' => 'Uporabniško ime',
@@ -72,7 +73,6 @@ $translations = array(
'Data' => 'Podatki',
'Database' => 'Baza',
'database' => 'baza',
'Use' => 'Uporabi',
'Select database' => 'Izberi bazo',
'Invalid database.' => 'Neveljavna baza.',
@@ -153,7 +153,6 @@ $translations = array(
'Auto Increment' => 'Samodejno povečevanje',
'Options' => 'Možnosti',
'Comment' => 'Komentar',
'Default values' => 'Privzete vrednosti',
'Drop' => 'Zavrzi',
'Are you sure?' => 'Ste prepričani?',
'Move up' => 'Premakni gor',
@@ -162,6 +161,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Največje število dovoljenih polje je preseženo. Prosimo, povečajte %s.',
'Partition by' => 'Porazdeli po',
'Partition' => null,
'Partitions' => 'Porazdelitve',
'Partition name' => 'Ime porazdelitve',
'Values' => 'Vrednosti',
@@ -215,6 +215,7 @@ $translations = array(
'Search' => 'Išči',
'anywhere' => 'kjerkoli',
'Search data in tables' => 'Išče podatke po tabelah',
'as a regular expression' => null,
'Sort' => 'Sortiraj',
'descending' => 'padajoče',
'Limit' => 'Limita',
@@ -352,4 +353,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Систем',
'Server' => 'Сервер',
'Username' => 'Корисничко име',
@@ -73,7 +74,6 @@ $translations = array(
'Data' => 'Податци',
'Database' => 'База података',
'database' => 'база података',
'Use' => 'Користи',
'Select database' => 'Изаберите базу',
'Invalid database.' => 'Неисправна база података.',
@@ -158,7 +158,6 @@ $translations = array(
'Auto Increment' => 'Ауто-прираштај',
'Options' => 'Опције',
'Comment' => 'Коментар',
'Default values' => 'Подразумеване вредности',
'Drop' => 'Избриши',
'Are you sure?' => 'Да ли сте сигурни?',
'Move up' => 'Помери на горе',
@@ -167,6 +166,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Премашен је максимални број дозвољених поља. Молим увећајте %s.',
'Partition by' => 'Подели по',
'Partition' => null,
'Partitions' => 'Поделе',
'Partition name' => 'Име поделе',
'Values' => 'Вредности',
@@ -220,6 +220,7 @@ $translations = array(
'Search' => 'Претрага',
'anywhere' => 'било где',
'Search data in tables' => 'Претражи податке у табелама',
'as a regular expression' => null,
'Sort' => 'Поређај',
'descending' => 'опадајуће',
'Limit' => 'Граница',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Не',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'System',
'Server' => 'Server',
'Username' => 'Användarnamn',
@@ -89,7 +90,6 @@ $translations = array(
'Data' => 'Data',
'Database' => 'Databas',
'database' => 'databas',
'DB' => 'DB',
'Use' => 'Använd',
'Select database' => 'Välj databas',
@@ -178,7 +178,6 @@ $translations = array(
'Options' => 'Inställningar',
'Comment' => 'Kommentar',
'Default value' => 'Standardvärde',
'Default values' => 'Standardvärden',
'Drop' => 'Ta bort',
'Drop %s?' => 'Ta bort %s?',
'Are you sure?' => 'Är du säker?',
@@ -190,6 +189,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Högsta nummer tillåtna fält är överskridet. Vänligen höj %s.',
'Partition by' => 'Partitionera om',
'Partition' => null,
'Partitions' => 'Partitioner',
'Partition name' => 'Partition',
'Values' => 'Värden',
@@ -244,6 +244,7 @@ $translations = array(
'Search' => 'Sök',
'anywhere' => 'överallt',
'Search data in tables' => 'Sök data i tabeller',
'as a regular expression' => null,
'Sort' => 'Sortera',
'descending' => 'Fallande',
'Limit' => 'Begränsning',
@@ -354,4 +355,10 @@ $translations = array(
'No' => 'Nej',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'நுழை',
'Logout successful.' => 'வெற்றிக‌ர‌மாய் வெளியேறியாயிற்று.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'த‌க‌வ‌ல்த‌ள‌த்தை உருவாக்கு',
'SQL command' => 'SQL க‌ட்ட‌ளை',
'Logout' => 'வெளியேறு',
'database' => 'த‌க‌வ‌ல்த‌ள‌ம்',
'Use' => 'உப‌யோகி',
'No tables.' => 'அட்ட‌வ‌ணை இல்லை.',
'select' => 'தேர்வு செய்',
@@ -68,7 +68,6 @@ $translations = array(
'Unable to select the table' => 'அட்ட‌வ‌ணையை தேர்வு செய்ய‌ முடிய‌வில்லை',
'Invalid CSRF token. Send the form again.' => 'CSRF டோக்க‌ன் செல்லாது. ப‌டிவ‌த்தை மீண்டும் அனுப்ப‌வும்.',
'Comment' => 'குறிப்பு',
'Default values' => 'உள்ளிருக்கும் (Default) ம‌திப்புக‌ள் ',
'%d byte(s)' => array('%d பைட்', '%d பைட்டுக‌ள்'),
'No commands to execute.' => 'செய‌ல் ப‌டுத்த‌ எந்த‌ க‌ட்ட‌ளைக‌ளும் இல்லை.',
'Unable to upload a file.' => 'கோப்பை மேலேற்ற‌ம் (upload) செய்ய‌ இயல‌வில்லை.',
@@ -187,6 +186,7 @@ $translations = array(
'Clone' => 'ந‌க‌லி (Clone)',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'அனும‌திக்க‌ப்ப‌ட்ட‌ அதிக‌ப‌ட்ச‌ கோப்புக‌ளின் எண்ணிக்கை மீற‌ப்ப‌ட்ட‌து. த‌ய‌வு செய்து %s ம‌ற்றும் %s யை அதிக‌ரிக்க‌வும்.',
'Partition by' => 'பிரித்த‌து',
'Partition' => null,
'Partitions' => 'பிரிவுக‌ள்',
'Partition name' => 'பிரிவின் பெய‌ர்',
'Values' => 'ம‌திப்புக‌ள்',
@@ -224,6 +224,7 @@ $translations = array(
'Alter schema' => 'அமைப்புமுறையை மாற்று',
'Create schema' => 'அமைப்புமுறையை உருவாக்கு',
'Search data in tables' => 'த‌க‌வ‌லை அட்ட‌வ‌ணையில் தேடு',
'as a regular expression' => null,
'Sequences' => 'வ‌ரிசைமுறை',
'Create sequence' => 'வ‌ரிசைமுறையை உருவாக்கு',
'User types' => 'ப‌ய‌னாள‌ர் வ‌கைக‌ள்',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,5 +1,6 @@
<?php
$translations = array(
'Home' => null,
'Login' => 'เข้าสู่ระบบ',
'Logout successful.' => 'ออกจากระบบเรียบร้อยแล้ว.',
'Invalid server or credentials.' => null,
@@ -31,7 +32,6 @@ $translations = array(
'Create database' => 'สร้างฐานข้อมูล',
'SQL command' => 'คำสั่ง SQL',
'Logout' => 'ออกจากระบบ',
'database' => 'ฐานข้อมูล',
'Use' => 'ใช้งาน',
'No tables.' => 'ไม่พบตาราง.',
'select' => 'เลือก',
@@ -69,7 +69,6 @@ $translations = array(
'Unable to select the table' => 'ไม่สามารถเลือกตารางได้',
'Invalid CSRF token. Send the form again.' => 'เครื่องหมาย CSRF ไม่ถูกต้อง ส่งข้อมูลใหม่อีกครั้ง.',
'Comment' => 'หมายเหตุ',
'Default values' => 'ค่าเริ่มต้น',
'%d byte(s)' => '%d ไบท์',
'No commands to execute.' => 'ไม่มีคำสั่งที่จะประมวลผล.',
'Unable to upload a file.' => 'ไม่สามารถอัปโหลดไฟล์ได้.',
@@ -190,6 +189,7 @@ $translations = array(
'Clone' => 'ทำซ้ำ',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'จำนวนสูงสุดของฟิลด์อนุญาตให้เกิน กรุณาเพิ่มอีก %s.',
'Partition by' => 'พาร์ทิชันโดย',
'Partition' => null,
'Partitions' => 'พาร์ทิชัน',
'Partition name' => 'ชื่อของพาร์ทิชัน',
'Values' => 'ค่า',
@@ -224,6 +224,7 @@ $translations = array(
'Permanent login' => 'จดจำการเข้าสู่ระบบตลอดไป',
'Databases have been dropped.' => 'ฐานข้อมูลถูกลบแล้ว.',
'Search data in tables' => 'ค้นหาในตาราง',
'as a regular expression' => null,
'Schema' => 'Schema',
'Alter schema' => 'เปลี่ยนแปลง schema',
'Create schema' => 'สร้าง schema',
@@ -310,4 +311,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Sistem',
'Server' => 'Sunucu',
'Username' => 'Kullanıcı',
@@ -84,7 +85,6 @@ $translations = array(
'Data' => 'Veri',
'Database' => 'Veri Tabanı',
'database' => 'veri tabanı',
'DB' => 'DB',
'Use' => 'Kullan',
'Select database' => 'Veri tabanı seç',
@@ -172,7 +172,6 @@ $translations = array(
'Options' => 'Seçenekler',
'Comment' => 'Yorum',
'Default value' => 'Varsayılan değer',
'Default values' => 'Varsayılan değerler',
'Drop' => 'Sil',
'Drop %s?' => 'Sil %s?',
'Are you sure?' => 'Emin misiniz?',
@@ -184,6 +183,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'İzin verilen en fazla alan sayısııldı. Lütfen %s değerlerini artırın.',
'Partition by' => 'Bununla bölümle',
'Partition' => null,
'Partitions' => 'Bölümler',
'Partition name' => 'Bölüm adı',
'Values' => 'Değerler',
@@ -238,6 +238,7 @@ $translations = array(
'Search' => 'Ara',
'anywhere' => 'hiçbir yerde',
'Search data in tables' => 'Tablolarda veri ara',
'as a regular expression' => null,
'Sort' => 'Sırala',
'descending' => 'Azalan',
'Limit' => 'Limit',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Hayır',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Система Бази Даних',
'Server' => 'Сервер',
'Username' => 'Користувач',
@@ -73,7 +74,6 @@ $translations = array(
'Data' => 'Дані',
'Database' => 'База даних',
'database' => 'база даних',
'Use' => 'Обрати',
'Select database' => 'Обрати базу даних',
'Invalid database.' => 'Погана база даних.',
@@ -158,7 +158,6 @@ $translations = array(
'Auto Increment' => 'Автоматичне збільшення',
'Options' => 'Опції',
'Comment' => 'Коментарі',
'Default values' => 'Значення за замовчуванням',
'Drop' => 'Видалити',
'Are you sure?' => 'Ви впевнені?',
'Move up' => 'Пересунути вгору',
@@ -167,6 +166,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Досягнута максимальна кількість доступних полів. Будь ласка, збільшіть %s.',
'Partition by' => 'Розділити по',
'Partition' => null,
'Partitions' => 'Розділи',
'Partition name' => 'Назва розділу',
'Values' => 'Значення',
@@ -220,6 +220,7 @@ $translations = array(
'Search' => 'Пошук',
'anywhere' => 'будь-де',
'Search data in tables' => 'Шукати дані в таблицях',
'as a regular expression' => null,
'Sort' => 'Сортувати',
'descending' => 'по спаданню',
'Limit' => 'Обмеження',
@@ -355,4 +356,10 @@ $translations = array(
'No' => 'Ні',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => 'Hệ thống',
'Server' => 'Máy chủ',
'Username' => 'Tên người dùng',
@@ -76,7 +77,6 @@ $translations = array(
'Data' => 'Dữ liệu',
'Database' => 'Cơ sở dữ liệu',
'database' => 'cơ sở dữ liệu',
'Use' => 'Sử dụng',
'Select database' => 'Chọn CSDL',
'Invalid database.' => 'CSDL sai.',
@@ -161,7 +161,6 @@ $translations = array(
'Auto Increment' => 'Tăng tự động',
'Options' => 'Tuỳ chọn',
'Comment' => 'Chú thích',
'Default values' => 'Giá trị mặc định',
'Drop' => 'Xoá',
'Are you sure?' => 'Bạn có chắc',
'Size' => 'Kích thước',
@@ -172,6 +171,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Thiết lập %s cần tăng thêm. (Đã vượt giới hạnố trường tối đa cho phép trong một biểu mẫu).',
'Partition by' => 'Phân chia bằng',
'Partition' => null,
'Partitions' => 'Phân hoạch',
'Partition name' => 'Tên phân hoạch',
'Values' => 'Giá trị',
@@ -225,6 +225,7 @@ $translations = array(
'Search' => 'Tìm kiếm',
'anywhere' => 'bất cứ đâu',
'Search data in tables' => 'Tìm kiếm dữ liệu trong các bảng',
'as a regular expression' => null,
'Sort' => 'Sắp xếp',
'descending' => 'giảm dần',
'Limit' => 'Giới hạn',
@@ -354,4 +355,10 @@ $translations = array(
'No' => 'Không',
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => 'Xx',
'System' => 'Xx',
'Server' => 'Xx',
'Username' => 'Xx',
@@ -20,6 +21,8 @@ $translations = array(
'Language' => 'Xx',
'Invalid CSRF token. Send the form again.' => 'Xx.',
'If you did not send this request from Adminer then close this page.' => 'Xx.',
'No driver' => 'Xx',
'Database driver not found.' => 'Xx.',
'No extension' => 'Xx',
'None of the supported PHP extensions (%s) are available.' => 'Xx (%s).',
'Connecting to privileged ports is not allowed.' => 'Xx.',
@@ -89,7 +92,6 @@ $translations = array(
'Data' => 'Xx',
'Database' => 'Xx',
'database' => 'xx',
'DB' => 'XX',
'Use' => 'Xx',
'Select database' => 'Xx',
@@ -178,7 +180,6 @@ $translations = array(
'Options' => 'Xx',
'Comment' => 'Xx',
'Default value' => 'Xx',
'Default values' => 'Xx',
'Drop' => 'Xx',
'Drop %s?' => 'Xx %s?',
'Are you sure?' => 'Xx?',
@@ -190,6 +191,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Xx %s.',
'Partition by' => 'Xx',
'Partition' => 'Xx',
'Partitions' => 'Xx',
'Partition name' => 'Xx',
'Values' => 'Xx',
@@ -244,6 +246,7 @@ $translations = array(
'Search' => 'Xx',
'anywhere' => 'xx',
'Search data in tables' => 'Xx',
'as a regular expression' => 'xx',
'Sort' => 'Xx',
'descending' => 'xx',
'Limit' => 'Xx',
@@ -324,12 +327,15 @@ $translations = array(
'Please use one of the extensions %s.' => 'Xx %s.',
// PostgreSQL and MS SQL schema support
'Schema' => 'Xx',
'Schemas' => 'Xx',
'No schemas.' => 'Xx.',
'Show schema' => 'Xx',
'Alter schema' => 'Xx',
'Create schema' => 'Xx',
'Schema has been dropped.' => 'Xx.',
'Schema has been created.' => 'Xx.',
'Schema has been altered.' => 'Xx.',
'Schema' => 'Xx',
'Invalid schema.' => 'Xx.',
// PostgreSQL sequences support

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => '資料庫系統',
'Server' => '伺服器',
'Username' => '帳號',
@@ -89,7 +90,6 @@ $translations = array(
'Data' => '資料',
'Database' => '資料庫',
'database' => '資料庫',
'DB' => '資料庫',
'Use' => '使用',
'Select database' => '選擇資料庫',
@@ -178,7 +178,6 @@ $translations = array(
'Options' => '選項',
'Comment' => '註解',
'Default value' => '預設值',
'Default values' => '預設值',
'Drop' => '刪除',
'Drop %s?' => '刪除 %s?',
'Are you sure?' => '你確定嗎?',
@@ -190,6 +189,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => '超過允許的字段數量的最大值。請增加 %s。',
'Partition by' => '分區類型',
'Partition' => null,
'Partitions' => '分區',
'Partition name' => '分區名稱',
'Values' => '值',
@@ -244,6 +244,7 @@ $translations = array(
'Search' => '搜尋',
'anywhere' => '任意位置',
'Search data in tables' => '在資料庫搜尋',
'as a regular expression' => null,
'Sort' => '排序',
'descending' => '降冪 (遞減)',
'Limit' => '限定',
@@ -355,4 +356,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -1,6 +1,7 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'Home' => null,
'System' => '系统',
'Server' => '服务器',
'Username' => '用户名',
@@ -89,7 +90,6 @@ $translations = array(
'Data' => '数据',
'Database' => '数据库',
'database' => '数据库',
'DB' => '数据库',
'Use' => '使用',
'Select database' => '选择数据库',
@@ -178,7 +178,6 @@ $translations = array(
'Options' => '选项',
'Comment' => '注释',
'Default value' => '默认值',
'Default values' => '默认值',
'Drop' => '删除',
'Drop %s?' => '删除 %s?',
'Are you sure?' => '您确定吗?',
@@ -190,6 +189,7 @@ $translations = array(
'Maximum number of allowed fields exceeded. Please increase %s.' => '超过最多允许的字段数量。请增加 %s。',
'Partition by' => '分区类型',
'Partition' => null,
'Partitions' => '分区',
'Partition name' => '分区名',
'Values' => '值',
@@ -244,6 +244,7 @@ $translations = array(
'Search' => '搜索',
'anywhere' => '任意位置',
'Search data in tables' => '在表中搜索数据',
'as a regular expression' => null,
'Sort' => '排序',
'descending' => '降序',
'Limit' => '范围',
@@ -354,4 +355,10 @@ $translations = array(
'No' => null,
'One Time Password' => null,
'Invalid OTP code.' => null,
'Schemas' => null,
'No schemas.' => null,
'Show schema' => null,
'No driver' => null,
'Database driver not found.' => null,
);

View File

@@ -2,15 +2,15 @@
function adminer_object() {
// required to run any plugin
include_once "../plugins/plugin.php";
// autoloader
foreach (glob("../plugins/*.php") as $filename) {
include_once $filename;
}
// enable extra drivers just by including them
//~ include "../plugins/drivers/simpledb.php";
$plugins = array(
// specify enabled plugins here
new AdminerDatabaseHide(array('information_schema')),
@@ -29,16 +29,16 @@ function adminer_object() {
new AdminerTranslation,
new AdminerForeignSystem,
new AdminerEnumOption,
new AdminerTablesFilter,
new AdminerEditForeign,
new AdminerLoginSsl(["TrustServerCertificate" => true]),
);
/* It is possible to combine customization and plugins:
class AdminerCustomization extends AdminerPlugin {
}
return new AdminerCustomization($plugins);
*/
return new AdminerPlugin($plugins);
}

View File

@@ -14,7 +14,7 @@ echo "<form action=''><p>\n";
hidden_fields_get();
echo "<input type='hidden' name='db' value='" . h(DB) . "'>\n";
echo ($grant ? "" : "<input type='hidden' name='grant' value=''>\n");
echo "<table cellspacing='0'>\n";
echo "<table>\n";
echo "<thead><tr><th>" . lang('Username') . "<th>" . lang('Server') . "<th></thead>\n";
while ($row = $result->fetch_assoc()) {

View File

@@ -39,12 +39,17 @@ $routine_languages = routine_languages();
<?php echo ($routine_languages ? lang('Language') . ": " . html_select("language", $routine_languages, $row["language"]) . "\n" : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<div class="scrollable">
<table cellspacing="0" class="nowrap">
<table cellspacing="0" class="nowrap" id="edit-fields">
<?php
edit_fields($row["fields"], $collations, $routine);
if (isset($_GET["function"])) {
echo "<tr><td>" . lang('Return type');
echo "<tbody><tr>",
(support("move_col") ? "<th></th>" : ""),
"<th>", lang('Return type'), "</th>";
edit_type("returns", $row["returns"], $collations, array(), ($jush == "pgsql" ? array("void", "trigger") : array()));
echo "<td></td></tr></tbody>\n";
}
?>
</table>

View File

@@ -50,9 +50,9 @@ foreach (table_status('', true) as $table => $table_status) {
?>
<div id="schema" style="height: <?php echo $top; ?>em;">
<script<?php echo nonce(); ?>>
qs('#schema').onselectstart = function () { return false; };
gid('schema').onselectstart = function () { return false; };
var tablePos = {<?php echo implode(",", $table_pos_js) . "\n"; ?>};
var em = qs('#schema').offsetHeight / <?php echo $top; ?>;
var em = gid('schema').offsetHeight / <?php echo $top; ?>;
document.onmousemove = schemaMousemove;
document.onmouseup = partialArg(schemaMouseup, '<?php echo js_escape(DB); ?>');
</script>
@@ -61,12 +61,12 @@ foreach ($schema as $name => $table) {
echo "<div class='table' style='top: " . $table["pos"][0] . "em; left: " . $table["pos"][1] . "em;'>";
echo '<a href="' . h(ME) . 'table=' . urlencode($name) . '"><b>' . h($name) . "</b></a>";
echo script("qsl('div').onmousedown = schemaMousedown;");
foreach ($table["fields"] as $field) {
$val = '<span' . type_class($field["type"]) . ' title="' . h($field["full_type"] . ($field["null"] ? " NULL" : '')) . '">' . h($field["field"]) . '</span>';
echo "<br>" . ($field["primary"] ? "<i>$val</i>" : $val);
}
foreach ((array) $table["references"] as $target_name => $refs) {
foreach ($refs as $left => $ref) {
$left1 = $left - $table_pos[$name][1];
@@ -76,7 +76,7 @@ foreach ($schema as $name => $table) {
}
}
}
foreach ((array) $referenced[$name] as $target_name => $refs) {
foreach ($refs as $left => $columns) {
$left1 = $left - $table_pos[$name][1];
@@ -86,7 +86,7 @@ foreach ($schema as $name => $table) {
}
}
}
echo "\n</div>\n";
}

View File

@@ -27,7 +27,7 @@ if (!$row) {
<form action="" method="post">
<p><input name="name" id="name" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php echo script("focus(qs('#name'));"); ?>
<?php echo script("focus(gid('name'));"); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php
if ($_GET["ns"] != "") {

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);
@@ -251,6 +253,7 @@ if (!$columns && support("table")) {
hidden_fields_get();
echo (DB != "" ? '<input type="hidden" name="db" value="' . h(DB) . '">' . (isset($_GET["ns"]) ? '<input type="hidden" name="ns" value="' . h($_GET["ns"]) . '">' : "") : ""); // not used in Editor
echo '<input type="hidden" name="select" value="' . h($TABLE) . '">';
echo '<input type="submit" value="' . h(lang('Select')) . '">'; # hidden default submit so filter remove buttons aren't "clicked" on submission from enter key
echo "</div>\n";
$adminer->selectColumnsPrint($select, $columns);
$adminer->selectSearchPrint($where, $search_columns, $indexes);
@@ -319,10 +322,10 @@ if (!$columns && support("table")) {
echo "<div class='scrollable'>";
echo "<table id='table' cellspacing='0' class='nowrap checkable'>";
echo script("mixin(qs('#table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true), onkeydown: editingKeydown});");
echo script("mixin(gid('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true), onkeydown: editingKeydown});");
echo "<thead><tr>" . (!$group && $select
? ""
: "<td><input type='checkbox' id='all-page' class='jsonly'>" . script("qs('#all-page').onclick = partial(formCheck, /check/);", "")
: "<td><input type='checkbox' id='all-page' class='jsonly'>" . script("gid('all-page').onclick = partial(formCheck, /check/);", "")
. " <a href='" . h($_GET["modify"] ? remove_from_uri("modify") : $_SERVER["REQUEST_URI"] . "&modify=1") . "'>" . lang('Modify') . "</a>");
$names = array();
$functions = array();
@@ -350,10 +353,10 @@ if (!$columns && support("table")) {
}
echo "<span class='column hidden'>";
if ($sortable) {
echo "<a href='" . h($href . $desc) . "' title='" . lang('descending') . "' class='text'> ↓</a>";
echo "<a href='" . h($href . $desc) . "' title='" . lang('descending') . "' class='text'> ↓</a>";
}
if (!$val["fun"] && isset($field["privileges"]["where"])) {
echo '<a href="#fieldset-search" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo '<a href="#fieldset-search" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo script("qsl('a').onclick = partial(selectSearch, '" . js_escape($key) . "');");
}
echo "</span>";
@@ -446,7 +449,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 +510,7 @@ if (!$columns && support("table")) {
echo "\n";
}
}
echo "<div class='footer'><div>\n";
if ($rows || $page) {
if ($pagination) {
@@ -539,7 +542,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,19 +21,25 @@ 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);
}
if (is_string($query)) { // get_file() returns error as number, fread() as false
if (function_exists('memory_get_usage')) {
@ini_set("memory_limit", max(ini_bytes("memory_limit"), 2 * strlen($query) + memory_get_usage() + 8e6)); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
if (function_exists('memory_get_usage') && ($memory_limit = ini_bytes("memory_limit")) != "-1") {
@ini_set("memory_limit", max($memory_limit, 2 * strlen($query) + memory_get_usage() + 8e6)); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
}
if ($query != "" && strlen($query) < 1e6) { // don't add big queries
@@ -81,7 +87,21 @@ if (!$error && $_POST) {
$offset = $pos + strlen($found);
if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end
while (preg_match('(' . ($found == '/*' ? '\*/' : ($found == '[' ? ']' : (preg_match('~^-- |^#~', $found) ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { //! respect sql_mode NO_BACKSLASH_ESCAPES
$c_style_escapes = is_c_style_escapes() || ($jush == "pgsql" && ($pos > 0 && strtolower($query[$pos - 1]) == "e"));
$pattern = '(';
if ($found == '/*') {
$pattern .= '\*/';
} elseif ($found == '[') {
$pattern .= ']';
} elseif (preg_match('~^-- |^#~', $found)) {
$pattern .= "\n";
} else {
$pattern .= preg_quote($found) . ($c_style_escapes ? "|\\\\." : "");
}
$pattern .= '|$)s';
while (preg_match($pattern, $query, $match, PREG_OFFSET_CAPTURE, $offset)) {
$s = $match[0][0];
if (!$s && $fp && !feof($fp)) {
$query .= fread($fp, 1e5);
@@ -169,7 +189,8 @@ if (!$error && $_POST) {
stop_session();
}
if (!$_POST["only_errors"]) {
echo "<p class='message' title='" . h($connection->info) . "'>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
$title = isset($connection->info) ? "title='" . h($connection->info) . "'" : "";
echo "<p class='message' $title>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
}
}
echo ($warnings ? "<div id='$warnings_id' class='hidden'>\n$warnings</div>\n" : "");
@@ -222,7 +243,7 @@ if (!isset($_GET["import"])) {
}
echo "<p>";
textarea("query", $q, 20);
echo script(($_POST ? "" : "qs('textarea').focus();\n") . "qs('#form').onsubmit = partial(sqlSubmit, qs('#form'), '" . js_escape(remove_from_uri("sql|limit|error_stops|only_errors|history")) . "');");
echo script(($_POST ? "" : "qs('textarea').focus();\n") . "gid('form').onsubmit = partial(sqlSubmit, gid('form'), '" . js_escape(remove_from_uri("sql|limit|error_stops|only_errors|history")) . "');");
echo "<p>$execute\n";
echo lang('Limit rows') . ": <input type='number' name='limit' class='size' value='" . h($_POST ? $_POST["limit"] : $_GET["limit"]) . "'>\n";
@@ -234,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

@@ -1,8 +1,7 @@
/** @author Ondrej Valka, http://valka.info */
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; width: -moz-fit-content; width: fit-content; }
a { color: blue; text-decoration: none; }
a:visited { color: navy; }
a:link:hover, a:visited:hover { color: red; text-decoration: underline; }
a:link:hover { color: red; text-decoration: underline; }
a.text:hover { text-decoration: none; }
a.jush-help:hover { color: inherit; }
h1 { font-size: 150%; margin: 0; padding: .8em 1em; border-bottom: 1px solid #999; font-weight: normal; color: #777; background: #eee; }
@@ -11,7 +10,7 @@ h3 { font-weight: normal; font-size: 130%; margin: 1em 0 0; }
form { margin: 0; }
td table { width: 100%; margin: 0; }
table { margin: 1em 20px 0 0; border-collapse: collapse; font-size: 90%; }
td, th { border: 1px solid #999; padding: .2em .3em; }
td, th { box-sizing: border-box; border: 1px solid #999; padding: .2em .3em; }
th { background: #eee; text-align: left; }
thead th { text-align: center; padding: .2em .5em; }
thead td, thead th { background: #ddf; } /* position: sticky; causes Firefox to lose borders */
@@ -19,20 +18,30 @@ fieldset { display: inline; vertical-align: top; padding: .5em .8em; margin: .8e
p { margin: .8em 20px 0 0; }
img { vertical-align: middle; border: 0; }
td img { max-width: 200px; max-height: 200px; }
code { background: #eee; }
tbody tr:hover td, tbody tr:hover th { background: #eee; }
code { font-size: 110%; padding: 1px 2px; background: #eee; }
pre { margin: 1em 0 0; }
pre, textarea { font: 100%/1.25 monospace; }
input, select { vertical-align: middle; }
pre code { display: block; font-size: 100%; }
pre, textarea { font: 110%/1.25 monospace; }
pre.jush { background: #fff; }
pre.comment { white-space: pre-wrap; }
form + pre.comment { margin-top: 2em; }
input, textarea, select { box-sizing: border-box; }
input[type="image"] { vertical-align: middle; margin-top: -3px; }
input[type="number"] { -moz-appearance: textfield; }
input::-webkit-inner-spin-button { -webkit-appearance: none; }
input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; }
input.maxlength { box-shadow: 1px 1px 1px red; }
input.wayoff { left: -1000px; position: absolute; }
input::placeholder { color: #000; opacity: 0.4; }
.center { text-align: center; }
.block { display: block; }
.version { color: #777; font-size: 67%; }
.version { color: #777; font-size: 62%; }
.js .hidden, .nojs .jsonly { display: none; }
.js .column { position: absolute; background: #ddf; padding: .27em 1ex .3em 0; margin-top: -.27em; }
.nowrap td, .nowrap th, td.nowrap, p.nowrap { white-space: pre; }
.nowrap { white-space: nowrap; }
p.nowrap { white-space: pre; }
.wrap td { white-space: normal; }
.error { color: red; background: #fee; }
.error b { background: #fff; font-weight: normal; }
@@ -62,8 +71,19 @@ input.wayoff { left: -1000px; position: absolute; }
.footer > div { background: #fff; padding: 0 0 .5em; }
.footer fieldset { margin-top: 0; }
.links a { white-space: nowrap; margin-right: 20px; }
.logout { margin-top: .5em; position: absolute; top: 0; right: 0; }
.logout { margin: .5em 20px 0 0; position: absolute; top: 0; right: 0; }
.loadmore { margin-left: 1ex; }
.tables-filter { padding: .8em 1em 0; }
.handle { cursor: grab; vertical-align: middle; }
.handle:before { content: "="; display: inline-block; width: 18px; height: 18px; overflow: hidden; font-size: 130%; text-align: center; line-height: 16px; opacity: 0.2; }
span.handle { display: inline-block; width: 18px; height: 18px; padding-right: .3em; }
th.handle:before { vertical-align: middle; }
.no-sort .handle { cursor: default; }
.no-sort .handle:before { content: "•"; font-size: 100%; }
.placeholder { opacity: 0; }
.dragging { position: absolute; margin: 0; background: #fff; }
.dragging * { cursor: grabbing; }
table.dragging { background: #eee; }
/* .edit used in designs */
#menu { position: absolute; margin: 10px 0 0; padding: 0 0 30px 0; top: 2em; left: 0; width: 19em; }
#menu p, #logins, #tables { padding: .8em 1em; margin: 0; border-bottom: 1px solid #ccc; }
@@ -75,11 +95,13 @@ input.wayoff { left: -1000px; position: absolute; }
#lang { position: absolute; top: 0; left: 0; line-height: 1.8em; padding: .3em 1em; }
#breadcrumb { white-space: nowrap; position: absolute; top: 0; left: 21em; background: #eee; height: 2em; line-height: 1.8em; padding: 0 1em; margin: 0 0 0 -18px; }
#h1 { color: #777; text-decoration: none; font-style: italic; }
#version { font-size: 67%; color: red; }
#version { color: red; }
#schema { margin-left: 60px; position: relative; -moz-user-select: none; -webkit-user-select: none; }
#schema .table { border: 1px solid silver; padding: 0 2px; cursor: move; position: absolute; }
#schema .references { position: absolute; }
#tables-filter, #database-select, #scheme-select { width: 100%; }
#help { position: absolute; border: 1px solid #999; background: #eee; padding: 5px; font-family: monospace; z-index: 1; }
#fieldset-select div:last-child > .remove, #fieldset-search div:last-child > .remove, #fieldset-sort div:last-child > .remove { display: none; }
.rtl h2 { margin: 0 -18px 20px 0; }
.rtl p, .rtl table, .rtl .error, .rtl .message { margin: 1em 0 0 20px; }
@@ -89,6 +111,7 @@ input.wayoff { left: -1000px; position: absolute; }
.rtl .pages { left: auto; right: 21em; }
.rtl input.wayoff { left: auto; right: -1000px; }
.rtl #lang, .rtl #menu { left: auto; right: 0; }
.rtl pre, .rtl code { direction: ltr; }
@media all and (max-width: 880px) {
.pages { left: auto; }

View File

@@ -16,17 +16,22 @@ function bodyLoad(version, maria) {
if (maria) {
for (var i = 1; i < obj.length; i++) {
obj[i] = obj[i]
.replace(/\.html/, '/')
.replace(/-type-syntax/, '-data-types')
.replace('.html', '/')
.replace('-type-syntax', '-data-types')
.replace(/numeric-(data-types)/, '$1-$&')
.replace(/#statvar_.*/, '#$$1')
.replace(/replication-options-(master|binary-log)\//, 'replication-and-binary-log-system-variables/')
.replace('server-options/', 'server-system-variables/')
.replace('innodb-parameters/', 'innodb-system-variables/')
.replace(/#(statvar|sysvar|option_mysqld)_(.*)/, '#$2')
.replace(/#sysvar_(.*)/, '#$1')
;
}
}
}
obj[key] = (maria ? obj[key].replace(/dev\.mysql\.com\/doc\/mysql\/en\//, 'mariadb.com/kb/en/library/') : obj[key]) // MariaDB
.replace(/\/doc\/mysql/, '/doc/refman/' + version) // MySQL
.replace(/\/docs\/current/, '/docs/' + version) // PostgreSQL
obj[key] = (maria ? obj[key].replace('dev.mysql.com/doc/mysql/en/', 'mariadb.com/kb/en/') : obj[key]) // MariaDB
.replace('/doc/mysql/', '/doc/refman/' + version) // MySQL
.replace('/docs/current/', '/docs/' + version) // PostgreSQL
;
}
}
@@ -83,13 +88,17 @@ function messagesPrint(el) {
/** Hide or show some login rows for selected driver
* @param HTMLSelectElement
*/
function loginDriver(driver) {
var trs = parentTag(driver, 'table').rows;
var disabled = /sqlite/.test(selectValue(driver));
alterClass(trs[1], 'hidden', disabled); // 1 - row with server
/**
* Hides or shows some login rows for selected driver.
*
* @param {HTMLSelectElement} driverSelect
*/
function loginDriver(driverSelect) {
const trs = parentTag(driverSelect, 'table').rows;
const disabled = /sqlite/.test(selectValue(driverSelect));
// 1 - row with server
trs[1].classList.toggle('hidden', disabled);
trs[1].getElementsByTagName('input')[0].disabled = disabled;
}
@@ -103,6 +112,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;
@@ -226,11 +240,13 @@ function editFields() {
els = qsa('[name$="[type]"]');
for (var i = 0; i < els.length; i++) {
mixin(els[i], {
onfocus: function () { lastType = selectValue(this); },
onfocus: () => {
lastType = selectValue(this);
},
onchange: editingTypeChange,
onmouseover: function (event) { helpMouseover.call(this, event, getTarget(event).value, 1) },
onmouseout: helpMouseout
});
initHelpFor(els[i], (value) => { return value; }, true);
}
}
@@ -239,7 +255,7 @@ function editFields() {
* @return boolean false to cancel action
*/
function editingClick(event) {
var el = getTarget(event);
var el = event.target;
if (!isTag(el, 'input')) {
el = parentTag(el, 'label');
el = el && qs('input', el);
@@ -248,10 +264,6 @@ function editingClick(event) {
var name = el.name;
if (/^add\[/.test(name)) {
editingAddRow.call(el, 1);
} else if (/^up\[/.test(name)) {
editingMoveRow.call(el, 1);
} else if (/^down\[/.test(name)) {
editingMoveRow.call(el);
} else if (/^drop_col\[/.test(name)) {
editingRemoveRow.call(el, 'fields\$1[field]');
} else {
@@ -272,7 +284,7 @@ function editingClick(event) {
* @param InputEvent
*/
function editingInput(event) {
var el = getTarget(event);
var el = event.target;
if (/\[default]$/.test(el.name)) {
el.previousSibling.checked = true;
}
@@ -348,7 +360,10 @@ function editingAddRow(focus) {
}
}
tags[0].oninput = editingNameChange;
initSortableRow(row2);
row.parentNode.insertBefore(row2, row.nextSibling);
if (focus) {
input.oninput = editingNameChange;
input.focus();
@@ -370,22 +385,6 @@ function editingRemoveRow(name) {
return false;
}
/** Move table row for field
* @param [boolean]
* @return boolean false for success
* @this HTMLInputElement
*/
function editingMoveRow(up){
var row = parentTag(this, 'tr');
if (!('nextElementSibling' in row)) {
return true;
}
row.parentNode.insertBefore(row, up
? row.previousElementSibling
: row.nextElementSibling ? row.nextElementSibling.nextElementSibling : row.parentNode.firstChild);
return false;
}
var lastType = '';
/** Clear length and hide collation or unsigned
@@ -410,26 +409,26 @@ function editingTypeChange() {
el.checked = false;
}
if (el.name === name + '[collation]') {
alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text));
el.classList.toggle('hidden', !/(char|text|enum|set)$/.test(text));
}
if (el.name === name + '[unsigned]') {
alterClass(el, 'hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
el.classList.toggle('hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
}
if (el.name === name + '[on_update]') {
alterClass(el, 'hidden', !/timestamp|datetime/.test(text)); // MySQL supports datetime since 5.6.5
// MySQL supports datetime since 5.6.5.
el.classList.toggle('hidden', !/timestamp|datetime/.test(text));
}
if (el.name === name + '[on_delete]') {
alterClass(el, 'hidden', !/`/.test(text));
el.classList.toggle('hidden', !/`/.test(text));
}
}
helpClose();
}
/** Mark length as required
* @this HTMLInputElement
*/
function editingLengthChange() {
alterClass(this, 'required', !this.value.length && /var(char|binary)$/.test(selectValue(this.parentNode.previousSibling.firstChild)));
this.classList.toggle('required', !this.value.length && /var(char|binary)$/.test(selectValue(this.parentNode.previousSibling.firstChild)));
}
/** Edit enum or set
@@ -438,7 +437,7 @@ function editingLengthChange() {
function editingLengthFocus() {
var td = this.parentNode;
if (/(enum|set)$/.test(selectValue(td.previousSibling.firstChild))) {
var edit = qs('#enum-edit');
var edit = gid('enum-edit');
edit.value = enumValues(this.value);
td.appendChild(edit);
this.style.display = 'none';
@@ -482,9 +481,9 @@ function editingLengthBlur() {
* @param number
*/
function columnShow(checked, column) {
var trs = qsa('tr', qs('#edit-fields'));
var trs = qsa('tr', gid('edit-fields'));
for (var i=0; i < trs.length; i++) {
alterClass(qsa('td', trs[i])[column], 'hidden', !checked);
qsa('td', trs[i])[column].classList.toggle('hidden', !checked);
}
}
@@ -493,9 +492,9 @@ function columnShow(checked, column) {
*/
function partitionByChange() {
var partitionTable = /RANGE|LIST/.test(selectValue(this));
alterClass(this.form['partitions'], 'hidden', partitionTable || !this.selectedIndex);
alterClass(qs('#partition-table'), 'hidden', !partitionTable);
helpClose();
this.form['partitions'].classList.toggle('hidden', partitionTable || !this.selectedIndex);
gid('partition-table').classList.toggle('hidden', !partitionTable);
}
/** Add next partition row
@@ -515,7 +514,7 @@ function partitionNameChange() {
function editingCommentsClick(el, focus) {
var comment = el.form['Comment'];
columnShow(el.checked, 6);
alterClass(comment, 'hidden', !el.checked);
comment.classList.toggle('hidden', !el.checked);
if (focus && el.checked) {
comment.focus();
}
@@ -528,7 +527,7 @@ function editingCommentsClick(el, focus) {
* @this HTMLTableElement
*/
function dumpClick(event) {
var el = parentTag(getTarget(event), 'label');
var el = parentTag(event.target, 'label');
if (el) {
el = qs('input', el);
var match = /(.+)\[]$/.exec(el.name);
@@ -658,7 +657,7 @@ function triggerChange(tableRe, table, form) {
if (tableRe.test(form['Trigger'].value)) {
form['Trigger'].value = table + '_' + (selectValue(form['Timing']).charAt(0) + formEvent.charAt(0)).toLowerCase();
}
alterClass(form['Of'], 'hidden', !/ OF/.test(formEvent));
form['Of'].classList.toggle('hidden', !/ OF/.test(formEvent));
}
@@ -732,55 +731,114 @@ function schemaMouseup(event, db) {
s += '_' + key + ':' + Math.round(tablePos[key][0] * 10000) / 10000 + 'x' + Math.round(tablePos[key][1] * 10000) / 10000;
}
s = encodeURIComponent(s.substr(1));
var link = qs('#schema-link');
var link = gid('schema-link');
link.href = link.href.replace(/[^=]+$/, '') + s;
cookie('adminer_schema-' + db + '=' + s, 30); //! special chars in db
}
}
// Help.
(function() {
let openTimeout = null;
let closeTimeout = null;
let helpVisible = false;
var helpOpen, helpIgnore; // when mouse outs <option> then it mouse overs border of <select> - ignore it
window.initHelpPopup = function () {
const help = gid("help");
/** Display help
* @param MouseEvent
* @param string
* @param bool display on left side (otherwise on top)
* @this HTMLElement
*/
function helpMouseover(event, text, side) {
var target = getTarget(event);
if (!text) {
helpClose();
} else if (window.jush && (!helpIgnore || this !== target)) {
helpOpen = 1;
var help = qs('#help');
help.innerHTML = text;
jush.highlight_tag([ help ]);
alterClass(help, 'hidden');
var rect = target.getBoundingClientRect();
var body = document.documentElement;
help.style.top = (body.scrollTop + rect.top - (side ? (help.offsetHeight - target.offsetHeight) / 2 : help.offsetHeight)) + 'px';
help.style.left = (body.scrollLeft + rect.left - (side ? help.offsetWidth : (help.offsetWidth - target.offsetWidth) / 2)) + 'px';
}
}
help.addEventListener("mouseenter", () => {
clearTimeout(closeTimeout);
closeTimeout = null;
});
/** Close help after timeout
* @param MouseEvent
* @this HTMLElement
*/
function helpMouseout(event) {
helpOpen = 0;
helpIgnore = (this !== getTarget(event));
setTimeout(function () {
if (!helpOpen) {
helpClose();
help.addEventListener("mouseleave", hideHelp);
};
/**
* @param {HTMLElement} element
* @param {string|function} content
* @param {boolean} side Displays on left side (otherwise on top).
*/
window.initHelpFor = function(element, content, side = false) {
const withCallback = typeof content === "function";
element.addEventListener("mouseenter", (event) => {
showHelp(event.target, withCallback ? content(event.target.value) : content, side)
});
element.addEventListener("mouseleave", hideHelp);
element.addEventListener("blur", hideHelp);
if (withCallback) {
element.addEventListener("change", hideHelp);
}
}, 200);
}
};
/** Close help
*/
function helpClose() {
alterClass(qs('#help'), 'hidden', true);
}
/**
* Displays help popup after a small delay.
*
* @param {HTMLElement} element
* @param {string} text
* @param {boolean} side display on left side (otherwise on top)
*/
function showHelp(element, text, side) {
if (!text) {
hideHelp();
return;
}
if (isSorting() || !window.jush) {
return;
}
clearTimeout(openTimeout);
openTimeout = null;
clearTimeout(closeTimeout);
closeTimeout = null;
const help = gid("help");
help.innerHTML = text;
jush.highlight_tag([help]);
// Display help briefly to calculate position properly.
help.classList.remove("hidden");
const rect = element.getBoundingClientRect();
const root = document.documentElement;
help.style.top = (root.scrollTop + rect.top - (side ? (help.offsetHeight - element.offsetHeight) / 2 : help.offsetHeight)) + 'px';
help.style.left = (root.scrollLeft + rect.left - (side ? help.offsetWidth : (help.offsetWidth - element.offsetWidth) / 2)) + 'px';
if (helpVisible) {
return;
}
help.classList.add("hidden");
openTimeout = setTimeout(() => {
gid("help").classList.remove("hidden");
helpVisible = true;
openTimeout = null;
}, 600);
}
/**
* Closes the help popup after a small delay.
*/
function hideHelp() {
if (openTimeout) {
clearTimeout(openTimeout);
openTimeout = null;
return;
}
closeTimeout = setTimeout(() => {
gid("help").classList.add("hidden");
helpVisible = false;
closeTimeout = null;
}, 200);
}
})();

View File

@@ -1,4 +1,15 @@
/**
* Returns the element found by given identifier.
*
* @param {string} id
* @param {?HTMLElement} context Defaults to document.
* @return {?HTMLElement}
*/
function gid(id, context = null) {
return (context || document).getElementById(id);
}
/** Get first element by selector
* @param string
* @param [HTMLElement] defaults to document
@@ -62,24 +73,15 @@ function mixin(target, source) {
}
}
/** Add or remove CSS class
* @param HTMLElement
* @param string
* @param [bool]
*/
function alterClass(el, className, enable) {
if (el) {
el.className = el.className.replace(RegExp('(^|\\s)' + className + '(\\s|$)'), '$2') + (enable ? ' ' + className : '');
}
}
/** Toggle visibility
* @param string
* @return boolean false
*/
/**
* Toggles visibility of element with ID.
*
* @param {string} id
* @return {boolean} Always false.
*/
function toggle(id) {
var el = qs('#' + id);
el.className = (el.className === 'hidden' ? '' : 'hidden');
gid(id).classList.toggle("hidden");
return false;
}
@@ -94,34 +96,27 @@ function cookie(assign, days) {
document.cookie = assign + '; expires=' + date;
}
/** Verify current Adminer version
* @param string
* @param string own URL base
* @param string
*/
function verifyVersion(current, url, token) {
/**
* Verifies current Adminer version.
*
* @param baseUrl string
* @param token string
*/
function verifyVersion(baseUrl, token) {
// Dummy value to prevent repeated verifications after AJAX failure.
cookie('adminer_version=0', 1);
var iframe = document.createElement('iframe');
iframe.src = 'https://www.adminer.org/version/?current=' + current;
iframe.frameBorder = 0;
iframe.marginHeight = 0;
iframe.scrolling = 'no';
iframe.style.width = '7ex';
iframe.style.height = '1.25em';
if (window.postMessage && window.addEventListener) {
iframe.style.display = 'none';
addEventListener('message', function (event) {
if (event.origin === 'https://www.adminer.org') {
var match = /version=(.+)/.exec(event.data);
if (match) {
cookie('adminer_version=' + match[1], 1);
ajax(url + 'script=version', function () {
}, event.data + '&token=' + token);
}
}
}, false);
}
qs('#version').appendChild(iframe);
ajax('https://api.github.com/repos/pematon/adminer/releases/latest', (request) => {
const response = JSON.parse(request.responseText);
const version = response.tag_name.replace(/^\D*/, '');
if (!version) return;
cookie('adminer_version=' + version, 1);
const data = 'version=' + version + '&token=' + token;
ajax(baseUrl + 'script=version', null, data);
}, null, null, true);
}
/** Get value of select
@@ -163,7 +158,7 @@ function parentTag(el, tag) {
*/
function trCheck(el) {
var tr = parentTag(el, 'tr');
alterClass(tr, 'checked', el.checked);
tr.classList.toggle('checked', el.checked);
if (el.form && el.form['all'] && el.form['all'].onclick) { // Opera treats form.all as document.all
el.form['all'].onclick();
}
@@ -176,7 +171,7 @@ function trCheck(el) {
*/
function selectCount(id, count) {
setHtml(id, (count === '' ? '' : '(' + (count + '').replace(/\B(?=(\d{3})+$)/g, thousandsSeparator) + ')'));
var el = qs('#' + id);
var el = gid(id);
if (el) {
var inputs = qsa('input', el.parentNode.parentNode);
for (var i = 0; i < inputs.length; i++) {
@@ -211,13 +206,21 @@ function tableCheck() {
}
}
/** Uncheck single element
* @param string
*/
/**
* Uncheck single element.
*/
function formUncheck(id) {
var el = qs('#' + id);
el.checked = false;
trCheck(el);
formUncheckAll("#" + id);
}
/**
* Uncheck elements matched by selector.
*/
function formUncheckAll(selector) {
for (const element of qsa(selector)) {
element.checked = false;
trCheck(element);
}
}
/** Get number of checked elements matching given name
@@ -241,7 +244,7 @@ function formChecked(el, name) {
* @param [boolean] force click
*/
function tableClick(event, click) {
var td = parentTag(getTarget(event), 'td');
var td = parentTag(event.target, 'td');
var text;
if (td && (text = td.getAttribute('data-text'))) {
if (selectClick.call(td, event, +text, td.getAttribute('data-warning'))) {
@@ -249,7 +252,7 @@ function tableClick(event, click) {
}
}
click = (click || !window.getSelection || getSelection().isCollapsed);
var el = getTarget(event);
var el = event.target;
while (!isTag(el, 'tr')) {
if (isTag(el, 'table|a|input|textarea')) {
if (el.type !== 'checkbox') {
@@ -349,14 +352,85 @@ function pageClick(href, page) {
}
}
let tablesFilterTimeout = null;
let tablesFilterValue = '';
function initTablesFilter(dbName) {
if (sessionStorage) {
document.addEventListener('DOMContentLoaded', function () {
if (dbName === sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')) {
gid('tables-filter').value = sessionStorage.getItem('adminer_tables_filter');
filterTables();
} else {
sessionStorage.removeItem('adminer_tables_filter');
}
sessionStorage.setItem('adminer_tables_filter_db', dbName);
});
}
const filterInput = gid('tables-filter');
filterInput.addEventListener('input', function () {
window.clearTimeout(tablesFilterTimeout);
tablesFilterTimeout = window.setTimeout(filterTables, 200);
});
document.body.addEventListener('keydown', function(event) {
if (isCtrl(event) && event.shiftKey && event.key.toUpperCase() === 'F') {
filterInput.focus();
filterInput.select();
event.preventDefault();
}
});
}
function filterTables() {
const value = gid('tables-filter').value.toLowerCase();
if (value === tablesFilterValue) {
return;
}
tablesFilterValue = value;
let reg
if (value !== '') {
const valueExp = (`${value}`).replace(/[\\.+*?\[^\]$(){}=!<>|:]/g, '\\$&');
reg = new RegExp(`(${valueExp})`, 'gi');
}
if (sessionStorage) {
sessionStorage.setItem('adminer_tables_filter', value);
}
const tables = qsa('#tables li');
for (let i = 0; i < tables.length; i++) {
let a = qs('a[data-main="true"], span[data-main="true"]', tables[i]);
let tableName = tables[i].dataset.tableName;
if (tableName == null) {
tableName = a.innerHTML.trim();
tables[i].dataset.tableName = tableName;
}
if (value === "") {
tables[i].classList.remove('hidden');
a.innerHTML = tableName;
} else if (tableName.toLowerCase().indexOf(value) >= 0) {
tables[i].classList.remove('hidden');
a.innerHTML = tableName.replace(reg, '<strong>$1</strong>');
} else {
tables[i].classList.add('hidden');
}
}
}
/** Display items in menu
* @param MouseEvent
* @this HTMLElement
*/
function menuOver(event) {
var a = getTarget(event);
var a = event.target;
if (isTag(a, 'a|span') && a.offsetLeft + a.offsetWidth > a.parentNode.offsetWidth - 15) { // 15 - ellipsis
this.style.overflow = 'visible';
}
@@ -371,30 +445,64 @@ function menuOut() {
/** Add row in select fieldset
* @this HTMLSelectElement
*/
function selectAddRow() {
var field = this;
var row = cloneNode(field.parentNode);
/**
* Adds row in select fieldset.
*
* @param {Event} event
* @this HTMLSelectElement
*/
function selectAddRow(event) {
const field = this;
const row = cloneNode(field.parentNode);
field.onchange = selectFieldChange;
field.onchange();
var selects = qsa('select', row);
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/[a-z]\[\d+/, '$&1');
selects[i].selectedIndex = 0;
field.onchange(event);
const selects = qsa('select', row);
for (const select of selects) {
select.name = select.name.replace(/[a-z]\[\d+/, '$&1');
select.selectedIndex = 0;
}
var inputs = qsa('input', row);
for (var i=0; i < inputs.length; i++) {
inputs[i].name = inputs[i].name.replace(/[a-z]\[\d+/, '$&1');
inputs[i].className = '';
if (inputs[i].type === 'checkbox') {
inputs[i].checked = false;
const inputs = qsa('input', row);
for (const input of inputs) {
// Skip buttons.
if (input.type === 'image') {
continue;
}
input.name = input.name.replace(/[a-z]\[\d+/, '$&1');
input.className = '';
if (input.type === 'checkbox') {
input.checked = false;
} else {
inputs[i].value = '';
input.value = '';
}
}
field.parentNode.parentNode.appendChild(row);
const button = qs('.remove', row);
button.onclick = selectRemoveRow;
const parent = field.parentNode.parentNode;
if (parent.classList.contains("sortable")) {
initSortableRow(field.parentElement);
}
parent.appendChild(row);
}
/**
* Removes a row in select fieldset.
*
* @this HTMLInputElement
* @return {boolean} Always false.
*/
function selectRemoveRow() {
const row = this.parentNode;
row.parentNode.removeChild(row);
return false;
}
/** Prevent onsearch handler on Enter
@@ -417,6 +525,159 @@ function selectSearchSearch() {
}
}
// Sorting.
(function() {
let placeholderRow = null, nextRow = null, dragHelper = null;
let startY, minY, maxY;
/**
* Initializes sortable list of DIV elements.
*
* @param {string} parentSelector
*/
window.initSortable = function(parentSelector) {
const parent = qs(parentSelector);
if (!parent) return;
for (const row of parent.children) {
if (!row.classList.contains("no-sort")) {
initSortableRow(row);
}
}
};
/**
* Initializes one row of sortable parent.
*
* @param {HTMLElement} row
*/
window.initSortableRow = function(row) {
row.classList.remove("no-sort");
const handle = qs(".handle", row);
handle.addEventListener("mousedown", (event) => { startSorting(row, event) });
handle.addEventListener("touchstart", (event) => { startSorting(row, event) });
};
window.isSorting = function () {
return dragHelper !== null;
};
function startSorting(row, event) {
event.preventDefault();
const pointerY = getPointerY(event);
const parent = row.parentNode;
startY = pointerY - getOffsetTop(row);
minY = getOffsetTop(parent);
maxY = minY + parent.offsetHeight - row.offsetHeight;
placeholderRow = row.cloneNode(true);
placeholderRow.classList.add("placeholder");
parent.insertBefore(placeholderRow, row);
nextRow = row.nextElementSibling;
let top = pointerY - startY;
let left = getOffsetLeft(row);
let width = row.getBoundingClientRect().width;
if (row.tagName === "TR") {
const firstChild = row.firstElementChild;
const borderWidth = (firstChild.offsetWidth - firstChild.clientWidth) / 2;
const borderHeight = (firstChild.offsetHeight - firstChild.clientHeight) / 2;
minY -= borderHeight;
maxY -= borderHeight;
top -= borderHeight;
left -= borderWidth;
width += 2 * borderWidth;
for (const child of row.children) {
child.style.width = child.getBoundingClientRect().width + "px";
}
dragHelper = document.createElement("table");
dragHelper.appendChild(row);
} else {
dragHelper = row;
}
dragHelper.style.top = `${top}px`;
dragHelper.style.left = `${left}px`;
dragHelper.style.width = `${width}px`;
dragHelper.classList.add("dragging");
document.body.appendChild(dragHelper);
window.addEventListener("mousemove", updateSorting);
window.addEventListener("touchmove", updateSorting);
window.addEventListener("mouseup", finishSorting);
window.addEventListener("touchend", finishSorting);
window.addEventListener("touchcancel", finishSorting);
}
function updateSorting(event) {
const pointerY = getPointerY(event);
let top = Math.min(Math.max(pointerY - startY, minY), maxY);
dragHelper.style.top = `${top}px`;
const parent = placeholderRow.parentNode;
top = top - minY + parent.offsetTop;
let sibling;
if (top > placeholderRow.offsetTop + placeholderRow.offsetHeight / 2) {
sibling = !nextRow.classList.contains("no-sort") ? nextRow.nextElementSibling : nextRow;
} else if (top + placeholderRow.offsetHeight < placeholderRow.offsetTop + placeholderRow.offsetHeight / 2) {
sibling = placeholderRow.previousElementSibling;
} else {
sibling = nextRow;
}
if (sibling !== nextRow) {
const parent = placeholderRow.parentNode;
nextRow = sibling;
if (sibling) {
parent.insertBefore(placeholderRow, nextRow);
} else {
parent.appendChild(placeholderRow);
}
}
}
function finishSorting() {
dragHelper.classList.remove("dragging");
dragHelper.style.top = null;
dragHelper.style.left = null;
dragHelper.style.width = null;
placeholderRow.parentNode.insertBefore(dragHelper.tagName === "TABLE" ? dragHelper.firstChild : dragHelper, placeholderRow);
placeholderRow.remove();
placeholderRow = nextRow = dragHelper = null;
window.removeEventListener("mousemove", updateSorting);
window.removeEventListener("touchmove", updateSorting);
window.removeEventListener("mouseup", finishSorting);
window.removeEventListener("touchend", finishSorting);
window.removeEventListener("touchcancel", finishSorting);
}
function getPointerY(event) {
if (event.type.includes("touch")) {
const touch = event.touches[0] || event.changedTouches[0];
return touch.clientY;
} else {
return event.clientY;
}
}
})();
/** Toggles column context menu
@@ -439,7 +700,7 @@ function columnMouse(className) {
* @return boolean false
*/
function selectSearch(name) {
var el = qs('#fieldset-search');
var el = gid('fieldset-search');
el.className = '';
var divs = qsa('div', el);
for (var i=0; i < divs.length; i++) {
@@ -466,16 +727,6 @@ function isCtrl(event) {
return (event.ctrlKey || event.metaKey) && !event.altKey; // shiftKey allowed
}
/** Return event target
* @param Event
* @return HTMLElement
*/
function getTarget(event) {
return event.target || event.srcElement;
}
/** Send form by Ctrl+Enter on <select> and <textarea>
* @param KeyboardEvent
* @param [string]
@@ -483,7 +734,7 @@ function getTarget(event) {
*/
function bodyKeydown(event, button) {
eventStop(event);
var target = getTarget(event);
var target = event.target;
if (target.jushTextarea) {
target = target.jushTextarea;
}
@@ -507,7 +758,7 @@ function bodyKeydown(event, button) {
* @param MouseEvent
*/
function bodyClick(event) {
var target = getTarget(event);
var target = event.target;
if ((isCtrl(event) || event.shiftKey) && target.type === 'submit' && isTag(target, 'input')) {
target.form.target = '_blank';
setTimeout(function () {
@@ -525,7 +776,7 @@ function bodyClick(event) {
*/
function editingKeydown(event) {
if ((event.keyCode === 40 || event.keyCode === 38) && isCtrl(event)) { // 40 - Down, 38 - Up
var target = getTarget(event);
var target = event.target;
var sibling = (event.keyCode === 40 ? 'nextSibling' : 'previousSibling');
var el = target.parentNode.parentNode[sibling];
if (el && (isTag(el, 'tr') || (el = el[sibling])) && isTag(el, 'tr') && (el = el.childNodes[nodePosition(target.parentNode)]) && (el = el.childNodes[nodePosition(target)])) {
@@ -539,37 +790,59 @@ function editingKeydown(event) {
return true;
}
/** Disable maxlength for functions
* @this HTMLSelectElement
*/
/**
* Disables maxlength for functions and manages value visibility.
*
* @this HTMLSelectElement
*/
function functionChange() {
var input = this.form[this.name.replace(/^function/, 'fields')];
if (input) { // undefined with the set data type
if (selectValue(this)) {
if (input.origType === undefined) {
input.origType = input.type;
input.origMaxLength = input.getAttribute('data-maxlength');
}
input.removeAttribute('data-maxlength');
input.type = 'text';
} else if (input.origType) {
input.type = input.origType;
if (input.origMaxLength >= 0) {
input.setAttribute('data-maxlength', input.origMaxLength);
}
}
oninput({target: input});
const input = this.form[this.name.replace(/^function/, 'fields')];
const value = selectValue(this);
// Undefined with the set data type.
if (!input) {
return;
}
helpClose();
if (value) {
if (input.origType === undefined) {
input.origType = input.type;
input.origMaxLength = input.getAttribute('data-maxlength');
}
input.removeAttribute('data-maxlength');
input.type = 'text';
} else if (input.origType) {
input.type = input.origType;
if (input.origMaxLength >= 0) {
input.setAttribute('data-maxlength', input.origMaxLength);
}
}
// Hide input value if it will be not used by selected function.
if (value === "NULL" || value === "now") {
if (input.value !== "") {
input.dataset.lastValue = input.value;
input.value = "";
}
} else if (input.dataset.lastValue) {
input.value = input.dataset.lastValue;
}
oninput({target: input});
}
/** Skip 'original' when typing
* @param number
* @this HTMLTableCellElement
*/
/**
* Unset 'original', 'NULL' and 'now' functions when typing.
*
* @param first number
* @this HTMLTableCellElement
*/
function skipOriginal(first) {
var fnSelect = this.previousSibling.firstChild;
if (fnSelect.selectedIndex < first) {
const fnSelect = this.previousSibling.firstChild;
const value = selectValue(fnSelect);
if (fnSelect.selectedIndex < first || value === "NULL" || value === "now") {
fnSelect.selectedIndex = first;
}
}
@@ -590,41 +863,51 @@ function fieldChange() {
/** Create AJAX request
* @param string
* @param function (XMLHttpRequest)
* @param [string]
* @param [string]
* @return XMLHttpRequest or false in case of an error
* @uses offlineMessage
*/
function ajax(url, callback, data, message) {
var request = (window.XMLHttpRequest ? new XMLHttpRequest() : (window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : false));
if (request) {
var ajaxStatus = qs('#ajaxstatus');
if (message) {
ajaxStatus.innerHTML = '<div class="message">' + message + '</div>';
ajaxStatus.className = ajaxStatus.className.replace(/ hidden/g, '');
} else {
ajaxStatus.className += ' hidden';
}
request.open((data ? 'POST' : 'GET'), url);
if (data) {
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (/^2/.test(request.status)) {
callback(request);
} else {
ajaxStatus.innerHTML = (request.status ? request.responseText : '<div class="error">' + offlineMessage + '</div>');
ajaxStatus.className = ajaxStatus.className.replace(/ hidden/g, '');
}
}
};
request.send(data);
/**
* Sends AJAX request.
*
* @param {string} url
* @param {function|null} onSuccess (XMLHttpRequest)
* @param {string|null} data POST data.
* @param {string|null} progressMessage
* @param {boolean} failSilently
* @return XMLHttpRequest or false in case of an error
* @uses offlineMessage
*/
function ajax(url, onSuccess = null, data = null, progressMessage = null, failSilently = false) {
const ajaxStatus = gid('ajaxstatus');
if (progressMessage) {
ajaxStatus.innerHTML = '<div class="message">' + progressMessage + '</div>';
ajaxStatus.classList.remove("hidden");
} else {
ajaxStatus.classList.add("hidden");
}
const request = new XMLHttpRequest();
request.open((data ? 'POST' : 'GET'), url);
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
if (data) {
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
if (onSuccess) {
onSuccess(request);
}
} else if (failSilently) {
console.error(request.status ? request.responseText : "No internet connection");
} else {
ajaxStatus.innerHTML = (request.status ? request.responseText : '<div class="error">' + offlineMessage + '</div>');
ajaxStatus.classList.remove("hidden");
}
}
};
request.send(data);
return request;
}
@@ -671,9 +954,9 @@ function ajaxForm(form, message, button) {
return ajax(url, function (request) {
setHtml('ajaxstatus', request.responseText);
if (window.jush) {
jush.highlight_tag(qsa('code', qs('#ajaxstatus')), 0);
jush.highlight_tag(qsa('code', gid('ajaxstatus')), 0);
}
messagesPrint(qs('#ajaxstatus'));
messagesPrint(gid('ajaxstatus'));
}, data, message);
}
@@ -688,7 +971,7 @@ function ajaxForm(form, message, button) {
*/
function selectClick(event, text, warning) {
var td = this;
var target = getTarget(event);
var target = event.target;
if (!isCtrl(event) || isTag(td.firstChild, 'input|textarea') || isTag(target, 'a')) {
return;
}
@@ -708,9 +991,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 () {
@@ -771,7 +1058,7 @@ function selectLoadMore(limit, loading) {
return !ajax(href, function (request) {
var tbody = document.createElement('tbody');
tbody.innerHTML = request.responseText;
qs('#table').appendChild(tbody);
gid('table').appendChild(tbody);
if (tbody.children.length < limit) {
a.parentNode.removeChild(a);
} else {
@@ -825,9 +1112,9 @@ function setupSubmitHighlightInput(input) {
* @this HTMLInputElement
*/
function inputFocus() {
var submit = findDefaultSubmit(this);
const submit = findDefaultSubmit(this);
if (submit) {
alterClass(submit, 'default', true);
submit.classList.toggle('default', true);
}
}
@@ -835,16 +1122,18 @@ function inputFocus() {
* @this HTMLInputElement
*/
function inputBlur() {
var submit = findDefaultSubmit(this);
const submit = findDefaultSubmit(this);
if (submit) {
alterClass(submit, 'default');
submit.classList.toggle('default', false);
}
}
/** Find submit button used by Enter
* @param HTMLElement
* @return HTMLInputElement
*/
/**
* Finds submit button used by Enter.
*
* @param {HTMLElement} el
* @return {HTMLInputElement}
*/
function findDefaultSubmit(el) {
if (el.jushTextarea) {
el = el.jushTextarea;
@@ -852,10 +1141,10 @@ function findDefaultSubmit(el) {
if (!el.form) {
return null;
}
var inputs = qsa('input', el.form);
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if (input.type === 'submit' && !input.style.zIndex) {
const inputs = qsa('input', el.form);
for (const input of inputs) {
if (input.type === 'submit' && !input.classList.contains("wayoff") && !input.style.zIndex) {
return input;
}
}
@@ -906,8 +1195,22 @@ function cloneNode(el) {
return el2;
}
function getOffsetTop(element) {
let box = element.getBoundingClientRect();
return box.top + window.scrollY;
}
function getOffsetLeft(element) {
let box = element.getBoundingClientRect();
return box.left + window.scrollX;
}
oninput = function (event) {
var target = event.target;
var maxLength = target.getAttribute('data-maxlength');
alterClass(target, 'maxlength', target.value && maxLength != null && target.value.length > maxLength); // maxLength could be 0
const target = event.target;
const maxLength = target.getAttribute('data-maxlength');
// maxLength could be 0
target.classList.toggle('maxlength', target.value && maxLength != null && target.value.length > maxLength);
};

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";
@@ -17,6 +27,22 @@ if ($comment != "") {
if ($fields) {
$adminer->tableStructurePrint($fields);
if (is_view($table_status)) {
$editLink = '<p class="links"><a href="' . h(ME) . 'view=' . urlencode($TABLE) . '">' . lang('Alter view') . "</a>\n";
} else {
$editLink = '<p class="links"><a href="' . h(ME) . 'create=' . urlencode($TABLE) . '">' . lang('Alter table') . "</a>\n";
}
echo $editLink;
if (support("partitioning") && preg_match("~partitioned~", $table_status["Create_options"])) {
echo "<h3 id='partition-by'>" . lang('Partition by') . "</h3>\n";
$partitions_info = get_partitions_info($TABLE);
$adminer->tablePartitionsPrint($partitions_info);
echo $editLink;
}
}
if (!is_view($table_status)) {
@@ -28,12 +54,12 @@ 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);
if ($foreign_keys) {
echo "<table cellspacing='0'>\n";
echo "<table>\n";
echo "<thead><tr><th>" . lang('Source') . "<td>" . lang('Target') . "<td>" . lang('ON DELETE') . "<td>" . lang('ON UPDATE') . "<td></thead>\n";
foreach ($foreign_keys as $name => $foreign_key) {
echo "<tr title='" . h($name) . "'>";
@@ -57,9 +83,9 @@ if (support(is_view($table_status) ? "view_trigger" : "trigger")) {
echo "<h3 id='triggers'>" . lang('Triggers') . "</h3>\n";
$triggers = triggers($TABLE);
if ($triggers) {
echo "<table cellspacing='0'>\n";
echo "<table>\n";
foreach ($triggers as $key => $val) {
echo "<tr valign='top'><td>" . h($val[0]) . "<td>" . h($val[1]) . "<th>" . h($key) . "<td><a href='" . h(ME . 'trigger=' . urlencode($TABLE) . '&name=' . urlencode($key)) . "'>" . lang('Alter') . "</a>\n";
echo "<tr><td>" . h($val[0]) . "<td>" . h($val[1]) . "<th>" . h($key) . "<td><a href='" . h(ME . 'trigger=' . urlencode($TABLE) . '&name=' . urlencode($key)) . "'>" . lang('Alter') . "</a>\n";
}
echo "</table>\n";
}

View File

@@ -40,7 +40,7 @@ page_header(($name != "" ? lang('Alter trigger') . ": " . h($name) : lang('Creat
<tr><th><?php echo lang('Type'); ?><td><?php echo html_select("Type", $trigger_options["Type"], $row["Type"]); ?>
</table>
<p><?php echo lang('Name'); ?>: <input name="Trigger" value="<?php echo h($row["Trigger"]); ?>" data-maxlength="64" autocapitalize="off">
<?php echo script("qs('#form')['Timing'].onchange();"); ?>
<?php echo script("gid('form')['Timing'].onchange();"); ?>
<p><?php textarea("Statement", $row["Statement"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">

View File

@@ -85,8 +85,8 @@ if ($_POST && !$error) {
unset($grants[$object]);
}
if (preg_match('~^(.+)\s*(\(.*\))?$~U', $object, $match) && (
!grant("REVOKE", $revoke, $match[2], " ON $match[1] FROM $new_user") //! SQL injection
|| !grant("GRANT", $grant, $match[2], " ON $match[1] TO $new_user")
!grant(false, $revoke, $match[2], $match[1], $new_user) //! SQL injection
|| !grant(true, $grant, $match[2], $match[1], $new_user)
)) {
$error = true;
break;
@@ -100,7 +100,7 @@ if ($_POST && !$error) {
} elseif (!isset($_GET["grant"])) {
foreach ($grants as $object => $revoke) {
if (preg_match('~^(.+)(\(.*\))?$~U', $object, $match)) {
grant("REVOKE", array_keys($revoke), $match[2], " ON $match[1] FROM $new_user");
grant(false, array_keys($revoke), $match[2], $match[1], $new_user);
}
}
}
@@ -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.
}
}
?>
@@ -135,48 +142,86 @@ if ($_POST) {
<tr><th><?php echo lang('Server'); ?><td><input name="host" data-maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="user" data-maxlength="80" value="<?php echo h($row["user"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>" autocomplete="new-password">
<?php if (!$row["hashed"]) { echo script("typePassword(qs('#pass'));"); } ?>
<?php if (!$row["hashed"]) { echo script("typePassword(gid('pass'));"); } ?>
<?php echo (min_version(8) ? "" : checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);")); ?>
</table>
<?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 "<table>\n";
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 (array(
foreach ([
"" => "",
"Server Admin" => lang('Server'),
"Databases" => lang('Database'),
"Tables" => lang('Table'),
"Columns" => lang('Column'),
"Procedures" => lang('Routine'),
) as $context => $desc) {
] as $context => $desc) {
foreach ((array) $privileges[$context] as $privilege => $comment) {
echo "<tr" . odd() . "><td" . ($desc ? ">$desc<td" : " colspan='2'") . ' lang="en" title="' . h($comment) . '">' . h($privilege);
echo "<tr" . odd() . ">";
if ($desc) {
echo "<td>$desc</td>";
}
echo "<td" . (!$desc ? " colspan='2'" : "") . ' lang="en" title="' . h($comment) . '">' . h($privilege) . "</td>";
$i = 0;
foreach ($grants as $object => $grant) {
$name = "'grants[$i][" . h(strtoupper($privilege)) . "]'";
$value = $grant[strtoupper($privilege)];
if ($context == "Server Admin" && $object != (isset($grants["*.*"]) ? "*.*" : ".*")) {
echo "<td>";
$proxiedUser = strpos($object, "@") !== false;
$newObject = $object == ".*";
$allPrivileges = $privilege == "All privileges";
$grantOption = $privilege == "Grant option";
if ($object == "*.*" && $privilege == "Proxy") {
echo "<td></td>";
} elseif ($proxiedUser && $privilege != "Proxy" && !$grantOption) {
echo "<td></td>";
} elseif ($context == "Server Admin" && $object != (isset($grants["*.*"]) ? "*.*" : ".*") && !(($proxiedUser || $newObject) && $privilege == "Proxy")) {
echo "<td></td>";
} elseif (isset($_GET["grant"])) {
echo "<td><select name=$name><option><option value='1'" . ($value ? " selected" : "") . ">" . lang('Grant') . "<option value='0'" . ($value == "0" ? " selected" : "") . ">" . lang('Revoke') . "</select>";
echo "<td><select name=$name>" .
"<option></option>" .
"<option value='1'" . ($value ? " selected" : "") . ">" . lang('Grant') . "</option>" .
"<option value='0'" . ($value == "0" ? " selected" : "") . ">" . lang('Revoke') . "</option>" .
"</select></td>";
} else {
echo "<td align='center'><label class='block'>";
echo "<input type='checkbox' name=$name value='1'" . ($value ? " checked" : "") . ($privilege == "All privileges"
? " id='grants-$i-all'>" //! uncheck all except grant if all is checked
: ">" . ($privilege == "Grant option" ? "" : script("qsl('input').onclick = function () { if (this.checked) formUncheck('grants-$i-all'); };")));
echo "<td class='center'><label class='block'>";
echo "<input type='checkbox' name=$name value='1'" .
($value ? " checked" : "") .
($allPrivileges ? " id='grants-$i-all'" : (!$grantOption ? " class='grants-$i'" : "")) .
">";
if ($allPrivileges) {
echo script("qsl('input').onclick = function () { if (this.checked) formUncheckAll('.grants-$i'); };");
} elseif (!$grantOption) {
echo script("qsl('input').onclick = function () { if (this.checked) formUncheck('grants-$i-all'); };");
}
echo "</label>";
}
$i++;
}
echo "</tr>";
}
}

View File

@@ -6,7 +6,7 @@ $variables = ($status ? show_status() : show_variables());
if (!$variables) {
echo "<p class='message'>" . lang('No rows.') . "\n";
} else {
echo "<table cellspacing='0'>\n";
echo "<table>\n";
foreach ($variables as $key => $val) {
echo "<tr>";
echo "<th><code class='jush-" . $jush . ($status ? "status" : "set") . "'>" . h($key) . "</code>";

View File

@@ -1,995 +0,0 @@
Adminer 4.9.2 (released 2024-09-18):
- Fix textarea height for single-line inputs (used typically for SQLite text field).
- Fix undefined property in error message if driver does not support error number (e.g. PostgreSQL).
- PostgreSQL: Fix search fields configuration (regression from 4.9).
- PostgreSQL: Fix search condition for network address types, add macaddr8 type.
- PostgreSQL: Fix exporting CREATE TABLE query with GENERATED default values.
- PostgreSQL: Fix exporting CREATE TABLE query with sequence default value.
- PostgreSQL: Allow to set connection's sslmode with AdminerLoginSsl plugin.
- MySQL: Do not show 'empty' enum value in strict mode.
- Editor: Fix searching in tables.
- Function to retrieve driver name that can be used in plugins.
Adminer 4.9.1 (released 2024-09-09):
- Compatibility with PHP 8.3.
- Fix compiling jush external files.
- Improved displaying of long table names in menu.
- Replace deprecated <acronym> with <abbr>.
- Add support for translations in plugins.
- Add .editorconfig file.
- MySQL: Add unix_timestamp to functions.
- PostgreSQL: Show only accessible databases.
- PostgreSQL: Make data length calculation more accurate.
- PostgreSQL: Fix documentation link for SERIAL type.
- PostgreSQL: Fix undefined properties on PHP 8.
- Elasticsearch: Fix field selection.
- AdminerEditForeign: Refactor and fix the plugin.
- AdminerLoginOtp: Autocomplete hints for OTP input field, code refactoring.
Adminer 4.9 (released 2024-08-19):
- Validate server input in login form.
- Validate connection to server in HTTP based drivers.
- Move dependencies from submodules to Composer.
- Update hydra and pepa-lintha-dark themes.
- Elasticsearch 5: Make unusable driver usable again, move it to plugins.
- Add new Elasticsearch 7 driver.
- Set saving to file as a default export option.
- Improve URL and email detection.
- Fix AdminerVersionNoverify plugin blocking other plugins to modify HTML head.
- Fix several bugs and security issues in AdminerFileUpload plugin.
- Skip dump of generated columns.
- Update composer.json.
- Add script for exporting compiled adminer variants.
Adminer 4.8.2 (released 2024-03-16):
Support multi-line table comments
MySQL: Use ST_SRID() instead of SRID() for MySQL 8 (PR #418)
PostgreSQL: Don't reset table comments (regression from 4.2.0)
PostgreSQL PDO: Allow editing rows identified by boolean column (PR #380)
Update several translations: lv, bn, fr, it, nl, ru, cs, sk
Allow responsive styles on larger devices
Adminer 4.8.1 (released 2021-05-14):
Internet Explorer or PDO in Adminer 4.7.8-4.8.0: Fix XSS in doc_link (bug #797)
Fix more PHP 8 warnings (bug #781)
Avoid PHP warnings with PDO drivers (bug #786, regression from 4.7.8)
MySQL: Allow moving views to other DB and renaming DB with views (bug #783)
MariaDB: Do not treat sequences as views (PR #416)
PostgreSQL: Support UPDATE OF triggers (bug #789)
PostgreSQL: Support triggers with more events (OR)
PostgreSQL: Fix parsing of foreign keys with non-ASCII column names
PostgreSQL < 10 PDO: Avoid displaying GENERATED ALWAYS BY IDENTITY everywhere (bug #785, regression from 4.7.9)
SQLite: Fix displayed types (bug #784, regression from 4.8.0)
Adminer 4.8.0 (released 2021-02-10):
Support function default values in insert (bug #713)
Allow SQL pseudo-function in insert
Skip date columns for non-date values in search anywhere
Add DB version to comment in export
Support PHP 8 in create table (regression from 4.7.9)
MySQL 8: Fix EXPLAIN in SQL command
PostgreSQL: Create PRIMARY KEY for auto increment columns
PostgreSQL: Avoid exporting empty sequence last value (bug #768)
PostgreSQL: Do not show triggers from other schemas (PR #412)
PostgreSQL: Fix multi-parameter functions in default values (bug #736)
PostgreSQL: Fix displaying NULL bytea fields
PostgreSQL PDO: Do not select NULL function for false values in edit
Oracle: Alter indexes
Oracle: Count tables
Oracle: Import from CSV
Oracle: Fix column size with string type
MongoDB: Handle errors
SimpleDB, Firebird, ClickHouse: Move to plugin
Adminer 4.7.9 (released 2021-02-07):
Fix XSS in browsers which don't encode URL parameters (bug #775, regression from 4.7.0)
Elasticsearch, ClickHouse: Do not print response if HTTP code is not 200
Don't syntax highlight during IME composition (bug #747)
Quote values with leading and trailing zeroes in CSV export (bug #777)
Link URLs in SQL command (PR #411)
Fix displayed foreign key columns from other DB (bug #766)
Re-enable PHP warnings (regression from 4.7.8)
MySQL: Do not export names in quotes with sql_mode='ANSI_QUOTES' (bug #749)
MySQL: Avoid error in PHP 8 when connecting to socket (PR #409)
MySQL: Don't quote default value of text fields (bug #779)
PostgreSQL: Export all FKs after all CREATE TABLE (PR #351)
PostgreSQL: Fix dollar-quoted syntax highlighting (bug #738)
PostgreSQL: Do not show view definition from other schema (PR #392)
PostgreSQL: Use bigserial for bigint auto increment (bug #765, regression from 3.0.0)
PostgreSQL PDO: Support PgBouncer, unsupport PostgreSQL < 9.1 (bug #771)
PostgreSQL 10: Support GENERATED ALWAYS BY IDENTITY (PR #386)
PostgreSQL 10: Support partitioned tables (PR #396)
PostgreSQL 11: Create PRIMARY KEY for auto increment columns
SQLite: Set busy_timeout to 500
MS SQL: Don't truncate comments to 30 chars (PR #376)
Elasticsearch 6: Fix displaying type mapping (PR #402)
MongoDB: Fix password-less check in the mongo extension (PR #405)
Editor: Cast to string when searching (bug #325)
Editor: Avoid trailing dot in export filename
Adminer 4.7.8 (released 2020-12-06):
Support PHP 8
Disallow connecting to privileged ports (bug #769)
Adminer 4.7.7 (released 2020-05-11):
Fix open redirect if Adminer is accessible at //adminer.php%2F@
Adminer 4.7.6 (released 2020-01-31):
Speed up alter table form (regression from 4.4.0)
Fix clicking on non-input fields in alter table (regression from 4.6.2)
Display time of procedure execution
Disallow connecting to ports > 65535 (bug #730)
MySQL: Always set foreign_key_checks in export
PostgreSQL: Support exporting views
Editor: Fix focusing foreign key search in select
Adminer 4.7.5 (released 2019-11-13):
Add id="" to cells with failed inline edit (bug #708)
PostgreSQL: Fix getting default value in PostgreSQL 12 (bug #719)
PostgreSQL, Oracle: Set schema for EXPLAIN queries in SQL command (bug #706)
ClickHouse: SQL command
Swedish translation
Adminer 4.7.4 (released 2019-10-22):
Fix XSS if Adminer is accessible at URL /data:
Adminer 4.7.3 (released 2019-08-27):
Allow editing foreign keys pointing to tables in other database/schema (bug #694)
Fix blocking of concurrent instances in PHP >7.2 (bug #703)
MySQL: Speed up displaying tables in large databases (bug #700, regression from 4.7.2)
MySQL: Allow editing rows identified by negative floats (bug #695)
MySQL: Skip editing generated columns
SQLite: Quote strings stored in integer columns in export (bug #696)
SQLite: Handle error in altering table (bug #697)
SQLite: Allow setting auto increment for empty tables
SQLite: Preserve auto increment when recreating table
MS SQL: Support foreign keys to other DB
MongoDB: Allow setting authSource from environment variable
Adminer 4.7.2 (released 2019-07-18):
Do not attempt logging in without password (bug #676)
Stretch footer over the whole table width (bug #624)
Allow overwriting tables when copying them
Fix displaying SQL command after Save and continue edit
Cache busting for adminer.css
MySQL: Fix displaying multi-columns foreign keys (bug #675, regression from 4.7.0)
MySQL: Fix creating users and changing password in MySQL 8 (bug #663)
MySQL: Pass SRID to GeomFromText
PostgreSQL: Fix setting column comments on new table
PostgreSQL: Display definitions of materialized views (bug #682)
PostgreSQL: Fix table status in PostgreSQL 12 (bug #683)
MS SQL: Support comments
Elasticsearch: Fix setting number of rows
Adminer 4.7.1 (released 2019-01-24):
Display the tables scrollbar (bug #647)
Remember visible columns in Create Table form (bug #493)
Add autocomplete attributes to login form
PHP <5.4 compatibility even with ClickHouse enabled (regression from 4.7.0)
SQLite: Hide server field in login form
Editor: Allow disabling boolean fields in PostgreSQL (bug #640)
Adminer 4.7.0 (released 2018-11-24):
Simplify storing executed SQL queries to bookmarks
Warn when using password with leading or trailing spaces
Hide import from server if importServerPath() returns an empty string
Fix inline editing of empty cells (regression from 4.6.3)
Allow adding more than two indexes and forign key columns at a time (regression from 4.4.0)
Avoid overwriting existing tables when copying tables (bug #642)
Fix function change with set data type
Increase username maxlength to 80 (bug #623)
Make maxlength in all fields a soft limit
Make tables horizontally scrollable
MySQL: Support foreign keys created with ANSI quotes (bug #620)
MySQL: Recognize ON UPDATE current_timestamp() (bug #632, bug #638)
MySQL: Descending indexes in MySQL 8 (bug #643)
PostgreSQL: Quote array values in export (bug #621)
PostgreSQL: Export DESC indexes (bug #639)
PostgreSQL: Support GENERATED BY DEFAULT AS IDENTITY in PostgreSQL 10
MS SQL: Pass database when connecting
ClickHouse: Connect, databases list, tables list, select, SQL command
Georgian translation
Adminer 4.6.3 (released 2018-06-28):
Disallow using password-less databases
Copy triggers when copying table
Stop session before connecting
Simplify running slow queries
Decrease timeout for running slow queries from 5 seconds to 2 seconds
Fix displaying info about non-alphabetical objects (bug #599)
Use secure cookies on HTTP if session.cookie_secure is set
PDO: Support binary fields download
MySQL: Disallow LOAD DATA LOCAL INFILE
MySQL: Use CONVERT() only when searching for non-ASCII (bug #603)
MySQL: Order database names in MySQL 8 (bug #613)
PostgreSQL: Fix editing data in views (bug #605, regression from 4.6.0)
PostgreSQL: Do not cast date/time/number/uuid searches to text (bug #608)
PostgreSQL: Export false as 0 in PDO (bug #619)
MS SQL: Support port with sqlsrv
Editor: Do not check boolean checkboxes with false in PostgreSQL (bug #607)
Adminer 4.6.2 (released 2018-02-20):
Semi-transparent border on table actions
Shorten JSON values in select (bug #594)
Speed up alter table form (regression from 4.4.0)
Store current version without authentication and in Editor
PostgreSQL: Fix exporting string default values
PostgreSQL: Fix exporting sequences in PostgreSQL 10
PostgreSQL: Add IF EXISTS to DROP SEQUENCE in export (bug #595)
Editor: Fix displaying of true boolean values (regression from 4.5.0)
Adminer 4.6.1 (released 2018-02-09):
Sticky position of table actions
Speed up rendering of long tables (regression from 4.4.0)
Display notification about performing action after relogin
Add system tables help links
MySQL: Support non-utf8 charset in search in column
MySQL: Support geometry in MySQL 8 (bug #574)
MariaDB: Links to documentation
SQLite: Allow deleting PRIMARY KEY from tables with auto increment
PostgreSQL: Support binary files in bytea fields
PostgreSQL: Don't treat interval type as number (bug #474)
PostgreSQL: Cast to string when searching using LIKE (bug #325)
PostgreSQL: Fix condition for selecting no rows
PostgreSQL: Support TRUNCATE+INSERT export
Customization: Support connecting to MySQL via SSL
Customization: Allow specifying server name displayed in breadcrumbs
Adminer 4.6.0 (released 2018-02-05):
Fix counting selected rows after going back to select page
PHP <5.3 compatibility even with Elasticsearch enabled
Fully support functions in default values
Stop redirecting links via adminer.org
Support X-Forwarded-Prefix
Display options for timestamp columns when creating a new table
Disable autocompleting password on create user page
Use primary key to edit rows even if not selected
MySQL, PostgreSQL: Display warnings
MySQL: Add floor and ceil select functions
MySQL: Add FIND_IN_SET search operator
MariaDB: Support JSON since MariaDB 10.2
SQLite, PostgreSQL: Limit rows in data manipulation without unique key
PostgreSQL: Support routines
PostgreSQL: Allow editing views with uppercase letters (bug #467)
PostgreSQL: Allow now() as default value (bug #525)
SimpleDB: Document that allow_url_fopen is required
Malay translation
Adminer 4.5.0 (released 2018-01-24):
Display name of the object in confirmation when dropping it
Display newlines in column comments (bug #573)
Support current_timestamp() as default of time fields (bug #572)
Hide window.opener from pages opened in a new window (bug #561)
Display error when getting row to edit
Store current Adminer version server-side to avoid excessive requests
Adminer: Fix Search data in tables (regression from 4.4.0)
CSP: Allow any styles, images, media and fonts, disallow base-uri
MySQL: Support geometry in MySQL 8 (bug #574)
MySQL: Support routines with comments in parameters (bug #460)
MariaDB: Support fulltext and spatial indexes in InnoDB (bug #583)
SQLite: Enable foreign key checks
PostgreSQL: Respect NULL default value
PostgreSQL: Display foreign tables (bug #576)
PostgreSQL: Do not export triggers if not requested
PostgreSQL: Export DROP SEQUENCE if dropping table
PostgreSQL: Display boolean values as code (bug #562)
MS SQL: Support freetds
non-MySQL: Avoid CONVERT() (bug #509)
Elasticsearch: Insert, update, delete
MongoDB: Support mongodb PHP extension
Editor: Fix displaying of false values in PostgreSQL (bug #568)
Adminer 4.4.0 (released 2018-01-17):
Add Content Security Policy
Disallow scripts without nonce
Rate limit password-less login attempts from the same IP address
Disallow connecting to privileged ports
Add nosniff header
PHP 7.1: Prevent warning when using empty limit
PHP 7.2: Prevent warning when searching in select
MySQL: Remove dedicated view for replication status (added in 4.3.0)
PostgreSQL: Sort table names (regression from 4.3.1)
Editor: Don't set time zone from PHP, fixes DST
Editor: Display field comment's text inside [] only in edit form
Editor: Fix doubleclick on database page
Editor: Fix Search data in tables
Customization: Always send security headers
Hebrew translation
Adminer 4.3.1 (released 2017-04-14):
Fix permanent login after logout (bug #539)
Fix SQL command autofocus (regression from 4.0.0)
PostgreSQL: Support JSON and JSONB data types
PostgreSQL: Fix index size computation in PostgreSQL < 9.0 (regression from 4.3.0)
PostgreSQL: Fix nullable fields in export
Adminer 4.3.0 (released 2017-03-15):
Make maxlength in edit fields a soft limit
Add accessibility labels
Add Cache-Control: immutable to static files
MySQL: Support MySQL 8
MySQL: Support JSON data type
MySQL: Add dedicated view for replication status
MySQL: Support spatial indexes
PostgreSQL: Export
PostgreSQL: Don't treat partial indexes as unique
MS SQL: Support pdo_dblib
Elasticsearch: Support HTTPS by inputting https://server
Adminer 4.2.5 (released 2016-06-01):
Fix remote execution in SQLite query
SQLite: Require credentials to use
PostgreSQL: Support KILL
Adminer 4.2.4 (released 2016-02-06):
Fix remote execution in SQLite query
MySQL: Support PHP 7
Bosnian translation
Finnish translation
Adminer 4.2.3 (released 2015-11-15):
Fix XSS in indexes (non-MySQL only)
Support PHP 7
Greek translation
Galician translation
Bulgarian translation
Adminer 4.2.2 (released 2015-08-05):
Fix XSS in alter table (found by HP Fortify)
Adminer 4.2.1 (released 2015-03-10):
Send referrer header to the same domain
MySQL: Fix usage of utf8mb4 if the client library doesn't support it
MySQL: Use utf8mb4 in export only if required
SQLite: Use EXPLAIN QUERY PLAN in SQL query
Adminer 4.2.0 (released 2015-02-07):
Fix XSS in login form (bug #436)
Allow limiting number of displayed rows in SQL command
Fix reading routine column collations
Unlock session in alter database
Make master key unreadable to others (bug #410)
Fix edit by long non-utf8 string
Specify encoding for PHP 5.6 with invalid default_charset
Fix saving NULL value, bug since Adminer 4.0.3
Send 403 for auth error
Report offline and other AJAX errors (bug #419)
Don't alter table comment if not changed
Add links to documentation on table status page
Fix handling of 64 bit numbers in auto_increment
Add referrer: never meta tag
MySQL: Use utf8mb4 if available
MySQL: Support foreign keys in NDB storage
PostgreSQL: Materialized views
SQLite: Support CURRENT_* default values (bug #417)
Elasticsearch: Use where in select
Firebird: Alpha version
Danish translation
Adminer 4.1.0 (released 2014-04-18):
Provide size of all databases in the overview
Prevent against brute force login attempts from the same IP address
Compute number of tables in the overview explicitly
Display edit form after error in clone or multi-edit
Trim trailing non-breaking spaces in SQL textarea
Display time of the select command
Print elapsed time in HTML instead of SQL command comment
Improve gzip export ratio (bug #387)
Use rel="noreferrer" for external links, skip adminer.org redirect in WebKit
MySQL: Fix enum types in routines (bug #391)
MySQL: Fix editing rows by binary values, bug since Adminer 3.7.1
MySQL: Respect daylight saving time in dump, bug since Adminer 3.6.4
MySQL 5.6.5+: Support ON UPDATE on datatime column
SQLite: Support UPDATE OF triggers
SQLite: Display auto-created unique indexes, bug since Adminer 3.5.0
Editor: Fix login() method, bug since Adminer 4.0.0
Translate numbers in ar, bn, fa
Vietnamese translation
Adminer 4.0.3 (released 2014-02-01)
MongoDB: insert, truncate, indexes
SimpleDB, MongoDB: insert more fields at once
SQLite: Fix creating table and altering primary key, bug since Adminer 4.0.0
Don't store invalid credentials to session, bug since Adminer 4.0.0
Norweigan translation
Adminer 4.0.2 (released 2014-01-11):
Fix handling of long text in SQL textarea
Support paste to SQL textarea in Opera
Adminer 4.0.1 (released 2014-01-11):
Don't use type=number if a SQL function is used
Disable highlighting in textareas with long texts
Don't autofocus SQL textarea in Firefox
Don't link NULL foreign key values
Fix displaying images in Editor, bug since Adminer 3.6.0
Fix uploading files, bug since Adminer 4.0.0
MongoDB: Count tables, display ObjectIds, sort, limit, offset, count rows
Elasticsearch: Fix compiled version, create and drop DB, drop table
Adminer 4.0.0 (released 2014-01-08):
Driver for SimpleDB, MongoDB and Elasticsearch
Highlight SQL in textareas
Save and continue edit by AJAX
Split SQL command and import
Add a new column in alter table on key press
Mark length as required for strings
Add label to database selection, move logout button
Add button for dropping an index
Display number of selected rows
Add links to documentation
Disable underlining links
Differentiate views in navigation
Improve speed of CSV import
Keep form values after refresh in Firefox
Mark auto_increment fields in edit
Don't append newlines to uploaded files, bug since Adminer 3.7.0
Don't display SQL edit form on Ctrl+click on the select query, introduced in Adminer 3.6.4
Use MD5 for editing long keys only in supported drivers, bug since Adminer 3.6.4
Don't reset column when searching for an empty value with Enter, bug since Adminer 3.6.4
Encrypt passwords stored in session by a key stored in cookie
Don't execute external JavaScript when verifying version
Include JUSH in the compiled version
Protect CSRF token against BREACH
Non-MySQL: View triggers
SQLite: Allow editing primary key
SQLite: Allow editing foreign keys
PostgreSQL: Fix handling of nextval() default values
PostgreSQL: Support creating array columns
Customization: Provide schemas()
Portugal Portuguese translation
Thai translation
Adminer 3.7.1 (released 2013-06-29):
Increase click target for checkboxes
Use shadow for highlighting default button
Don't use LIMIT 1 if inline updating unique row
Don't check previous checkbox on added column in create table (bug #326)
Order table list by name
Verify UTF-8 encoding of CSV import
Notify user about expired master password for permanent login
Highlight table being altered in navigation
Send 404 for invalid database and schema
Fix title and links on invalid table pages
Display error on invalid alter table and view pages
MySQL: Speed up updating rows without numeric or UTF-8 primary key
Non-MySQL: Descending indexes
PostgreSQL: Fix detecting oid column in PDO
PostgreSQL: Handle timestamp types (bug #324)
Add Korean translation
Adminer 3.7.0 (released 2013-05-19):
Allow more SQL files to be uploaded at the same time
Print run time next to executed queries
Don't drop original view and routine before creating the new one
Highlight default submit button
Add server placeholder to login form
Disable SQL export when applying functions in select
Allow using lang() in plugins (customization)
Remove bzip2 compression support
Constraint memory used in TAR export
Allow exporting views dependent on each other (bug #214)
Fix resetting search (bug #318)
Don't use LIMIT 1 if updating unique row (bug #320)
Restrict editing rows without unique identifier to search results
Display navigation bellow main content on mobile browsers
Get number of rows on export page asynchronously
Respect 'whole result' even if some rows are checked (bug #339 since Adminer 3.7.0)
MySQL: Optimize create table page and Editor navigation
MySQL: Display bit type as binary number
MySQL: Improve export of binary data types
MySQL: Fix handling of POINT data type (bug #282)
MySQL: Don't export binary and geometry columns twice in select
MySQL: Fix EXPLAIN in MySQL < 5.1, bug since Adminer 3.6.4
SQLite: Export views
PostgreSQL: Fix swapped NULL and NOT NULL columns in PDO
Adminer 3.6.4 (released 2013-04-26):
Display pagination on a fixed position
Increase default select limit to 50
Display SQL edit form on Ctrl+click on the select query
Display SQL history from newest
Recover original view, trigger, routine if creating fails
Do not store plain text password to history in creating user
Selectable ON UPDATE CURRENT_TIMESTAMP field in create table
Open database to a new window after selecting it with Ctrl
Clear column name after resetting search (bug #296)
Explain partitions in SQL query (bug #294)
Allow loading more data with inline edit (bug #299)
Stay on the same page after deleting rows (bug #301)
Respect checked tables in export filename (bug #133)
Respect PHP configuration max_input_vars
Fix unsetting permanent login after logout
Disable autocapitalize in identifiers on mobile browsers
MySQL: Compatibility with MySQL 5.6
MySQL: Move ALTER export to plugin
MySQL: Use numeric time zone in export
MySQL: Link processlist documentation
SQLite: Export indexes
Adminer 3.6.3 (released 2013-01-23):
Display error code in SQL query
Allow specifying external links
Treat Meta key same as Ctrl
Fix XSS in displaying non-UTF-8 strings
Don't use type="number" for decimal numbers
Adminer 3.6.2 (released 2012-12-21):
Edit values by Ctrl+click instead of double click
Don't select row on double click
Support NULL in routine calls
Shorten printed values in varchar fields
Display table default values on wide screens
Display date in SQL history
HTML5 input fields
Display warning for missing UPDATE privilege
Fix switching language on first load
Support enabled mbstring.func_overload
MySQL: Prolong comment length since MySQL 5.5
PostgreSQL: Fix process list in version 9.2
MS SQL: Support databases starting with number
Adminer 3.6.1 (released 2012-09-17):
Fix compiled version on PHP with multibyte support
Adminer 3.6.0 (released 2012-09-16):
Load more data in select
Edit strings with \n in textarea
Time out long running database list and select count
Use VALUES() in INSERT+UPDATE export
Style logout button as link
Store selected database to permanent login
Ctrl+click and Shift+click on button opens form to a blank window
Switch language by POST
Compress translations
MySQL: Support geometry data types
selectQueryBuild() method (customization)
Serbian translation
Adminer 3.5.1 (released 2012-08-10):
Support same name fields in CSV export
Support Shift+click in export
Adminer 3.5.0 (released 2012-08-05):
Links for column search in select
Autohide column context menu in select
Autodisplay long table names in tables list
Display assigned auto_increment after clone
SQLite: Full alter table
SQLite: Better editing in tables without primary key
SQLite: Display number of rows in database overview
Adminer 3.4.0 (released 2012-06-30):
Link to descending order
Shift+click on checkbox to select consecutive rows
Print current time next to executed SQL queries
Warn about selecting data without index
Allow specifying database in login form
Link to original table in EXPLAIN of SELECT * FROM table t
Format numbers in translations
MySQL: inform about disabled event_scheduler
SQLite: support binary data
PostgreSQL: approximate row count in table overview
PostgreSQL: improve PDO support in SQL command
Oracle: schema, processlist, table overview numbers
Simplify work with NULL values (customization)
Use namespace in login form (customization)
Customizable export filename (customization)
Replace JSMin by better JavaScript minifier
Don't use AJAX links and forms
Indonesian translation
Ukrainian translation
Bengali translation
Adminer 3.3.4 (released 2012-03-07):
Foreign keys default actions (bug #188)
SET DEFAULT foreign key action
Fix minor parser bug in SQL command with webserver file
Ctrl+click on button opens form to a blank window
Trim table and column names (bug #195)
Error message with no response from server in AJAX
Esc to cancel AJAX request
Move AJAX loading indicator to the right
Don't quote bit type in export
Don't check row while selecting text
Fix invalid references line position on Database schema
Disable selecting text on Database schema
Ability to disable export (customization)
Extensible list of databases (customization)
MySQL: set autocommit after connect
SQLite, PostgreSQL: vacuum
SQLite, PostgreSQL: don't use LIKE for numbers (bug #202)
PostgreSQL: fix alter foreign key
PostgreSQL over PDO: connect if the eponymous database does not exist (bug #185)
Boolean search (Editor)
Persian translation
Adminer 3.3.3 (released 2011-08-12):
Highlight checked rows
Titles of links in database overview and navigation
Fix trigger export (SQLite)
Default trigger statement (SQLite, PostgreSQL)
Remove search by expression (PostgreSQL, MS SQL)
Adminer 3.3.2 (released 2011-08-08):
Display error with non-existent row in edit
Fix minor parser bug in SQL command with webserver file
Fix SQL command Stop on error
Don't scroll with AJAX select order and alter move column
Fast number of rows with big tables (PostgreSQL)
Sort databases and schemas (PostgreSQL)
Adminer 3.3.1 (released 2011-07-27):
Fix XSS introduced in Adminer 3.2.0
Fix altering default values (PostgreSQL)
Process list (PostgreSQL)
Adminer 3.3.0 (released 2011-07-19):
Use Esc to disable in-place edit
Shortcut for database privileges
Editable index names
Append new index with auto index selection (bug #138)
Preserve original timestamp value in multiple update (bug #158)
Bit type default value
Display foreign key name in tooltip
Display default column value in table overview
Display column collation in tooltip
Keyboard shortcuts: Alt+Shift+1 for homepage, Ctrl+Shift+Enter for Save and continue edit
Show only errors with Webserver file SQL command
Remember select export and import options
Link tables and indexes from SQL command EXPLAIN (MySQL)
Display error with all wrong SQL commands (MySQL)
Display foreign keys from other schemas (PostgreSQL)
Pagination support (Oracle)
Autocomplete for big foreign keys (Editor)
Display name of the referenced record in PostgreSQL (Editor)
Prefer NULL to empty string (Editor, bug #162)
Display searched columns (Editor)
Customizable favicon (customization)
Method name can return a link (customization)
Easier sending of default headers (customization)
Lithuanian and Romanian translation
Adminer 3.2.2 (released 2011-03-28):
Fix AJAX history after reload
Adminer 3.2.1 (released 2011-03-23):
Ability to save expression in edit
Respect default database collation (bug #119)
Don't export triggers without table (bug #123)
Esc to focus next field in Tab textarea
Send forms by Ctrl+Enter on <select>
Enum editor and textarea Ctrl+Enter working in IE
AJAX forms in Google Chrome
Parse UTF-16 and UTF-8 BOM in all text uploads
Display ; in history
Use DELIMITER in history
Show databases even with skip_show_database in MySQL 5
Disable maxlength with functions in edit
Better placement of AJAX icon
Table header in CSV export (Editor)
Time format hint (Editor)
Respect order after search (Editor)
Set MySQL time zone by PHP setting (Editor)
Allow own code in <head> (customization)
Polish translation
Adminer 3.2.0 (released 2011-02-24):
Get long texts and slow information by AJAX
Most links and forms by AJAX in browsers with support for history.pushState
Copy tables
Ability to search by expression in select
Export SQL command result (bug #99)
Focus first field with insert (bug #106)
Permanent link in schema
Display total time in show only errors mode in SQL command
History: edit all
MS SQL: auto primary and foreign key
SQLite: display 0
Create table default data type: int
Focus upper/lower fields by Ctrl+Up/Ctrl+Down
Hide credentials for SQLite
Utilize oids in PostgreSQL
Homepage customization
Use IN for search in numeric fields (Editor)
Use password input for _md5 and _sha1 fields (Editor)
Work without session.use_cookies (bug #107)
Fix saving schema to cookie in Opera
Portuguese, Slovenian and Turkish translation
Adminer 3.1.0 (released 2010-11-16):
TSV export and import
Customizable export
Option to show only errors in SQL command
Link to bookmark SQL command
Recognize $$ strings in SQL command (PostgreSQL)
Highlight and edit SQL command in processlist
Always display all drivers
Timestamp at the end of export
Link to refresh database cache (bug #96)
Support for virtual foreign keys
Disable XSS "protection" of IE8
Immunity against zend.ze1_compatibility_mode (bug #86)
Fix last page with empty result set
Arabic translation and RTL support
Dual licensing: Apache or GPL
Adminer 3.0.1 (released 2010-10-18):
Send the form by Ctrl+Enter in all textareas
Disable creating SQLite databases with extension other than db, sdb, sqlite
Ability to use Adminer in a frame through customization
Catalan translation
MS SQL 2005 compatibility
PostgreSQL: connect if the eponymous database does not exist
Adminer 3.0.0 (released 2010-10-15):
Drivers for MS SQL, SQLite, PostgreSQL, Oracle
Allow concurrent logins on the same server
Allow permanent login without customization
In-place editation in select
Foreign key options in Table creation
Treat binary type as hex
Show number of tables in server overview
Operator LIKE %%
Remember export parameters in cookie
Allow semicolon as CSV separator
Schemas, sequences and types support (PostgreSQL)
Autofocus username in login form
Allow to insert Tab in SQL textareas and send the form by Ctrl+Enter
Disable spellchecking in SQL textareas
Display auto_increment value of inserted item
Allow disabling auto_increment value export
Prefill auto_increment column name
Ability to jump to any page in select by JavaScript
Display comment in table overview
Link last page above data in select
Link table names in SQL queries
Hungarian, Japanese and Tamil translation
Defer table information in database overview to JavaScript (performance)
Big tables optimizations (performance)
Adminer 2.3.2 (released 2010-04-21):
Fix COUNT(*) link
Fix Save and continue edit
Adminer 2.3.1 (released 2010-04-06):
Add Drop button to Alter pages (regression from 2.0.0)
Link COUNT(*) result to listing
Newlines in select query edit
Return to referrer after edit
Respect session.auto_start (bug #42)
Adminer 2.3.0 (released 2010-02-26):
Support for permanent login (customization required)
Search in all tables
Show status variables
Print sums in tables overview
Add Delete button to Edit page (regression from 2.0.0)
Print error summary in SQL command
Simplify SQL syntax error message
Show SQL query info if available
Delete length when changing type in alter table
Ability to check table prefix in export
Adminer 2.2.1 (released 2009-11-26):
Highlight current links
Improve concurrency
Move number of tables to DB info (performance)
Search by foreign keys (Editor)
Link new item in backward keys (Editor)
Adminer 2.2.0 (released 2009-10-20):
Database list - bulk drop, number of tables
Enlarge field for enum and set definition
Display table links above table structure
Link URLs in select
Display number of manipulated rows in JS confirm
Set required memory in SQL command
Fix removed default in ALTER
Display whitespace in texts (bug #11)
ClickJacking protection in modern browsers
E-mail attachments (Editor)
Optional year in date (Editor)
Search operators (Editor)
Align numbers to right in select (Editor)
Move <h1> to $adminer->navigation (customization)
Rename get_dbh to connection (customization)
Adminer 2.1.0 (released 2009-09-12):
Edit default values directly in table creation
Execute SQL file stored on server disk
Display EXPLAIN in SQL query
Compress export and import
Display column comments in table overview
Use ON DUPLICATE KEY UPDATE for CSV import
Print ALTER export instead of executing it
Click on row selects it
Fix Editor date format
Fix long SQL query crash (bug #3)
Speed up simple alter table
Traditional Chinese translation
Adminer 2.0.0 (released 2009-08-06):
Editor: User friendly data editor
Customization: Adminer class
Create single column foreign key in table structure
Table relations (Editor)
Send e-mails (Editor)
Display images in blob (Editor)
Localize date (Editor)
Treat tinyint(1) as bool (Editor)
Divide types to groups in table creation
Link e-mails in select
Show type in field name title
Preselect now() for timestamp columns
Clear history
Prefill insert by foreign key searches
Print number of rows in SQL command
Remove Delete button from Edit page - use mass operation for it
Faster multiple update, clone and delete
Faster table list in navigation
Download version checker and syntax highlighting from HTTPS
Use HTML Strict instead of XHTML
Remove function minification in favor of performance and customization
Fix grant ALL PRIVILEGES with GRANT OPTION
Fix CSV import
Fix work with default values
Adminer 1.11.1 (released 2009-07-03):
Fix problem with enabled Filter extension
Adminer 1.11.0 (released 2009-07-02):
Connection through socket by server :/path/to/socket
Simplify export
Display execution time in SQL query
Relative date and time functions
Version checker
Save queries to history and display it on SQL page
Display MySQL variables
Ability to select all rows on current page of select
Separate JavaScript functions
Always use the default style before the external one
Always try to use the syntax highlighter
All privileges in user rights
Fix FOUND_ROWS() in SQL command
Export only selected columns in select
Bulk database creation
Include views in drop and move on database overview
Hide fieldsets in select
Automatically add new fields in table creation
Use \n in SQL commands
phpMinAdmin 1.10.1 (released 2009-05-07):
Highlight odd and hover rows
Partition editing comfort (bug #12)
Allow full length in limited int
phpMinAdmin 1.10.0 (released 2009-04-28):
Partitioning (MySQL 5.1)
CSV import
Plus and minus functions
Option to stop on error in SQL command
Cross links to select and table (bug #2236232), link new item
Suhosin compatibility
Remove max_allowed_packet from export
Read style from phpMinAdmin.css if exists
Size reduction by minification of variables and functions
Russian translation
phpMinAdmin 1.9.1 (released 2008-10-27):
Update translations
phpMinAdmin 1.9.0 (released 2008-10-16):
List of tables and views with maintenance commands
Clone rows
Bulk edit and clone
Function results in edit
NOT operators in select
Search without column restriction
Use type=password for unhashed password
Only one button for each action in select
Choose language through option-list
XHTML syntax errors
Don't set global variable in export
SHOW DATABASES can be revoked
Order by function result working also in older MySQL versions
Tested on IIS
phpMinAdmin 1.8.0 (released 2008-09-12):
Events (MySQL 5.1)
Access without login - accept ?username=
Print SQL query in select, messages and warnings
Display number of found rows
Don't wrap lines in select table
Italian and Estonian translation
Order by COUNT(*)
phpMinAdmin 1.7.0 (released 2008-08-26):
Customizable export (select objects to export, SQL or CSV)
Ability to alter existing tables and drop old tables in export
Choose columns in select, aggregation
Order rows by clicking on table heading
Truncate only search results
Automatically select name for trigger
Chinese and French translation
Preserve default values when altering table
Maintain auto_increment when moving columns
Smaller multilingual file
Cache static files
Faster checking of number of results
phpMinAdmin 1.6.1 (released 2008-05-22):
Set session parameters only if not session.auto_start
phpMinAdmin 1.6.0 (released 2008-05-16):
Order of columns in table
Set max_allowed_packet in dump and use extended insert
Spanish and German translations
Use images for editing buttons
Protection against big POST data
Logout by POST
Information about logged user
Separate stylesheet
Last-Modified header for files
Several bug fixes
phpMinAdmin 1.5.0 (released 2008-01-09):
Mass delete
Vertical privileges
Specify connection port by colon in server
Ignore length in date and time types
Boolean fulltext search for all columns in MyISAM
Shrink compiled output
Remove maxlength from server and username
Uncheck NULL by change
Mark shortened fields in select
phpMinAdmin 1.4.0 (released 2007-08-15):
Privileges
New design
Dutch translation
Use NULL for auto_increment (bug #1)
Fix dropping procedure parameters
phpMinAdmin 1.3.2 (released 2007-08-06):
Next field by JavaScript in foreign keys
Set time zone in dump
Refresh lang cookie
Remember drop result in case of faulty create
Move vertical lines in schema properly
Fix maximum page in select
phpMinAdmin 1.3.1 (released 2007-07-31):
Move references lines in schema
Fix dump
Fix update links
phpMinAdmin 1.3.0 (released 2007-07-27):
Breadcrumb navigation
Operator IN
Timestamp default values
Draggable tables in schema
Number of rows in navigation
Display MySQL version and used PHP extension
More friendly user interface
Slovak translation
phpMinAdmin 1.2.0 (released 2007-07-25):
Manipulate triggers
PDO Abstraction
Auto_increment value
JavaScript for adding rows
phpMinAdmin 1.1.0 (released 2007-07-19):
Routines manipulation
Views manipulation
Foreign keys manipulation
Database schema with references
Processlist
Index length
Dump individual tables
JavaScript for next rows in table edit
Cache databases list
phpMinAdmin 1.0.0 (released 2007-07-11):
First official release

View File

@@ -6,9 +6,18 @@ function adminer_errors($errno, $errstr) {
error_reporting(6135); // errors and warnings
set_error_handler('adminer_errors', E_WARNING);
include dirname(__FILE__) . "/adminer/include/debug.inc.php";
include dirname(__FILE__) . "/adminer/include/version.inc.php";
include dirname(__FILE__) . "/vendor/vrana/jsshrink/jsShrink.php";
function is_dev_version()
{
global $VERSION;
return (bool)preg_match('~-dev$~', $VERSION);
}
function add_apo_slashes($s) {
return addcslashes($s, "\\'");
}
@@ -21,85 +30,85 @@ function add_quo_slashes($s) {
return $return;
}
function remove_lang($match) {
global $translations;
$idf = strtr($match[2], array("\\'" => "'", "\\\\" => "\\"));
$s = ($translations[$idf] ? $translations[$idf] : $idf);
if ($match[3] == ",") { // lang() has parameters
return $match[1] . (is_array($s) ? "lang(array('" . implode("', '", array_map('add_apo_slashes', $s)) . "')," : "sprintf('" . add_apo_slashes($s) . "',");
}
return ($match[1] && $match[4] ? $s : "$match[1]'" . add_apo_slashes($s) . "'$match[4]");
}
function lang_ids($match) {
function replace_lang($match) {
global $lang_ids;
$lang_id = &$lang_ids[stripslashes($match[1])];
if ($lang_id === null) {
$lang_id = count($lang_ids) - 1;
$text = stripslashes($match[1]);
if (!isset($lang_ids[$text])) {
$lang_ids[$text] = count($lang_ids);
}
return ($_SESSION["lang"] ? $match[0] : "lang($lang_id$match[2]");
return "lang($lang_ids[$text]$match[2]";
}
function put_file($match) {
global $project, $VERSION, $driver;
if (basename($match[2]) == '$LANG.inc.php') {
return $match[0]; // processed later
}
$return = file_get_contents(dirname(__FILE__) . "/$project/$match[2]");
if (basename($match[2]) == "file.inc.php") {
$return = str_replace("\n// caching headers added in compile.php", (preg_match('~-dev$~', $VERSION) ? '' : '
if ($_SERVER["HTTP_IF_MODIFIED_SINCE"]) {
header("HTTP/1.1 304 Not Modified");
exit;
}
global $project, $selected_languages, $single_driver;
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 365*24*60*60) . " GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: immutable");
'), $return, $count);
$filename = basename($match[2]);
// Language is processed later.
if ($filename == '$LANG.inc.php') {
return $match[0];
}
$content = file_get_contents(dirname(__FILE__) . "/$project/$match[2]");
if ($filename == "file.inc.php") {
$content = str_replace("\n// caching headers added in compile.php", (is_dev_version() ? '' : '
if ($_SERVER["HTTP_IF_MODIFIED_SINCE"]) {
header("HTTP/1.1 304 Not Modified");
exit;
}
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 365*24*60*60) . " GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: immutable");
'), $content, $count);
if (!$count) {
echo "adminer/file.inc.php: Caching headers placeholder not found\n";
}
}
if ($driver && dirname($match[2]) == "../adminer/drivers") {
$return = preg_replace('~^if \(isset\(\$_GET\["' . $driver . '"]\)\) \{(.*)^}~ms', '\1', $return);
}
if (basename($match[2]) != "lang.inc.php" || !$_SESSION["lang"]) {
if (basename($match[2]) == "lang.inc.php") {
$return = str_replace('function lang($idf, $number = null) {', 'function lang($idf, $number = null) {
if (is_string($idf)) { // compiled version uses numbers, string comes from a plugin
// English translation is closest to the original identifiers //! pluralized translations are not found
$pos = array_search($idf, get_translations("en")); //! this should be cached
if ($pos !== false) {
$idf = $pos;
}
}', $return, $count);
if (!$count) {
echo "lang() not found\n";
}
}
$tokens = token_get_all($return); // to find out the last token
return "?>\n$return" . (in_array($tokens[count($tokens) - 1][0], array(T_CLOSE_TAG, T_INLINE_HTML), true) ? "<?php" : "");
} elseif (preg_match('~\s*(\$pos = (.+\n).+;)~sU', $return, $match2)) {
// single language lang() is used for plural
return "function get_lang() {
return '$_SESSION[lang]';
}
function lang(\$translation, \$number = null) {
if (is_array(\$translation)) {
\$pos = $match2[2]\t\t\t: " . (preg_match("~\\\$LANG == '$_SESSION[lang]'.* \\? (.+)\n~U", $match2[1], $match3) ? $match3[1] : "1") . '
if ($filename == "lang.inc.php") {
$content = str_replace(
'return $key; // compile: convert translation key',
'static $en_translations = null;
// Convert string key used in plugins to compiled numeric key.
if (is_string($key)) {
if (!$en_translations) {
$en_translations = get_translations("en");
}
// Find text in English translations or plurals map.
if (($index = array_search($key, $en_translations)) !== false) {
$key = $index;
} elseif (($index = get_plural_translation_id($key)) !== null) {
$key = $index;
}
}
return $key;',
$content, $count
);
$translation = $translation[$pos];
}
$translation = str_replace("%d", "%s", $translation);
$number = format_number($number);
return sprintf($translation, $number);
}
';
} else {
echo "lang() \$pos not found\n";
if (!$count) {
echo "function lang() not found\n";
}
if ($selected_languages) {
$available_languages = array_fill_keys($selected_languages, true);
$content = str_replace(
'return $languages; // compile: available languages',
'return ' . var_export($available_languages, true) . ';',
$content
);
}
}
$tokens = token_get_all($content); // to find out the last token
return "?>\n$content" . (in_array($tokens[count($tokens) - 1][0], array(T_CLOSE_TAG, T_INLINE_HTML), true) ? "<?php" : "");
}
function lzw_compress($string) {
@@ -139,45 +148,73 @@ function lzw_compress($string) {
return $return . ($rest_length ? chr($rest << (8 - $rest_length)) : "");
}
function put_file_lang($match) {
global $lang_ids, $project, $langs;
if ($_SESSION["lang"]) {
return "";
}
$return = "";
foreach ($langs as $lang => $val) {
include dirname(__FILE__) . "/adminer/lang/$lang.inc.php"; // assign $translations
function put_file_lang() {
global $lang_ids, $selected_languages;
$languages = array_map(function ($filename) {
preg_match('~/([^/.]+)\.inc\.php$~', $filename, $matches);
return $matches[1];
}, glob(dirname(__FILE__) . "/adminer/lang/*.inc.php"));
$cases = "";
$plurals_map = [];
foreach ($languages as $language) {
// Include only selected language and "en" into single language compilation.
// "en" is used for translations in plugins.
if ($selected_languages && !in_array($language, $selected_languages) && $language != "en") {
continue;
}
// Assign $translations
$translations = [];
include dirname(__FILE__) . "/adminer/lang/$language.inc.php";
$translation_ids = array_flip($lang_ids); // default translation
foreach ($translations as $key => $val) {
if ($val !== null) {
$translation_ids[$lang_ids[$key]] = implode("\t", (array) $val);
$translation_ids[$lang_ids[$key]] = $val;
if ($language == "en" && is_array($val)) {
$plurals_map[$key] = $lang_ids[$key];
}
}
}
$return .= '
case "' . $lang . '": $compressed = "' . add_quo_slashes(lzw_compress(implode("\n", $translation_ids))) . '"; break;';
}
$translations_version = crc32($return);
return '$translations = $_SESSION["translations"];
if ($_SESSION["translations_version"] != ' . $translations_version . ') {
$translations = array();
$_SESSION["translations_version"] = ' . $translations_version . ';
}
function get_translations($lang) {
switch ($lang) {' . $return . '
$cases .= 'case "' . $language . '": $compressed = "' . add_quo_slashes(lzw_compress(json_encode($translation_ids, JSON_UNESCAPED_UNICODE))) . '"; break;';
}
$translations = array();
foreach (explode("\n", lzw_decompress($compressed)) as $val) {
$translations[] = (strpos($val, "\t") ? explode("\t", $val) : $val);
}
return $translations;
}
if (!$translations) {
$translations = get_translations($LANG);
$_SESSION["translations"] = $translations;
}
';
$translations_version = crc32($cases);
return '
function get_translations($lang) {
switch ($lang) {' . $cases . '}
return json_decode(lzw_decompress($compressed), true);
}
function get_plural_translation_id($key) {
$plurals_map = ' . var_export($plurals_map, true) . ';
return isset($plurals_map[$key]) ? $plurals_map[$key] : null;
}
$translations = $_SESSION["translations"];
if ($_SESSION["translations_version"] != ' . $translations_version . ') {
$translations = [];
$_SESSION["translations_version"] = ' . $translations_version . ';
}
if ($_SESSION["translations_language"] != $LANG) {
$translations = [];
$_SESSION["translations_language"] = $LANG;
}
if (!$translations) {
$translations = get_translations($LANG);
$_SESSION["translations"] = $translations;
}
';
}
function short_identifier($number, $chars) {
@@ -224,7 +261,7 @@ function php_shrink($input) {
}
$tokens = array_values($tokens);
foreach ($tokens as $i => $token) {
foreach ($tokens as $token) {
if ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) {
$short_variables[$token[1]]++;
}
@@ -258,7 +295,7 @@ function php_shrink($input) {
$tokens[$i+4] = array(0, ';');
}
if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE || ($token[0] == T_DOC_COMMENT && $doc_comment)) {
$space = "\n";
$space = " ";
} else {
if ($token[0] == T_DOC_COMMENT) {
$doc_comment = true;
@@ -287,9 +324,13 @@ function php_shrink($input) {
} elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) {
$token[1] = '$' . $short_variables[$token[1]];
}
if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
if ($token[0] == T_FUNCTION || $token[0] == T_CLASS || $token[0] == T_INTERFACE || $token[0] == T_TRAIT) {
$space = "\n";
} elseif (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
$space = '';
}
$output .= $space . $token[1];
$space = '';
}
@@ -340,60 +381,78 @@ function number_type() {
}
$project = "adminer";
if ($_SERVER["argv"][1] == "editor") {
array_shift($argv);
if ($argv[0] == "editor") {
$project = "editor";
array_shift($_SERVER["argv"]);
array_shift($argv);
}
$driver = "";
if (file_exists(dirname(__FILE__) . "/adminer/drivers/" . $_SERVER["argv"][1] . ".inc.php")) {
$driver = $_SERVER["argv"][1];
array_shift($_SERVER["argv"]);
$selected_drivers = [];
if ($argv) {
$params = explode(",", $argv[0]);
if (file_exists(dirname(__FILE__) . "/adminer/drivers/" . $params[0] . ".inc.php")) {
$selected_drivers = $params;
array_shift($argv);
}
}
$single_driver = count($selected_drivers) == 1 ? $selected_drivers[0] : null;
unset($_COOKIE["adminer_lang"]);
$_SESSION["lang"] = $_SERVER["argv"][1]; // Adminer functions read language from session
include dirname(__FILE__) . "/adminer/include/lang.inc.php";
if (isset($langs[$_SESSION["lang"]])) {
include dirname(__FILE__) . "/adminer/lang/$_SESSION[lang].inc.php";
array_shift($_SERVER["argv"]);
$selected_languages = [];
if ($argv) {
$params = explode(",", $argv[0]);
if (file_exists(dirname(__FILE__) . "/adminer/lang/" . $params[0] . ".inc.php")) {
$selected_languages = $params;
array_shift($argv);
}
}
$single_language = count($selected_languages) == 1 ? $selected_languages[0] : null;
if ($_SERVER["argv"][1]) {
echo "Usage: php compile.php [editor] [driver] [lang]\n";
if ($argv) {
echo "Usage: php compile.php [editor] [driver] [language]\n";
echo "Purpose: Compile adminer[-driver][-lang].php or editor[-driver][-lang].php.\n";
exit(1);
}
// check function definition in drivers
// Check function definition in drivers.
$file = file_get_contents(dirname(__FILE__) . "/adminer/drivers/mysql.inc.php");
$file = preg_replace('~class Min_Driver.*\n\t}~sU', '', $file);
preg_match_all('~\bfunction ([^(]+)~', $file, $matches); //! respect context (extension, class)
$functions = array_combine($matches[1], $matches[0]);
//! do not warn about functions without declared support()
unset($functions["__construct"], $functions["__destruct"], $functions["set_charset"]);
foreach (glob(dirname(__FILE__) . "/adminer/drivers/" . ($driver ? $driver : "*") . ".inc.php") as $filename) {
if ($filename != "mysql.inc.php") {
$file = file_get_contents($filename);
foreach ($functions as $val) {
if (!strpos($file, "$val(")) {
fprintf(STDERR, "Missing $val in $filename\n");
}
foreach (glob(dirname(__FILE__) . "/adminer/drivers/*.inc.php") as $filename) {
preg_match('~/([^/.]+)\.inc\.php$~', $filename, $matches);
if ($matches[1] == "mysql" || ($selected_drivers && !in_array($matches[1], $selected_drivers))) {
continue;
}
$file = file_get_contents($filename);
foreach ($functions as $function) {
if (!strpos($file, "$function(")) {
fprintf(STDERR, "Missing $function in $filename\n");
}
}
}
include dirname(__FILE__) . "/adminer/include/pdo.inc.php";
include dirname(__FILE__) . "/adminer/include/driver.inc.php";
$features = array("call" => "routine", "dump", "event", "privileges", "procedure" => "routine", "processlist", "routine", "scheme", "sequence", "status", "trigger", "type", "user" => "privileges", "variables", "view");
$lang_ids = array(); // global variable simplifies usage in a callback function
$features = ["call" => "routine", "dump", "event", "privileges", "procedure" => "routine", "processlist", "routine", "scheme", "sequence", "status", "trigger", "type", "user" => "privileges", "variables", "view"];
$lang_ids = []; // global variable simplifies usage in a callback functions
// Start with index.php.
$file = file_get_contents(dirname(__FILE__) . "/$project/index.php");
if ($driver) {
$_GET[$driver] = true; // to load the driver
include_once dirname(__FILE__) . "/adminer/drivers/$driver.inc.php";
// Remove including source code for unsupported features in single-driver file.
if ($single_driver) {
$_GET[$single_driver] = true; // to load the driver
include_once dirname(__FILE__) . "/adminer/drivers/$single_driver.inc.php";
foreach ($features as $key => $feature) {
if (!support($feature)) {
if (!is_int($key)) {
if (is_string($key)) {
$feature = $key;
}
$file = str_replace("} elseif (isset(\$_GET[\"$feature\"])) {\n\tinclude \"./$feature.inc.php\";\n", "", $file);
@@ -403,55 +462,70 @@ if ($driver) {
$file = str_replace("if (isset(\$_GET[\"callf\"])) {\n\t\$_GET[\"call\"] = \$_GET[\"callf\"];\n}\nif (isset(\$_GET[\"function\"])) {\n\t\$_GET[\"procedure\"] = \$_GET[\"function\"];\n}\n", "", $file);
}
}
// Compile files included into the index.php.
$file = preg_replace_callback('~\b(include|require) "([^"]*)";~', 'put_file', $file);
// Remove including debug files.
$file = str_replace('include "../adminer/include/debug.inc.php";', '', $file);
$file = str_replace('include "../adminer/include/coverage.inc.php";', '', $file);
if ($driver) {
$file = preg_replace('(include "../adminer/drivers/(?!' . preg_quote($driver) . '\.).*\s*)', '', $file);
// Remove including unwanted drivers.
if ($selected_drivers) {
$file = preg_replace_callback('~include "../adminer/drivers/([^.]+).*\n~', function ($match) use ($selected_drivers) {
return in_array($match[1], $selected_drivers) ? $match[0] : "";
}, $file);
}
$file = preg_replace_callback('~\b(include|require) "([^"]*)";~', 'put_file', $file); // bootstrap.inc.php
if ($driver) {
// Compile files included into the bootstrap.inc.php.
$file = preg_replace_callback('~\b(include|require) "([^"]*)";~', 'put_file', $file);
if ($single_driver) {
// Remove source code for unsupported features.
foreach ($features as $feature) {
if (!support($feature)) {
$file = preg_replace("((\t*)" . preg_quote('if (support("' . $feature . '")') . ".*\n\\1\\})sU", '', $file);
}
}
if (count($drivers) == 1) {
$file = str_replace('<?php echo html_select("auth[driver]", $drivers, DRIVER) . "\n"; ?>', "<input type='hidden' name='auth[driver]' value='" . ($driver == "mysql" ? "server" : $driver) . "'>" . reset($drivers), $file);
}
$file = preg_replace('(;\.\./vendor/vrana/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($driver == "mysql" ? "sql" : $driver) . '\.)[^.]+.js)', '', $file);
$file = preg_replace_callback('~doc_link\(array\((.*)\)\)~sU', function ($match) use ($driver) {
$file = preg_replace('(;\.\./vendor/vrana/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($single_driver == "mysql" ? "sql" : $single_driver) . '\.)[^.]+.js)', '', $file);
$file = preg_replace_callback('~doc_link\(array\((.*)\)\)~sU', function ($match) use ($single_driver) {
list(, $links) = $match;
$links = preg_replace("~'(?!(" . ($driver == "mysql" ? "sql|mariadb" : $driver) . ")')[^']*' => [^,]*,?~", '', $links);
$links = preg_replace("~'(?!(" . ($single_driver == "mysql" ? "sql|mariadb" : $single_driver) . ")')[^']*' => [^,]*,?~", '', $links);
return (trim($links) ? "doc_link(array($links))" : "''");
}, $file);
//! strip doc_link() definition
}
if ($project == "editor") {
$file = preg_replace('~;\.\./vendor/vrana/jush/jush\.css~', '', $file);
$file = preg_replace('~compile_file\(\'\.\./(vendor/vrana/jush/modules/jush\.js|adminer/static/[^.]+\.gif)[^)]+\)~', "''", $file);
}
$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file);
$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'replace_lang', $file);
$file = preg_replace_callback('~\b(include|require) "([^"]*\$LANG.inc.php)";~', 'put_file_lang', $file);
$file = str_replace("\r", "", $file);
if ($_SESSION["lang"]) {
// single language version
$file = preg_replace_callback("~(<\\?php\\s*echo )?lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])(;\\s*\\?>)?~s", 'remove_lang', $file);
$file = str_replace("<?php switch_lang(); ?>\n", "", $file);
$file = str_replace('<?php echo $LANG; ?>', $_SESSION["lang"], $file);
}
$file = str_replace('<?php echo script_src("static/editing.js"); ?>' . "\n", "", $file);
$file = str_replace('<?php echo script_src("static/editing.js?" . filemtime("../adminer/static/editing.js")); ?>' . "\n", "", $file);
$file = preg_replace('~\s+echo script_src\("\.\./vendor/vrana/jush/modules/jush-(textarea|txt|js|\$jush)\.js"\);~', '', $file);
$file = str_replace('<link rel="stylesheet" type="text/css" href="../vendor/vrana/jush/jush.css">' . "\n", "", $file);
$file = preg_replace_callback("~compile_file\\('([^']+)'(?:, '([^']*)')?\\)~", 'compile_file', $file); // integrate static files
$replace = 'preg_replace("~\\\\\\\\?.*~", "", ME) . "?file=\1&version=' . substr(md5(microtime()), 0, 8) . '"';
$file = preg_replace('~\.\./adminer/static/(default\.css|favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~"\.\./adminer/static/(functions\.js)"~', $replace, $file);
$file = preg_replace('~\.\./adminer/static/(favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~\.\./adminer/static/(default\.css)\?.*default.css"\);\s+\?>~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~"\.\./adminer/static/(functions\.js)\?".*functions.js"\)~', $replace, $file);
$file = preg_replace('~\.\./adminer/static/([^\'"]*)~', '" . h(' . $replace . ') . "', $file);
$file = preg_replace('~"\.\./vendor/vrana/jush/modules/(jush\.js)"~', $replace, $file);
$file = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $file);
$file = php_shrink($file);
@mkdir("temp/export", 0777, true);
$filename = "temp/export/$project" . (preg_match('~-dev$~', $VERSION) ? "" : "-$VERSION") . ($driver ? "-$driver" : "") . ($_SESSION["lang"] ? "-$_SESSION[lang]" : "") . ".php";
@mkdir("temp", 0777, true);
$filename = "temp/$project"
. (is_dev_version() ? "" : "-$VERSION")
. ($single_driver ? "-$single_driver" : "")
. ($single_language ? "-$single_language" : "")
. ".php";
file_put_contents($filename, $file);
echo "$filename created (" . strlen($file) . " B).\n";

View File

@@ -1,19 +1,22 @@
{
"name": "vrana/adminer",
"name": "pematon/adminer",
"description": "Database management in a single PHP file.",
"homepage": "https://www.adminer.org/",
"homepage": "https://github.com/pematon/adminer",
"keywords": [
"database"
],
"support": {
"issues": "https://sourceforge.net/p/adminer/bugs-and-features/",
"forum": "https://sourceforge.net/p/adminer/discussion/",
"source": "https://github.com/vrana/adminer/"
"issues": "https://github.com/pematon/adminer/issues",
"forum": "https://github.com/pematon/adminer/discussions",
"source": "https://github.com/pematon/adminer"
},
"authors": [
{
"name": "Jakub Vrána",
"homepage": "https://www.vrana.cz/"
},
{
"name": "Peter Knut"
}
],
"autoload": {
@@ -29,7 +32,7 @@
"php": "5.6 - 8.3",
"ext-pdo": "*",
"ext-json": "*",
"vrana/jush": "@dev",
"vrana/jush": "2.0.*",
"vrana/jsshrink": "@dev"
},
"suggest": {
@@ -39,6 +42,7 @@
"ext-mysql": "*",
"ext-pgsql": "*",
"ext-mongo": "*",
"ext-mongodb": "*",
"ext-sqlsrv": "*",
"ext-mssql": "*",
"ext-oci8": "*",
@@ -57,7 +61,7 @@
"repositories": [
{
"type": "vcs",
"url": "https://github.com/vrana/jush.git"
"url": "https://github.com/pematon/jush.git"
},
{
"type": "vcs",

View File

@@ -62,7 +62,7 @@ if (!extension_loaded("xdebug")) {
if (file_exists($coverage_filename)) {
// display list of files
$coverage = unserialize(file_get_contents($coverage_filename));
echo "<table border='1' cellspacing='0'>\n";
echo "<table>\n";
foreach (array_merge(glob("adminer/*.php"), glob("adminer/include/*.php"), glob("editor/*.php"), glob("editor/include/*.php")) as $filename) {
$cov = $coverage[realpath($filename)];
$ratio = 0;

14
docs/upgrade.md Normal file
View File

@@ -0,0 +1,14 @@
Upgrade guide
=============
Migrating to 4.10
-----------------
- Remove plugin AdminerTablesFilter (plugins/tables-filter.php) if you use it. Its functionality was integrated into the
base code.
- If you use complex custom theme, you will probably need to adjust a thing or two.
Migrating to 4.9
----------------
- Minimum required PHP version is 5.6.

View File

@@ -11,11 +11,11 @@ if ($adminer->homepage()) {
echo "<table cellspacing='0' class='nowrap checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo '<thead><tr class="wrap">';
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("qs('#check-all').onclick = partial(formCheck, /^tables\[/);", "");
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("gid('check-all').onclick = partial(formCheck, /^tables\[/);", "");
echo '<th>' . lang('Table');
echo '<td>' . lang('Rows');
echo "</thead>\n";
foreach (table_status() as $table => $row) {
$name = $adminer->tableName($row);
if (isset($row["Engine"]) && $name != "") {
@@ -25,7 +25,7 @@ if ($adminer->homepage()) {
echo "<td align='right'><a href='" . h(ME . "edit=") . urlencode($table) . "'>" . ($row["Engine"] == "InnoDB" && $val ? "~ $val" : $val) . "</a>";
}
}
echo "</table>\n";
echo "</div>\n";
echo "</form>\n";

View File

@@ -1,10 +1,12 @@
<?php
class Adminer {
var $operators = array("<=", ">=");
var $operator_like = null;
var $operator_regexp = null;
var $_values = array();
function name() {
return "<a href='https://www.adminer.org/editor/'" . target_blank() . " id='h1'>" . lang('Editor') . "</a>";
return "<a id='h1' href='" . h(HOME_URL) . "'>" . lang('Editor') . "</a>";
}
//! driver, ns
@@ -16,8 +18,11 @@ class Adminer {
function connectSsl() {
}
/**
* @throws \Random\RandomException
*/
function permanentLogin($create = false) {
return password_file($create);
return get_private_key($create);
}
function bruteForceKey() {
@@ -72,7 +77,7 @@ class Adminer {
function loginForm() {
echo "<table cellspacing='0' class='layout'>\n";
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input type="hidden" name="auth[driver]" value="server"><input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(qs('#username'));"));
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input type="hidden" name="auth[driver]" value="mysql"><input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(gid('username'));"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">' . "\n");
echo "</table>\n";
echo "<p><input type='submit' value='" . lang('Login') . "'>\n";
@@ -259,15 +264,20 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5
if (($val["col"] == "" || $columns[$val["col"]]) && "$val[col]$val[val]" != "") {
echo "<div><select name='where[$i][col]'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, $val["col"], true) . "</select>";
echo html_select("where[$i][op]", array(-1 => "") + $this->operators, $val["op"]);
echo "<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "'>" . script("mixin(qsl('input'), {onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", "") . "</div>\n";
echo "<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "'>" . script("mixin(qsl('input'), {onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", "");
echo " <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>" . script('qsl("#fieldset-search .remove").onclick = selectRemoveRow;', "");
echo "</div>\n";
$i++;
}
}
echo "<div><select name='where[$i][col]'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, null, true) . "</select>";
echo script("qsl('select').onchange = selectAddRow;", "");
echo html_select("where[$i][op]", array(-1 => "") + $this->operators);
echo "<input type='search' name='where[$i][val]'></div>";
echo "<input type='search' name='where[$i][val]'>";
echo script("mixin(qsl('input'), {onchange: function () { this.parentNode.firstChild.onchange(); }, onsearch: selectSearchSearch});");
echo " <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>";
echo script('qsl("#fieldset-search .remove").onclick = selectRemoveRow;', "");
echo "</div>";
echo "</div></fieldset>\n";
}
@@ -350,10 +360,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);
@@ -480,7 +490,7 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5
return $return;
}
function editInput($table, $field, $attrs, $value) {
function editInput($table, $field, $attrs, $value, $function) {
if ($field["type"] == "enum") {
return (isset($_GET["select"]) ? "<label><input type='radio'$attrs value='-1' checked><i>" . lang('original') . "</i></label> " : "")
. enum_input("radio", $attrs, $field, ($value || isset($_GET["select"]) ? $value : 0), ($field["null"] ? "" : null))
@@ -508,7 +518,9 @@ qsl('div').onclick = whisperClick;", "")
$hint = lang('[yyyy]-mm-dd') . ($hint ? " [$hint]" : "");
}
if ($hint) {
return "<input value='" . h($value) . "'$attrs> ($hint)"; //! maxlength
return "<input"
. ($function != "now" ? " value='" . h($value) . "'" : " data-last-value='" . h($value) . "'")
. "$attrs> ($hint)"; //! maxlength
}
if (preg_match('~_(md5|sha1)$~i', $field["field"])) {
return "<input type='password' value='" . h($value) . "'$attrs>";
@@ -579,6 +591,7 @@ qsl('div').onclick = whisperClick;", "")
}
function importServerPath() {
return null;
}
function homepage() {
@@ -587,14 +600,26 @@ qsl('div').onclick = whisperClick;", "")
function navigation($missing) {
global $VERSION;
?>
?>
<h1>
<?php echo $this->name(); ?>
<?php if ($missing != "auth"): ?>
<span class="version"><?php echo $VERSION; ?></span>
<a href="https://www.adminer.org/editor/#download"<?php echo target_blank(); ?> id="version"><?php echo (version_compare($VERSION, $_COOKIE["adminer_version"]) < 0 ? h($_COOKIE["adminer_version"]) : ""); ?></a>
<?php echo $this->name(); ?>
<?php if ($missing != "auth"): ?>
<span class="version">
<?php echo $VERSION; ?>
<a href="https://github.com/pematon/adminer/releases"<?php echo target_blank(); ?> id="version">
<?php echo (version_compare($VERSION, $_COOKIE["adminer_version"]) < 0 ? h($_COOKIE["adminer_version"]) : ""); ?>
</a>
</span>
<?php
if (!isset($_COOKIE["adminer_version"])) {
echo script("verifyVersion('" . js_escape(ME) . "', '" . get_token() . "');");
}
?>
<?php endif; ?>
</h1>
<?php
if ($missing == "auth") {
$first = true;
@@ -603,7 +628,7 @@ qsl('div').onclick = whisperClick;", "")
if ($password !== null) {
if ($first) {
echo "<ul id='logins'>";
echo script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});");
echo script("mixin(gid('logins'), {onmouseover: menuOver, onmouseout: menuOut});");
$first = false;
}
echo "<li><a href='" . h(auth_url($vendor, "", $username)) . "'>" . ($username != "" ? h($username) : "<i>" . lang('empty') . "</i>") . "</a>\n";
@@ -617,6 +642,7 @@ qsl('div').onclick = whisperClick;", "")
if (!$table_status) {
echo "<p class='message'>" . lang('No tables.') . "\n";
} else {
$this->printTablesFilter();
$this->tablesPrint($table_status);
}
}
@@ -626,19 +652,32 @@ qsl('div').onclick = whisperClick;", "")
function databasesPrint($missing) {
}
function printTablesFilter()
{
global $adminer;
echo "<div class='tables-filter jsonly'>"
. "<input id='tables-filter' autocomplete='off' placeholder='" . lang('Table') . "'>"
. script("initTablesFilter(" . json_encode($adminer->database()) . ");")
. "</div>\n";
}
function tablesPrint($tables) {
echo "<ul id='tables'>";
echo script("mixin(qs('#tables'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='tables'>" . script("mixin(gid('tables'), {onmouseover: menuOver, onmouseout: menuOut});");
foreach ($tables as $row) {
echo '<li>';
$name = $this->tableName($row);
if (isset($row["Engine"]) && $name != "") { // ignore views and tables without name
echo "<a href='" . h(ME) . 'select=' . urlencode($row["Name"]) . "'"
. bold($_GET["select"] == $row["Name"] || $_GET["edit"] == $row["Name"], "select")
. " title='" . lang('Select data') . "'>$name</a>\n"
;
// Skip views and tables without a name.
if (!isset($row["Engine"]) || ($name = $this->tableName($row)) == "") {
continue;
}
$active = $_GET["select"] == $row["Name"] || $_GET["edit"] == $row["Name"];
echo '<li><a href="' . h(ME) . 'select=' . urlencode($row["Name"]) . '"'
. bold($active, "select")
. " title='" . lang('Select data') . "' data-main='true'>$name</a></li>\n";
}
echo "</ul>\n";
}
@@ -652,6 +691,8 @@ qsl('div').onclick = whisperClick;", "")
}
}
}
return null;
}
function _foreignKeyOptions($table, $column, $value = null) {

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

@@ -1,11 +1,14 @@
<?php
/** Adminer Editor - Compact database editor
* @link https://www.adminer.org/
* @author Jakub Vrana, https://www.vrana.cz/
* @copyright 2009 Jakub Vrana
* @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)
*/
/**
* Adminer Editor - Compact database editor for end-users
*
* @link https://github.com/pematon/adminer
* @author Jakub Vrana (https://www.vrana.cz/)
* @author Peter Knut
* @copyright 2009-2021 Jakub Vrana, 2024 Peter Knut
* @license Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
* @license GNU General Public License, version 2 (https://www.gnu.org/licenses/gpl-2.0.html)
*/
include "../adminer/include/bootstrap.inc.php";
$drivers[DRIVER] = lang('Login');

View File

@@ -2,16 +2,16 @@
function adminer_object() {
include_once "../plugins/plugin.php";
include_once "../plugins/login-password-less.php";
class AdminerCustomization extends AdminerPlugin {
function loginFormField($name, $heading, $value) {
return parent::loginFormField($name, $heading, str_replace('value="server"', 'value="sqlite"', $value));
return parent::loginFormField($name, $heading, str_replace('value="mysql"', 'value="sqlite"', $value));
}
function database() {
return "PATH_TO_YOUR_SQLITE_HERE";
}
}
return new AdminerCustomization(array(
// TODO: inline the result of password_hash() so that the password is not visible in source codes
new AdminerLoginPasswordLess(password_hash("YOUR_PASSWORD_HERE", PASSWORD_DEFAULT)),

View File

@@ -6,13 +6,14 @@ function messagesPrint() {
function selectFieldChange() {
}
var helpOpen;
// Help.
(function() {
window.initHelpPopup = function () {
};
function helpMouseover() {
}
function helpMouseout() {
}
window.initHelpFor = function(element, content, side = false) {
};
})();
/** Display typeahead
* @param string
@@ -42,7 +43,7 @@ function whisper(url) {
*/
function whisperClick(event) {
var field = this.previousSibling;
var el = getTarget(event);
var el = event.target;
if (isTag(el, 'a') && !(event.button || event.shiftKey || event.altKey || isCtrl(event))) {
field.value = el.firstChild.data;
field.previousSibling.value = decodeURIComponent(el.href.replace(/.*=/, ''));

View File

@@ -5,7 +5,7 @@ unset($_COOKIE["adminer_lang"]);
$_SESSION["lang"] = isset($_SERVER["argv"][1]) ? $_SERVER["argv"][1] : null; // Adminer functions read language from session
if (isset($_SESSION["lang"])) {
include dirname(__FILE__) . "/adminer/include/lang.inc.php";
if (isset($_SERVER["argv"][2]) || (!isset($langs[$_SESSION["lang"]]) && $_SESSION["lang"] != "xx")) {
if (isset($_SERVER["argv"][2]) || (!isset($languages[$_SESSION["lang"]]) && $_SESSION["lang"] != "xx")) {
echo "Usage: php lang.php [lang]\nPurpose: Update adminer/lang/*.inc.php from source code messages.\n";
exit(1);
}

21
plugins/adminer.js.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
/**
* Enables auto-detection and inclusion of adminer.js, like adminer.css
*
* @author Roy Orbitson, https://github.com/Roy-Orbison
*
* @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 AdminerDotJs
{
const FileName = "adminer.js";
function head()
{
if (file_exists(self::FileName)) {
echo script_src(self::FileName . "?v=" . crc32(file_get_contents(self::FileName))), "\n";
}
}
}

View File

@@ -427,6 +427,7 @@ if (isset($_GET["clickhouse"])) {
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"),
'operator_like' => "LIKE %%",
'functions' => array(),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(),

Some files were not shown because too many files have changed in this diff Show More