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

Compare commits

...

337 Commits

Author SHA1 Message Date
Jakub Vrana
99a0949d2a Release 5.1.0 2025-03-24 17:35:22 +01:00
Jakub Vrana
1cf5a91d98 Export: Use output buffering 2025-03-24 17:28:53 +01:00
Jakub Vrana
dcde78eef2 Document //! 2025-03-24 17:21:44 +01:00
Jakub Vrana
88821a5780 Move beforeunload to plugin 2025-03-24 16:55:40 +01:00
Jakub Vrana
078a8b3d6b Improve handling of translations with ' 2025-03-24 15:57:46 +01:00
Inoyatulloh
4df205d4ec Added Uzbek language 2025-03-24 15:44:30 +01:00
Karel Uhlík
a50395c275 AdminerTablesFilter: Fix JS variable visibility
fix error: Uncaught ReferenceError: reg is not defined
2025-03-24 15:28:02 +01:00
Jakub Vrana
8b93d51c68 MS SQL PDO: Hide unsupported EXPLAIN 2025-03-24 14:47:55 +01:00
Jakub Vrana
50cdbbe415 Non-MySQL: Better field types in SQL command 2025-03-24 14:43:15 +01:00
Jakub Vrana
f5d23a8cad MS SQL PDO: Display last insert ID 2025-03-24 14:25:38 +01:00
Jakub Vrana
3bc675b0fc MS SQL: Common parent for PDO Db 2025-03-24 14:11:25 +01:00
Jakub Vrana
b86a9cb5fb Turn on output buffering only after sending headers
Otherwise output sent before Location (usually errors) is lost.
2025-03-24 14:04:17 +01:00
Jakub Vrana
cd53c54b6a Tests MS SQL: Connect to default server 2025-03-24 13:53:11 +01:00
Jakub Vrana
99163feefb SQLite PDO: Display results in SQL query 2025-03-24 13:53:11 +01:00
Jakub Vrana
84e4971b1e Tests: Check loaded plugin 2025-03-24 13:53:11 +01:00
Jakub Vrana
d22b1091f1 Notices: fetch_field in PDO 2025-03-24 13:53:10 +01:00
Jakub Vrana
b349830758 PostgreSQL: Fix number of affected rows after clone 2025-03-24 12:18:24 +01:00
Jakub Vrana
b8eb0ad8f5 Notices: Declare properties in fetch_field() 2025-03-24 12:18:24 +01:00
Jakub Vrana
c47590bb0d Fix JS error on AI column input 2025-03-24 12:18:24 +01:00
Jakub Vrana
486f164247 Notices: Declare Db::$info at least in MySQL 2025-03-24 12:18:24 +01:00
Jakub Vrana
edce93ca80 Tests: Fix AI 2025-03-24 12:18:20 +01:00
Jakub Vrana
858c914a50 AdminerDarkSwitcher: Icon 2025-03-24 07:38:33 +01:00
Jakub Vrana
9fd9a1fc8d Mute the same error in PHP 5 2025-03-24 07:30:22 +01:00
Jakub Vrana
60555c5736 Editor: Fix pre-selecting empty enum 2025-03-24 07:30:22 +01:00
Jakub Vrana
8cec1bd611 Notices: Declare Adminer::$error 2025-03-24 07:30:22 +01:00
Jakub Vrana
9b84908b99 Notices: Require declared properties 2025-03-24 07:30:22 +01:00
Jakub Vrana
3dd1b41472 Notices: Store maria into a declared variable 2025-03-24 07:30:22 +01:00
Jakub Vrana
b89f628e40 Reset onbeforeupload after Save and continue edit 2025-03-24 07:30:22 +01:00
Jakub Vrana
708646156a Notices: Enable E_NOTICE and E_STRICT 2025-03-24 07:30:20 +01:00
Jakub Vrana
9e52f0fa2e Notices: Check session status before restarting 2025-03-23 22:09:46 +01:00
Jakub Vrana
3cd50c9a02 Notices: Silent unavoidable error 2025-03-23 21:47:32 +01:00
Jakub Vrana
f5ecb18896 Notices: Add helper for reset() with expression 2025-03-23 21:39:25 +01:00
Jakub Vrana
0501846743 AdminerSqlGemini: Support multiple instructions
Example:
Cities speaking Czech.
Then create indexes so it's fast.
2025-03-23 20:24:25 +01:00
Jakub Vrana
8db8b7a10d Plugins: Use call_user_func_array 2025-03-23 20:22:41 +01:00
Jakub Vrana
d6a417fa58 Add comment 2025-03-23 20:22:41 +01:00
Jakub Vrana
4477f95426 AdminerEditCalendar: Avoid work in constructor 2025-03-23 20:22:41 +01:00
Jakub Vrana
6a64c7771b Plugins: Display doc-comments at server overview 2025-03-23 20:22:41 +01:00
Jakub Vrana
c32e4f82fe AdminerSqlGemini: Display progress 2025-03-23 20:22:41 +01:00
Jakub Vrana
19bb320e7a New plugin: Verify new versions from GitHub
Thanks to @adrianbj in 441e7f0.
2025-03-23 20:22:40 +01:00
Jakub Vrana
fb47ba6bbb Add instructions to translation files 2025-03-23 15:35:30 +01:00
Jakub Vrana
03ff0bbc04 JS: Use classList instead of className 2025-03-23 15:10:18 +01:00
Jakub Vrana
e8055329a6 CSS: Move Logout down on narrow screens (fix #938) 2025-03-23 14:06:11 +01:00
Jakub Vrana
9142e7e8a5 AdminerDumpAlter: Rename colliding method (fix #943) 2025-03-23 13:56:40 +01:00
Jakub Vrana
e975e546e1 Docs: improve style thanks to ChatGPT 2025-03-23 13:52:38 +01:00
Jakub Vrana
1b59b10f62 MySQLi: Avoid using PHP 8.1 method
This reverts 359fdf3.
2025-03-23 12:40:12 +01:00
Jakub Vrana
f1a8bd9ef8 Chrome 134 on iOS: Allow zooming out (bug #940) 2025-03-23 12:40:07 +01:00
Jakub Vrana
204176b33b New plugin: AI prompt in SQL command creating the queries with Google Gemini 2025-03-23 08:02:48 +01:00
Jakub Vrana
cf436d7317 Add CONTRIBUTING 2025-03-23 00:25:49 +01:00
Jakub Vrana
7eb92d9601 Add notes for developers 2025-03-23 00:25:48 +01:00
Jakub Vrana
8da9239279 Plugins: Remove obsolete instructions 2025-03-22 22:34:52 +01:00
Jakub Vrana
e0dde9034f Doc-comments: Use consistent style 2025-03-22 21:04:58 +01:00
Jakub Vrana
9b162e8291 PostgreSQL: Fix clone after e395fe5 2025-03-22 20:55:51 +01:00
Jakub Vrana
359fdf3d07 MySQLi: Use fetch_column 2025-03-22 08:50:47 +01:00
Jakub Vrana
00b7056147 MySQLi: Add comment 2025-03-22 08:47:21 +01:00
Jakub Vrana
db829fd463 PDO: Handle PHP warnings for internal queries 2025-03-22 08:47:21 +01:00
Jakub Vrana
359d153130 Tests PostgreSQL: Fix after e395fe5 2025-03-22 08:47:21 +01:00
Jakub Vrana
ab44927442 Tests: Run also in PDO 2025-03-22 08:47:03 +01:00
Jakub Vrana
01a6af8b70 Tests: Remove localhost:8080 2025-03-22 08:20:30 +01:00
Jakub Vrana
3f2eec9b92 URL parameter ?ext=pdo to force using PDO 2025-03-22 08:18:39 +01:00
Jakub Vrana
aaca1eee8e JS: Unsupport event.srcElement 2025-03-21 23:58:45 +01:00
Jakub Vrana
26db8596aa JS: Simplify hiding ajaxstatus 2025-03-21 23:58:45 +01:00
Jakub Vrana
5aedb33fb6 JS: Simplify onbeforeunload 2025-03-21 23:58:45 +01:00
Jakub Vrana
7fca87dfd7 JS: Unsupport old IE 2025-03-21 23:58:42 +01:00
Jakub Vrana
711f41d05b Ctrl+click in select moves the cursor in modern browsers 2025-03-21 23:58:15 +01:00
Jakub Vrana
f7b20b5f6f Increase space after SQL result (fix #937) 2025-03-21 22:32:49 +01:00
Jakub Vrana
719c1e7067 Plugins autoloading: Link help 2025-03-21 22:23:45 +01:00
John F. Arroyave Gutiérrez
83a8b18c85 Spanish translation upgrade
Just some edditions and new translations
2025-03-21 22:23:44 +01:00
Matthaiks
4d082d4fcd Update Polish translation 2025-03-21 07:33:40 +01:00
Jakub Vrana
a705be7a94 Confirm before exiting edited edit form 2025-03-20 17:15:18 +01:00
Jakub Vrana
a2586e7265 Update comment: Chrome doesn't propagate Ctrl+Up 2025-03-20 16:00:25 +01:00
Jakub Vrana
f38bbff5bf Increase maximum width of string edit (bug #930) 2025-03-20 15:39:55 +01:00
Peter Knut
09720b31f1 Remove hardcoded textarea height 2025-03-20 15:26:06 +01:00
Jakub Vrana
0e28daac55 Multi-edit: Increase size of textarea 2025-03-20 15:19:32 +01:00
Jakub Vrana
3eb478b65a CSS: Fix adminer.css recognition (includes version) 2025-03-20 14:50:58 +01:00
Jakub Vrana
192ce41bd3 Tests: Run on compiled version 2025-03-20 14:33:17 +01:00
Jakub Vrana
bcd5164e2f Plugins: Handle autoloading errors 2025-03-20 14:33:17 +01:00
Jakub Vrana
cd686c7a1e CSS: Light background in dark bold error 2025-03-20 14:33:17 +01:00
Jakub Vrána
e9feb1587a Add plugins/README.md 2025-03-20 14:32:56 +01:00
Jakub Vrana
1f5a7fa717 JS: Use arrow functions
All function () {} left in the code reference `this` and thus couldn't use arrow functions.
2025-03-20 10:35:08 +01:00
Jakub Vrana
3c310ddfaf Designs: Link gallery 2025-03-20 09:54:45 +01:00
Jakub Vrana
6d4896e03c JS: Add ESLint config
To use this: Create package.json and run:
npm install --save-dev eslint @eslint/js
2025-03-20 09:54:44 +01:00
Jakub Vrana
5ef77ec399 JS: Fix typo after def9e07 2025-03-20 09:17:04 +01:00
Jakub Vrana
62c18efbd5 JS: Use let/const for globals 2025-03-20 08:59:07 +01:00
Jakub Vrana
101229043e JS: Use let/const in spaghetti code 2025-03-20 08:58:48 +01:00
Jakub Vrana
0e21106e48 JS: Change var to let/const
Created by `eslint . --fix` with rules no-var and then prefer-const.
2025-03-20 08:32:23 +01:00
Jakub Vrana
f16a6d415a JS: Style issues 2025-03-20 08:03:54 +01:00
Jakub Vrana
11699223df JS: Remove outdated check 2025-03-20 07:39:21 +01:00
Jakub Vrana
7c75d3f86c JS: Remove unnecessary escape 2025-03-20 07:26:17 +01:00
Jakub Vrana
287667d631 Designs: Link screenshots 2025-03-20 06:53:52 +01:00
Jakub Vrana
ef4c340cc2 PostgreSQL 11: Support PROCEDURE 2025-03-19 22:43:40 +01:00
Jakub Vrana
f2a5d5127a Display collation at table structure if different from table 2025-03-19 22:42:02 +01:00
Jakub Vrana
889ffe28c7 JS: Add missing function 2025-03-19 22:04:30 +01:00
Jakub Vrana
5f6aa1e267 JS: Depend on JSON 2025-03-19 21:51:25 +01:00
Jakub Vrana
def9e07831 JS: Use for..of 2025-03-19 21:51:23 +01:00
Jakub Vrana
c73bd1233e Changelog for new plugins 2025-03-19 20:29:20 +01:00
Jakub Vrana
e6ead2d12c New plugin: Allow switching light and dark mode (fix #926) 2025-03-19 20:20:43 +01:00
Jakub Vrana
4802389ce6 Delete stale comment after 3eba731 2025-03-19 19:21:22 +01:00
Takashi SHIRAI
7845b70d7d Modify the Japanese messages.
Signed-off-by: Takashi SHIRAI <shirai@nintendo.co.jp>
2025-03-19 18:38:54 +01:00
Takashi SHIRAI
9f8344e53c Fix the uncaught exception because of namespace.
Signed-off-by: Takashi SHIRAI <shirai@nintendo.co.jp>
2025-03-19 18:35:32 +01:00
Jakub Vrana
2dd32cf534 Plugin pretty-json-column: fix with enum (fix #928)
Also add syntax highlighting.
2025-03-19 18:22:57 +01:00
Jakub Vrana
0b063262ee Remove ns= from auth_url 2025-03-19 17:53:26 +01:00
Peter Knut
458d07122f Bigger font size for code blocks 2025-03-19 17:45:31 +01:00
Jakub Vrana
740a4b8b1c Issue template: Use italics 2025-03-19 17:33:46 +01:00
Jakub Vrana
6be1e1c069 Plugins: Fix displaying with legacy AdminerPlugin 2025-03-19 17:29:42 +01:00
Jakub Vrana
b861500910 Make Adminer\Plugins visible for adminer_object 2025-03-19 17:29:42 +01:00
Jakub Vrana
eca176f362 MS SQL: Fix collation issues when retrieving default values
I was getting this error:
Error in query (4189): Cannot convert to text/ntext or collate to 'Czech_100_CI_AI_SC_UTF8' because these legacy LOB types do not support UTF-8 or UTF-16 encodings. Use types varchar(max), nvarchar(max) or a collation which does not have the _SC or _UTF8 flags.

This reverts part of a2adb67.
2025-03-19 17:29:42 +01:00
Jakub Vrana
8f489da2bd Tests MS SQL: Use default server 2025-03-19 17:29:42 +01:00
Jakub Vrana
3138b1de88 CockroachDB: not actually fixed 2025-03-19 17:29:42 +01:00
Matthaiks
e723158bbf Update Polish translation 2025-03-19 17:29:31 +01:00
Jakub Vrana
feed6e4488 PostgreSQL: Use language sql when creating routines by default 2025-03-19 06:49:48 +01:00
Jakub Vrana
9b345fbafb CockroachDB: Do not use version number when linking docs 2025-03-19 06:49:48 +01:00
Jakub Vrana
ca30d04575 PostgreSQL: Display shorter version (regression from 5.0.5) 2025-03-19 06:49:48 +01:00
Jakub Vrana
b4e41f5e4b CockroachDB: Pass param length to routine drop (cockroachdb/cockroach#142886) 2025-03-19 06:49:30 +01:00
Jakub Vrana
8979baca28 Remove forgotten newline 2025-03-19 05:45:22 +01:00
Jakub Vrana
8019b9ae4d Autoloaded plugins: Drivers work too 2025-03-19 05:14:41 +01:00
Jakub Vrana
7fec2992d9 Autoloaded plugins: Use in Editor 2025-03-19 05:08:24 +01:00
Jakub Vrana
df98f2453d Plugins: Load config from adminer-plugins.php 2025-03-19 05:05:42 +01:00
Jakub Vrana
eb1d8d5468 Display loaded plugins 2025-03-18 22:30:51 +01:00
Jakub Vrana
ea3da56b6d Add plugins/plugin.php for backwards compatibility 2025-03-18 22:30:51 +01:00
Jakub Vrana
41dabfb4f2 Plugins: Autoload plugins in adminer-plugins/ 2025-03-18 22:30:49 +01:00
Jakub Vrana
ff0fe92c00 Add forgotten space 2025-03-18 19:51:25 +01:00
Jakub Vrana
06c15aa263 IMAP: Use db mail 2025-03-18 19:46:40 +01:00
Jakub Vrana
8a64fb16cd IMAP: Use imap_num_msg() 2025-03-18 19:46:08 +01:00
Jakub Vrana
bda53f0734 CSS: Allow more custom styles with dark mode (fix #925) 2025-03-18 17:49:33 +01:00
Jakub Vrana
bc9de24d77 Add helper for <input type=hidden> 2025-03-18 17:15:10 +01:00
Jakub Vrana
9cfea02e19 Avoid excessive PHP and HTML mixing 2025-03-18 16:45:15 +01:00
Jakub Vrana
eeb78d7e48 Vendor display: Do not overwrite PostgreSQL by MySQL at the same server 2025-03-18 16:30:23 +01:00
Jakub Vrana
751405e006 - PostgreSQL: Avoid warning about crdb_version (fix #924, regression from 5.0.5) 2025-03-18 16:20:44 +01:00
Jakub Vrana
3fb6cac361 PostgreSQL: Display description of system variables 2025-03-18 16:00:21 +01:00
Matrixman
8613f97948 New version of design rmSOFT 2025-03-18 15:43:50 +01:00
Jakub Vrana
249807fc48 IMAP: Simplify expunge 2025-03-18 14:56:37 +01:00
Jakub Vrana
6e76454f59 Update changes 2025-03-18 14:45:10 +01:00
Jakub Vrana
655cca0872 IMAP: Export 2025-03-18 14:05:51 +01:00
Jakub Vrana
16989a736c IMAP: Use halfopen 2025-03-18 13:58:05 +01:00
Jakub Vrana
a3d1ab34bb Move engines() to Driver 2025-03-18 13:41:24 +01:00
Jakub Vrana
b2f904c64f IMAP: Add Data_length 2025-03-18 13:36:49 +01:00
Jakub Vrana
05d27a132d Compile: Do not require unsupported functions 2025-03-18 13:29:48 +01:00
Jakub Vrana
4861c88cc6 IMAP: Create, drop, truncate 2025-03-18 13:10:45 +01:00
Jakub Vrana
1424a42b1f IMAP: Avoid globals 2025-03-18 13:00:40 +01:00
Jakub Vrana
1c5a192cb5 Add forgotten colon 2025-03-18 12:57:29 +01:00
Jakub Vrana
336fdaf09c Revert "Table-less drivers: Hide Create table link"
This reverts commit 841f76fb00.
This reverts commit 8fed1523ec.
2025-03-18 12:55:30 +01:00
Jakub Vrana
57e6c2651c IMAP: Number of rows 2025-03-18 12:52:17 +01:00
Jakub Vrana
693dc5b8a7 IMAP: Delete message
Also support mailboxes with spaces
2025-03-18 12:35:36 +01:00
Jakub Vrana
753642630b IMAP: Select columns 2025-03-18 12:15:31 +01:00
Jakub Vrana
8fed1523ec Table-less drivers: Hide Create table link 2025-03-18 11:35:15 +01:00
Jakub Vrana
ebb31bdac8 IMAP: New driver created just for fun 2025-03-18 11:35:14 +01:00
Jakub Vrana
5069e5a400 JSON: Remove unnecessary escape 2025-03-18 11:15:03 +01:00
Jakub Vrana
33b69ed82b Edit: prefer JSON over text 2025-03-18 11:12:07 +01:00
Jakub Vrana
4e4f280061 Table-less drivers: display empty field only without fields() 2025-03-18 11:00:57 +01:00
Jakub Vrana
841f76fb00 Table-less drivers: Hide Create table link 2025-03-18 11:00:28 +01:00
Jakub Vrana
73e7e00c77 fieldName: Display : before comment only with type 2025-03-18 09:26:16 +01:00
Jakub Vrana
29f954069d CSS: Sticky table headers (fix #918) 2025-03-18 02:10:57 +01:00
Jakub Vrana
c1eccc9cdd Use CHANGELOG.md 2025-03-17 21:13:15 +01:00
Jakub Vrana
430cdaeb3a Use README.md 2025-03-17 20:29:50 +01:00
Jakub Vrana
e395fe583a PostgreSQL: Display auto_increment of inserted rows 2025-03-17 19:58:22 +01:00
Jakub Vrana
19313a8dab Pass $result to last_id 2025-03-17 19:58:21 +01:00
Jakub Vrana
17c0960e7f Consider plugins autoloading 2025-03-17 19:58:21 +01:00
Jakub Vrana
a9b020452e Plugins: Add backward-keys 2025-03-17 19:58:20 +01:00
Jakub Vrana
e1f0fded69 Add helper for <input type=hidden name=token> 2025-03-17 18:45:08 +01:00
Jakub Vrana
91f9980267 Bug reports: Add screenshot 2025-03-17 17:37:29 +01:00
Jakub Vrana
5f3fac4b48 Develop 2025-03-17 17:15:17 +01:00
Jakub Vrana
b7679701ce Release 5.0.6 2025-03-17 17:13:46 +01:00
Jakub Vrana
b7258d2e95 Shorten queries saved from SQL command to URL (fix #917) 2025-03-17 15:05:56 +01:00
Jakub Vrana
c51d9919fe Update tests 2025-03-17 14:29:07 +01:00
Jakub Vrana
78c431ab20 Fix typos after 22a3efe 2025-03-17 14:28:04 +01:00
Jakub Vrana
916889bb8e Compile: Fix joining conditional echos 2025-03-17 14:25:57 +01:00
Jakub Vrana
e8b15c99f4 Add back function to get driver name (fix #919)
This reverts fe88f83.
2025-03-17 08:07:24 +01:00
Jakub Vrana
a460019535 Compile PostgreSQL: Address warnings (fix #916) 2025-03-17 07:43:10 +01:00
Jakub Vrana
ea5a7453fb CSS: Set also light color-scheme 2025-03-17 07:14:26 +01:00
Jakub Vrana
587f6a5375 CSS: Dark input fields in dark mode 2025-03-17 07:04:21 +01:00
Jakub Vrana
2bb74e7467 Compile: fetch_column() is used only internally 2025-03-17 06:38:16 +01:00
Jakub Vrana
a684044bb3 Compile SQLite: Remove server login field 2025-03-17 06:13:48 +01:00
Jakub Vrana
36a3465a64 Compile: Rename variable with other meaning in Adminer 2025-03-17 05:54:24 +01:00
Jakub Vrana
223aee70d5 Mark bugs at https://sourceforge.net/p/adminer/bugs-and-features/ 2025-03-17 05:38:14 +01:00
Jakub Vrana
c02a7d6abe Add missing namespace 2025-03-17 00:49:12 +01:00
Jakub Vrana
22a3efe4ed Code style: avoid excesive mixing of PHP and HTML 2025-03-17 00:02:41 +01:00
Jakub Vrana
dd47df9b9c Display comment in title of field 2025-03-16 22:49:50 +01:00
Jakub Vrana
0b0e8940e0 Update externals 2025-03-16 22:42:45 +01:00
Jakub Vrana
fa8339c8c2 Plugins: Remove fragile autoloader 2025-03-16 22:09:43 +01:00
Jakub Vrana
f0ee812b29 Add todo 2025-03-16 21:55:36 +01:00
Jakub Vrana
f093cb6db2 Rename file 2025-03-16 21:49:39 +01:00
Jakub Vrana
68d4a5a650 Delete adminer.version before writing (bug #855) 2025-03-16 21:43:09 +01:00
Jakub Vrana
6576fa6a73 Security: Disallow writing temporary files to symlinks (bug #855)
Cc @peterpp
2025-03-16 21:43:08 +01:00
Peter Knut
28535bf384 Refactor generating of private key
Generating of private key is atomic now.
2025-03-16 20:54:28 +01:00
Peter Knut
43e3fe375d Refactor working with a locked file 2025-03-16 20:54:24 +01:00
Jakub Vrana
d8a9a3db8d CockroachDB: Display CockroachDB instead of PostgreSQL 2025-03-16 19:07:42 +01:00
Jakub Vrana
777d5dca0e Store information about vendor 2025-03-16 19:03:12 +01:00
Jakub Vrana
6d71cd678e Separate HTML functions 2025-03-16 19:03:02 +01:00
Jakub Vrana
30714d98f9 Save bytes 2025-03-16 18:05:52 +01:00
Jakub Vrana
8353bd48de MariaDB: Display MariaDB instead of MySQL 2025-03-16 18:02:34 +01:00
Peter Knut
0762c761ac Rename functions for settings stored in a cookie 2025-03-16 17:24:28 +01:00
Jakub Vrana
529197f403 Compile: Move caching headers to file.inc.php 2025-03-16 17:16:23 +01:00
Jakub Vrana
d20cbf14e7 Remember export setting at SQL command 2025-03-16 15:13:10 +01:00
Jakub Vrana
517f63835d Plugins: add syntaxHighlighting() and CodeMirror 2025-03-16 14:00:39 +01:00
Jakub Vrana
4fee062b73 Simplify autofocus 2025-03-16 11:08:01 +01:00
Jakub Vrana
26769b2357 Do not align right non-numbers, e.g. NULL or foreign keys 2025-03-16 09:10:43 +01:00
Jakub Vrana
42bf7b9ca0 Align numbers right (bug #912) 2025-03-15 15:13:41 +01:00
Jakub Vrana
d8755c903d Save bytes 2025-03-15 13:57:29 +01:00
Jakub Vrana
a391fcb6c4 Compile: Use external PhpShrink 2025-03-15 09:38:06 +01:00
Jakub Vrana
c99ca863ce php_shrink: Move add_apo_slashes to compile.php 2025-03-15 09:10:43 +01:00
Jakub Vrana
e0283543f3 Support adminer.css + adminer-dark.css together 2025-03-15 08:51:51 +01:00
Jakub Vrana
a72e053520 php_shrink: Use foreach 2025-03-15 07:35:37 +01:00
Jakub Vrana
de654712d5 php_shrink: Preprocess ?>HTML<?php 2025-03-15 07:33:47 +01:00
Jakub Vrana
9c1d5484a2 php_shrink: Join echos interleaved with comments 2025-03-15 07:21:37 +01:00
Jakub Vrana
1fd8aa885b Fix bs,ru,sr,uk single lang version after f2ce6c0 2025-03-15 02:32:37 +01:00
Jakub Vrana
08882c6a8e Add comments to places processed by compile.php 2025-03-15 02:26:16 +01:00
Jakub Vrana
fd199ec156 php_shrink: Document bug 2025-03-15 02:26:07 +01:00
Jakub Vrana
e3515fd63f CSS: Dark mode syntax highlighting and adminer-dark.css 2025-03-15 02:00:21 +01:00
Jakub Vrana
be0a485b14 JUSH: Revert to original colors 2025-03-14 12:35:06 +01:00
Jakub Vrana
94c04712d6 SQL textarea: Open help on Ctrl+click 2025-03-14 11:01:20 +01:00
Jakub Vrana
caea0b7f68 JUSH: Use dark mode 2025-03-14 09:55:34 +01:00
Jakub Vrana
134301b3ff Tests CockroachDB: Link bug 2025-03-14 08:02:11 +01:00
Jakub Vrana
d14f3dd2d8 Tests: Check status variables 2025-03-14 07:31:57 +01:00
Jakub Vrana
67c313c86d Tests SQLite: Add more 2025-03-14 07:27:58 +01:00
Jakub Vrana
5eaa73583a Tests PostgreSQL: Materialized view 2025-03-14 06:44:02 +01:00
Jakub Vrana
68b6af6fce Tests: Check that check constraints work 2025-03-14 06:38:26 +01:00
Jakub Vrana
e65fdba5d1 Test PostgreSQL: enum 2025-03-14 06:18:42 +01:00
Jakub Vrana
8f336cd0b3 Tests: Remove useless xpath= 2025-03-14 05:58:45 +01:00
Jakub Vrana
5f3bfe8451 JUSH textarea: Use oninput 2025-03-14 05:56:30 +01:00
Jakub Vrana
1a3d58e74e Tests: Add newlines 2025-03-13 23:04:22 +01:00
Jakub Vrana
af9a851c5e Tests: generated columns 2025-03-13 23:00:14 +01:00
Jakub Vrana
3a40a855ea Develop 2025-03-13 18:29:28 +01:00
Jakub Vrana
967647759e Release 5.0.5 2025-03-13 18:28:43 +01:00
Jakub Vrana
e4323ced55 Tests: Fix CockroachDB after 48308f3 2025-03-13 18:22:06 +01:00
Jakub Vrana
85c6af6f87 Compile: strip space after CSS comment 2025-03-13 18:00:54 +01:00
Jakub Vrana
9226804aa2 CSS: Move media selector to <link> 2025-03-13 17:55:42 +01:00
Jakub Vrana
041e7064ca php_shrink: Simplify test 2025-03-13 17:45:16 +01:00
Jakub Vrana
4c2a8b0050 Compile: Move ?><? removal to php_shrink 2025-03-13 17:43:20 +01:00
Jakub Vrana
9afbf1a465 Compile: dark.css 2025-03-13 17:33:19 +01:00
Jakub Vrana
352ef9c778 CSS: Don't use dark theme with adminer.css 2025-03-13 17:11:40 +01:00
Jakub Vrana
45107dc46e Don't highlight NULL as JSON 2025-03-13 16:55:17 +01:00
Jakub Vrana
21f3426adb Design: Update dark mode (by rmsoft) 2025-03-13 16:48:56 +01:00
Jakub Vrana
95dccfe9fb MongoDB: Rename file 2025-03-13 15:21:19 +01:00
Jakub Vrana
fe88f83c95 Elastic: Fix number of rows in group queries 2025-03-13 14:34:26 +01:00
Jakub Vrana
078957fe32 MongoDB: Move to plugin 2025-03-13 14:27:54 +01:00
Jakub Vrana
61f07867f9 Update readme 2025-03-13 14:09:45 +01:00
Jakub Vrana
0135dd5b81 Tests: Add tests for MS SQL 2025-03-13 14:07:31 +01:00
Jakub Vrana
773a2253d3 Export: Display unknown number of rows as ? 2025-03-13 13:29:10 +01:00
Jakub Vrana
272042a30e Fix skipOriginal after unconvertFunction 2025-03-13 13:13:06 +01:00
Jakub Vrana
48308f3357 CockroachDB: Recognize unique_rowid() as auto_increment 2025-03-13 13:09:05 +01:00
Jakub Vrana
c90033a962 Test PostgreSQL: SQL command 2025-03-13 13:03:24 +01:00
Jakub Vrana
8bd022f974 CockroachDB: Fix test 2025-03-13 13:02:53 +01:00
Jakub Vrana
b1550b052d MySQL: Simplify checking for MariaDB 2025-03-13 12:24:35 +01:00
Jakub Vrana
9862846a7c CockroachDB: Declare support 2025-03-13 12:15:37 +01:00
Jakub Vrana
f14e3e38f6 CockroachDB: Disable processlist 2025-03-13 12:12:44 +01:00
Jakub Vrana
95262c4215 CSS: Fix style 2025-03-13 12:08:01 +01:00
Jakub Vrana
dacfdc4608 Tests: Work with JUSH textarea 2025-03-13 12:07:49 +01:00
Jakub Vrana
7636c253fb CockroachDB: Display version 2025-03-13 11:51:03 +01:00
Jakub Vrana
44d26a9dd3 Tests: Add tests for CockroachDB 2025-03-13 11:08:42 +01:00
Jakub Vrana
b229e7b583 Tests: Add tests for MariaDB and PostgreSQL 2025-03-13 10:45:53 +01:00
Jakub Vrana
8e91417be1 MySQL: Display converting function for binary, bit or geometry fields 2025-03-13 07:50:20 +01:00
Peter Knut
db7202fcf0 MySQL: Fix saving string default value of json field 2025-03-13 07:19:27 +01:00
Jakub Vrana
260487fbc2 Designs: Update rmsoft (fix #911) 2025-03-13 07:10:23 +01:00
Jakub Vrana
3ae964c915 Designs: Fix price 2025-03-13 07:06:43 +01:00
Jakub Vrana
d56c8cbaae CSS: Simplify .odds 2025-03-13 07:03:42 +01:00
Jakub Vrana
d347f88c54 Design: Update rmsoft (fix #911) 2025-03-13 06:38:32 +01:00
Jakub Vrana
b9b4db0c8e Compile: Add more php_shrink tests 2025-03-13 06:10:58 +01:00
Jakub Vrana
818b9ad903 Compile: Strip public 2025-03-12 23:15:24 +01:00
Jakub Vrana
4a6436773f Compile: Add tests for php_shrink 2025-03-12 23:15:22 +01:00
Jakub Vrana
81594e4a2d Issues: Prefer MySQLi 2025-03-12 18:28:56 +01:00
Jakub Vrana
f0bdb0e6ca Designs: Update .odds 2025-03-12 17:50:24 +01:00
Jakub Vrana
b9e4806d3c CSS: lowercase color names 2025-03-12 17:43:58 +01:00
Jakub Vrana
7e708dae57 CSS: Add dark theme 2025-03-12 17:42:53 +01:00
Jakub Vrana
a0fe44ec18 CSS: Expand <code> in <pre> 2025-03-12 17:35:44 +01:00
Jakub Vrana
eb0f280776 CSS: Fix highlighting checked odd rows 2025-03-12 17:35:34 +01:00
Jakub Vrana
3b1189cd3c MySQL: Allow setting default values of json column 2025-03-12 14:25:19 +01:00
Jakub Vrana
434a8f7705 CSS: Disable odd on hover 2025-03-12 13:58:20 +01:00
Jakub Vrana
f9478c67d2 CSS: Merge rules 2025-03-12 12:57:59 +01:00
Jakub Vrana
f2ce6c0a71 Wrap long lines 2025-03-12 11:43:21 +01:00
Jakub Vrana
a50b3d6385 MS SQL: Fix editing rows with datetime column in primary key
Inspired by adminneo-org@b4afc08.
This fixes https://sourceforge.net/p/adminer/discussion/960418/thread/a547e79622/.
2025-03-12 09:28:22 +01:00
Jakub Vrana
e39deca4f1 Wrap Schema: in navigation to <span> (fix #907) 2025-03-12 09:26:04 +01:00
Jakub Vrana
ce69970f54 Update German translation (by @wintstar) 2025-03-12 09:09:09 +01:00
Jakub Vrana
51ac1312a1 MariaDB: Don't display NULL as default value 2025-03-12 08:51:25 +01:00
Jakub Vrana
4505544953 Code style: exclude removed extensions 2025-03-12 08:12:28 +01:00
Jakub Vrana
fa75213ff6 Coverage: Fix newlines 2025-03-12 06:15:47 +01:00
Jakub Vrana
63acb37ea6 Coverage: Display drivers 2025-03-12 06:09:18 +01:00
Jakub Vrana
3ad6c16f59 Coverage: Modernize HTML 2025-03-12 06:06:28 +01:00
Jakub Vrana
22d08b4a50 Add comment 2025-03-12 06:01:29 +01:00
Jakub Vrana
dd3cc4e683 Add plugin AdminerEditorViews (fix #905) 2025-03-12 05:22:57 +01:00
Jakub Vrana
5504a617d0 Compile: Support private static 2025-03-12 05:03:42 +01:00
Jakub Vrana
2fdebfda29 Ensure PHP 5.3 compatibility 2025-03-11 21:43:59 +01:00
Jakub Vrana
dc2e945aef MySQL: Convert binary default value to hex when editing 2025-03-11 20:25:52 +01:00
Jakub Vrana
43d86287c4 Fix focusing first field 2025-03-11 20:16:49 +01:00
Jakub Vrana
a94a727af7 PostgreSQL PDO: Escape bytea values (bug #218) 2025-03-11 19:42:10 +01:00
Jakub Vrana
c2d29a6937 MySQL: Display default values of binary columns 2025-03-11 19:25:42 +01:00
Jakub Vrana
c082136558 Rename variable 2025-03-11 18:40:34 +01:00
Jakub Vrana
7b1ea5fa2c AdminerDumpAlter: Use dumpFooter 2025-03-11 18:20:11 +01:00
Jakub Vrana
156839142e Fix plugin AdminerPrettyJsonColumn 2025-03-11 18:16:44 +01:00
Jakub Vrana
2ee4e3b2e1 Compile: Fix shortening in protected functions 2025-03-11 17:56:21 +01:00
Jakub Vrana
8b4c8b0156 Fix coverage 2025-03-11 14:37:08 +01:00
Jakub Vrana
9702878297 Develop 2025-03-11 14:00:37 +01:00
Jakub Vrana
4a54648995 Release 5.0.4 2025-03-11 13:52:53 +01:00
Jakub Vrana
2e5027a1aa Compile: Fix shortening in private methods 2025-03-11 13:50:36 +01:00
Jakub Vrana
5a4c4dd892 Release 5.0.3 2025-03-11 13:16:35 +01:00
Jakub Vrana
7ef009336f PostgreSQL: Fix where and order privileges (fix #902) 2025-03-11 13:07:50 +01:00
Jakub Vrana
1defc94d12 Fix $result visibility 2025-03-11 12:53:35 +01:00
Jakub Vrana
5d3376e620 Check more style 2025-03-11 12:21:07 +01:00
Jakub Vrana
d410cdc5be Mongo: Add helper method 2025-03-11 11:13:40 +01:00
Jakub Vrana
a44e625882 Set visibility to protected 2025-03-11 11:05:39 +01:00
Jakub Vrana
ae57d42105 SQLite: Fix calling private property 2025-03-11 11:05:10 +01:00
Jakub Vrana
199edfe11f Plugins: Add method dumpFooter() 2025-03-11 08:59:38 +01:00
Jakub Vrana
b02c3e1f7f Use private visibility 2025-03-11 08:36:35 +01:00
Jakub Vrana
98cb9b9aca Add comment 2025-03-11 08:29:01 +01:00
Jakub Vrana
514d64048d Disallow var 2025-03-11 08:17:02 +01:00
Jakub Vrana
1e963cf90f Change var to public 2025-03-11 08:17:00 +01:00
Jakub Vrana
0c15a9f42d Use private visibility on methods 2025-03-11 08:16:41 +01:00
Jakub Vrana
c454ea8430 Use protected visibility 2025-03-11 08:16:41 +01:00
Jakub Vrana
607febea8e Use private visibility 2025-03-11 08:16:39 +01:00
Jakub Vrana
ebd5f19dd4 Use protected visibility 2025-03-11 08:12:09 +01:00
Jakub Vrana
1b0984ff31 Compile: Change public to var 2025-03-11 07:16:20 +01:00
Jakub Vrana
b017928256 Revert accidental revert 2025-03-11 07:05:16 +01:00
Jakub Vrana
526077535e Update changes 2025-03-11 07:00:21 +01:00
Jakub Vrana
8274b2e0e8 Update bug template 2025-03-11 06:50:04 +01:00
Jakub Vrana
8f7d456887 Update changes 2025-03-11 06:45:38 +01:00
Jakub Vrana
91b735c576 Compile: Support \r\n line ends 2025-03-11 06:30:31 +01:00
Jakub Vrana
916b9e62de Fix double unescaping 2025-03-11 06:24:21 +01:00
Jakub Vrana
f25c65837f Add comment 2025-03-11 06:24:21 +01:00
Jakub Vrana
b0182834bf Fix typo 2025-03-11 06:24:21 +01:00
David Grudl
6bf0b85919 Compile: supports visibility modifiers 2025-03-11 06:24:07 +01:00
Jakub Vrana
37e63dd82f MySQL: Stop treating enum as set as numbers (bug #475) 2025-03-10 23:40:07 +01:00
Jakub Vrana
6fdde32f86 Remove check for PHP version 2025-03-10 23:03:20 +01:00
Jakub Vrana
aeac0a3329 MySQL: Allow setting default values of text column 2025-03-10 21:15:01 +01:00
Christian Weiske
fde7d7dde2 Elastic: Properly display sparse result rows
Result records in Elasticsearch do not always have all columns
that are defined in an index.
This often happens when multiple document types are stored in the same index.

The first row has columns ["_id", "html", "url"], while the second
misses the "html" column: ["_id", "url"].

Adminer expects that all result rows include all columns.
This leads to the problem that the "url" value in the 2nd example row
was rendered in the "html" column.

This patch fixes this problem by fetching the actual column list first
when all fields are to be shown, and using that field list
as base for all rows.
2025-03-10 21:14:54 +01:00
Christian Weiske
e993462412 Elastic: Fix record insertion on Elasticsearch 7
1. Make values NULLable by default, so that empty values do not
get submitted to the Elasticsearch server.
This helps e.g. with empty date fields - Elasticsearch would try to
convert the field type to string when the value is an empty string,
but that fails when there are documents with properly filled date fields

2. Remove _id from the POST array because this is not allowed.
The server fails if it is included with
> mapper_parsing_exception:
> Field [_id] is a metadata field and cannot be added inside a document.
> Use the index API request parameters.

3. Use the correct URL to create a document: "$index/_doc/"
and "$index/_doc/$id". This is the same for ES 7 and 8:
- https://www.elastic.co/guide/en/elasticsearch/reference/8.17/docs-index_.html#docs-index-api-request
- https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docs-index_.html#docs-index-api-request

4. Handle failed creations by checking for false

5. Return the "result" property string instead of the non-existing
"created" property.
2025-03-10 21:13:16 +01:00
Jakub Vrana
31f8f61d0e MySQL, MariaDB: Fix default values with ' (fix #895) 2025-03-10 21:01:21 +01:00
Jakub Vrana
e589ee3fde MariaDB: Fix creating and altering generated columns (fixes #897) 2025-03-10 19:18:14 +01:00
Jakub Vrána
35274f18bb Update issue templates 2025-03-10 19:09:56 +01:00
Jakub Vrana
f8b2640156 Fix gzip export (fixes #896) 2025-03-10 18:51:28 +01:00
Jakub Vrana
bb23546478 Use <datalist> for altering collations 2025-03-10 14:13:34 +01:00
Jakub Vrana
dddfc190a5 Split helper html_radios 2025-03-10 11:31:43 +01:00
Jakub Vrana
40760d153c Update changes 2025-03-10 09:09:09 +01:00
Peter Knut
4fe3d17255 Update Slovak translation 2025-03-10 09:09:09 +01:00
Jakub Vrana
6dcc5081e1 Fix importing multiple SQL files not terminated by semicolon
Inspired by adminneo-org/adminneo#1c08e86.
2025-03-10 09:09:09 +01:00
Jakub Vrana
df6fe6b108 Fix link 2025-03-10 09:09:09 +01:00
Jakub Vrana
e6339046ff Remove unused variable 2025-03-10 09:09:09 +01:00
Jakub Vrana
2c0cfbdd3f Develop 2025-03-10 09:09:09 +01:00
Christian Weiske
f13770c664 Make login to Elasticsearch work again
By partially reverting the changes made by
commit 2c9f380c64
> Elastic: Remove plugin for version 5
which removed the passwordless login plugin from adminer/elastic.php
2025-03-10 08:53:19 +01:00
226 changed files with 7496 additions and 4373 deletions

15
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,15 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Adminer version:** please use latest published or Git
**Driver:** e.g. MySQLi
**Database version:** e.g. 10.2.12-MariaDB
_Please provide reproducible steps including a SQL dump (with no personal information) if applicable.
Also please include a screenshot._

6
.gitignore vendored
View File

@@ -1,4 +1,10 @@
/adminer/adminer.css
/adminer/adminer-dark.css
/editor/adminer.css
/editor/adminer-dark.css
/adminer*.php
/editor*.php
/tests/pdo-*.html
/vendor/
adminer-plugins/
adminer-plugins.php

3
.gitmodules vendored
View File

@@ -4,3 +4,6 @@
[submodule "JsShrink"]
path = externals/JsShrink
url = https://github.com/vrana/JsShrink
[submodule "PhpShrink"]
path = externals/PhpShrink
url = https://github.com/vrana/PhpShrink

1158
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

3
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,3 @@
- Reproducible [bug reports](https://github.com/vrana/adminer/issues/new?template=bug_report.md) are warmly welcomed.
- [Feature requests](https://github.com/vrana/adminer/issues/new?template=BLANK_ISSUE) are also fine, but I'm quite picky about what to accept into Adminer. Please don't be offended if I close the issue as "Not Planned," especially if it can be achieved with a plugin.
- [Pull requests](https://github.com/vrana/adminer/pulls) for both bug fixes and simple features are welcome. Before working on anything more complicated, get familiar with the [Adminer philosophy](https://github.com/vrana/adminer/blob/master/developing.md).

50
README.md Normal file
View File

@@ -0,0 +1,50 @@
# 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.
**Adminer Editor** offers data manipulation for end-users.
[Official Website](https://www.adminer.org/)
## Features
- **Supports:** MySQL, MariaDB, PostgreSQL, CockroachDB, SQLite, MS SQL, Oracle
- **Plugins for:** Elasticsearch, SimpleDB, MongoDB, Firebird, ClickHouse, IMAP
- **Requirements:** PHP 5.3+
## Screenshot
![Screenshot](https://www.adminer.org/static/screenshots/table.png)
## Installation
If downloaded from Git then run: `git submodule update --init`
- `adminer/index.php` - Run development version of Adminer
- `editor/index.php` - Run development version of Adminer Editor
- `editor/example.php` - Example customization
- `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/*.html` - Katalon Recorder test suites
## Plugins
There are [several plugins](/plugins/) distributed with Adminer, as well as many user-contributed plugins linked on the [Adminer Plugins page](https://www.adminer.org/plugins/).
To use a plugin, simply upload it to the `adminer-plugins/` directory next to `adminer.php`. You can also upload plugins for drivers (e.g., `elastic.php`) in this directory.
```
- adminer.php
- adminer-plugins/
- dump-xml.php
- login-password-less.php
- elastic.php
- ...
- adminer-plugins.php
```
Some plugins require configuration. To use them, create a file named `adminer-plugins.php`. You can also specify the loading order in this file.
```php
<?php // adminer-plugins.php
return array(
new AdminerLoginPasswordLess('$2y$07$Czp9G/aLi3AnaUqpvkF05OHO1LMizrAgMLvnaOdvQovHaRv28XDhG'),
// You can specify all plugins here or just the ones needing configuration.
);
```

View File

@@ -2,10 +2,10 @@
## Supported Versions
I support only the last published version and the last development version (last commit).
Only the latest published version and the latest development version (last commit) are supported.
## Reporting a Vulnerability
To report a vulnerability, add a new draft security advisory at https://github.com/vrana/adminer/security/advisories/new.
To report a vulnerability, create a new draft security advisory at [GitHub Security Advisories](https://github.com/vrana/adminer/security/advisories/new).
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.
Security issues are handled with top priority. If you don't receive a response within a week, please follow up on the report. Once a vulnerability is acknowledged, a fix should be available and a new version released within a few days. The issue will be made public after the fix is released or if the report is declined.

View File

@@ -73,11 +73,8 @@ if ($in) {
echo "<tr><th>" . $adminer->fieldName($field);
$value = $_POST["fields"][$name];
if ($value != "") {
if ($field["type"] == "enum") {
$value = +$value;
}
if ($field["type"] == "set") {
$value = array_sum($value);
$value = implode(",", $value);
}
}
input($field, $value, (string) $_POST["function"][$name]); // param name can be empty
@@ -88,7 +85,7 @@ if ($in) {
?>
<p>
<input type="submit" value="<?php echo lang('Call'); ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>
<pre>

View File

@@ -47,5 +47,5 @@ echo doc_link(array(
<?php if ($name != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>

View File

@@ -30,7 +30,7 @@ if ($row["auto_increment_col"]) {
}
if ($_POST) {
set_adminer_settings(array("comments" => $_POST["comments"], "defaults" => $_POST["defaults"]));
save_settings(array("comments" => $_POST["comments"], "defaults" => $_POST["defaults"]));
}
if ($_POST && !process_fields($row["fields"]) && !$error) {
@@ -83,17 +83,18 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
$partitioning = "";
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);
$params = array();
foreach ($row as $key => $val) {
if (preg_match('~^partition~', $key)) {
$params[$key] = $val;
}
}
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 = array();
if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') {
@@ -102,7 +103,6 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
$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) {
@@ -168,7 +168,7 @@ if (!$_POST) {
}
$collations = collations();
$engines = engines();
$engines = $driver->engines();
// case of engine may differ
foreach ($engines as $engine) {
if (!strcasecmp($engine, $row["Engine"])) {
@@ -180,27 +180,27 @@ foreach ($engines as $engine) {
<form action="" method="post" id="form">
<p>
<?php if (support("columns") || $TABLE == "") { ?>
<?php echo lang('Table name'); ?>: <input name="name"<?php echo ($TABLE == "" && !$_POST ? " autofocus" : ""); ?> data-maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php echo ($engines ? html_select("Engine", array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?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 } ?>
<?php
if (support("columns") || $TABLE == "") {
echo lang('Table name') . ": <input name='name'" . ($TABLE == "" && !$_POST ? " autofocus" : "") . " data-maxlength='64' value='" . h($row["name"]) . "' autocapitalize='off'>\n";
echo ($engines ? html_select("Engine", array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . on_help("event.target.value", 1) . script("qsl('select').onchange = helpClose;") . "\n" : "");
if ($collations) {
echo "<datalist id='collations'>" . optionlist($collations) . "</datalist>";
echo (preg_match("~sqlite|mssql~", JUSH) ? "" : "<input list='collations' name='Collation' value='" . h($row["Collation"]) . "' placeholder='(" . lang('collation') . ")'>");
}
echo "<input type='submit' value='" . lang('Save') . "'>\n";
}
<?php if (support("columns")) { ?>
<div class="scrollable">
<table id="edit-fields" class="nowrap">
<?php
if (support("columns")) {
echo "<div class='scrollable'>\n";
echo "<table id='edit-fields' class='nowrap'>\n";
edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
?>
</table>
<?php echo script("editFields();"); ?>
</div>
<p>
<?php echo lang('Auto Increment'); ?>: <input type="number" name="Auto_increment" class="size" 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 "</table>\n";
echo script("editFields();");
echo "</div>\n<p>\n";
echo lang('Auto Increment') . ": <input type='number' name='Auto_increment' class='size' value='" . h($row["Auto_increment"]) . "'>\n";
echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : get_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly");
$comments = ($_POST ? $_POST["comments"] : get_setting("comments"));
echo (support("comment")
? checkbox("comments", 1, $comments, lang('Comment'), "editingCommentsClick(this, true);", "jsonly")
. ' ' . (preg_match('~\n~', $row["Comment"])
@@ -221,25 +221,19 @@ foreach ($engines as $engine) {
if (support("partitioning")) {
$partition_table = preg_match('~RANGE|LIST~', $row["partition_by"]);
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
<p>
<?php echo html_select("partition_by", array("" => "") + $partition_by, $row["partition_by"]) . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . 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 id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>
<thead><tr><th><?php echo lang('Partition name'); ?><th><?php echo lang('Values'); ?></thead>
<?php
echo "<p>" . html_select("partition_by", array("" => "") + $partition_by, $row["partition_by"]) . on_help("event.target.value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;");
echo "(<input name='partition' value='" . h($row["partition"]) . "'>)\n";
echo lang('Partitions') . ": <input type='number' name='partitions' class='size" . ($partition_table || !$row["partition_by"] ? " hidden" : "") . "' value='" . h($row["partitions"]) . "'>\n";
echo "<table id='partition-table'" . ($partition_table ? "" : " class='hidden'") . ">\n";
echo "<thead><tr><th>" . lang('Partition name') . "<th>" . lang('Values') . "</thead>\n";
foreach ($row["partition_names"] as $key => $val) {
echo '<tr>';
echo '<td><input name="partition_names[]" value="' . h($val) . '" autocapitalize="off">';
echo ($key == count($row["partition_names"]) - 1 ? script("qsl('input').oninput = partitionNameChange;") : '');
echo '<td><input name="partition_values[]" value="' . h($row["partition_values"][$key]) . '">';
}
?>
</table>
</div></fieldset>
<?php
echo "</table>\n</div></fieldset>\n";
}
echo input_token();
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -76,6 +76,6 @@ if (DB != "") {
} elseif (!$_POST["add_x"] && $_GET["db"] == "") {
echo "<input type='image' class='icon' name='add' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>\n";
}
echo input_token();
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -157,7 +157,7 @@ if ($adminer->homepage()) {
}
echo "<input type='hidden' name='all' value=''>"; // used by trCheck()
echo script("qsl('input').onclick = function () { selectCount('selected', formChecked(this, /^(tables|views)\[/));" . (support("table") ? " selectCount('selected2', formChecked(this, /^tables\[/) || $tables);" : "") . " }");
echo "<input type='hidden' name='token' value='$token'>\n";
echo input_token();
echo "</div></fieldset>\n";
echo "</div></div>\n";
}
@@ -165,8 +165,8 @@ if ($adminer->homepage()) {
echo script("tableCheck();");
}
echo '<p class="links"><a href="' . h(ME) . 'create=">' . lang('Create table') . "</a>\n";
echo (support("view") ? '<a href="' . h(ME) . 'view=">' . lang('Create view') . "</a>\n" : "");
echo "<p class='links'><a href='" . h(ME) . "create='>" . lang('Create table') . "</a>\n";
echo (support("view") ? "<a href='" . h(ME) . "view='>" . lang('Create view') . "</a>\n" : "");
if (support("routine")) {
echo "<h3 id='routines'>" . lang('Routines') . "</h3>\n";

View File

@@ -3,8 +3,13 @@ function adminer_object() {
include_once "../plugins/plugin.php";
include_once "../plugins/designs.php";
$designs = array();
foreach (glob("../designs/*", GLOB_ONLYDIR) as $filename) {
$designs["$filename/adminer.css"] = basename($filename);
foreach (glob("../designs/*", GLOB_ONLYDIR) as $dirname) {
foreach (array("", "-dark") as $mode) {
$filename = "$dirname/adminer$mode.css";
if (file_exists($filename)) {
$designs[$filename] = basename($dirname);
}
}
}
return new AdminerPlugin(array(
new AdminerDesigns($designs),

View File

@@ -11,11 +11,12 @@ $drivers["mssql"] = "MS SQL";
if (isset($_GET["mssql"])) {
define('Adminer\DRIVER', "mssql");
if (extension_loaded("sqlsrv")) {
if (extension_loaded("sqlsrv") && $_GET["ext"] != "pdo") {
class Db {
var $extension = "sqlsrv", $_link, $_result, $server_info, $affected_rows, $errno, $error;
public $extension = "sqlsrv", $flavor = '', $server_info, $affected_rows, $errno, $error;
private $link, $result;
function _get_error() {
private function get_error() {
$this->error = "";
foreach (sqlsrv_errors() as $error) {
$this->errno = $error["code"];
@@ -38,14 +39,14 @@ if (isset($_GET["mssql"])) {
if ($db != "") {
$connection_info["Database"] = $db;
}
$this->_link = @sqlsrv_connect(preg_replace('~:~', ',', $server), $connection_info);
if ($this->_link) {
$info = sqlsrv_server_info($this->_link);
$this->link = @sqlsrv_connect(preg_replace('~:~', ',', $server), $connection_info);
if ($this->link) {
$info = sqlsrv_server_info($this->link);
$this->server_info = $info['SQLServerVersion'];
} else {
$this->_get_error();
$this->get_error();
}
return (bool) $this->_link;
return (bool) $this->link;
}
function quote($string) {
@@ -58,20 +59,20 @@ if (isset($_GET["mssql"])) {
}
function query($query, $unbuffered = false) {
$result = sqlsrv_query($this->_link, $query); //! , array(), ($unbuffered ? array() : array("Scrollable" => "keyset"))
$result = sqlsrv_query($this->link, $query); //! , array(), ($unbuffered ? array() : array("Scrollable" => "keyset"))
$this->error = "";
if (!$result) {
$this->_get_error();
$this->get_error();
return false;
}
return $this->store_result($result);
}
function multi_query($query) {
$this->_result = sqlsrv_query($this->_link, $query);
$this->result = sqlsrv_query($this->link, $query);
$this->error = "";
if (!$this->_result) {
$this->_get_error();
if (!$this->result) {
$this->get_error();
return false;
}
return true;
@@ -79,7 +80,7 @@ if (isset($_GET["mssql"])) {
function store_result($result = null) {
if (!$result) {
$result = $this->_result;
$result = $this->result;
}
if (!$result) {
return false;
@@ -92,7 +93,7 @@ if (isset($_GET["mssql"])) {
}
function next_result() {
return $this->_result ? sqlsrv_next_result($this->_result) : null;
return $this->result ? sqlsrv_next_result($this->result) : null;
}
function result($query, $field = 0) {
@@ -106,14 +107,15 @@ if (isset($_GET["mssql"])) {
}
class Result {
var $_result, $_offset = 0, $_fields, $num_rows;
public $num_rows;
private $result, $offset = 0, $fields;
function __construct($result) {
$this->_result = $result;
$this->result = $result;
// $this->num_rows = sqlsrv_num_rows($result); // available only in scrollable results
}
function _convert($row) {
private function convert($row) {
foreach ((array) $row as $key => $val) {
if (is_a($val, 'DateTime')) {
$row[$key] = $val->format("Y-m-d H:i:s");
@@ -124,62 +126,85 @@ if (isset($_GET["mssql"])) {
}
function fetch_assoc() {
return $this->_convert(sqlsrv_fetch_array($this->_result, SQLSRV_FETCH_ASSOC));
return $this->convert(sqlsrv_fetch_array($this->result, SQLSRV_FETCH_ASSOC));
}
function fetch_row() {
return $this->_convert(sqlsrv_fetch_array($this->_result, SQLSRV_FETCH_NUMERIC));
return $this->convert(sqlsrv_fetch_array($this->result, SQLSRV_FETCH_NUMERIC));
}
function fetch_field() {
if (!$this->_fields) {
$this->_fields = sqlsrv_field_metadata($this->_result);
if (!$this->fields) {
$this->fields = sqlsrv_field_metadata($this->result);
}
$field = $this->_fields[$this->_offset++];
$field = $this->fields[$this->offset++];
$return = new \stdClass;
$return->name = $field["Name"];
$return->orgname = $field["Name"];
$return->type = ($field["Type"] == 1 ? 254 : 0);
$return->type = ($field["Type"] == 1 ? 254 : 15);
$return->charsetnr = 0;
return $return;
}
function seek($offset) {
for ($i=0; $i < $offset; $i++) {
sqlsrv_fetch($this->_result); // SQLSRV_SCROLL_ABSOLUTE added in sqlsrv 1.1
sqlsrv_fetch($this->result); // SQLSRV_SCROLL_ABSOLUTE added in sqlsrv 1.1
}
}
function __destruct() {
sqlsrv_free_stmt($this->_result);
sqlsrv_free_stmt($this->result);
}
}
} elseif (extension_loaded("pdo_sqlsrv")) {
class Db extends PdoDb {
var $extension = "PDO_SQLSRV";
function last_id($result) {
return get_val("SELECT SCOPE_IDENTITY()"); // @@IDENTITY can return trigger INSERT
}
function connect($server, $username, $password) {
$this->dsn("sqlsrv:Server=" . str_replace(":", ",", $server), $username, $password);
return true;
}
function explain($connection, $query) {
$connection->query("SET SHOWPLAN_ALL ON");
$return = $connection->query($query);
$connection->query("SET SHOWPLAN_ALL OFF"); // connection is used also for indexes
return $return;
}
} else {
class MssqlDb extends PdoDb {
function select_db($database) {
// database selection is separated from the connection so dbname in DSN can't be used
return $this->query(use_sql($database));
}
function lastInsertId() {
return $this->pdo->lastInsertId();
}
}
} elseif (extension_loaded("pdo_dblib")) {
class Db extends PdoDb {
var $extension = "PDO_DBLIB";
function last_id($result) {
global $connection;
return $connection->lastInsertId();
}
function connect($server, $username, $password) {
$this->dsn("dblib:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password);
return true;
function explain($connection, $query) {
}
if (extension_loaded("pdo_sqlsrv")) {
class Db extends MssqlDb {
public $extension = "PDO_SQLSRV";
function connect($server, $username, $password) {
$this->dsn("sqlsrv:Server=" . str_replace(":", ",", $server), $username, $password);
return true;
}
}
function select_db($database) {
return $this->query(use_sql($database));
} elseif (extension_loaded("pdo_dblib")) {
class Db extends MssqlDb {
public $extension = "PDO_DBLIB";
function connect($server, $username, $password) {
$this->dsn("dblib:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password);
return true;
}
}
}
}
@@ -189,7 +214,7 @@ if (isset($_GET["mssql"])) {
static $possibleDrivers = array("SQLSRV", "PDO_SQLSRV", "PDO_DBLIB");
static $jush = "mssql";
var $editFunctions = array(
public $editFunctions = array(
array(
"date|time" => "getdate",
), array(
@@ -198,11 +223,11 @@ if (isset($_GET["mssql"])) {
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
var $functions = array("len", "lower", "round", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
var $onActions = "NO ACTION|CASCADE|SET NULL|SET DEFAULT";
var $generated = array("PERSISTED", "VIRTUAL");
public $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
public $functions = array("len", "lower", "round", "upper");
public $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
public $onActions = "NO ACTION|CASCADE|SET NULL|SET DEFAULT";
public $generated = array("PERSISTED", "VIRTUAL");
function __construct($connection) {
parent::__construct($connection);
@@ -307,10 +332,6 @@ if (isset($_GET["mssql"])) {
return get_val("SELECT collation_name FROM sys.databases WHERE name = " . q($db));
}
function engines() {
return array();
}
function logged_user() {
return get_val("SELECT SUSER_NAME()");
}
@@ -357,7 +378,7 @@ WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V')
$return = array();
$table_id = get_val("SELECT object_id FROM sys.all_objects WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') AND name = " . q($table));
foreach (
get_rows("SELECT c.max_length, c.precision, c.scale, c.name, c.is_nullable, c.is_identity, c.collation_name, t.name type, CAST(d.definition as text) [default], d.name default_constraint, i.is_primary_key
get_rows("SELECT c.max_length, c.precision, c.scale, c.name, c.is_nullable, c.is_identity, c.collation_name, t.name type, d.definition [default], d.name default_constraint, i.is_primary_key
FROM sys.all_columns c
JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints d ON c.default_object_id = d.object_id
@@ -507,7 +528,16 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table), $connection2) as $row
foreach ($comments as $key => $val) {
$comment = substr($val, 9); // 9 - strlen(" COMMENT ")
queries("EXEC sp_dropextendedproperty @name = N'MS_Description', @level0type = N'Schema', @level0name = " . q(get_schema()) . ", @level1type = N'Table', @level1name = " . q($name) . ", @level2type = N'Column', @level2name = " . q($key));
queries("EXEC sp_addextendedproperty @name = N'MS_Description', @value = " . $comment . ", @level0type = N'Schema', @level0name = " . q(get_schema()) . ", @level1type = N'Table', @level1name = " . q($name) . ", @level2type = N'Column', @level2name = " . q($key));
queries("EXEC sp_addextendedproperty
@name = N'MS_Description',
@value = $comment,
@level0type = N'Schema',
@level0name = " . q(get_schema()) . ",
@level1type = N'Table',
@level1name = " . q($name) . ",
@level2type = N'Column',
@level2name = " . q($key))
;
}
return true;
}
@@ -536,17 +566,6 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table), $connection2) as $row
;
}
function last_id() {
return get_val("SELECT SCOPE_IDENTITY()"); // @@IDENTITY can return trigger INSERT
}
function explain($connection, $query) {
$connection->query("SET SHOWPLAN_ALL ON");
$return = $connection->query($query);
$connection->query("SET SHOWPLAN_ALL OFF"); // connection is used also for indexes
return $return;
}
function found_rows($table_status, $where) {
}

View File

@@ -1,19 +1,20 @@
<?php
namespace Adminer;
$drivers = array("server" => "MySQL") + $drivers;
$drivers = array("server" => "MySQL / MariaDB") + $drivers;
if (!defined('Adminer\DRIVER')) {
define('Adminer\DRIVER', "server"); // server - backwards compatibility
// MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
if (extension_loaded("mysqli")) {
if (extension_loaded("mysqli") && $_GET["ext"] != "pdo") {
class Db extends \MySQLi {
var $extension = "MySQLi";
public $extension = "MySQLi", $flavor = '';
function __construct() {
parent::init();
}
/** @see https://php.net/mysqli.construct */
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
@@ -50,7 +51,7 @@ if (!defined('Adminer\DRIVER')) {
return false;
}
$row = $result->fetch_array();
return $row[$field];
return ($row ? $row[$field] : false);
}
function quote($string) {
@@ -60,14 +61,16 @@ if (!defined('Adminer\DRIVER')) {
} elseif (extension_loaded("mysql") && !((ini_bool("sql.safe_mode") || ini_bool("mysql.allow_local_infile")) && extension_loaded("pdo_mysql"))) {
class Db {
var
public
$extension = "MySQL", ///< @var string extension name
$flavor = '', ///< @var string different vendor with the same API, e.g. MariaDB, usually stays empty
$server_info, ///< @var string server version
$affected_rows, ///< @var int number of affected rows
$info, ///< @var string see https://php.net/mysql_info
$errno, ///< @var int last error code
$error, ///< @var string last error message
$_link, $_result ///< @access private
$error ///< @var string last error message
;
private $link, $result;
/** Connect to server
* @param string
@@ -80,32 +83,32 @@ if (!defined('Adminer\DRIVER')) {
$this->error = lang('Disable %s or enable %s or %s extensions.', "'mysql.allow_local_infile'", "MySQLi", "PDO_MySQL");
return false;
}
$this->_link = @mysql_connect(
$this->link = @mysql_connect(
($server != "" ? $server : ini_get("mysql.default_host")),
("$server$username" != "" ? $username : ini_get("mysql.default_user")),
("$server$username$password" != "" ? $password : ini_get("mysql.default_password")),
true,
131072 // CLIENT_MULTI_RESULTS for CALL
);
if ($this->_link) {
$this->server_info = mysql_get_server_info($this->_link);
if ($this->link) {
$this->server_info = mysql_get_server_info($this->link);
} else {
$this->error = mysql_error();
}
return (bool) $this->_link;
return (bool) $this->link;
}
/** Sets the client character set
/** Set the client character set
* @param string
* @return bool
*/
function set_charset($charset) {
if (function_exists('mysql_set_charset')) {
if (mysql_set_charset($charset, $this->_link)) {
if (mysql_set_charset($charset, $this->link)) {
return true;
}
// the client library may not support utf8mb4
mysql_set_charset('utf8', $this->_link);
mysql_set_charset('utf8', $this->link);
}
return $this->query("SET NAMES $charset");
}
@@ -115,7 +118,7 @@ if (!defined('Adminer\DRIVER')) {
* @return string escaped string enclosed in '
*/
function quote($string) {
return "'" . mysql_real_escape_string($string, $this->_link) . "'";
return "'" . mysql_real_escape_string($string, $this->link) . "'";
}
/** Select database
@@ -123,7 +126,7 @@ if (!defined('Adminer\DRIVER')) {
* @return bool
*/
function select_db($database) {
return mysql_select_db($database, $this->_link);
return mysql_select_db($database, $this->link);
}
/** Send query
@@ -132,16 +135,16 @@ if (!defined('Adminer\DRIVER')) {
* @return mixed bool or Result
*/
function query($query, $unbuffered = false) {
$result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode
$result = @($unbuffered ? mysql_unbuffered_query($query, $this->link) : mysql_query($query, $this->link)); // @ - mute mysql.trace_mode
$this->error = "";
if (!$result) {
$this->errno = mysql_errno($this->_link);
$this->error = mysql_error($this->_link);
$this->errno = mysql_errno($this->link);
$this->error = mysql_error($this->link);
return false;
}
if ($result === true) {
$this->affected_rows = mysql_affected_rows($this->_link);
$this->info = mysql_info($this->_link);
$this->affected_rows = mysql_affected_rows($this->link);
$this->info = mysql_info($this->link);
return true;
}
return new Result($result);
@@ -152,14 +155,14 @@ if (!defined('Adminer\DRIVER')) {
* @return bool
*/
function multi_query($query) {
return $this->_result = $this->query($query);
return $this->result = $this->query($query);
}
/** Get current resultset
* @return Result
*/
function store_result() {
return $this->_result;
return $this->result;
}
/** Fetch next resultset
@@ -177,24 +180,19 @@ if (!defined('Adminer\DRIVER')) {
*/
function result($query, $field = 0) {
$result = $this->query($query);
if (!$result || !$result->num_rows) {
return false;
}
return mysql_result($result->_result, 0, $field);
return ($result ? $result->fetch_column($field) : false);
}
}
class Result {
var
$num_rows, ///< @var int number of rows in the result
$_result, $_offset = 0 ///< @access private
;
public $num_rows; ///< @var int number of rows in the result
private $result, $offset = 0;
/** Constructor
* @param resource
*/
function __construct($result) {
$this->_result = $result;
$this->result = $result;
$this->num_rows = mysql_num_rows($result);
}
@@ -202,23 +200,30 @@ if (!defined('Adminer\DRIVER')) {
* @return array
*/
function fetch_assoc() {
return mysql_fetch_assoc($this->_result);
return mysql_fetch_assoc($this->result);
}
/** Fetch next row as numbered array
* @return array
*/
function fetch_row() {
return mysql_fetch_row($this->_result);
return mysql_fetch_row($this->result);
}
/** Fetch a single column
* @param int
* @return string or false if there are no rows
*/
function fetch_column($field) {
return ($this->num_rows ? mysql_result($this->result, 0, $field) : false);
}
/** Fetch next field
* @return object properties: name, type, orgtable, orgname, charsetnr
* @return object properties: name, type (0 number, 15 varchar, 254 char), charsetnr (63 binary); optionally: table, orgtable, orgname
*/
function fetch_field() {
$return = mysql_fetch_field($this->_result, $this->_offset++); // offset required under certain conditions
$return = mysql_fetch_field($this->result, $this->offset++); // offset required under certain conditions
$return->orgtable = $return->table;
$return->orgname = $return->name;
$return->charsetnr = ($return->blob ? 63 : 0);
return $return;
}
@@ -226,13 +231,13 @@ if (!defined('Adminer\DRIVER')) {
/** Free result set
*/
function __destruct() {
mysql_free_result($this->_result);
mysql_free_result($this->result);
}
}
} elseif (extension_loaded("pdo_mysql")) {
class Db extends PdoDb {
var $extension = "PDO_MySQL";
public $extension = "PDO_MySQL";
function connect($server, $username, $password) {
global $adminer;
@@ -284,10 +289,10 @@ if (!defined('Adminer\DRIVER')) {
static $possibleDrivers = array("MySQLi", "MySQL", "PDO_MySQL");
static $jush = "sql"; ///< @var string JUSH identifier
var $unsigned = array("unsigned", "zerofill", "unsigned zerofill");
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL");
var $functions = array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper");
var $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
public $unsigned = array("unsigned", "zerofill", "unsigned zerofill");
public $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL");
public $functions = array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper");
public $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
@@ -327,6 +332,13 @@ if (!defined('Adminer\DRIVER')) {
}
}
function unconvertFunction($field) {
return (preg_match("~binary~", $field["type"]) ? "<code class='jush-sql'>UNHEX</code>"
: ($field["type"] == "bit" ? doc_link(array('sql' => 'bit-value-literals.html'), "<code>b''</code>")
: (preg_match("~geometry|point|linestring|polygon~", $field["type"]) ? "<code class='jush-sql'>GeomFromText</code>"
: "")));
}
function insert($table, $set) {
return ($set ? parent::insert($table, $set) : queries("INSERT INTO " . table($table) . " ()\nVALUES ()"));
}
@@ -358,7 +370,7 @@ if (!defined('Adminer\DRIVER')) {
function slowQuery($query, $timeout) {
if (min_version('5.7.8', '10.1.2')) {
if (preg_match('~MariaDB~', $this->_conn->server_info)) {
if ($this->conn->flavor == 'maria') {
return "SET STATEMENT max_statement_time=$timeout FOR $query";
} elseif (preg_match('~^(SELECT\b)(.+)~is', $query, $match)) {
return "$match[1] /*+ MAX_EXECUTION_TIME(" . ($timeout * 1000) . ") */ $match[2]";
@@ -368,13 +380,13 @@ if (!defined('Adminer\DRIVER')) {
function convertSearch($idf, $val, $field) {
return (preg_match('~char|text|enum|set~', $field["type"]) && !preg_match("~^utf8~", $field["collation"]) && preg_match('~[\x80-\xFF]~', $val['val'])
? "CONVERT($idf USING " . charset($this->_conn) . ")"
? "CONVERT($idf USING " . charset($this->conn) . ")"
: $idf
);
}
function warnings() {
$result = $this->_conn->query("SHOW WARNINGS");
$result = $this->conn->query("SHOW WARNINGS");
if ($result && $result->num_rows) {
ob_start();
select($result); // select() usually needs to print a big table progressively
@@ -383,7 +395,7 @@ if (!defined('Adminer\DRIVER')) {
}
function tableHelp($name, $is_view = false) {
$maria = preg_match('~MariaDB~', $this->_conn->server_info);
$maria = ($this->conn->flavor == 'maria');
if (information_schema(DB)) {
return strtolower("information-schema-" . ($maria ? "$name-table/" : str_replace("_", "-", $name) . "-table.html"));
}
@@ -395,11 +407,21 @@ if (!defined('Adminer\DRIVER')) {
function hasCStyleEscapes() {
static $c_style;
if ($c_style === null) {
$sql_mode = $this->_conn->result("SHOW VARIABLES LIKE 'sql_mode'", 1);
$sql_mode = $this->conn->result("SHOW VARIABLES LIKE 'sql_mode'", 1);
$c_style = (strpos($sql_mode, 'NO_BACKSLASH_ESCAPES') === false);
}
return $c_style;
}
function engines() {
$return = array();
foreach (get_rows("SHOW ENGINES") as $row) {
if (preg_match("~YES|DEFAULT~", $row["Support"])) {
$return[] = $row["Engine"];
}
}
return $return;
}
}
@@ -425,10 +447,13 @@ if (!defined('Adminer\DRIVER')) {
* @return mixed Db or string for error
*/
function connect($credentials) {
global $drivers;
$connection = new Db;
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");
$connection->flavor = (preg_match('~MariaDB~', $connection->server_info) ? 'maria' : '');
$drivers[DRIVER] = ($connection->flavor == 'maria' ? "MariaDB" : "MySQL");
return $connection;
}
$return = $connection->error;
@@ -495,19 +520,6 @@ if (!defined('Adminer\DRIVER')) {
return $return;
}
/** Get supported engines
* @return array
*/
function engines() {
$return = array();
foreach (get_rows("SHOW ENGINES") as $row) {
if (preg_match("~YES|DEFAULT~", $row["Support"])) {
$return[] = $row["Engine"];
}
}
return $return;
}
/** Get logged user
* @return string
*/
@@ -584,30 +596,45 @@ if (!defined('Adminer\DRIVER')) {
/** Get information about fields
* @param string
* @return array [$name => ["field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => , "generated" => ]]
* @return array [$name => ["field" =>, "full_type" =>, "type" =>, "length" =>, "unsigned" =>, "default" =>, "null" =>, "auto_increment" =>, "on_update" =>, "collation" =>, "privileges" =>, "comment" =>, "primary" =>, "generated" =>]]
*/
function fields($table) {
global $connection;
$maria = ($connection->flavor == 'maria');
$return = array();
foreach (get_rows("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . q($table) . " ORDER BY ORDINAL_POSITION") as $row) {
$field = $row["COLUMN_NAME"];
$default = $row["COLUMN_DEFAULT"];
$type = $row["COLUMN_TYPE"];
$generation = $row["GENERATION_EXPRESSION"];
$extra = $row["EXTRA"];
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186
preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $extra, $generated);
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match);
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match_type);
$default = $row["COLUMN_DEFAULT"];
if ($default != "") {
$is_text = preg_match('~text|json~', $match_type[1]);
if (!$maria && $is_text) {
// default value a'b of text column is stored as _utf8mb4\'a\\\'b\' in MySQL
$default = preg_replace("~^(_\w+)?('.*')$~", '\2', stripslashes($default));
}
if ($maria || $is_text) {
$default = ($default == "NULL" ? null : preg_replace_callback("~^'(.*)'$~", function ($match) {
return stripslashes(str_replace("''", "'", $match[1]));
}, $default));
}
if (!$maria && preg_match('~binary~', $match_type[1]) && preg_match('~^0x(\w*)$~', $default, $match)) {
$default = pack("H*", $match[1]);
}
}
$return[$field] = array(
"field" => $field,
"full_type" => $type,
"type" => $match[1],
"length" => $match[2],
"unsigned" => ltrim($match[3] . $match[4]),
"type" => $match_type[1],
"length" => $match_type[2],
"unsigned" => ltrim($match_type[3] . $match_type[4]),
"default" => ($generated
? $row["GENERATION_EXPRESSION"]
: ($default != "" || preg_match("~char|set~", $match[1])
? (preg_match('~text~', $match[1]) ? stripslashes(preg_replace("~^'(.*)'\$~", '\1', $default)) : $default)
: null
)
? ($maria ? $generation : stripslashes($generation))
: $default
),
"null" => ($row["IS_NULLABLE"] == "YES"),
"auto_increment" => ($extra == "auto_increment"),
@@ -649,7 +676,12 @@ if (!defined('Adminer\DRIVER')) {
$return = array();
$create_table = get_val("SHOW CREATE TABLE " . table($table), 1);
if ($create_table) {
preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($driver->onActions))?(?: ON UPDATE ($driver->onActions))?~", $create_table, $matches, PREG_SET_ORDER);
preg_match_all(
"~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($driver->onActions))?(?: ON UPDATE ($driver->onActions))?~",
$create_table,
$matches,
PREG_SET_ORDER
);
foreach ($matches as $match) {
preg_match_all("~$pattern~", $match[2], $source);
preg_match_all("~$pattern~", $match[5], $target);
@@ -786,12 +818,14 @@ if (!defined('Adminer\DRIVER')) {
* @return bool
*/
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
global $connection;
$alter = array();
foreach ($fields as $field) {
if ($field[1]) {
$default = $field[1][3];
if (preg_match('~ GENERATED~', $default)) {
$field[1][3] = $field[1][2];
// swap default and null
$field[1][3] = ($connection->flavor == 'maria' ? "" : $field[1][2]); // MariaDB doesn't support NULL on virtual columns
$field[1][2] = $default;
}
$alter[] = ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "");
@@ -967,7 +1001,9 @@ if (!defined('Adminer\DRIVER')) {
global $driver;
$aliases = array("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($driver->types()), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$driver->enumLength)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$enum = $driver->enumLength;
$type_pattern = "((" . implode("|", array_merge(array_keys($driver->types()), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum)++)\\))?"
. "\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $driver->inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = get_val("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
@@ -977,7 +1013,7 @@ if (!defined('Adminer\DRIVER')) {
$fields[] = array(
"field" => str_replace("``", "`", $param[2]) . $param[3],
"type" => strtolower($param[5]),
"length" => preg_replace_callback("~$driver->enumLength~s", 'Adminer\normalize_enum', $param[6]),
"length" => preg_replace_callback("~$enum~s", 'Adminer\normalize_enum', $param[6]),
"unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))),
"null" => 1,
"full_type" => $param[4],
@@ -1019,9 +1055,10 @@ if (!defined('Adminer\DRIVER')) {
}
/** Get last auto increment ID
* @param Result or true
* @return string
*/
function last_id() {
function last_id($result) {
return get_val("SELECT LAST_INSERT_ID()"); // mysql_insert_id() truncates bigint
}
@@ -1121,10 +1158,17 @@ if (!defined('Adminer\DRIVER')) {
}
/** Get server variables
* @return array [$name => $value]
* @return array [[$name, $value]]
*/
function show_variables() {
return get_key_vals("SHOW VARIABLES");
return get_rows("SHOW VARIABLES");
}
/** Get status variables
* @return array [[$name, $value]]
*/
function show_status() {
return get_rows("SHOW STATUS");
}
/** Get process list
@@ -1134,13 +1178,6 @@ if (!defined('Adminer\DRIVER')) {
return get_rows("SHOW FULL PROCESSLIST");
}
/** Get status variables
* @return array [$name => $value]
*/
function show_status() {
return get_key_vals("SHOW STATUS");
}
/** Convert field in select and edit
* @param array one element from fields()
* @return string
@@ -1177,7 +1214,7 @@ if (!defined('Adminer\DRIVER')) {
}
/** Check whether a feature is supported
* @param string "check", "comment", "copy", "database", "descidx", "drop_col", "dump", "event", "indexes", "kill", "materializedview", "partitioning", "privileges", "procedure", "processlist", "routine", "scheme", "sequence", "status", "table", "trigger", "type", "variables", "view", "view_trigger"
* @param string "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|partitioning|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger"
* @return bool
*/
function support($feature) {

View File

@@ -5,10 +5,11 @@ $drivers["oracle"] = "Oracle (beta)";
if (isset($_GET["oracle"])) {
define('Adminer\DRIVER', "oracle");
if (extension_loaded("oci8")) {
if (extension_loaded("oci8") && $_GET["ext"] != "pdo") {
class Db {
var $extension = "oci8", $_link, $_result, $server_info, $affected_rows, $errno, $error;
var $_current_db;
public $extension = "oci8", $flavor = '', $server_info, $affected_rows, $errno, $error;
public $_current_db;
private $link, $result;
function _error($errno, $error) {
if (ini_bool("html_errors")) {
@@ -19,9 +20,9 @@ if (isset($_GET["oracle"])) {
}
function connect($server, $username, $password) {
$this->_link = @oci_new_connect($username, $password, $server, "AL32UTF8");
if ($this->_link) {
$this->server_info = oci_server_version($this->_link);
$this->link = @oci_new_connect($username, $password, $server, "AL32UTF8");
if ($this->link) {
$this->server_info = oci_server_version($this->link);
return true;
}
$error = oci_error();
@@ -39,10 +40,10 @@ if (isset($_GET["oracle"])) {
}
function query($query, $unbuffered = false) {
$result = oci_parse($this->_link, $query);
$result = oci_parse($this->link, $query);
$this->error = "";
if (!$result) {
$error = oci_error($this->_link);
$error = oci_error($this->link);
$this->errno = $error["code"];
$this->error = $error["message"];
return false;
@@ -61,11 +62,11 @@ if (isset($_GET["oracle"])) {
}
function multi_query($query) {
return $this->_result = $this->query($query);
return $this->result = $this->query($query);
}
function store_result() {
return $this->_result;
return $this->result;
}
function next_result() {
@@ -74,21 +75,19 @@ if (isset($_GET["oracle"])) {
function result($query, $field = 0) {
$result = $this->query($query);
if (!is_object($result) || !oci_fetch($result->_result)) {
return false;
}
return oci_result($result->_result, $field + 1);
return (is_object($result) ? $result->fetch_column($field) : false);
}
}
class Result {
var $_result, $_offset = 1, $num_rows;
public $num_rows;
private $result, $offset = 1;
function __construct($result) {
$this->_result = $result;
$this->result = $result;
}
function _convert($row) {
private function convert($row) {
foreach ((array) $row as $key => $val) {
if (is_a($val, 'OCI-Lob')) {
$row[$key] = $val->load();
@@ -98,32 +97,35 @@ if (isset($_GET["oracle"])) {
}
function fetch_assoc() {
return $this->_convert(oci_fetch_assoc($this->_result));
return $this->convert(oci_fetch_assoc($this->result));
}
function fetch_row() {
return $this->_convert(oci_fetch_row($this->_result));
return $this->convert(oci_fetch_row($this->result));
}
function fetch_column($field) {
return (oci_fetch($this->result) ? oci_result($this->result, $field + 1) : false);
}
function fetch_field() {
$column = $this->_offset++;
$column = $this->offset++;
$return = new \stdClass;
$return->name = oci_field_name($this->_result, $column);
$return->orgname = $return->name;
$return->type = oci_field_type($this->_result, $column);
$return->name = oci_field_name($this->result, $column);
$return->type = oci_field_type($this->result, $column); //! map to MySQL numbers
$return->charsetnr = (preg_match("~raw|blob|bfile~", $return->type) ? 63 : 0); // 63 - binary
return $return;
}
function __destruct() {
oci_free_statement($this->_result);
oci_free_statement($this->result);
}
}
} elseif (extension_loaded("pdo_oci")) {
class Db extends PdoDb {
var $extension = "PDO_OCI";
var $_current_db;
public $extension = "PDO_OCI";
public $_current_db;
function connect($server, $username, $password) {
$this->dsn("oci:dbname=//$server;charset=AL32UTF8", $username, $password);
@@ -144,7 +146,7 @@ if (isset($_GET["oracle"])) {
static $possibleDrivers = array("OCI8", "PDO_OCI");
static $jush = "oracle";
var $editFunctions = array(
public $editFunctions = array(
array( //! no parentheses
"date" => "current_date",
"timestamp" => "current_timestamp",
@@ -155,9 +157,9 @@ if (isset($_GET["oracle"])) {
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL");
var $functions = array("length", "lower", "round", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
public $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL");
public $functions = array("length", "lower", "round", "upper");
public $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
@@ -244,10 +246,6 @@ ORDER BY 1"
return get_val("SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET'"); //! respect $db
}
function engines() {
return array();
}
function logged_user() {
return get_val("SELECT USER FROM DUAL");
}
@@ -492,7 +490,7 @@ AND c_src.TABLE_NAME = " . q($table);
return apply_queries("DROP TABLE", $tables);
}
function last_id() {
function last_id($result) {
return 0; //!
}
@@ -514,11 +512,29 @@ AND c_src.TABLE_NAME = " . q($table);
}
function show_variables() {
return get_key_vals('SELECT name, display_value FROM v$parameter');
return get_rows('SELECT name, display_value FROM v$parameter');
}
function show_status() {
$return = array();
$rows = get_rows('SELECT * FROM v$instance');
foreach (reset($rows) as $key => $val) {
$return[] = array($key, $val);
}
return $return;
}
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"
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
ON sql.sql_id = sess.sql_id
WHERE sess.type = \'USER\'
@@ -526,11 +542,6 @@ ORDER BY PROCESS
');
}
function show_status() {
$rows = get_rows('SELECT * FROM v$instance');
return reset($rows);
}
function convert_field($field) {
}

View File

@@ -5,9 +5,10 @@ $drivers["pgsql"] = "PostgreSQL";
if (isset($_GET["pgsql"])) {
define('Adminer\DRIVER', "pgsql");
if (extension_loaded("pgsql")) {
if (extension_loaded("pgsql") && $_GET["ext"] != "pdo") {
class Db {
var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error, $timeout;
public $extension = "PgSQL", $flavor = '', $server_info, $affected_rows, $error, $timeout;
private $link, $result, $string, $database = true;
function _error($errno, $error) {
if (ini_bool("html_errors")) {
@@ -21,59 +22,56 @@ if (isset($_GET["pgsql"])) {
global $adminer;
$db = $adminer->database();
set_error_handler(array($this, '_error'));
$this->_string = "host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' user='" . addcslashes($username, "'\\") . "' password='" . addcslashes($password, "'\\") . "'";
$this->string = "host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' user='" . addcslashes($username, "'\\") . "' password='" . addcslashes($password, "'\\") . "'";
$ssl = $adminer->connectSsl();
if (isset($ssl["mode"])) {
$this->_string .= " sslmode='" . $ssl["mode"] . "'";
$this->string .= " sslmode='" . $ssl["mode"] . "'";
}
$this->_link = @pg_connect("$this->_string dbname='" . ($db != "" ? addcslashes($db, "'\\") : "postgres") . "'", PGSQL_CONNECT_FORCE_NEW);
if (!$this->_link && $db != "") {
$this->link = @pg_connect("$this->string dbname='" . ($db != "" ? addcslashes($db, "'\\") : "postgres") . "'", PGSQL_CONNECT_FORCE_NEW);
if (!$this->link && $db != "") {
// try to connect directly with database for performance
$this->_database = false;
$this->_link = @pg_connect("$this->_string dbname='postgres'", PGSQL_CONNECT_FORCE_NEW);
$this->database = false;
$this->link = @pg_connect("$this->string dbname='postgres'", PGSQL_CONNECT_FORCE_NEW);
}
restore_error_handler();
if ($this->_link) {
$version = pg_version($this->_link);
$this->server_info = $version["server"];
pg_set_client_encoding($this->_link, "UTF8");
if ($this->link) {
pg_set_client_encoding($this->link, "UTF8");
}
return (bool) $this->_link;
return (bool) $this->link;
}
function quote($string) {
return pg_escape_literal($this->_link, $string);
return (function_exists('pg_escape_literal')
? pg_escape_literal($this->link, $string) // available since PHP 5.4.4
: "'" . pg_escape_string($this->link, $string) . "'"
);
}
function value($val, $field) {
return ($field["type"] == "bytea" && $val !== null ? pg_unescape_bytea($val) : $val);
}
function quoteBinary($string) {
return "'" . pg_escape_bytea($this->_link, $string) . "'";
}
function select_db($database) {
global $adminer;
if ($database == $adminer->database()) {
return $this->_database;
return $this->database;
}
$return = @pg_connect("$this->_string dbname='" . addcslashes($database, "'\\") . "'", PGSQL_CONNECT_FORCE_NEW);
$return = @pg_connect("$this->string dbname='" . addcslashes($database, "'\\") . "'", PGSQL_CONNECT_FORCE_NEW);
if ($return) {
$this->_link = $return;
$this->link = $return;
}
return $return;
}
function close() {
$this->_link = @pg_connect("$this->_string dbname='postgres'");
$this->link = @pg_connect("$this->string dbname='postgres'");
}
function query($query, $unbuffered = false) {
$result = @pg_query($this->_link, $query);
$result = @pg_query($this->link, $query);
$this->error = "";
if (!$result) {
$this->error = pg_last_error($this->_link);
$this->error = pg_last_error($this->link);
$return = false;
} elseif (!pg_num_fields($result)) {
$this->affected_rows = pg_affected_rows($result);
@@ -89,11 +87,11 @@ if (isset($_GET["pgsql"])) {
}
function multi_query($query) {
return $this->_result = $this->query($query);
return $this->result = $this->query($query);
}
function store_result() {
return $this->_result;
return $this->result;
}
function next_result() {
@@ -103,54 +101,53 @@ if (isset($_GET["pgsql"])) {
function result($query, $field = 0) {
$result = $this->query($query);
if (!$result || !$result->num_rows) {
return false;
}
return pg_fetch_result($result->_result, 0, $field);
return ($result ? $result->fetch_column($field) : false);
}
function warnings() {
return h(pg_last_notice($this->_link)); // second parameter is available since PHP 7.1.0
return h(pg_last_notice($this->link)); // second parameter is available since PHP 7.1.0
}
}
class Result {
var $_result, $_offset = 0, $num_rows;
public $num_rows;
private $result, $offset = 0;
function __construct($result) {
$this->_result = $result;
$this->result = $result;
$this->num_rows = pg_num_rows($result);
}
function fetch_assoc() {
return pg_fetch_assoc($this->_result);
return pg_fetch_assoc($this->result);
}
function fetch_row() {
return pg_fetch_row($this->_result);
return pg_fetch_row($this->result);
}
function fetch_column($field) {
return ($this->num_rows ? pg_fetch_result($this->result, 0, $field) : false);
}
function fetch_field() {
$column = $this->_offset++;
$column = $this->offset++;
$return = new \stdClass;
if (function_exists('pg_field_table')) {
$return->orgtable = pg_field_table($this->_result, $column);
}
$return->name = pg_field_name($this->_result, $column);
$return->orgname = $return->name;
$return->type = pg_field_type($this->_result, $column);
$return->orgtable = pg_field_table($this->result, $column);
$return->name = pg_field_name($this->result, $column);
$return->type = pg_field_type($this->result, $column); //! map to MySQL numbers
$return->charsetnr = ($return->type == "bytea" ? 63 : 0); // 63 - binary
return $return;
}
function __destruct() {
pg_free_result($this->_result);
pg_free_result($this->result);
}
}
} elseif (extension_loaded("pdo_pgsql")) {
class Db extends PdoDb {
var $extension = "PDO_PgSQL", $timeout;
public $extension = "PDO_PgSQL", $timeout;
function connect($server, $username, $password) {
global $adminer;
@@ -170,10 +167,6 @@ if (isset($_GET["pgsql"])) {
return ($adminer->database() == $database);
}
function quoteBinary($s) {
return q($s);
}
function query($query, $unbuffered = false) {
$return = parent::query($query, $unbuffered);
if ($this->timeout) {
@@ -199,9 +192,9 @@ if (isset($_GET["pgsql"])) {
static $possibleDrivers = array("PgSQL", "PDO_PgSQL");
static $jush = "pgsql";
var $operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // no "SQL" to avoid CSRF
var $functions = array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
public $operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // no "SQL" to avoid CSRF
public $functions = array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper");
public $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
@@ -243,6 +236,13 @@ if (isset($_GET["pgsql"])) {
$this->types[lang('User types')] = array_flip($types);
}
function insertReturning($table) {
$auto_increment = array_filter(fields($table), function ($field) {
return $field['auto_increment'];
});
return (count($auto_increment) == 1 ? " RETURNING " . idf_escape(key($auto_increment)) : "");
}
function insertUpdate($table, $rows, $primary) {
global $connection;
foreach ($rows as $set) {
@@ -265,8 +265,8 @@ if (isset($_GET["pgsql"])) {
}
function slowQuery($query, $timeout) {
$this->_conn->query("SET statement_timeout = " . (1000 * $timeout));
$this->_conn->timeout = 1000 * $timeout;
$this->conn->query("SET statement_timeout = " . (1000 * $timeout));
$this->conn->timeout = 1000 * $timeout;
return $query;
}
@@ -280,11 +280,11 @@ if (isset($_GET["pgsql"])) {
}
function quoteBinary($s) {
return $this->_conn->quoteBinary($s);
return "'\\x" . bin2hex($s) . "'"; // available since PostgreSQL 8.1
}
function warnings() {
return $this->_conn->warnings();
return $this->conn->warnings();
}
function tableHelp($name, $is_view = false) {
@@ -299,13 +299,14 @@ if (isset($_GET["pgsql"])) {
}
function supportsIndex($table_status) {
// returns true for "materialized view"
return $table_status["Engine"] != "view";
}
function hasCStyleEscapes() {
static $c_style;
if ($c_style === null) {
$c_style = ($this->_conn->result("SHOW standard_conforming_strings") == "off");
$c_style = ($this->conn->result("SHOW standard_conforming_strings") == "off");
}
return $c_style;
}
@@ -322,11 +323,18 @@ if (isset($_GET["pgsql"])) {
}
function connect($credentials) {
global $drivers;
$connection = new Db;
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
if (min_version(9, 0, $connection)) {
$connection->query("SET application_name = 'Adminer'");
}
$version = $connection->result("SELECT version()");
$connection->flavor = (preg_match('~CockroachDB~', $version) ? 'cockroach' : '');
$connection->server_info = preg_replace('~^\D*([\d.]+[-\w]*).*~', '\1', $version);
if ($connection->flavor == 'cockroach') { // we don't use "PostgreSQL / CockroachDB" by default because it's too long
$drivers[DRIVER] = "CockroachDB";
}
return $connection;
}
return $connection->error;
@@ -353,10 +361,6 @@ ORDER BY datname");
return get_val("SELECT datcollate FROM pg_database WHERE datname = " . q($db));
}
function engines() {
return array();
}
function logged_user() {
return get_val("SELECT user");
}
@@ -428,7 +432,14 @@ WHERE relkind IN ('r', 'm', 'v', 'f', 'p')
'timestamp with time zone' => 'timestamptz',
);
foreach (
get_rows("SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, pg_get_expr(d.adbin, d.adrelid) AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment" . (min_version(10) ? ", a.attidentity" . (min_version(12) ? ", a.attgenerated" : "") : "") . "
get_rows("SELECT
a.attname AS field,
format_type(a.atttypid, a.atttypmod) AS full_type,
pg_get_expr(d.adbin, d.adrelid) AS default,
a.attnotnull::int,
col_description(c.oid, a.attnum) AS comment" . (min_version(10) ? ",
a.attidentity" . (min_version(12) ? ",
a.attgenerated" : "") : "") . "
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_attribute a ON c.oid = a.attrelid
@@ -456,8 +467,9 @@ ORDER BY a.attnum") as $row
}
$row["generated"] = ($row["attgenerated"] == "s" ? "STORED" : "");
$row["null"] = !$row["attnotnull"];
$row["auto_increment"] = $row['attidentity'] || preg_match('~^nextval\(~i', $row["default"]);
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1);
$row["auto_increment"] = $row['attidentity'] || preg_match('~^nextval\(~i', $row["default"])
|| preg_match('~^unique_rowid\(~', $row["default"]); // CockroachDB
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1, "where" => 1, "order" => 1);
if (preg_match('~(.+)::[^,)]+(.*)~', $row["default"], $match)) {
$row["default"] = ($match[1] == "NULL" ? null : idf_unescape($match[1]) . $match[2]);
}
@@ -474,7 +486,12 @@ ORDER BY a.attnum") as $row
$return = array();
$table_oid = $connection2->result("SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) AND relname = " . q($table));
$columns = get_key_vals("SELECT attnum, attname FROM pg_attribute WHERE attrelid = $table_oid AND attnum > 0", $connection2);
foreach (get_rows("SELECT relname, indisunique::int, indisprimary::int, indkey, indoption, (indpred IS NOT NULL)::int as indispartial FROM pg_index i, pg_class ci WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid ORDER BY indisprimary DESC, indisunique DESC", $connection2) as $row) {
foreach (
get_rows("SELECT relname, indisunique::int, indisprimary::int, indkey, indoption, (indpred IS NOT NULL)::int as indispartial
FROM pg_index i, pg_class ci
WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid
ORDER BY indisprimary DESC, indisunique DESC", $connection2) as $row
) {
$relname = $row["relname"];
$return[$relname]["type"] = ($row["indispartial"] ? "INDEX" : ($row["indisprimary"] ? "PRIMARY" : ($row["indisunique"] ? "UNIQUE" : "INDEX")));
$return[$relname]["columns"] = array();
@@ -658,7 +675,6 @@ ORDER BY conkey, conname") as $row
function truncate_tables($tables) {
return queries("TRUNCATE " . implode(", ", array_map('Adminer\table', $tables)));
return true;
}
function drop_views($views) {
@@ -695,7 +711,12 @@ ORDER BY conkey, conname") as $row
$columns[] = $row["event_object_column"];
}
$return = array();
foreach (get_rows('SELECT trigger_name AS "Trigger", action_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement" FROM information_schema.triggers ' . "$where ORDER BY event_manipulation DESC") as $row) {
foreach (
get_rows('SELECT trigger_name AS "Trigger", action_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement"
FROM information_schema.triggers' . "
$where
ORDER BY event_manipulation DESC") as $row
) {
if ($columns && $row["Event"] == "UPDATE") {
$row["Event"] .= " OF";
}
@@ -752,13 +773,14 @@ ORDER BY SPECIFIC_NAME');
function routine_id($name, $row) {
$return = array();
foreach ($row["fields"] as $field) {
$return[] = $field["type"];
$length = $field["length"];
$return[] = $field["type"] . ($length ? "($length)" : "");
}
return idf_escape($name) . "(" . implode(", ", $return) . ")";
}
function last_id() {
return 0; // there can be several sequences
function last_id($result) {
return (is_object($result) && $result->num_rows ? $result->fetch_column(0) : 0);
}
function explain($connection, $query) {
@@ -851,7 +873,7 @@ AND typelem = 0"
// sequences for fields
if (preg_match('~nextval\(\'([^\']+)\'\)~', $field['default'], $matches)) {
$sequence_name = $matches[1];
$sq = reset(get_rows((min_version(10)
$sq = first(get_rows((min_version(10)
? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q(idf_unescape($sequence_name))
: "SELECT * FROM $sequence_name"
), null, "-- "));
@@ -920,7 +942,7 @@ AND typelem = 0"
}
function show_variables() {
return get_key_vals("SHOW ALL");
return get_rows("SHOW ALL");
}
function process_list() {
@@ -935,7 +957,11 @@ AND typelem = 0"
}
function support($feature) {
return preg_match('~^(check|database|table|columns|sql|indexes|descidx|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|routine|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature);
global $connection;
return preg_match('~^(check|database|table|columns|sql|indexes|descidx|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|' . (min_version(11) ? 'procedure|' : '') . 'routine|sequence|trigger|type|variables|drop_col'
. ($connection->flavor == 'cockroach' ? '' : '|processlist') // https://github.com/cockroachdb/cockroach/issues/24745
. '|kill|dump)$~', $feature)
;
}
function kill_process($val) {

View File

@@ -5,40 +5,41 @@ $drivers["sqlite"] = "SQLite";
if (isset($_GET["sqlite"])) {
define('Adminer\DRIVER', "sqlite");
if (class_exists("SQLite3")) {
if (class_exists("SQLite3") && $_GET["ext"] != "pdo") {
class SqliteDb {
var $extension = "SQLite3", $server_info, $affected_rows, $errno, $error, $_link;
public $extension = "SQLite3", $server_info, $affected_rows, $errno, $error;
private $link;
function __construct($filename) {
$this->_link = new \SQLite3($filename);
$version = $this->_link->version();
$this->link = new \SQLite3($filename);
$version = $this->link->version();
$this->server_info = $version["versionString"];
}
function query($query) {
$result = @$this->_link->query($query);
$result = @$this->link->query($query);
$this->error = "";
if (!$result) {
$this->errno = $this->_link->lastErrorCode();
$this->error = $this->_link->lastErrorMsg();
$this->errno = $this->link->lastErrorCode();
$this->error = $this->link->lastErrorMsg();
return false;
} elseif ($result->numColumns()) {
return new Result($result);
}
$this->affected_rows = $this->_link->changes();
$this->affected_rows = $this->link->changes();
return true;
}
function quote($string) {
return (is_utf8($string)
? "'" . $this->_link->escapeString($string) . "'"
: "x'" . reset(unpack('H*', $string)) . "'"
? "'" . $this->link->escapeString($string) . "'"
: "x'" . first(unpack('H*', $string)) . "'"
);
}
function store_result() {
return $this->_result;
return $this->result;
}
function result($query, $field = 0) {
@@ -46,44 +47,45 @@ if (isset($_GET["sqlite"])) {
if (!is_object($result)) {
return false;
}
$row = $result->_result->fetchArray();
$row = $result->fetch_row();
return $row ? $row[$field] : false;
}
}
class Result {
var $_result, $_offset = 0, $num_rows;
public $num_rows;
private $result, $offset = 0;
function __construct($result) {
$this->_result = $result;
$this->result = $result;
}
function fetch_assoc() {
return $this->_result->fetchArray(SQLITE3_ASSOC);
return $this->result->fetchArray(SQLITE3_ASSOC);
}
function fetch_row() {
return $this->_result->fetchArray(SQLITE3_NUM);
return $this->result->fetchArray(SQLITE3_NUM);
}
function fetch_field() {
$column = $this->_offset++;
$type = $this->_result->columnType($column);
$column = $this->offset++;
$type = $this->result->columnType($column);
return (object) array(
"name" => $this->_result->columnName($column),
"type" => $type,
"name" => $this->result->columnName($column),
"type" => ($type == SQLITE3_TEXT ? 15 : 0),
"charsetnr" => ($type == SQLITE3_BLOB ? 63 : 0), // 63 - binary
);
}
function __desctruct() {
return $this->_result->finalize();
function __destruct() {
return $this->result->finalize();
}
}
} elseif (extension_loaded("pdo_sqlite")) {
class SqliteDb extends PdoDb {
var $extension = "PDO_SQLite";
public $extension = "PDO_SQLite";
function __construct($filename) {
$this->dsn(DRIVER . ":$filename", "", "");
@@ -98,6 +100,7 @@ if (isset($_GET["sqlite"])) {
if (class_exists('Adminer\SqliteDb')) {
class Db extends SqliteDb {
public $flavor = '';
function __construct() {
parent::__construct(":memory:");
@@ -113,14 +116,6 @@ if (isset($_GET["sqlite"])) {
}
return false;
}
function multi_query($query) {
return $this->_result = $this->query($query);
}
function next_result() {
return false;
}
}
}
@@ -132,7 +127,7 @@ if (isset($_GET["sqlite"])) {
protected $types = array(array("integer" => 0, "real" => 0, "numeric" => 0, "text" => 0, "blob" => 0));
var $editFunctions = array(
public $editFunctions = array(
array(
// "text" => "date('now')/time('now')/datetime('now')",
), array(
@@ -142,9 +137,9 @@ if (isset($_GET["sqlite"])) {
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"); // REGEXP can be user defined function
var $functions = array("hex", "length", "lower", "round", "unixepoch", "upper");
var $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
public $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"); // REGEXP can be user defined function
public $functions = array("hex", "length", "lower", "round", "unixepoch", "upper");
public $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
@@ -175,7 +170,7 @@ if (isset($_GET["sqlite"])) {
}
function checkConstraints($table) {
preg_match_all('~ CHECK *(\( *(((?>[^()]*[^() ])|(?1))*) *\))~', $this->_conn->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table)), $matches); //! could be inside a comment
preg_match_all('~ CHECK *(\( *(((?>[^()]*[^() ])|(?1))*) *\))~', $this->conn->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table)), $matches); //! could be inside a comment
return array_combine($matches[2], $matches[2]);
}
}
@@ -217,10 +212,6 @@ if (isset($_GET["sqlite"])) {
return get_val("PRAGMA encoding"); // there is no database list so $db == DB
}
function engines() {
return array();
}
function logged_user() {
return get_current_user(); // should return effective user
}
@@ -395,7 +386,7 @@ if (isset($_GET["sqlite"])) {
}
try {
$link = new SqliteDb($db);
} catch (Exception $ex) {
} catch (\Exception $ex) {
$connection->error = $ex->getMessage();
return false;
}
@@ -678,7 +669,7 @@ if (isset($_GET["sqlite"])) {
return queries("BEGIN");
}
function last_id() {
function last_id($result) {
return get_val("SELECT LAST_INSERT_ROWID()");
}
@@ -720,8 +711,9 @@ if (isset($_GET["sqlite"])) {
foreach (get_rows("PRAGMA pragma_list") as $row) {
$name = $row["name"];
if ($name != "pragma_list" && $name != "compile_options") {
$return[$name] = array($name, '');
foreach (get_rows("PRAGMA $name") as $row) {
$return[$name] .= implode(", ", $row) . "\n";
$return[$name][1] .= implode(", ", $row) . "\n";
}
}
}
@@ -731,8 +723,7 @@ if (isset($_GET["sqlite"])) {
function show_status() {
$return = array();
foreach (get_vals("PRAGMA compile_options") as $option) {
list($key, $val) = explode("=", $option, 2);
$return[$key] = $val;
$return[] = explode("=", $option, 2);
}
return $return;
}

View File

@@ -4,11 +4,10 @@ namespace Adminer;
$TABLE = $_GET["dump"];
if ($_POST && !$error) {
$cookie = "";
foreach (array("output", "format", "db_style", "types", "routines", "events", "table_style", "auto_increment", "triggers", "data_style") as $key) {
$cookie .= "&$key=" . urlencode($_POST[$key]);
}
cookie("adminer_export", substr($cookie, 1));
save_settings(
array_intersect_key($_POST, array_flip(array("output", "format", "db_style", "types", "routines", "events", "table_style", "auto_increment", "triggers", "data_style"))),
"adminer_export"
);
$tables = array_flip((array) $_POST["tables"]) + array_flip((array) $_POST["data"]);
$ext = dump_headers(
(count($tables) == 1 ? key($tables) : DB),
@@ -140,9 +139,7 @@ SET foreign_key_checks = 0;
}
}
if ($is_sql) {
echo "-- " . gmdate("Y-m-d H:i:s e") . "\n";
}
$adminer->dumpFooter();
exit;
}
@@ -158,7 +155,7 @@ $data_style = array('', 'TRUNCATE+INSERT', 'INSERT');
if (JUSH == "sql") { //! use insertUpdate() in all drivers
$data_style[] = 'INSERT+UPDATE';
}
parse_str($_COOKIE["adminer_export"], $row);
$row = get_settings("adminer_export");
if (!$row) {
$row = array("output" => "text", "format" => "sql", "db_style" => (DB != "" ? "" : "CREATE"), "table_style" => "DROP+CREATE", "data_style" => "INSERT");
}
@@ -167,9 +164,9 @@ if (!isset($row["events"])) { // backwards compatibility
$row["triggers"] = $row["table_style"];
}
echo "<tr><th>" . lang('Output') . "<td>" . html_select("output", $adminer->dumpOutput(), $row["output"], 0) . "\n"; // 0 - radio
echo "<tr><th>" . lang('Output') . "<td>" . html_radios("output", $adminer->dumpOutput(), $row["output"]) . "\n";
echo "<tr><th>" . lang('Format') . "<td>" . html_select("format", $adminer->dumpFormat(), $row["format"], 0) . "\n"; // 0 - radio
echo "<tr><th>" . lang('Format') . "<td>" . html_radios("format", $adminer->dumpFormat(), $row["format"]) . "\n";
echo (JUSH == "sqlite" ? "" : "<tr><th>" . lang('Database') . "<td>" . html_select('db_style', $db_style, $row["db_style"])
. (support("type") ? checkbox("types", 1, $row["types"], lang('User types')) : "")
@@ -186,7 +183,7 @@ echo "<tr><th>" . lang('Data') . "<td>" . html_select('data_style', $data_style,
?>
</table>
<p><input type="submit" value="<?php echo lang('Export'); ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
<table>
<?php

View File

@@ -55,7 +55,7 @@ if ($_POST && !$error && !isset($_GET["select"])) {
}
} else {
$result = $driver->insert($TABLE, $set);
$last_id = ($result ? last_id() : 0);
$last_id = ($result ? last_id($result) : 0);
queries_redirect($location, lang('Item%s has been inserted.', ($last_id ? " $last_id" : "")), $result); //! link
}
}
@@ -68,13 +68,7 @@ if ($_POST["save"]) {
$select = array();
foreach ($fields as $name => $field) {
if (isset($field["privileges"]["select"])) {
$as = convert_field($field);
if ($_POST["clone"] && $field["auto_increment"]) {
$as = "''";
}
if (JUSH == "sql" && preg_match("~enum|set~", $field["type"])) {
$as = "1*" . idf_escape($name);
}
$as = ($_POST["clone"] && $field["auto_increment"] ? "''" : convert_field($field));
$select[] = ($as ? "$as AS " : "") . idf_escape($name);
}
}

View File

@@ -2,8 +2,13 @@
// To create Adminer just for Elasticsearch, run `../compile.php elastic`.
function adminer_object() {
include_once "../plugins/plugin.php";
include_once "../plugins/login-password-less.php";
include_once "../plugins/drivers/elastic.php";
return new Adminer\Adminer;
return new AdminerPlugin(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)),
));
}
include "./index.php";

View File

@@ -56,5 +56,5 @@ if (!$row && $EVENT != "") {
<?php if ($EVENT != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $EVENT)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>

View File

@@ -1,7 +1,15 @@
<?php
namespace Adminer;
// caching headers added in compile.php
if (substr($VERSION, -4) != '-dev') {
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");
}
if ($_GET["file"] == "favicon.ico") {
header("Content-Type: image/x-icon");
@@ -9,6 +17,9 @@ if ($_GET["file"] == "favicon.ico") {
} elseif ($_GET["file"] == "default.css") {
header("Content-Type: text/css; charset=utf-8");
echo lzw_decompress(compile_file('../adminer/static/default.css;../externals/jush/jush.css', 'minify_css'));
} elseif ($_GET["file"] == "dark.css") {
header("Content-Type: text/css; charset=utf-8");
echo lzw_decompress(compile_file('../adminer/static/dark.css;../externals/jush/jush-dark.css', 'minify_css'));
} elseif ($_GET["file"] == "functions.js") {
header("Content-Type: text/javascript; charset=utf-8");
echo lzw_decompress(compile_file('../adminer/static/functions.js;static/editing.js', 'minify_js'));

View File

@@ -85,8 +85,8 @@ if (support("scheme")) {
}
echo lang('DB') . ": " . html_select("db", $dbs, $row["db"] != "" ? $row["db"] : $_GET["db"], $onchange);
}
echo input_hidden("change-js");
?>
<input type="hidden" name="change-js" value="">
<noscript><p><input type="submit" name="change" value="<?php echo lang('Change'); ?>"></noscript>
<table>
<thead><tr><th id="label-source"><?php echo lang('Source'); ?><th id="label-target"><?php echo lang('Target'); ?></thead>
@@ -94,8 +94,8 @@ if (support("scheme")) {
$j = 0;
foreach ($row["source"] as $key => $val) {
echo "<tr>";
echo "<td>" . html_select("source[" . (+$key) . "]", array(-1 => "") + $source, $val, ($j == count($row["source"]) - 1 ? "foreignAddRow.call(this);" : 1), "label-source");
echo "<td>" . html_select("target[" . (+$key) . "]", $target, $row["target"][$key], 1, "label-target");
echo "<td>" . html_select("source[" . (+$key) . "]", array(-1 => "") + $source, $val, ($j == count($row["source"]) - 1 ? "foreignAddRow.call(this);" : ""), "label-source");
echo "<td>" . html_select("target[" . (+$key) . "]", $target, $row["target"][$key], "", "label-target");
$j++;
}
?>
@@ -116,5 +116,5 @@ foreach ($row["source"] as $key => $val) {
<?php if ($name != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>

View File

@@ -4,8 +4,8 @@ namespace Adminer;
// any method change in this file should be transferred to editor/include/adminer.inc.php and plugins/plugin.php
class Adminer {
/** @var array operators used in select, null for all operators */
var $operators;
public $operators; ///< @var array operators used in select, null for all operators
public $error = ''; ///< @var protected(set) string HTML
/** Name in title and navigation
* @return string HTML code
@@ -94,12 +94,13 @@ class Adminer {
}
/** Print HTML code inside <head>
* @return bool true to link favicon.ico and adminer.css if exists
* @param bool dark CSS: false to disable, true to force, null to base on user preferences
* @return bool true to link favicon.ico
*/
function head() {
?>
<link rel="stylesheet" type="text/css" href="../externals/jush/jush.css">
<?php
function head($dark = null) {
// this is matched by compile.php
echo "<link rel='stylesheet' href='../externals/jush/jush.css'>\n";
echo ($dark !== false ? "<link rel='stylesheet'" . ($dark ? "" : " media='(prefers-color-scheme: dark)'") . " href='../externals/jush/jush-dark.css'>\n" : "");
return true;
}
@@ -108,9 +109,11 @@ class Adminer {
*/
function css() {
$return = array();
$filename = "adminer.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
foreach (array("", "-dark") as $mode) {
$filename = "adminer$mode.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
}
}
return $return;
}
@@ -121,8 +124,10 @@ class Adminer {
function loginForm() {
global $drivers;
echo "<table class='layout'>\n";
// this is matched by compile.php
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);"));
echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">');
// this is matched by compile.php
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" autofocus value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("qs('#username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">');
echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">');
@@ -167,7 +172,9 @@ class Adminer {
* @return string HTML code, "" to ignore field
*/
function fieldName($field, $order = 0) {
return '<span title="' . h($field["full_type"]) . '">' . h($field["field"]) . '</span>';
$type = $field["full_type"];
$comment = $field["comment"];
return '<span title="' . h($type . ($comment != "" ? ($type ? ": " : "") . $comment : '')) . '">' . h($field["field"]) . '</span>';
}
/** Print links after select heading
@@ -256,6 +263,11 @@ class Adminer {
return shorten_utf8(trim($query), 1000);
}
/** Print HTML code just before the Execute button in SQL command
*/
function sqlPrintAfter() {
}
/** Description of a row in a table
* @param string
* @return string SQL expression, empty string for no description
@@ -289,13 +301,14 @@ class Adminer {
* @return string
*/
function selectVal($val, $link, $field, $original) {
$return = ($val === null ? "<i>NULL</i>" : (preg_match("~char|binary|boolean~", $field["type"]) && !preg_match("~var~", $field["type"]) ? "<code>$val</code>" : $val));
$return = ($val === null ? "<i>NULL</i>"
: (preg_match("~char|binary|boolean~", $field["type"]) && !preg_match("~var~", $field["type"]) ? "<code>$val</code>"
: (preg_match('~json~', $field["type"]) ? "<code class='jush-js'>$val</code>"
: $val)
));
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && !is_utf8($val)) {
$return = "<i>" . lang('%d byte(s)', strlen($original)) . "</i>";
}
if (preg_match('~json~', $field["type"])) {
$return = "<code class='jush-js'>$return</code>";
}
return ($link ? "<a href='" . h($link) . "'" . (is_url($link) ? target_blank() : "") . ">$return</a>" : $return);
}
@@ -310,9 +323,10 @@ class Adminer {
/** Print table structure in tabular format
* @param array data about individual fields
* @param array
* @return null
*/
function tableStructurePrint($fields) {
function tableStructurePrint($fields, $tableStatus = null) {
global $driver;
echo "<div class='scrollable'>\n";
echo "<table class='nowrap odds'>\n";
@@ -321,8 +335,11 @@ class Adminer {
foreach ($fields as $field) {
echo "<tr><th>" . h($field["field"]);
$type = h($field["full_type"]);
echo "<td><span title='" . h($field["collation"]) . "'>"
. (in_array($type, (array) $structured_types[lang('User types')]) ? "<a href='" . h(ME . 'type=' . urlencode($type)) . "'>$type</a>" : $type)
$collation = h($field["collation"]);
echo "<td><span title='$collation'>"
. (in_array($type, (array) $structured_types[lang('User types')])
? "<a href='" . h(ME . 'type=' . urlencode($type)) . "'>$type</a>"
: $type . ($collation && isset($tableStatus["Collation"]) && $collation != $tableStatus["Collation"] ? " $collation" : ""))
. "</span>"
;
echo ($field["null"] ? " <i>NULL</i>" : "");
@@ -375,7 +392,7 @@ class Adminer {
($key !== "" ? "selectFieldChange" : "selectAddRow")
);
echo "<div>" . ($driver->functions || $driver->grouping ? html_select("columns[$i][fun]", array(-1 => "") + array_filter(array(lang('Functions') => $driver->functions, lang('Aggregation') => $driver->grouping)), $val["fun"])
. on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1)
. on_help("event.target.value && event.target.value.replace(/ |\$/, '(') + ')'", 1)
. script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "")
. "($column)" : $column) . "</div>\n";
$i++;
@@ -472,7 +489,7 @@ class Adminer {
echo "<input type='submit' value='" . lang('Select') . "'>";
echo " <span id='noindex' title='" . lang('Full table scan') . "'></span>";
echo "<script" . nonce() . ">\n";
echo "var indexColumns = ";
echo "const indexColumns = ";
$columns = array();
foreach ($indexes as $index) {
$current_key = reset($index["columns"]);
@@ -761,7 +778,7 @@ class Adminer {
return unconvert_field($field, $return);
}
/** Returns export output options
/** Return export output options
* @return array
*/
function dumpOutput() {
@@ -772,7 +789,7 @@ class Adminer {
return $return;
}
/** Returns export format options
/** Return export format options
* @return array empty to disable export
*/
function dumpFormat() {
@@ -937,11 +954,23 @@ class Adminer {
($ext == "sql" || $output != "file" ? "text/plain" : "text/csv") . "; charset=utf-8"
)));
if ($output == "gz") {
ob_start('ob_gzencode', 1e6);
ob_start(function ($string) {
// ob_start() callback receives an optional parameter $phase but gzencode() accepts optional parameter $level
return gzencode($string);
}, 1e6);
}
return $ext;
}
/** Print text after export
* @return null prints data
*/
function dumpFooter() {
if ($_POST["format"] == "sql") {
echo "-- " . gmdate("Y-m-d H:i:s e") . "\n";
}
}
/** Set the path of the file for webserver load
* @return string path of the sql dump file
*/
@@ -960,31 +989,28 @@ class Adminer {
return true;
}
/** Prints navigation after Adminer title
/** Print navigation after Adminer title
* @param string can be "auth" if there is no database connection, "db" if there is no database selected, "ns" with invalid schema
* @return null
*/
function navigation($missing) {
global $VERSION, $drivers, $connection;
?>
<h1>
<?php echo $this->name(); ?>
<span class="version">
<?php echo $VERSION; ?>
<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>
</span>
</h1>
<?php
echo "<h1>" . $this->name() . " <span class='version'>$VERSION";
$new_version = $_COOKIE["adminer_version"];
echo " <a href='https://www.adminer.org/#download'" . target_blank() . " id='version'>" . (version_compare($VERSION, $new_version) < 0 ? h($new_version) : "") . "</a>";
echo "</span></h1>\n";
// this is matched by compile.php
switch_lang();
if ($missing == "auth") {
$output = "";
foreach ((array) $_SESSION["pwds"] as $vendor => $servers) {
foreach ($servers as $server => $usernames) {
$name = h(get_setting("vendor-$vendor-$server") ?: $drivers[$vendor]);
foreach ($usernames as $username => $password) {
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)) . "'>($name) " . h($username . ($server != "" ? "@" . $this->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "</a>\n";
}
}
}
@@ -999,31 +1025,7 @@ class Adminer {
$connection->select_db(DB);
$tables = table_status('', true);
}
echo script_src("../externals/jush/modules/jush.js");
echo script_src("../externals/jush/modules/jush-textarea.js");
echo script_src("../externals/jush/modules/jush-txt.js");
echo script_src("../externals/jush/modules/jush-js.js");
if (support("sql")) {
echo script_src("../externals/jush/modules/jush-" . JUSH . ".js");
?>
<script<?php echo nonce(); ?>>
<?php
if ($tables) {
$links = array();
foreach ($tables as $table => $type) {
$links[] = preg_quote($table, '/');
}
echo "var jushLinks = { " . JUSH . ": [ '" . js_escape(ME) . (support("table") ? "table=" : "select=") . "\$&', /\\b(" . implode("|", $links) . ")\\b/g ] };\n";
foreach (array("bac", "bra", "sqlite_quo", "mssql_bra") as $val) {
echo "jushLinks.$val = jushLinks." . JUSH . ";\n";
}
}
$server_info = $connection->server_info;
?>
bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $server_info) : ""); ?>'<?php echo (preg_match('~MariaDB~', $server_info) ? ", true" : ""); ?>);
</script>
<?php
}
$this->syntaxHighlighting($tables);
$this->databasesPrint($missing);
$actions = array();
if (DB == "" || !$missing) {
@@ -1048,7 +1050,37 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
}
}
/** Prints databases list in menu
/** Set up syntax highlight for code and <textarea>
* @param array result of table_status()
*/
function syntaxHighlighting($tables) {
global $connection;
// this is matched by compile.php
echo script_src("../externals/jush/modules/jush.js");
echo script_src("../externals/jush/modules/jush-textarea.js");
echo script_src("../externals/jush/modules/jush-txt.js");
echo script_src("../externals/jush/modules/jush-js.js");
if (support("sql")) {
echo script_src("../externals/jush/modules/jush-" . JUSH . ".js");
echo "<script" . nonce() . ">\n";
if ($tables) {
$links = array();
foreach ($tables as $table => $type) {
$links[] = preg_quote($table, '/');
}
echo "var jushLinks = { " . JUSH . ": [ '" . js_escape(ME) . (support("table") ? "table=" : "select=") . "\$&', /\\b(" . implode("|", $links) . ")\\b/g ] };\n";
foreach (array("bac", "bra", "sqlite_quo", "mssql_bra") as $val) {
echo "jushLinks.$val = jushLinks." . JUSH . ";\n";
}
}
echo "</script>\n";
}
echo script("syntaxHighlighting('" . (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $connection->server_info) : "") . "'"
. ($connection->flavor == 'maria' ? ", 'maria'" : ($connection->flavor == 'cockroach' ? ", 'cockroach'" : "")) . ");"
);
}
/** Print databases list in menu
* @param string
* @return null
*/
@@ -1058,20 +1090,17 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
if (DB && $databases && !in_array(DB, $databases)) {
array_unshift($databases, DB);
}
?>
<form action="">
<p id="dbs">
<?php
echo "<form action=''>\n<p id='dbs'>\n";
hidden_fields_get();
$db_events = script("mixin(qsl('select'), {onmousedown: dbMouseDown, onchange: dbChange});");
echo "<span title='" . lang('Database') . "'>" . lang('DB') . "</span>: " . ($databases
echo "<span title='" . lang('Database') . "'>" . lang('DB') . ":</span> " . ($databases
? html_select("db", array("" => "") + $databases, DB) . $db_events
: "<input name='db' value='" . h(DB) . "' autocapitalize='off' size='19'>\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') . ": " . html_select("ns", array("" => "") + $adminer->schemas(), $_GET["ns"]) . $db_events;
echo "<br><span>" . lang('Schema') . ":</span> " . html_select("ns", array("" => "") + $adminer->schemas(), $_GET["ns"]) . $db_events;
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
}
@@ -1079,14 +1108,14 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
}
foreach (array("import", "sql", "schema", "dump", "privileges") as $val) {
if (isset($_GET[$val])) {
echo "<input type='hidden' name='$val' value=''>";
echo input_hidden($val);
break;
}
}
echo "</p></form>\n";
}
/** Prints table list in menu
/** Print table list in menu
* @param array result of table_status('', true)
* @return null
*/

View File

@@ -19,7 +19,17 @@ if ($_COOKIE["adminer_permanent"]) {
function add_invalid_login() {
global $adminer;
$fp = file_open_lock(get_temp_dir() . "/adminer.invalid");
$base = get_temp_dir() . "/adminer.invalid";
// adminer.invalid may not be writable by us, try the files with random suffixes
foreach (glob("$base*") ?: array($base) as $filename) {
$fp = file_open_lock($filename);
if ($fp) {
break;
}
}
if (!$fp) {
$fp = file_open_lock("$base-" . rand_string());
}
if (!$fp) {
return;
}
@@ -42,7 +52,15 @@ function add_invalid_login() {
function check_invalid_login() {
global $adminer;
$invalids = unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
$invalids = array();
foreach (glob(get_temp_dir() . "/adminer.invalid*") as $filename) {
$fp = file_open_lock($filename);
if ($fp) {
$invalids = unserialize(stream_get_contents($fp));
file_unlock($fp);
break;
}
}
$invalid = ($invalids ? $invalids[$adminer->bruteForceKey()] : array());
$next_attempt = ($invalid[1] > 29 ? $invalid[0] - time() : 0); // allow 30 invalid attempts
if ($next_attempt > 0) { //! do the same with permanent login
@@ -61,7 +79,7 @@ if ($auth) {
set_password($vendor, $server, $username, $password);
$_SESSION["db"][$vendor][$server][$username][$db] = true;
if ($auth["permanent"]) {
$key = base64_encode($vendor) . "-" . base64_encode($server) . "-" . base64_encode($username) . "-" . base64_encode($db);
$key = implode("-", array_map('base64_encode', array($vendor, $server, $username, $db)));
$private = $adminer->permanentLogin(true);
$permanent[$key] = "$key:" . base64_encode($private ? encrypt_string($password, $private) : "");
cookie("adminer_permanent", implode(" ", $permanent));
@@ -105,7 +123,7 @@ function unset_permanent() {
cookie("adminer_permanent", implode(" ", $permanent));
}
/** Renders an error message and a login form
/** Render an error message and a login form
* @param string plain text
* @return null exits
*/
@@ -169,6 +187,9 @@ if (isset($_GET["username"]) && is_string(get_password())) {
if ($adminer->operators === null) {
$adminer->operators = $driver->operators;
}
if (Driver::$jush == 'sql' || $connection->flavor == 'cockroach') {
save_settings(array("vendor-" . DRIVER . "-" . SERVER => $drivers[DRIVER]));
}
}
}

View File

@@ -3,6 +3,7 @@ namespace Adminer;
include "../adminer/include/version.inc.php";
include "../adminer/include/errors.inc.php";
// this is matched by compile.php
include "../adminer/include/coverage.inc.php";
// disable filter.default
@@ -21,6 +22,7 @@ if (function_exists("mb_internal_encoding")) {
}
include "../adminer/include/functions.inc.php";
include "../adminer/include/html.inc.php";
// used only in compiled file
if (isset($_GET["file"])) {
@@ -28,7 +30,9 @@ if (isset($_GET["file"])) {
}
if ($_GET["script"] == "version") {
$fp = file_open_lock(get_temp_dir() . "/adminer.version");
$filename = get_temp_dir() . "/adminer.version";
@unlink($filename); // it may not be writable by us, @ - it may not exist
$fp = file_open_lock($filename);
if ($fp) {
file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
}
@@ -62,7 +66,6 @@ if (function_exists("get_magic_quotes_runtime") && get_magic_quotes_runtime()) {
set_magic_quotes_runtime(false);
}
@set_time_limit(0); // @ - can be disabled
@ini_set("zend.ze1_compatibility_mode", false); // @ - deprecated
@ini_set("precision", 15); // @ - can be disabled, 15 - internal PHP precision
include "../adminer/include/lang.inc.php";
@@ -73,9 +76,18 @@ include "../adminer/drivers/sqlite.inc.php";
include "../adminer/drivers/pgsql.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/include/plugins.inc.php";
if (function_exists('adminer_object')) {
$adminer = adminer_object();
} elseif (is_dir("adminer-plugins") || file_exists("adminer-plugins.php")) {
$adminer = new Plugins(null);
} else {
$adminer = new Adminer;
}
// this is matched by compile.php
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
define('Adminer\JUSH', Driver::$jush);
@@ -86,6 +98,7 @@ define(
preg_replace('~\?.*~', '', relative_uri()) . '?'
. (sid() ? SID . '&' : '')
. (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '')
. ($_GET["ext"] ? "ext=" . urlencode($_GET["ext"]) . '&' : '')
. (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
. (DB != "" ? 'db=' . urlencode(DB) . '&' . (isset($_GET["ns"]) ? "ns=" . urlencode($_GET["ns"]) . "&" : "") : '')
);

View File

@@ -8,7 +8,13 @@ if (isset($_GET["import"])) {
$_GET["sql"] = $_GET["import"];
}
if (!(DB != "" ? $connection->select_db(DB) : isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]) || isset($_GET["variables"]) || $_GET["script"] == "connect" || $_GET["script"] == "kill")) {
if (
!(DB != ""
? $connection->select_db(DB)
: isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]) || isset($_GET["variables"])
|| $_GET["script"] == "connect" || $_GET["script"] == "kill"
)
) {
if (DB != "" || $_GET["refresh"]) {
restart_session();
set_session("dbs", null);
@@ -38,6 +44,14 @@ if (!(DB != "" ? $connection->select_db(DB) : isset($_GET["sql"]) || isset($_GET
}
echo "<p>" . lang('%s version: %s through PHP extension %s', $drivers[DRIVER], "<b>" . h($connection->server_info) . "</b>", "<b>$connection->extension</b>") . "\n";
echo "<p>" . lang('Logged as: %s', "<b>" . h(logged_user()) . "</b>") . "\n";
if (isset($adminer->plugins) && is_array($adminer->plugins)) {
echo "<p>" . lang('Loaded plugins') . ":\n<ul>\n";
foreach ($adminer->plugins as $plugin) {
$reflection = new \ReflectionObject($plugin);
echo "<li><b>" . get_class($plugin) . "</b>" . h(preg_match('~^/[\s*]+(.+)~', $reflection->getDocComment(), $match) ? ": $match[1]" : "") . "\n";
}
echo "</ul>\n";
}
$databases = $adminer->databases();
if ($databases) {
$scheme = support("scheme");
@@ -72,13 +86,13 @@ if (!(DB != "" ? $connection->select_db(DB) : isset($_GET["sql"]) || isset($_GET
echo (support("database")
? "<div class='footer'><div>\n"
. "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>\n"
. "<input type='hidden' name='all' value=''>" . script("qsl('input').onclick = function () { selectCount('selected', formChecked(this, /^db/)); };") // used by trCheck()
. input_hidden("all") . script("qsl('input').onclick = function () { selectCount('selected', formChecked(this, /^db/)); };") // used by trCheck()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm() . "\n"
. "</div></fieldset>\n"
. "</div></div>\n"
: ""
);
echo "<input type='hidden' name='token' value='$token'>\n";
echo input_token();
echo "</form>\n";
echo script("tableCheck();");
}

View File

@@ -2,9 +2,9 @@
namespace Adminer;
// coverage is used in tests and removed in compilation
if (extension_loaded("xdebug") && file_exists(sys_get_temp_dir() . "/adminer_coverage.ser")) {
if (extension_loaded("xdebug") && file_exists(sys_get_temp_dir() . "/adminer.coverage")) {
function save_coverage() {
$coverage_filename = sys_get_temp_dir() . "/adminer_coverage.ser";
$coverage_filename = sys_get_temp_dir() . "/adminer.coverage";
$coverage = unserialize(file_get_contents($coverage_filename));
foreach (xdebug_get_code_coverage() as $filename => $lines) {
foreach ($lines as $l => $val) {

View File

@@ -1,10 +1,6 @@
<?php
namespace Adminer;
if (!ob_get_level()) {
ob_start(null, 4096);
}
/** Print HTML header
* @param string used in title, breadcrumb and heading, should be HTML escaped
* @param string
@@ -19,28 +15,52 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
page_messages($error);
exit;
}
if (!ob_get_level()) {
ob_start(null, 4096);
}
$title_all = $title . ($title2 != "" ? ": $title2" : "");
$title_page = strip_tags($title_all . (SERVER != "" && SERVER != "localhost" ? h(" - " . SERVER) : "") . " - " . $adminer->name());
// initial-scale=1 is the default but Chrome 134 on iOS is not able to zoom out without it
?>
<!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">
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="width=device-width,initial-scale=1">
<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"); ?>
<?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">
<?php foreach ($adminer->css() as $css) { ?>
<link rel="stylesheet" type="text/css" href="<?php echo h($css); ?>">
<?php } ?>
<?php } ?>
<body class="<?php echo lang('ltr'); ?> nojs">
<link rel="stylesheet" href="../adminer/static/default.css">
<?php
$css = $adminer->css();
$has_light = false;
$has_dark = false;
foreach ($css as $filename) {
if (strpos($filename, "adminer.css") !== false) {
$has_light = true;
}
if (strpos($filename, "adminer-dark.css") !== false) {
$has_dark = true;
}
}
$dark = ($has_light
? ($has_dark ? null : false) // both styles - autoswitching, only adminer.css - light
: ($has_dark ?: null) // only adminer-dark.css - dark, neither - autoswitching
);
$media = " media='(prefers-color-scheme: dark)'";
if ($dark !== false) {
echo "<link rel='stylesheet'" . ($dark ? "" : $media) . " href='../adminer/static/dark.css'>\n";
}
echo "<meta name='color-scheme' content='" . ($dark === null ? "light dark" : ($dark ? "dark" : "light")) . "'>\n";
// this is matched by compile.php
echo script_src("../adminer/static/functions.js");
echo script_src("static/editing.js");
if ($adminer->head($dark)) {
echo "<link rel='shortcut icon' type='image/x-icon' href='../adminer/static/favicon.ico'>\n";
echo "<link rel='apple-touch-icon' href='../adminer/static/favicon.ico'>\n";
}
foreach ($css as $val) {
echo "<link rel='stylesheet'" . (preg_match('~-dark~', $val) && !$dark ? $media : "") . " href='" . h($val) . "'>\n";
}
echo "\n<body class='" . lang('ltr') . " nojs'>\n";
$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));
@@ -58,21 +78,16 @@ fQIDAQAB
$_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(',')); ?>';
</script>
<div id="help" class="jush-<?php echo JUSH; ?> jsonly hidden"></div>
<?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?>
<div id="content">
<?php
echo script("mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick"
. (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '$VERSION', '" . js_escape(ME) . "', '" . get_token() . "')") // $token may be empty in auth.inc.php
. "});
document.body.classList.replace('nojs', 'js');
const offlineMessage = '" . js_escape(lang('You are offline.')) . "';
const thousandsSeparator = '" . js_escape(lang(',')) . "';")
;
echo "<div id='help' class='jush-" . JUSH . " jsonly hidden'></div>\n";
echo script("mixin(qs('#help'), {onmouseover: () => { helpOpen = 1; }, onmouseout: helpMouseout});");
echo "<div id='content'>\n";
if ($breadcrumb !== null) {
$link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1);
echo '<p id="breadcrumb"><a href="' . h($link ?: ".") . '">' . $drivers[DRIVER] . '</a> » ';
@@ -165,6 +180,7 @@ function get_nonce() {
* @return null
*/
function page_messages($error) {
global $adminer;
$uri = preg_replace('~^[^?]*~', '', $_SERVER["REQUEST_URI"]);
$messages = $_SESSION["messages"][$uri];
if ($messages) {
@@ -174,6 +190,9 @@ function page_messages($error) {
if ($error) {
echo "<div class='error'>$error</div>\n";
}
if ($adminer->error) { // separate <div>
echo "<div class='error'>$adminer->error</div>\n";
}
}
/** Print HTML footer
@@ -181,23 +200,20 @@ function page_messages($error) {
* @return null
*/
function page_footer($missing = "") {
global $adminer, $token;
?>
</div>
<div id="menu">
<?php $adminer->navigation($missing); ?>
</div>
<?php if ($missing != "auth") { ?>
global $adminer;
echo "</div>\n\n<div id='menu'>\n";
$adminer->navigation($missing);
echo "</div>\n\n";
if ($missing != "auth") {
?>
<form action="" method="post">
<p class="logout">
<span><?php echo h($_GET["username"]) . "\n"; ?></span>
<input type="submit" name="logout" value="<?php echo lang('Logout'); ?>" id="logout">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</p>
</form>
<?php } ?>
<?php
}
echo script("setupSubmitHighlight(document);");
}

View File

@@ -26,23 +26,23 @@ abstract class SqlDriver {
static $possibleDrivers = array();
static $jush; ///< @var string JUSH identifier
var $_conn;
protected $conn;
protected $types = array(); ///< @var array [$description => [$type => $maximum_unsigned_length, ...], ...]
var $editFunctions = array(); ///< @var array of ["$type|$type2" => "$function/$function2"] functions used in editing, [0] - edit and insert, [1] - edit only
var $unsigned = array(); ///< @var array number variants
var $operators = array(); ///< @var array operators used in select
var $functions = array(); ///< @var array functions used in select
var $grouping = array(); ///< @var array grouping functions used in select
var $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()
var $inout = "IN|OUT|INOUT";
var $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'";
var $generated = array();
public $editFunctions = array(); ///< @var array of ["$type|$type2" => "$function/$function2"] functions used in editing, [0] - edit and insert, [1] - edit only
public $unsigned = array(); ///< @var array number variants
public $operators = array(); ///< @var array operators used in select
public $functions = array(); ///< @var array functions used in select
public $grouping = array(); ///< @var array grouping functions used in select
public $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()
public $inout = "IN|OUT|INOUT"; ///< @var string used in routines
public $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'"; ///< @var string regular expression for parsing enum lengths
public $generated = array(); ///< @var array allowed types of generated columns
/** Create object for performing database operations
* @param Db
*/
function __construct($connection) {
$this->_conn = $connection;
$this->conn = $connection;
}
/** Get all types
@@ -66,6 +66,13 @@ abstract class SqlDriver {
function enumLength($field) {
}
/** Function used to convert the value inputted by user
* @param array
* @return string or null
*/
function unconvertFunction($field) {
}
/** Select data from table
* @param string
* @param array result of $adminer->selectColumnsProcess()[0]
@@ -91,7 +98,7 @@ abstract class SqlDriver {
);
}
$start = microtime(true);
$return = $this->_conn->query($query);
$return = $this->conn->query($query);
if ($print) {
echo $adminer->selectQuery($query, $start, !$return);
}
@@ -135,7 +142,15 @@ abstract class SqlDriver {
return queries("INSERT INTO " . table($table) . ($set
? " (" . implode(", ", array_keys($set)) . ")\nVALUES (" . implode(", ", $set) . ")"
: " DEFAULT VALUES"
));
) . $this->insertReturning($table));
}
/** Get RETURNING clause for INSERT queries, PostgreSQL specific
* @param string
* @return string
*/
function insertReturning($table) {
return "";
}
/** Insert or update data in table
@@ -201,8 +216,8 @@ abstract class SqlDriver {
* @return string
*/
function value($val, $field) {
return (method_exists($this->_conn, 'value')
? $this->_conn->value($val, $field)
return (method_exists($this->conn, 'value')
? $this->conn->value($val, $field)
: (is_resource($val) ? stream_get_contents($val) : $val)
);
}
@@ -237,6 +252,13 @@ abstract class SqlDriver {
return false;
}
/** Get supported engines
* @return array
*/
function engines() {
return array();
}
/** Check whether table supports indexes
* @param array result of table_status()
* @return bool

View File

@@ -25,12 +25,14 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
for ($j=0; $j < count($row); $j++) {
$field = $result->fetch_field();
$name = $field->name;
$orgtable = $field->orgtable;
$orgname = $field->orgname;
$return[$field->table] = $orgtable;
$orgtable = (isset($field->orgtable) ? $field->orgtable : "");
$orgname = (isset($field->orgname) ? $field->orgname : $name);
if ($orgtables && JUSH == "sql") { // MySQL EXPLAIN
$links[$j] = ($name == "table" ? "table=" : ($name == "possible_keys" ? "indexes=" : null));
} elseif ($orgtable != "") {
if (isset($field->table)) {
$return[$field->table] = $orgtable;
}
if (!isset($indexes[$orgtable])) {
// find primary key in each table
$indexes[$orgtable] = array();
@@ -90,7 +92,8 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
if ($link) {
$val = "<a href='" . h($link) . "'" . (is_url($link) ? target_blank() : '') . ">$val</a>";
}
echo "<td>$val";
// https://dev.mysql.com/doc/dev/mysql-server/latest/field__types_8h.html
echo "<td" . ($types[$key] <= 9 || $types[$key] == 246 ? " class='number'" : "") . ">$val";
}
}
echo ($i ? "</table>\n</div>" : "<p class='message'>" . lang('No rows.')) . "\n";
@@ -119,31 +122,6 @@ function referencable_primary($self) {
return $return;
}
/** Get settings stored in a cookie
* @return array
*/
function adminer_settings() {
parse_str($_COOKIE["adminer_settings"], $settings);
return $settings;
}
/** Get setting stored in a cookie
* @param string
* @return array
*/
function adminer_setting($key) {
$settings = adminer_settings();
return $settings[$key];
}
/** Store settings to a cookie
* @param array
* @return bool
*/
function set_adminer_settings($settings) {
return cookie("adminer_settings", http_build_query($settings + adminer_settings()));
}
/** Print SQL <textarea> tag
* @param string
* @param string or array in which case [0] of every element is used
@@ -209,7 +187,7 @@ function json_row($key, $val = null) {
function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_types = array()) {
global $driver;
$type = $field["type"];
?><td><select name="<?php echo h($key); ?>[type]" class="type" aria-labelledby="label-type"><?php
echo "<td><select name='" . h($key) . "[type]' class='type' aria-labelledby='label-type'>";
if ($type && !array_key_exists($type, $driver->types()) && !isset($foreign_keys[$type]) && !in_array($type, $extra_types)) {
$extra_types[] = $type;
}
@@ -218,19 +196,24 @@ function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_ty
$structured_types[lang('Foreign keys')] = $foreign_keys;
}
echo optionlist(array_merge($extra_types, $structured_types), $type);
?></select><td><input
name="<?php echo h($key); ?>[length]"
value="<?php echo h($field["length"]); ?>"
size="3"
<?php echo (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : ""); //! type="number" with enabled JavaScript ?>
aria-labelledby="label-length"><td class="options"><?php
echo ($collations ? "<select name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . '><option value="">(' . lang('collation') . ')' . optionlist($collations, $field["collation"]) . '</select>' : '');
echo "</select><td>";
echo "<input name='" . h($key) . "[length]' value='" . h($field["length"]) . "' size='3'"
. (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : "") //! type="number" with enabled JavaScript
. " aria-labelledby='label-length'>";
echo "<td class='options'>";
echo ($collations
? "<input list='collations' name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . " value='" . h($field["collation"]) . "' placeholder='(" . lang('collation') . ")'>"
: ''
);
echo ($driver->unsigned ? "<select name='" . h($key) . "[unsigned]'" . (!$type || preg_match(number_type(), $type) ? "" : " class='hidden'") . '><option>' . optionlist($driver->unsigned, $field["unsigned"]) . '</select>' : '');
echo (isset($field['on_update']) ? "<select name='" . h($key) . "[on_update]'" . (preg_match('~timestamp|datetime~', $type) ? "" : " class='hidden'") . '>'
. optionlist(array("" => "(" . lang('ON UPDATE') . ")", "CURRENT_TIMESTAMP"), (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? "CURRENT_TIMESTAMP" : $field["on_update"]))
. '</select>' : ''
);
echo ($foreign_keys ? "<select name='" . h($key) . "[on_delete]'" . (preg_match("~`~", $type) ? "" : " class='hidden'") . "><option value=''>(" . lang('ON DELETE') . ")" . optionlist(explode("|", $driver->onActions), $field["on_delete"]) . "</select> " : " "); // space for IE
echo ($foreign_keys
? "<select name='" . h($key) . "[on_delete]'" . (preg_match("~`~", $type) ? "" : " class='hidden'") . "><option value=''>(" . lang('ON DELETE') . ")" . optionlist(explode("|", $driver->onActions), $field["on_delete"]) . "</select> "
: " " // space for IE
);
}
/** Get partition info
@@ -307,8 +290,8 @@ function default_value($field) {
$generated = $field["generated"];
return ($default === null ? "" : (in_array($generated, $driver->generated)
? (JUSH == "mssql" ? " AS ($default)" . ($generated == "VIRTUAL" ? "" : " $generated") . "" : " GENERATED ALWAYS AS ($default) $generated")
: " DEFAULT " . (!preg_match('~^GENERATED ~i', $default) && (preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default))
? q($default)
: " DEFAULT " . (!preg_match('~^GENERATED ~i', $default) && (preg_match('~char|binary|text|json|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default))
? (JUSH == "sql" && preg_match('~text|json~', $field["type"]) ? "(" . q($default) . ")" : q($default)) // MySQL requires () around default value of text column
: str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", (JUSH == "sqlite" ? "($default)" : $default))
)
));
@@ -343,54 +326,49 @@ function type_class($type) {
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
global $driver;
$fields = array_values($fields);
$default_class = (($_POST ? $_POST["defaults"] : adminer_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : " class='hidden'");
?>
<thead><tr>
<?php echo ($type == "PROCEDURE" ? "<td>" : ""); ?>
<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' => "t-sql/statements/create-table-transact-sql-identity-property",
)); ?>
<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
$default_class = (($_POST ? $_POST["defaults"] : get_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : get_setting("comments")) ? "" : " class='hidden'");
echo "<thead><tr>\n";
echo ($type == "PROCEDURE" ? "<td>" : "");
echo "<th id='label-name'>" . ($type == "TABLE" ? lang('Column name') : lang('Parameter name'));
echo "<td id='label-type'>" . lang('Type') . "<textarea id='enum-edit' rows='4' cols='12' wrap='off' style='display: none;'></textarea>" . script("qs('#enum-edit').onblur = editingLengthBlur;");
echo "<td id='label-length'>" . lang('Length');
echo "<td>" . lang('Options'); // no label required, options have their own label
if ($type == "TABLE") {
echo "<td id='label-null'>NULL\n";
echo "<td><input type='radio' name='auto_increment_col' value=''><abbr id='label-ai' title='" . lang('Auto Increment') . "'>AI</abbr>";
echo doc_link(array(
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "t-sql/statements/create-table-transact-sql-identity-property",
));
echo "<td id='label-default'$default_class>" . lang('Default value');
echo (support("comment") ? "<td id='label-comment'$comment_class>" . lang('Comment') : "");
}
echo "<td><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) . ";");
echo "</thead>\n<tbody>\n";
echo script("mixin(qsl('tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput});");
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("|", $driver->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
echo "<tr" . ($display ? "" : " style='display: none;'") . ">\n";
echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $driver->inout), $field["inout"]) : "") . "<th>";
if ($display) {
echo "<input name='fields[$i][field]' value='" . h($field["field"]) . "' data-maxlength='64' autocapitalize='off' aria-labelledby='label-name'>";
}
echo input_hidden("fields[$i][orig]", $orig);
edit_type("fields[$i]", $field, $collations, $foreign_keys);
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 echo ($field["auto_increment"] ? " checked" : ""); ?> aria-labelledby="label-ai"></label><td<?php echo $default_class; ?>><?php
echo ($driver->generated
echo "<td>" . checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null");
echo "<td><label class='block'><input type='radio' name='auto_increment_col' value='$i'" . ($field["auto_increment"] ? " checked" : "") . " aria-labelledby='label-ai'></label>";
echo "<td$default_class>" . ($driver->generated
? html_select("fields[$i][generated]", array_merge(array("", "DEFAULT"), $driver->generated), $field["generated"]) . " "
: checkbox("fields[$i][generated]", 1, $field["generated"], "", "", "", "label-default")
);
?>
<input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" aria-labelledby="label-default"><?php
echo "<input name='fields[$i][default]' value='" . h($field["default"]) . "' aria-labelledby='label-default'>";
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'>" : "");
}
echo "<td>";
@@ -620,26 +598,17 @@ function doc_link($paths, $text = "<sup>?</sup>") {
$urls = array(
'sql' => "https://dev.mysql.com/doc/refman/$version/en/",
'sqlite' => "https://www.sqlite.org/",
'pgsql' => "https://www.postgresql.org/docs/$version/",
'pgsql' => "https://www.postgresql.org/docs/" . ($connection->flavor == 'cockroach' ? "current" : $version) . "/",
'mssql' => "https://learn.microsoft.com/en-us/sql/",
'oracle' => "https://www.oracle.com/pls/topic/lookup?ctx=db" . preg_replace('~^.* (\d+)\.(\d+)\.\d+\.\d+\.\d+.*~s', '\1\2', $server_info) . "&id=",
);
if (preg_match('~MariaDB~', $server_info)) {
if ($connection->flavor == 'maria') {
$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] . (JUSH == 'mssql' ? "?view=sql-server-ver$version" : "")) . "'" . target_blank() . ">$text</a>" : "");
}
/** Wrap gzencode() for usage in ob_start()
* @param string
* @return string
*/
function ob_gzencode($string) {
// ob_start() callback receives an optional parameter $phase but gzencode() accepts optional parameter $level
return gzencode($string);
}
/** Compute size of database
* @param string
* @return string formatted

View File

@@ -1,7 +1,10 @@
<?php
namespace Adminer;
error_reporting(6135); // errors and warnings
error_reporting(24575); // all but E_DEPRECATED (overriding mysqli methods without types is deprecated)
set_error_handler(function ($errno, $errstr) {
return !!preg_match('~^(Trying to access array offset on( value of type)? null|Undefined (array key|property))~', $errstr);
}, E_WARNING);
// "offset on null" mutes $_GET["fields"][0] if there's no ?fields[]= (62017e3 is a wrong fix for this)
// "Undefined array key" mutes $_GET["q"] if there's no ?q=
// "Undefined offset" and "Undefined index" are older messages for the same thing
return !!preg_match('~^(Trying to access array offset on( value of type)? null|Undefined (array key|offset|index))~', $errstr);
}, E_WARNING | E_NOTICE); // warning since PHP 8.0

View File

@@ -20,6 +20,14 @@ function adminer() {
return $adminer;
}
/** Get Driver object
* @return Driver
*/
function driver() {
global $driver;
return $driver;
}
/** Get Adminer version
* @return string
*/
@@ -40,6 +48,15 @@ function idf_unescape($idf) {
return str_replace($last . $last, $last, substr($idf, 1, -1));
}
/** Shortcut for $connection->quote($string)
* @param string
* @return string
*/
function q($string) {
global $connection;
return $connection->quote($string);
}
/** Escape string to use inside ''
* @param string
* @return string
@@ -122,164 +139,6 @@ function charset($connection) {
return (min_version("5.5.3", 0, $connection) ? "utf8mb4" : "utf8"); // SHOW CHARSET would require an extra query
}
/** Return <script> element
* @param string
* @param string
* @return string
*/
function script($source, $trailing = "\n") {
return "<script" . nonce() . ">$source</script>$trailing";
}
/** Return <script src> element
* @param string
* @return string
*/
function script_src($url) {
return "<script src='" . h($url) . "'" . nonce() . "></script>\n";
}
/** Get a nonce="" attribute with CSP nonce
* @return string
*/
function nonce() {
return ' nonce="' . get_nonce() . '"';
}
/** Get a target="_blank" attribute
* @return string
*/
function target_blank() {
return ' target="_blank" rel="noreferrer noopener"';
}
/** Escape for HTML
* @param string
* @return string
*/
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
* @param bool
* @param string
* @param string
* @param string
* @param string
* @return string
*/
function checkbox($name, $value, $checked, $label = "", $onclick = "", $class = "", $labelled_by = "") {
$return = "<input type='checkbox' name='$name' value='" . h($value) . "'"
. ($checked ? " checked" : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">"
. ($onclick ? script("qsl('input').onclick = function () { $onclick };", "") : "")
;
return ($label != "" || $class ? "<label" . ($class ? " class='$class'" : "") . ">$return" . h($label) . "</label>" : $return);
}
/** Generate list of HTML options
* @param array array of strings or arrays (creates optgroup)
* @param mixed
* @param bool always use array keys for value="", otherwise only string keys are used
* @return string
*/
function optionlist($options, $selected = null, $use_keys = false) {
$return = "";
foreach ($options as $k => $v) {
$opts = array($k => $v);
if (is_array($v)) {
$return .= '<optgroup label="' . h($k) . '">';
$opts = $v;
}
foreach ($opts as $key => $val) {
$return .= '<option'
. ($use_keys || is_string($key) ? ' value="' . h($key) . '"' : '')
. ($selected !== null && ($use_keys || is_string($key) ? (string) $key : $val) === $selected ? ' selected' : '')
. '>' . h($val)
;
}
if (is_array($v)) {
$return .= '</optgroup>';
}
}
return $return;
}
/** Generate HTML radio list
* @param string
* @param array
* @param string
* @param string true for no onchange, false for radio
* @param string
* @return string
*/
function html_select($name, $options, $value = "", $onchange = true, $labelled_by = "") {
if ($onchange) {
return "<select name='" . h($name) . "'"
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">" . optionlist($options, $value) . "</select>"
. (is_string($onchange) ? script("qsl('select').onchange = function () { $onchange };", "") : "")
;
}
$return = "";
foreach ($options as $key => $val) {
$return .= "<label><input type='radio' name='" . h($name) . "' value='" . h($key) . "'" . ($key == $value ? " checked" : "") . ">" . h($val) . "</label>";
}
return $return;
}
/** Get onclick confirmation
* @param string
* @param string
* @return string
*/
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) {
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";
}
/** Return class='active' if $bold is true
* @param bool
* @param string
* @return string
*/
function bold($bold, $class = "") {
return ($bold ? " class='active $class'" : ($class ? " class='$class'" : ""));
}
/** Escape string for JavaScript apostrophes
* @param string
* @return string
*/
function js_escape($string) {
return addcslashes($string, "\r\n'\\/"); // slash for <script>
}
/** Get INI boolean value
* @param string
* @return bool
@@ -328,15 +187,6 @@ function get_password() {
return $return;
}
/** Shortcut for $connection->quote($string)
* @param string
* @return string
*/
function q($string) {
global $connection;
return $connection->quote($string);
}
/** Get single value from database
* @param string
* @param int
@@ -452,14 +302,14 @@ function where($where, $fields = array()) {
foreach ((array) $where["where"] as $key => $val) {
$key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key);
$field_type = $fields[$key]["type"];
$return[] = $column
. (JUSH == "sql" && $fields[$key]["type"] == "json" ? " = CAST(" . q($val) . " AS JSON)"
. (JUSH == "sql" && $field_type == "json" ? " = CAST(" . q($val) . " AS JSON)"
: (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))
)))
: (JUSH == "mssql" && strpos($field_type, "datetime") === false ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text but it does not work with datetime
: " = " . 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
if (JUSH == "sql" && preg_match('~char|text~', $field_type) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
}
}
@@ -529,11 +379,39 @@ function cookie($name, $value, $lifetime = 2592000) {
);
}
/** Get settings stored in a cookie
* @param string
* @return array
*/
function get_settings($cookie) {
parse_str($_COOKIE[$cookie], $settings);
return $settings;
}
/** Get setting stored in a cookie
* @param string
* @param string
* @return mixed
*/
function get_setting($key, $cookie = "adminer_settings") {
$settings = get_settings($cookie);
return $settings[$key];
}
/** Store settings to a cookie
* @param array
* @param string
* @return bool
*/
function save_settings($settings, $cookie = "adminer_settings") {
return cookie($cookie, http_build_query($settings + get_settings($cookie)));
}
/** Restart stopped session
* @return null
*/
function restart_session() {
if (!ini_bool("session.use_cookies")) {
if (!ini_bool("session.use_cookies") && (!function_exists('session_status') || session_status() == 1)) { // 1 - PHP_SESSION_NONE, session_status() available since PHP 5.4
session_start();
}
}
@@ -578,10 +456,17 @@ function set_session($key, $val) {
*/
function auth_url($vendor, $server, $username, $db = null) {
global $drivers;
preg_match('~([^?]*)\??(.*)~', remove_from_uri(implode("|", array_keys($drivers)) . "|username|" . ($db !== null ? "db|" : "") . session_name()), $match);
$uri = remove_from_uri(implode("|", array_keys($drivers))
. "|username|ext|"
. ($db !== null ? "db|" : "")
. ($vendor == 'mssql' || $vendor == 'pgsql' ? "" : "ns|") // we don't have access to support() here
. session_name())
;
preg_match('~([^?]*)\??(.*)~', $uri, $match);
return "$match[1]?"
. (sid() ? SID . "&" : "")
. ($vendor != "server" || $server != "" ? urlencode($vendor) . "=" . urlencode($server) . "&" : "")
. ($_GET["ext"] ? "ext=" . urlencode($_GET["ext"]) . "&" : "")
. "username=" . urlencode($username)
. ($db != "" ? "&db=" . urlencode($db) : "")
. ($match[2] ? "&$match[2]" : "")
@@ -713,24 +598,13 @@ function remove_from_uri($param = "") {
return substr(preg_replace("~(?<=[?&])($param" . (SID ? "" : "|" . session_name()) . ")=[^&]*&~", '', relative_uri() . "&"), 0, -1);
}
/** Generate page number for pagination
* @param int
* @param int
* @return string
*/
function pagination($page, $current) {
return " " . ($page == $current
? $page + 1
: '<a href="' . h(remove_from_uri("page") . ($page ? "&page=$page" . ($_GET["next"] ? "&next=" . urlencode($_GET["next"]) : "") : "")) . '">' . ($page + 1) . "</a>"
);
}
/** Get file contents from $_FILES
* @param string
* @param bool
* @param string
* @return mixed int for error, string otherwise
*/
function get_file($key, $decompress = false) {
function get_file($key, $decompress = false, $delimiter = "") {
$file = $_FILES[$key];
if (!$file) {
return null;
@@ -752,17 +626,17 @@ function get_file($key, $decompress = false) {
); //! may not be reachable because of open_basedir
if ($decompress) {
$start = substr($content, 0, 3);
if (function_exists("iconv") && preg_match("~^\xFE\xFF|^\xFF\xFE~", $start, $regs)) { // not ternary operator to save memory
if (function_exists("iconv") && preg_match("~^\xFE\xFF|^\xFF\xFE~", $start)) { // not ternary operator to save memory
$content = iconv("utf-16", "utf-8", $content);
} elseif ($start == "\xEF\xBB\xBF") { // UTF-8 BOM
$content = substr($content, 3);
}
$return .= $content . "\n\n";
} else {
$return .= $content;
}
$return .= $content;
if ($delimiter) {
$return .= (preg_match("($delimiter\\s*\$)", $content) ? "" : $delimiter) . "\n\n";
}
}
//! support SQL files not ending with semicolon
return $return;
}
@@ -824,36 +698,6 @@ function friendly_url($val) {
return preg_replace('~\W~i', '-', $val);
}
/** Print hidden fields
* @param array
* @param array
* @param string
* @return bool
*/
function hidden_fields($process, $ignore = array(), $prefix = '') {
$return = false;
foreach ($process as $key => $val) {
if (!in_array($key, $ignore)) {
if (is_array($val)) {
hidden_fields($val, array(), $key);
} else {
$return = true;
echo '<input type="hidden" name="' . h($prefix ? $prefix . "[$key]" : $key) . '" value="' . h($val) . '">';
}
}
}
return $return;
}
/** Print hidden fields for GET forms
* @return null
*/
function hidden_fields_get() {
echo (sid() ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
echo (SERVER !== null ? '<input type="hidden" name="' . DRIVER . '" value="' . h(SERVER) . '">' : "");
echo '<input type="hidden" name="username" value="' . h($_GET["username"]) . '">';
}
/** Get status of a single table and fall back to name on error
* @param string
* @param bool
@@ -879,179 +723,6 @@ function column_foreign_keys($table) {
return $return;
}
/** Print enum input field
* @param string "radio"|"checkbox"
* @param string
* @param array
* @param mixed int|string|array
* @param string
* @return null
*/
function enum_input($type, $attrs, $field, $value, $empty = null) {
global $adminer;
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val));
$return .= " <label><input type='$type'$attrs value='" . (JUSH == "sql" ? $i+1 : h($val)) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
}
return $return;
}
/** Print edit input field
* @param array one field from fields()
* @param mixed
* @param string
* @return null
*/
function input($field, $value, $function) {
global $driver, $adminer;
$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
$function = "json";
}
$reset = (JUSH == "mssql" && $field["auto_increment"]);
if ($reset && !$_POST["save"]) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]'$disabled";
$enums = $driver->enumLength($field);
if ($enums) {
$field["type"] = "enum";
$field["length"] = $enums;
}
if ($field["type"] == "enum") {
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
} else {
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]'$disabled>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. on_help("getTarget(event).value.replace(/^SQL\$/, '')", 1)
. script("qsl('select').onchange = functionChange;", "")
: h(reset($functions))
) . '<td>';
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
if ($input != "") {
echo $input;
} elseif (preg_match('~bool~', $field["type"])) {
echo "<input type='hidden'$attrs value='0'>"
. "<input type='checkbox'" . (preg_match('~^(1|t|true|y|yes|on)$~i', $value) ? " checked='checked'" : "") . "$attrs value='1'>";
} elseif ($field["type"] == "set") { //! 64 bits
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_int($value) ? ($value >> $i) & 1 : in_array($val, explode(",", $value), true));
echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . (1 << $i) . "'" . ($checked ? ' checked' : '') . ">" . h($adminer->editVal($val, $field)) . '</label>';
}
} elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'>";
} elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) {
if ($text && JUSH != "sqlite") {
$attrs .= " cols='50' rows='12'";
} else {
$rows = min(12, substr_count($value, "\n") + 1);
$attrs .= " cols='30' rows='$rows'" . ($rows == 1 ? " style='height: 1.2em;'" : ""); // 1.2em - line-height
}
echo "<textarea$attrs>" . h($value) . '</textarea>';
} elseif ($function == "json" || preg_match('~^jsonb?$~', $field["type"])) {
echo "<textarea$attrs cols='50' rows='12' class='jush-js'>" . h($value) . '</textarea>';
} else {
// int(3) is only a display hint
$types = $driver->types();
$maxlength = (!preg_match('~int~', $field["type"]) && preg_match('~^(\d+)(,(\d+))?$~', $field["length"], $match)
? ((preg_match("~binary~", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0))
: ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)
);
if (JUSH == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) {
$maxlength += 7; // microtime
}
// 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'" : "")
. (preg_match('~char|binary~', $field["type"]) && $maxlength > 20 ? " size='40'" : "")
. "$attrs>"
;
}
echo $adminer->editHint($_GET["edit"], $field, $value);
// skip 'original'
$first = 0;
foreach ($functions as $key => $val) {
if ($key === "" || !$val) {
break;
}
$first++;
}
if ($first) {
echo script("mixin(qsl('td'), {onchange: partial(skipOriginal, $first), oninput: function () { this.onchange(); }});");
}
}
}
/** Process edit input field
* @param one field from fields()
* @return string or false to leave the original value
*/
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];
if ($field["type"] == "enum" || $driver->enumLength($field)) {
if ($value == -1) {
return false;
}
if ($value == "") {
return "NULL";
}
}
if ($field["type"] == "enum") {
return +$value;
}
if ($field["auto_increment"] && $value == "") {
return null;
}
if ($function == "orig") {
return (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? idf_escape($field["field"]) : false);
}
if ($function == "NULL") {
return "NULL";
}
if ($field["type"] == "set") {
return array_sum((array) $value);
}
if ($function == "json") {
$function = "";
$value = json_decode($value, true);
if (!is_array($value)) {
return false; //! report errors
}
return $value;
}
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
$file = get_file("fields-$idf");
if (!is_string($file)) {
return false; //! report errors
}
return $driver->quoteBinary($file);
}
return $adminer->processInput($field, $value, $function);
}
/** Compute fields() from $_POST edit data
* @return array
*/
@@ -1077,29 +748,6 @@ function fields_from_edit() {
return $return;
}
/** Print results of search in all tables
* @uses $_GET["where"][0]
* @uses $_POST["tables"]
* @return null
*/
function search_tables() {
global $adminer, $connection;
$_GET["where"][0]["val"] = $_POST["query"];
$sep = "<ul>\n";
foreach (table_status('', true) as $table => $table_status) {
$name = $adminer->tableName($table_status);
if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
$result = $connection->query("SELECT" . limit("1 FROM " . table($table), " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
if (!$result || $result->fetch_row()) {
$print = "<a href='" . h(ME . "select=" . urlencode($table) . "&where[0][op]=" . urlencode($_GET["where"][0]["op"]) . "&where[0][val]=" . urlencode($_GET["where"][0]["val"])) . "'>$name</a>";
echo "$sep<li>" . ($result ? $print : "<p class='error'>$print: " . error()) . "\n";
$sep = "";
}
}
}
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/** Send headers for export
* @param string
* @param bool
@@ -1113,6 +761,9 @@ function dump_headers($identifier, $multi_table = false) {
header("Content-Disposition: attachment; filename=" . $adminer->dumpFilename($identifier) . ".$return" . ($output != "file" && preg_match('~^[0-9a-z]+$~', $output) ? ".$output" : ""));
}
session_write_close();
if (!ob_get_level()) {
ob_start(null, 4096);
}
ob_flush();
flush();
return $return;
@@ -1165,15 +816,18 @@ function get_temp_dir() {
* @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);
if (is_link($filename)) {
return; // https://cwe.mitre.org/data/definitions/61.html
}
$fp = @fopen($filename, "c+"); // @ - may not be writable
if (!$fp) {
return;
}
chmod($filename, 0660);
if (!flock($fp, LOCK_EX)) {
fclose($fp);
return;
}
flock($fp, LOCK_EX);
return $fp;
}
@@ -1185,26 +839,45 @@ function file_write_unlock($fp, $data) {
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, strlen($data));
file_unlock($fp);
}
/** Unlock and close a file
* @param resource
*/
function file_unlock($fp) {
flock($fp, LOCK_UN);
fclose($fp);
}
/** Get first element of an array
* @param array
* @return mixed or false if not found
*/
function first($array) {
// reset(f()) triggers a notice
return reset($array);
}
/** 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) {
$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);
$fp = file_open_lock($filename);
if (!$fp) {
return false;
}
$return = stream_get_contents($fp);
if (!$return) {
$return = rand_string();
fwrite($fp, $return);
fclose($fp);
file_write_unlock($fp, $return);
} else {
file_unlock($fp);
}
return $return;
}
@@ -1314,14 +987,7 @@ function slow_query($query) {
$connection2 = null;
if (!$slow_query && support("kill") && is_object($connection2 = connect($adminer->credentials())) && ($db == "" || $connection2->select_db($db))) {
$kill = $connection2->result(connection_id()); // MySQL and MySQLi can use thread_id but it's not in PDO_MySQL
?>
<script<?php echo nonce(); ?>>
var timeout = setTimeout(function () {
ajax('<?php echo js_escape(ME); ?>script=kill', function () {
}, 'kill=<?php echo $kill; ?>&token=<?php echo $token; ?>');
}, <?php echo 1000 * $timeout; ?>);
</script>
<?php
echo script("const timeout = setTimeout(() => { ajax('" . js_escape(ME) . "script=kill', function () {}, 'kill=$kill&token=$token'); }, 1000 * $timeout);");
}
ob_flush();
flush();
@@ -1387,123 +1053,3 @@ 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});", "");
}
/** Print edit data form
* @param string
* @param array
* @param mixed
* @param bool
* @return null
*/
function edit_form($table, $fields, $row, $update) {
global $adminer, $token, $error;
$table_name = $adminer->tableName(table_status1($table, true));
page_header(
($update ? lang('Edit') : lang('Insert')),
$error,
array("select" => array($table, $table_name)),
$table_name
);
$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">
<?php
$first = 0;
if (!$fields) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else {
echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field);
$default = $_GET["set"][bracket_escape($name)];
if ($default === null) {
$default = $field["default"];
if ($field["type"] == "bit" && preg_match("~^b'([01]*)'\$~", $default, $regs)) {
$default = $regs[1];
}
}
$value = ($row !== null
? ($row[$name] != "" && JUSH == "sql" && preg_match("~enum|set~", $field["type"])
? (is_array($row[$name]) ? array_sum($row[$name]) : +$row[$name])
: (is_bool($row[$name]) ? +$row[$name] : $row[$name])
)
: (!$update && $field["auto_increment"]
? ""
: (isset($_GET["select"]) ? false : $default)
)
);
if (!$_POST["save"] && is_string($value)) {
$value = $adminer->editVal($value, $field);
}
$function = ($_POST["save"]
? (string) $_POST["function"][$name]
: ($update && preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"])
? "now"
: ($value === false ? null : ($value !== null ? '' : 'NULL'))
)
);
if (!$_POST && !$update && $value == $field["default"] && preg_match('~^[\w.]+\(~', $value)) {
$function = "SQL";
}
if (preg_match("~time~", $field["type"]) && preg_match('~^CURRENT_TIMESTAMP~i', $value)) {
$value = "";
$function = "now";
}
if ($field["type"] == "uuid" && $value == "uuid()") {
$value = "";
$function = "uuid";
}
if ($field["auto_increment"] || $function == "now" || $function == "uuid") {
$first++;
}
input($field, $value, $function);
echo "\n";
}
if (!support("table")) {
echo "<tr>"
. "<th><input name='field_keys[]'>"
. script("qsl('input').oninput = fieldChange;")
. "<td class='function'>" . html_select("field_funs[]", $adminer->editFunctions(array("null" => isset($_GET["select"]))))
. "<td><input name='field_vals[]'>"
. "\n"
;
}
echo "</table>\n";
}
echo "<p>\n";
if ($fields) {
echo "<input type='submit' value='" . lang('Save') . "'>\n";
if (!isset($_GET["select"])) {
echo "<input type='submit' name='insert' value='" . ($update
? lang('Save and continue edit')
: lang('Save and insert next')
) . "' title='Ctrl+Shift+Enter'>\n";
echo ($update ? script("qsl('input').onclick = function () { return !ajaxForm(this.form, '" . lang('Saving') . "…', this); };") : "");
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[2*$first+1].firstChild);"))
);
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));
}
?>
<input type="hidden" name="referer" value="<?php echo h(isset($_POST["referer"]) ? $_POST["referer"] : $_SERVER["HTTP_REFERER"]); ?>">
<input type="hidden" name="save" value="1">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php
}

View File

@@ -0,0 +1,536 @@
<?php
namespace Adminer;
/** Return <script> element
* @param string
* @param string
* @return string
*/
function script($source, $trailing = "\n") {
return "<script" . nonce() . ">$source</script>$trailing";
}
/** Return <script src> element
* @param string
* @return string
*/
function script_src($url) {
return "<script src='" . h($url) . "'" . nonce() . "></script>\n";
}
/** Get a nonce="" attribute with CSP nonce
* @return string
*/
function nonce() {
return ' nonce="' . get_nonce() . '"';
}
/** Get <input type="hidden">
* @param string
* @param string
* @return string HTML
*/
function input_hidden($name, $value = "") {
return "<input type='hidden' name='" . h($name) . "' value='" . h($value) . "'>\n";
}
/** Get <input type="hidden" name="token">
* @param string token to use instead of global $token
* @return string HTML
*/
function input_token($special = "") {
global $token;
return input_hidden("token", ($special ?: $token));
}
/** Get a target="_blank" attribute
* @return string
*/
function target_blank() {
return ' target="_blank" rel="noreferrer noopener"';
}
/** Escape for HTML
* @param string
* @return string
*/
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
* @param bool
* @param string
* @param string
* @param string
* @param string
* @return string
*/
function checkbox($name, $value, $checked, $label = "", $onclick = "", $class = "", $labelled_by = "") {
$return = "<input type='checkbox' name='$name' value='" . h($value) . "'"
. ($checked ? " checked" : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">"
. ($onclick ? script("qsl('input').onclick = function () { $onclick };", "") : "")
;
return ($label != "" || $class ? "<label" . ($class ? " class='$class'" : "") . ">$return" . h($label) . "</label>" : $return);
}
/** Generate list of HTML options
* @param array array of strings or arrays (creates optgroup)
* @param mixed
* @param bool always use array keys for value="", otherwise only string keys are used
* @return string
*/
function optionlist($options, $selected = null, $use_keys = false) {
$return = "";
foreach ($options as $k => $v) {
$opts = array($k => $v);
if (is_array($v)) {
$return .= '<optgroup label="' . h($k) . '">';
$opts = $v;
}
foreach ($opts as $key => $val) {
$return .= '<option'
. ($use_keys || is_string($key) ? ' value="' . h($key) . '"' : '')
. ($selected !== null && ($use_keys || is_string($key) ? (string) $key : $val) === $selected ? ' selected' : '')
. '>' . h($val)
;
}
if (is_array($v)) {
$return .= '</optgroup>';
}
}
return $return;
}
/** Generate HTML <select>
* @param string
* @param array
* @param string
* @param string
* @param string
* @return string
*/
function html_select($name, $options, $value = "", $onchange = "", $labelled_by = "") {
return "<select name='" . h($name) . "'"
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">" . optionlist($options, $value) . "</select>"
. ($onchange ? script("qsl('select').onchange = function () { $onchange };", "") : "")
;
}
/** Generate HTML radio list
* @param string
* @param array
* @param string
* @return string
*/
function html_radios($name, $options, $value = "") {
$return = "";
foreach ($options as $key => $val) {
$return .= "<label><input type='radio' name='" . h($name) . "' value='" . h($key) . "'" . ($key == $value ? " checked" : "") . ">" . h($val) . "</label>";
}
return $return;
}
/** Get onclick confirmation
* @param string
* @param string
* @return string
*/
function confirm($message = "", $selector = "qsl('input')") {
return script("$selector.onclick = () => 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) {
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";
}
/** Return class='active' if $bold is true
* @param bool
* @param string
* @return string
*/
function bold($bold, $class = "") {
return ($bold ? " class='active $class'" : ($class ? " class='$class'" : ""));
}
/** Escape string for JavaScript apostrophes
* @param string
* @return string
*/
function js_escape($string) {
return addcslashes($string, "\r\n'\\/"); // slash for <script>
}
/** Generate page number for pagination
* @param int
* @param int
* @return string
*/
function pagination($page, $current) {
return " " . ($page == $current
? $page + 1
: '<a href="' . h(remove_from_uri("page") . ($page ? "&page=$page" . ($_GET["next"] ? "&next=" . urlencode($_GET["next"]) : "") : "")) . '">' . ($page + 1) . "</a>"
);
}
/** Print hidden fields
* @param array
* @param array
* @param string
* @return bool
*/
function hidden_fields($process, $ignore = array(), $prefix = '') {
$return = false;
foreach ($process as $key => $val) {
if (!in_array($key, $ignore)) {
if (is_array($val)) {
hidden_fields($val, array(), $key);
} else {
$return = true;
echo input_hidden(($prefix ? $prefix . "[$key]" : $key), $val);
}
}
}
return $return;
}
/** Print hidden fields for GET forms
* @return null
*/
function hidden_fields_get() {
echo (sid() ? input_hidden(session_name(), session_id()) : '');
echo (SERVER !== null ? input_hidden(DRIVER, SERVER) : "");
echo input_hidden("username", $_GET["username"]);
}
/** Print enum or set input field
* @param string "radio"|"checkbox"
* @param string
* @param array
* @param mixed string|array
* @param string
* @return null
*/
function enum_input($type, $attrs, $field, $value, $empty = null) {
global $adminer;
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === $empty) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_array($value) ? in_array($val, $value) : $value === $val);
$return .= " <label><input type='$type'$attrs value='" . h($val) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
}
return $return;
}
/** Print edit input field
* @param array one field from fields()
* @param mixed
* @param string
* @param bool
* @return null
*/
function input($field, $value, $function, $autofocus = false) {
global $driver, $adminer;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
$value = json_encode($value, 128 | 64 | 256); // 128 - JSON_PRETTY_PRINT, 64 - JSON_UNESCAPED_SLASHES, 256 - JSON_UNESCAPED_UNICODE available since PHP 5.4
$function = "json";
}
$reset = (JUSH == "mssql" && $field["auto_increment"]);
if ($reset && !$_POST["save"]) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]'$disabled" . ($autofocus ? " autofocus" : "");
$enums = $driver->enumLength($field);
if ($enums) {
$field["type"] = "enum";
$field["length"] = $enums;
}
echo $driver->unconvertFunction($field) . " ";
if ($field["type"] == "enum") {
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
} else {
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]'$disabled>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. on_help("event.target.value.replace(/^SQL\$/, '')", 1)
. script("qsl('select').onchange = functionChange;", "")
: h(reset($functions))
) . '<td>';
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
if ($input != "") {
echo $input;
} elseif (preg_match('~bool~', $field["type"])) {
echo "<input type='hidden'$attrs value='0'>"
. "<input type='checkbox'" . (preg_match('~^(1|t|true|y|yes|on)$~i', $value) ? " checked='checked'" : "") . "$attrs value='1'>";
} elseif ($field["type"] == "set") {
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = in_array($val, explode(",", $value), true);
echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . h($val) . "'" . ($checked ? ' checked' : '') . ">" . h($adminer->editVal($val, $field)) . '</label>';
}
} elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'>";
} elseif ($function == "json" || preg_match('~^jsonb?$~', $field["type"])) {
echo "<textarea$attrs cols='50' rows='12' class='jush-js'>" . h($value) . '</textarea>';
} elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) {
if ($text && JUSH != "sqlite") {
$attrs .= " cols='50' rows='12'";
} else {
$rows = min(12, substr_count($value, "\n") + 1);
$attrs .= " cols='30' rows='$rows'";
}
echo "<textarea$attrs>" . h($value) . '</textarea>';
} else {
// int(3) is only a display hint
$types = $driver->types();
$maxlength = (!preg_match('~int~', $field["type"]) && preg_match('~^(\d+)(,(\d+))?$~', $field["length"], $match)
? ((preg_match("~binary~", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0))
: ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)
);
if (JUSH == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) {
$maxlength += 7; // microtime
}
// 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'" : "")
. (preg_match('~char|binary~', $field["type"]) && $maxlength > 20 ? " size='" . ($maxlength > 99 ? 60 : 40) . "'" : "")
. "$attrs>"
;
}
echo $adminer->editHint($_GET["edit"], $field, $value);
// skip 'original'
$first = 0;
foreach ($functions as $key => $val) {
if ($key === "" || !$val) {
break;
}
$first++;
}
if ($first && count($functions) > 1) {
echo script("qsl('td').oninput = partial(skipOriginal, $first);");
}
}
}
/** Process edit input field
* @param one field from fields()
* @return string or false to leave the original value
*/
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];
if ($field["type"] == "enum" || $driver->enumLength($field)) {
if ($value == -1) {
return false;
}
if ($value == "") {
return "NULL";
}
}
if ($field["auto_increment"] && $value == "") {
return null;
}
if ($function == "orig") {
return (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? idf_escape($field["field"]) : false);
}
if ($function == "NULL") {
return "NULL";
}
if ($field["type"] == "set") {
$value = implode(",", (array) $value);
}
if ($function == "json") {
$function = "";
$value = json_decode($value, true);
if (!is_array($value)) {
return false; //! report errors
}
return $value;
}
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
$file = get_file("fields-$idf");
if (!is_string($file)) {
return false; //! report errors
}
return $driver->quoteBinary($file);
}
return $adminer->processInput($field, $value, $function);
}
/** Print results of search in all tables
* @uses $_GET["where"][0]
* @uses $_POST["tables"]
* @return null
*/
function search_tables() {
global $adminer, $connection;
$_GET["where"][0]["val"] = $_POST["query"];
$sep = "<ul>\n";
foreach (table_status('', true) as $table => $table_status) {
$name = $adminer->tableName($table_status);
if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
$result = $connection->query("SELECT" . limit("1 FROM " . table($table), " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
if (!$result || $result->fetch_row()) {
$print = "<a href='" . h(ME . "select=" . urlencode($table) . "&where[0][op]=" . urlencode($_GET["where"][0]["op"]) . "&where[0][val]=" . urlencode($_GET["where"][0]["val"])) . "'>$name</a>";
echo "$sep<li>" . ($result ? $print : "<p class='error'>$print: " . error()) . "\n";
$sep = "";
}
}
}
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/** 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});", "");
}
/** Print edit data form
* @param string
* @param array
* @param mixed
* @param bool
* @return null
*/
function edit_form($table, $fields, $row, $update) {
global $adminer, $error;
$table_name = $adminer->tableName(table_status1($table, true));
page_header(
($update ? lang('Edit') : lang('Insert')),
$error,
array("select" => array($table, $table_name)),
$table_name
);
$adminer->editRowPrint($table, $fields, $row, $update);
if ($row === false) {
echo "<p class='error'>" . lang('No rows.') . "\n";
return;
}
echo "<form action='' method='post' enctype='multipart/form-data' id='form'>\n";
if (!$fields) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else {
echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
$autofocus = !$_POST;
foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field);
$default = $_GET["set"][bracket_escape($name)];
if ($default === null) {
$default = $field["default"];
if ($field["type"] == "bit" && preg_match("~^b'([01]*)'\$~", $default, $regs)) {
$default = $regs[1];
}
if (JUSH == "sql" && preg_match('~binary~', $field["type"])) {
$default = bin2hex($default); // same as UNHEX
}
}
$value = ($row !== null
? ($row[$name] != "" && JUSH == "sql" && preg_match("~enum|set~", $field["type"]) && is_array($row[$name])
? implode(",", $row[$name])
: (is_bool($row[$name]) ? +$row[$name] : $row[$name])
)
: (!$update && $field["auto_increment"]
? ""
: (isset($_GET["select"]) ? false : $default)
)
);
if (!$_POST["save"] && is_string($value)) {
$value = $adminer->editVal($value, $field);
}
$function = ($_POST["save"]
? (string) $_POST["function"][$name]
: ($update && preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"])
? "now"
: ($value === false ? null : ($value !== null ? '' : 'NULL'))
)
);
if (!$_POST && !$update && $value == $field["default"] && preg_match('~^[\w.]+\(~', $value)) {
$function = "SQL";
}
if (preg_match("~time~", $field["type"]) && preg_match('~^CURRENT_TIMESTAMP~i', $value)) {
$value = "";
$function = "now";
}
if ($field["type"] == "uuid" && $value == "uuid()") {
$value = "";
$function = "uuid";
}
if ($autofocus !== false) {
$autofocus = ($field["auto_increment"] || $function == "now" || $function == "uuid" ? null : true); // null - don't autofocus this input but check the next one
}
input($field, $value, $function, $autofocus);
if ($autofocus) {
$autofocus = false;
}
echo "\n";
}
if (!support("table") && !fields($table)) {
echo "<tr>"
. "<th><input name='field_keys[]'>"
. script("qsl('input').oninput = fieldChange;")
. "<td class='function'>" . html_select("field_funs[]", $adminer->editFunctions(array("null" => isset($_GET["select"]))))
. "<td><input name='field_vals[]'>"
. "\n"
;
}
echo "</table>\n";
}
echo "<p>\n";
if ($fields) {
echo "<input type='submit' value='" . lang('Save') . "'>\n";
if (!isset($_GET["select"])) {
echo "<input type='submit' name='insert' value='" . ($update
? lang('Save and continue edit')
: lang('Save and insert next')
) . "' title='Ctrl+Shift+Enter'>\n";
echo ($update ? script("qsl('input').onclick = function () { return !ajaxForm(this.form, '" . lang('Saving') . "…', this); };") : "");
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n" : "");
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));
}
echo input_hidden("referer", (isset($_POST["referer"]) ? $_POST["referer"] : $_SERVER["HTTP_REFERER"]));
echo input_hidden("save", 1);
echo input_token();
echo "</form>\n";
}

View File

@@ -45,6 +45,7 @@ $langs = array(
'th' => 'ภาษาไทย', // Panya Saraphi, elect.tu@gmail.com - http://www.opencart2u.com/
'tr' => 'Türkçe', // Bilgehan Korkmaz - turktron.com
'uk' => 'Українська', // Valerii Kryzhov
'uz' => 'Oʻzbekcha', // Junaydullaev Inoyatullokhon - https://av.uz/
'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
@@ -63,10 +64,12 @@ function get_lang() {
* @param int
* @return string
*/
// this is matched by compile.php
function lang($idf, $number = null) {
global $LANG, $translations;
$translation = ($translations[$idf] ?: $idf);
if (is_array($translation)) {
// this is matched by compile.php
$pos = ($number == 1 ? 0
: ($LANG == 'cs' || $LANG == 'sk' ? ($number && $number < 5 ? 1 : 2) // different forms for 1, 2-4, other
: ($LANG == 'fr' ? (!$number ? 0 : 1) // different forms for 0-1, other
@@ -74,11 +77,12 @@ function lang($idf, $number = null) {
: ($LANG == 'sl' ? ($number % 100 == 1 ? 0 : ($number % 100 == 2 ? 1 : ($number % 100 == 3 || $number % 100 == 4 ? 2 : 3))) // different forms for 1, 2, 3-4, other
: ($LANG == 'lt' ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number % 10 > 1 && $number / 10 % 10 != 1 ? 1 : 2)) // different forms for 1, 12-19, other
: ($LANG == 'lv' ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number ? 1 : 2)) // different forms for 1 except 11, other, 0
: ($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
: (in_array($LANG, array('bs', 'ru', 'sr', '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];
}
$translation = str_replace("'", '', $translation); // translations can contain HTML or be used in optionlist (we couldn't escape them here) but they can also be used e.g. in title='' //! escape plaintext translations
$args = func_get_args();
array_shift($args);
$format = str_replace("%d", "%s", $translation);
@@ -93,7 +97,7 @@ function switch_lang() {
echo "<form action='' method='post'>\n<div id='lang'>";
echo lang('Language') . ": " . html_select("lang", $langs, $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 input_token(get_token()); // $token may be empty in auth.inc.php
echo "</div>\n</form>\n";
}

View File

@@ -4,14 +4,16 @@ namespace Adminer;
// PDO can be used in several database drivers
if (extension_loaded('pdo')) {
abstract class PdoDb {
var $_result, $server_info, $affected_rows, $errno, $error, $pdo;
public $flavor = '', $server_info, $affected_rows, $errno, $error;
protected $pdo;
private $result;
function dsn($dsn, $username, $password, $options = array()) {
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_SILENT;
$options[\PDO::ATTR_STATEMENT_CLASS] = array('Adminer\PdoDbStatement');
try {
$this->pdo = new \PDO($dsn, $username, $password, $options);
} catch (Exception $ex) {
} catch (\Exception $ex) {
auth_error(h($ex->getMessage()));
}
$this->server_info = @$this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION);
@@ -38,12 +40,12 @@ if (extension_loaded('pdo')) {
}
function multi_query($query) {
return $this->_result = $this->query($query);
return $this->result = $this->query($query);
}
function store_result($result = null) {
if (!$result) {
$result = $this->_result;
$result = $this->result;
if (!$result) {
return false;
}
@@ -57,11 +59,11 @@ if (extension_loaded('pdo')) {
}
function next_result() {
if (!$this->_result) {
if (!$this->result) {
return false;
}
$this->_result->_offset = 0;
return @$this->_result->nextRowset(); // @ - PDO_PgSQL doesn't support it
$this->result->_offset = 0;
return @$this->result->nextRowset(); // @ - PDO_PgSQL doesn't support it
}
function result($query, $field = 0) {
@@ -70,12 +72,12 @@ if (extension_loaded('pdo')) {
return false;
}
$row = $result->fetch();
return $row[$field];
return $row ? $row[$field] : false;
}
}
class PdoDbStatement extends \PDOStatement {
var $_offset = 0, $num_rows;
public $_offset = 0, $num_rows;
function fetch_assoc() {
return $this->fetch(\PDO::FETCH_ASSOC);
@@ -85,11 +87,15 @@ if (extension_loaded('pdo')) {
return $this->fetch(\PDO::FETCH_NUM);
}
function fetch_column($field) {
return $this->fetchColumn($field);
}
function fetch_field() {
$row = (object) $this->getColumnMeta($this->_offset++);
$row->orgtable = $row->table;
$row->orgname = $row->name;
$row->charsetnr = (in_array("blob", (array) $row->flags) ? 63 : 0);
$type = $row->pdo_type;
$row->type = ($type == \PDO::PARAM_INT ? 0 : 15);
$row->charsetnr = ($type == \PDO::PARAM_LOB || (isset($row->flags) && in_array("blob", (array) $row->flags)) ? 63 : 0);
return $row;
}

View File

@@ -0,0 +1,427 @@
<?php
namespace Adminer;
class Plugins extends Adminer {
public $plugins; ///< @var protected(set) array
/** Register plugins
* @param array object instances or null to autoload plugins from adminer-plugins/
*/
function __construct($plugins) {
if ($plugins === null) {
$plugins = array();
$basename = "adminer-plugins";
if (is_dir($basename)) {
foreach (glob("$basename/*.php") as $filename) {
$include = include_once "./$filename";
}
}
$help = " href='https://www.adminer.org/plugins/#use'" . target_blank();
if (file_exists("$basename.php")) {
$include = include_once "./$basename.php"; // example: return array(new AdminerLoginOtp($secret))
if (is_array($include)) {
foreach ($include as $plugin) {
$plugins[get_class($plugin)] = $plugin;
}
} else {
$this->error .= lang('%s must <a%s>return an array</a>.', "<b>$basename.php</b>", $help) . "<br>";
}
}
foreach (get_declared_classes() as $class) {
if (!$plugins[$class] && preg_match('~^Adminer\w~i', $class)) {
$reflection = new \ReflectionClass($class);
$constructor = $reflection->getConstructor();
if ($constructor && $constructor->getNumberOfRequiredParameters()) {
$this->error .= lang('<a%s>Configure</a> %s in %s.', $help, "<b>$class</b>", "<b>$basename.php</b>") . "<br>";
} else {
$plugins[$class] = new $class;
}
}
}
}
$this->plugins = $plugins;
}
private function callParent($function, $args) {
return call_user_func_array(array('parent', $function), $args);
}
private function applyPlugin($function, $params) {
$args = array();
foreach ($params as $key => $val) {
// some plugins accept params by reference - we don't need to propage it outside, just to the other plugins
$args[] = &$params[$key];
}
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
$return = call_user_func_array(array($plugin, $function), $args);
if ($return !== null) {
return $return;
}
}
}
return $this->callParent($function, $args);
}
private function appendPlugin($function, $args) {
$return = $this->callParent($function, $args);
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
$value = call_user_func_array(array($plugin, $function), $args);
if ($value) {
$return += $value;
}
}
}
return $return;
}
// appendPlugin
function dumpFormat() {
$args = func_get_args();
return $this->appendPlugin(__FUNCTION__, $args);
}
function dumpOutput() {
$args = func_get_args();
return $this->appendPlugin(__FUNCTION__, $args);
}
function editRowPrint($table, $fields, $row, $update) {
$args = func_get_args();
return $this->appendPlugin(__FUNCTION__, $args);
}
function editFunctions($field) {
$args = func_get_args();
return $this->appendPlugin(__FUNCTION__, $args);
}
// applyPlugin
function name() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function credentials() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function connectSsl() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function permanentLogin($create = false) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function bruteForceKey() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function serverName($server) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function database() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function schemas() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function databases($flush = true) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function queryTimeout() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function headers() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function csp() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function head($dark = null) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function css() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function loginForm() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function loginFormField($name, $heading, $value) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function login($login, $password) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function tableName($tableStatus) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function fieldName($field, $order = 0) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLinks($tableStatus, $set = "") {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function foreignKeys($table) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function backwardKeys($table, $tableName) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function backwardKeysPrint($backwardKeys, $row) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectQuery($query, $start, $failed = false) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function sqlCommandQuery($query) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function sqlPrintAfter() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function rowDescription($table) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function rowDescriptions($rows, $foreignKeys) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLink($val, $field) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectVal($val, $link, $field, $original) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function editVal($val, $field) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function tableStructurePrint($fields, $tableStatus = null) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function tableIndexesPrint($indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectColumnsPrint($select, $columns) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectSearchPrint($where, $columns, $indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectOrderPrint($order, $columns, $indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLimitPrint($limit) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLengthPrint($text_length) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectActionPrint($indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectCommandPrint() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectImportPrint() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectEmailPrint($emailFields, $columns) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectColumnsProcess($columns, $indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectSearchProcess($fields, $indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectOrderProcess($fields, $indexes) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLimitProcess() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectLengthProcess() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectEmailProcess($where, $foreignKeys) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function selectQueryBuild($select, $where, $group, $order, $limit, $page) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function messageQuery($query, $time, $failed = false) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function editInput($table, $field, $attrs, $value) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function editHint($table, $field, $value) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function processInput($field, $value, $function = "") {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpDatabase($db) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpTable($table, $style, $is_view = 0) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpData($table, $style, $query) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpFilename($identifier) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpHeaders($identifier, $multi_table = false) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function dumpFooter() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function importServerPath() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function homepage() {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function navigation($missing) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function syntaxHighlighting($tables) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function databasesPrint($missing) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function tablesPrint($tables) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
}

View File

@@ -2,8 +2,7 @@
namespace Adminer;
class TmpFile {
var $handler;
var $size;
private $handler, $size;
function __construct() {
$this->handler = tmpfile();

View File

@@ -1,4 +1,4 @@
<?php
namespace Adminer;
$VERSION = "5.0.2";
$VERSION = "5.1.0";

View File

@@ -6,6 +6,7 @@
* @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)
*/
// this is matched by compile.php
namespace Adminer;
@@ -15,6 +16,7 @@ include "./include/tmpfile.inc.php";
if (isset($_GET["select"]) && ($_POST["edit"] || $_POST["clone"]) && !$_POST["save"]) {
$_GET["edit"] = $_GET["select"];
}
// this is matched by compile.php
if (isset($_GET["callf"])) {
$_GET["call"] = $_GET["callf"];
}

View File

@@ -19,7 +19,7 @@ if (JUSH == "mongo") { // doesn't support primary key
}
$row = $_POST;
if ($row) {
set_adminer_settings(array("index_options" => $row["options"]));
save_settings(array("index_options" => $row["options"]));
}
if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"]) {
$alter = array();
@@ -97,7 +97,7 @@ if (!$row) {
$row["indexes"] = $indexes;
}
$lengths = (JUSH == "sql" || JUSH == "mssql");
$show_options = ($_POST ? $_POST["options"] : adminer_setting("index_options"));
$show_options = ($_POST ? $_POST["options"] : get_setting("index_options"));
?>
<form action="" method="post">
@@ -126,7 +126,7 @@ if ($primary) {
$j = 1;
foreach ($row["indexes"] as $index) {
if (!$_POST["drop_col"] || $j != key($_POST["drop_col"])) {
echo "<tr><td>" . html_select("indexes[$j][type]", array(-1 => "") + $index_types, $index["type"], ($j == count($row["indexes"]) ? "indexesAddRow.call(this);" : 1), "label-type");
echo "<tr><td>" . html_select("indexes[$j][type]", array(-1 => "") + $index_types, $index["type"], ($j == count($row["indexes"]) ? "indexesAddRow.call(this);" : ""), "label-type");
echo "<td>";
ksort($index["columns"]);
@@ -155,5 +155,5 @@ foreach ($row["indexes"] as $index) {
</div>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>

View File

@@ -266,3 +266,5 @@ $translations = array(
'Edit all' => 'تعديل الكل',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php ar` to update this file

View File

@@ -256,7 +256,7 @@ $translations = array(
// in-place editing in select
'Modify' => 'Промяна',
'Ctrl+click on a value to modify it.' => 'Ctrl+щракване в стойността, за да я промените.',
'Use edit link to modify this value.' => 'Използвайте "редакция" за промяна на данните.',
'Use edit link to modify this value.' => 'Използвайте \'редакция\' за промяна на данните.',
// %s can contain auto-increment value
'Item%s has been inserted.' => 'Елементи%s бяха вмъкнати.',
@@ -335,3 +335,5 @@ $translations = array(
'Type has been created.' => 'Вида беше създаден.',
'Alter type' => 'Промяна на вид',
);
// run `php ../../lang.php bg` to update this file

View File

@@ -266,3 +266,5 @@ $translations = array(
'Edit all' => 'সবগুলো সম্পাদনা করুন',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php bn` to update this file

View File

@@ -320,3 +320,5 @@ $translations = array(
'Type has been created.' => 'tip je spašen.',
'Alter type' => 'Ažuriraj tip',
);
// run `php ../../lang.php bs` to update this file

View File

@@ -267,3 +267,5 @@ $translations = array(
'Edit all' => 'Edita-ho tot',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php ca` to update this file

View File

@@ -13,6 +13,9 @@ $translations = array(
'Logged as: %s' => 'Přihlášen jako: %s',
'Logout successful.' => 'Odhlášení proběhlo v pořádku.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Díky za použití Admineru, <a href="https://www.adminer.org/cs/donation/">přispějte</a> na vývoj.',
'Loaded plugins' => 'Nahrané pluginy',
'%s must <a%s>return an array</a>.' => '%s musí <a%s>vracet pole</a>.',
'<a%s>Configure</a> %s in %s.' => '<a%s>Nakonfigurujte</a> %s v %s.',
'Invalid credentials.' => 'Neplatné přihlašovací údaje.',
'There is a space in the input password which might be the cause.' => 'Problém může být, že je v zadaném hesle mezera.',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Adminer nepodporuje přístup k databázi bez hesla, <a href="https://www.adminer.org/cs/password/"%s>více informací</a>.',
@@ -356,3 +359,5 @@ $translations = array(
'Check has been altered.' => 'Kontrola byla změněna.',
'Check has been dropped.' => 'Kontrola byla odstraněna.',
);
// run `php ../../lang.php cs` to update this file

View File

@@ -281,3 +281,5 @@ $translations = array(
'Alter type' => 'Ændre type',
'Saving' => 'Gemmer',
);
// run `php ../../lang.php da` to update this file

View File

@@ -302,4 +302,12 @@ $translations = array(
'Unknown error.' => 'Unbekannter Fehler.',
'Database does not support password.' => 'Die Datenbank unterstützt kein Passwort.',
'Disable %s or enable %s or %s extensions.' => 'Deaktivieren Sie %s oder aktivieren Sie die Erweiterungen %s oder %s.',
'Check has been dropped.' => 'Check wurde abgebrochen.',
'Check has been altered.' => 'Check wurde geändert.',
'Check has been created.' => 'Check wurde erstellt.',
'Alter check' => 'Check ändern',
'Create check' => 'Check erstellen',
'Checks' => 'Checks',
);
// run `php ../../lang.php de` to update this file

View File

@@ -335,3 +335,5 @@ $translations = array(
'Type has been created.' => 'Ο τύπος δημιουργήθηκε.',
'Alter type' => 'Τροποποίηση τύπου',
);
// run `php ../../lang.php el` to update this file

View File

@@ -15,3 +15,5 @@ $translations = array(
'%d in total' => '%d in total',
'%d query(s) executed OK.' => array('%d query executed OK.', '%d queries executed OK.'),
);
// run `php ../../lang.php en` to update this file

View File

@@ -44,6 +44,7 @@ $translations = array(
'Save and insert next' => 'Guardar e insertar siguiente',
'Delete' => 'Eliminar',
'Database' => 'Base de datos',
'DB' => 'BD',
'Routines' => 'Procedimientos',
'Indexes have been altered.' => 'Índices actualizados.',
'Indexes' => 'Índices',
@@ -62,18 +63,22 @@ $translations = array(
'Page' => 'Página',
'Query executed OK, %d row(s) affected.' => array('Consulta ejecutada, %d registro afectado.', 'Consulta ejecutada, %d registros afectados.'),
'Error in query' => 'Error al ejecutar consulta',
'Unknown error.' => 'Error desconocido.',
'Warnings' => 'Advertencias',
'ATTACH queries are not supported.' => 'Consultas tipo ATTACH no soportadas.',
'Execute' => 'Ejecutar',
'Table' => 'Tabla',
'Foreign keys' => 'Claves externas',
'Triggers' => 'Disparadores',
'View' => 'Vista',
'Materialized view' => 'Vista materializada',
'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.',
'No commands to execute.' => 'Ningún comando para ejecutar.',
'Unable to upload a file.' => 'No es posible cargar el archivo.',
'File upload' => 'Importar archivo',
'File uploads are disabled.' => 'Importación de archivos deshablilitada.',
'Routine has been called, %d row(s) affected.' => array('Consulta ejecutada, %d registro afectado.', 'Consulta ejecutada, %d registros afectados.'),
@@ -83,9 +88,9 @@ $translations = array(
'Session support must be enabled.' => 'Deben estar habilitadas las sesiones.',
'Session expired, please login again.' => 'Sesión caducada, por favor escriba su clave de nuevo.',
'Text length' => 'Longitud de texto',
'Foreign key has been dropped.' => 'Clave externa eliminada.',
'Foreign key has been altered.' => 'Clave externa modificada.',
'Foreign key has been created.' => 'Clave externa creada.',
'Foreign key has been dropped.' => 'Clave foranea eliminada.',
'Foreign key has been altered.' => 'Clave foranea modificada.',
'Foreign key has been created.' => 'Clave foranea creada.',
'Foreign key' => 'Clave externa',
'Target table' => 'Tabla de destino',
'Change' => 'Modificar',
@@ -140,6 +145,8 @@ $translations = array(
'Grant' => 'Conceder',
'Revoke' => 'Impedir',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'POST data demasiado grande. Reduzca el tamaño o aumente la directiva de configuración %s.',
'You can upload a big SQL file via FTP and import it from server.' => 'Usted puede cargar un SQL grande mediante FTP e importarlo desde el servidor.',
'You are offline.' => 'Usted no esta en linea.',
'Logged as: %s' => 'Logueado como: %s',
'Move up' => 'Mover arriba',
'Move down' => 'Mover abajo',
@@ -147,8 +154,8 @@ $translations = array(
'Aggregation' => 'Agregados',
'Export' => 'Exportar',
'Output' => 'Salida',
'open' => 'mostrar',
'save' => 'archivo',
'open' => 'abrir',
'save' => 'guardar',
'Format' => 'Formato',
'Tables' => 'Tablas',
'Data' => 'Datos',
@@ -195,6 +202,7 @@ $translations = array(
'Partition name' => 'Nombre de partición',
'Values' => 'Valores',
'%d row(s) have been imported.' => array('%d registro importado.', '%d registros importados.'),
'File must be in UTF-8 encoding.' => 'El archivo tiene que ser codificacion UTF-8.',
'anywhere' => 'donde sea',
'Import' => 'Importar',
'Stop on error' => 'Parar en caso de error',
@@ -256,7 +264,7 @@ $translations = array(
'Attachments' => 'Adjuntos',
'%d query(s) executed OK.' => array('%d sentencia SQL ejecutada correctamente.', '%d sentencias SQL ejecutadas correctamente.'),
'Show only errors' => 'Mostrar solamente errores',
'Refresh' => 'Refrescar',
'Refresh' => 'Actualizar',
'Invalid schema.' => 'Esquema inválido.',
'Please use one of the extensions %s.' => 'Por favor, use una de las extensiones %s.',
'now' => 'ahora',
@@ -266,4 +274,28 @@ $translations = array(
'Permanent link' => 'Enlace permanente',
'Edit all' => 'Editar todos',
'HH:MM:SS' => 'HH:MM:SS',
'Loaded plugins' => 'Plugins cargados',
// '<b>%s</b> must return an array.' => '<b>%s</b> tiene que retornar un arreglo.',
// 'Configure <b>%s</b> in <b>%s</b>.' => 'Configurar <b>%s</b> en <b>%s</b>.',
'There is a space in the input password which might be the cause.' => 'Hay un espacio en el password, lo cual puede ser la causa.',
'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 accesar una base de datos sin clave, <a href="https://www.adminer.org/en/password/"%s>Ver detalles</a>.',
'Database does not support password.' => 'La base de datos no soporta password.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Muchos intentos de acceso Intente en %d minutos.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Password maestro expirado. <a href="https://www.adminer.org/en/extension/"%s>Implemente</a> %s metodo para hacerlo permanente.',
'If you did not send this request from Adminer then close this page.' => 'Si no puede enviar la solicitud por Adminer entonces cierre esta pagina.',
'Connecting to privileged ports is not allowed.' => 'Conexiones a puertos privilegiados no son permitidas.',
'Disable %s or enable %s or %s extensions.' => 'Desactivar %s o activar %s o %s extensiones.',
'The action will be performed after successful login with the same credentials.' => 'La operacion sera ejecutada despues de ingresar nuevamente con las mismas credenciales.',
'You have no privileges to update this table.' => 'Usted no tiene privilegios para actualizar esta tabla.',
// Table check constraints
'Checks' => 'Chequeos',
'Create check' => 'Crear chequeo',
'Alter check' => 'Cambiar chequeo',
'Check has been created.' => 'Chequeo creado.',
'Check has been altered.' => 'Chequeo cambiado.',
'Check has been dropped.' => 'Chequeo eliminado.',
);
// run `php ../../lang.php es` to update this file

View File

@@ -267,3 +267,5 @@ $translations = array(
'Edit all' => 'Muuda kõiki',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php et` to update this file

View File

@@ -333,3 +333,5 @@ $translations = array(
'Type has been created.' => 'نوع ایجاد شد.',
'Alter type' => 'ویرایش نوع',
);
// run `php ../../lang.php fa` to update this file

View File

@@ -349,3 +349,5 @@ $translations = array(
'Database does not support password.' => 'Tietokanta ei tue salasanaa.',
'Disable %s or enable %s or %s extensions.' => 'Poista käytöstä %s tai ota käyttöön laajennus %s tai %s.',
);
// run `php ../../lang.php fi` to update this file

View File

@@ -242,7 +242,7 @@ $translations = array(
'Type has been dropped.' => 'Le type a été supprimé.',
'Type has been created.' => 'Le type a été créé.',
'Ctrl+click on a value to modify it.' => 'Ctrl+cliquez sur une valeur pour la modifier.',
'Use edit link to modify this value.' => 'Utilisez le lien "modifier" pour modifier cette valeur.',
'Use edit link to modify this value.' => 'Utilisez le lien \'modifier\' pour modifier cette valeur.',
'last' => 'dernière',
'From server' => 'Depuis le serveur',
'System' => 'Système',
@@ -302,3 +302,5 @@ $translations = array(
'Database does not support password.' => 'La base de données ne support pas les mots de passe.',
'Disable %s or enable %s or %s extensions.' => 'Désactiver %s ou activer %s or %s extensions.',
);
// run `php ../../lang.php fr` to update this file

View File

@@ -290,3 +290,5 @@ $translations = array(
'yes' => 'si',
'no' => 'non',
);
// run `php ../../lang.php gl` to update this file

View File

@@ -292,3 +292,5 @@ $translations = array(
'yes' => 'כן',
'no' => 'לא',
);
// run `php ../../lang.php he` to update this file

View File

@@ -266,3 +266,5 @@ $translations = array(
'Edit all' => 'Összes szerkesztése',
'HH:MM:SS' => 'óó:pp:mm',
);
// run `php ../../lang.php hu` to update this file

View File

@@ -315,3 +315,5 @@ $translations = array(
'Type has been created.' => 'Jenis berhasil dibuat.',
'Alter type' => 'Ubah jenis',
);
// run `php ../../lang.php id` to update this file

View File

@@ -302,3 +302,5 @@ $translations = array(
'yes' => 'si',
'no' => 'no',
);
// run `php ../../lang.php it` to update this file

View File

@@ -3,17 +3,24 @@ namespace Adminer;
$translations = array(
'Login' => 'ログイン',
'Logout successful.' => 'ログアウト',
'Invalid credentials.' => '不正なログイン',
'Logout successful.' => 'ログアウトしました。',
'Invalid credentials.' => '不正なログインです。',
'Server' => 'サーバ',
'Username' => 'ユーザ名',
'Password' => 'パスワード',
'Loaded plugins' => '読込済プラグイン',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Adminerのご利用ありがとうございました。(寄付は<a href="https://www.adminer.org/en/donation/">こちら</a>)',
'There is a space in the input password which might be the cause.' => '入力されたパスワードに空白が含まれているので、それが原因かもしれません。',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Adminer はパスワードのないデータベースへの接続には対応していません。(<a href="https://www.adminer.org/en/password/"%s>詳細</a>)',
'Database does not support password.' => 'データベースがパスワードに対応していません。',
'Too many unsuccessful logins, try again in %d minute(s).' => 'ログインの失敗数が多すぎます。%d分後に再試行してください。',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'マスタパスワードが期限切れになりました。<a href="https://www.adminer.org/en/extension/"%s>(実装例)</a> 無期限にするには %s 関数を用います。',
'Select database' => 'データベースを選択してください',
'Invalid database.' => '不正なデータベース',
'Table has been dropped.' => 'テーブルを削除しました',
'Table has been altered.' => 'テーブルを変更しました',
'Table has been created.' => 'テーブルを作成しました',
'Alter table' => 'テーブル変更',
'Invalid database.' => '不正なデータベースです。',
'Table has been dropped.' => 'テーブルを削除しました',
'Table has been altered.' => 'テーブルを変更しました',
'Table has been created.' => 'テーブルを作成しました',
'Alter table' => 'テーブル変更',
'Create table' => 'テーブルを作成',
'Table name' => 'テーブル名',
'engine' => 'エンジン',
@@ -25,10 +32,11 @@ $translations = array(
'Options' => '設定',
'Save' => '保存',
'Drop' => '削除',
'Database has been dropped.' => 'データベースを削除しました',
'Database has been created.' => 'データベースを作成しました',
'Database has been renamed.' => 'データベースの名前を変えました',
'Database has been altered.' => 'データベースを変更しました',
'Drop %s?' => '%s を削除しますか?',
'Database has been dropped.' => 'データベースを削除しました',
'Database has been created.' => 'データベースを作成しました',
'Database has been renamed.' => 'データベースの名前を変えました',
'Database has been altered.' => 'データベースを変更しました。',
'Alter database' => 'データベースを変更',
'Create database' => 'データベースを作成',
'SQL command' => 'SQLコマンド',
@@ -36,15 +44,17 @@ $translations = array(
'Use' => '使用',
'No tables.' => 'テーブルがありません。',
'select' => '選択',
'Item has been deleted.' => '項目を削除しました',
'Item has been updated.' => '項目を更新しました',
'Item has been deleted.' => '項目を削除しました',
'Item has been updated.' => '項目を更新しました',
'Edit' => '編集',
'Insert' => '挿入',
'Save and insert next' => '保存/追加',
'Delete' => '削除',
'You have no privileges to update this table.' => 'このテーブルを更新する権限がありません。',
'Database' => 'データベース',
'DB' => 'DB',
'Routines' => 'ルーチン',
'Indexes have been altered.' => '索引を変更しました',
'Indexes have been altered.' => '索引を変更しました',
'Indexes' => '索引',
'Alter indexes' => '索引の変更',
'Add next' => '追加',
@@ -55,36 +65,46 @@ $translations = array(
'Sort' => 'ソート',
'descending' => '降順',
'Limit' => '制約',
'No rows.' => '行がありません',
'Limit rows' => '行数の制約',
'No rows.' => '行がありません。',
'Action' => '動作',
'edit' => '編集',
'Page' => 'ページ',
'Query executed OK, %d row(s) affected.' => 'クエリーを実行しました。%d 行を変更しました',
'Query executed OK, %d row(s) affected.' => 'クエリーを実行しました。%d 行を変更しました',
'Error in query' => 'クエリーのエラー',
'Unknown error.' => '不明なエラーです。',
'Warnings' => '警告',
'ATTACH queries are not supported.' => 'ATTACH クエリーは対応していません。',
'Execute' => '実行',
'Table' => 'テーブル',
'Foreign keys' => '外部キー',
'Triggers' => 'トリガー',
'View' => 'ビュー',
'Materialized view' => 'マテビュー',
'Full table scan' => 'テーブルの全スキャン',
'Unable to select the table' => 'テーブルを選択できません',
'Invalid CSRF token. Send the form again.' => '不正なCSRFトークン。再送信してください',
'Invalid CSRF token. Send the form again.' => '不正なCSRFトークン。再送信してください',
'If you did not send this request from Adminer then close this page.' => 'Adminerからのリクエストを送信しない場合はこのページを閉じてください。',
'Comment' => 'コメント',
'Default values' => '規定値',
'%d byte(s)' => '%d バイト',
'No commands to execute.' => '実行するコマンドがありません',
'Unable to upload a file.' => 'ファイルをアップロードできません',
'No commands to execute.' => '実行するコマンドがありません',
'Unable to upload a file.' => 'ファイルをアップロードできません',
'File upload' => 'ファイルをアップロード',
'File uploads are disabled.' => 'ファイルのアップロードが無効です',
'Routine has been called, %d row(s) affected.' => 'ルーチンを呼びました。%d 行を変更しました',
'File uploads are disabled.' => 'ファイルのアップロードが無効です',
'Routine has been called, %d row(s) affected.' => 'ルーチンを呼びました。%d 行を変更しました',
'Call' => '呼出し',
'No extension' => '拡張機能がありません',
'None of the supported PHP extensions (%s) are available.' => 'PHPの拡張機能%sがセットアップされていません',
'Session support must be enabled.' => 'セッションを有効にしてください',
'Session expired, please login again.' => 'セッションの期限切れ。ログインし直してください',
'None of the supported PHP extensions (%s) are available.' => 'PHPの拡張機能%sがセットアップされていません',
'Connecting to privileged ports is not allowed.' => '特権ポートへの接続は許可されていません。',
'Disable %s or enable %s or %s extensions.' => '%s を無効にするか、拡張機能 %s または %s を有効にしてください',
'Session support must be enabled.' => 'セッションを有効にしてください。',
'Session expired, please login again.' => 'セッションの期限切れ。ログインし直してください。',
'The action will be performed after successful login with the same credentials.' => '同じアカウントで正しくログインすると作業を実行します。',
'Text length' => '文字列の長さ',
'Foreign key has been dropped.' => '外部キーを削除しました',
'Foreign key has been altered.' => '外部キーを変更しました',
'Foreign key has been created.' => '外部キーを作成しました',
'Foreign key has been dropped.' => '外部キーを削除しました',
'Foreign key has been altered.' => '外部キーを変更しました',
'Foreign key has been created.' => '外部キーを作成しました',
'Foreign key' => '外キー',
'Target table' => 'テーブル',
'Change' => '変更',
@@ -97,49 +117,52 @@ $translations = array(
'ON UPDATE' => 'ON UPDATE',
'Index Type' => '索引の型',
'length' => '長さ',
'View has been dropped.' => 'ビューを削除しました',
'View has been altered.' => 'ビューを変更しました',
'View has been created.' => 'ビューを作成しました',
'View has been dropped.' => 'ビューを削除しました',
'View has been altered.' => 'ビューを変更しました',
'View has been created.' => 'ビューを作成しました',
'Alter view' => 'ビューを変更',
'Create view' => 'ビューを作成',
'Name' => '名称',
'Process list' => 'プロセス一覧',
'%d process(es) have been killed.' => '%d プロセスを強制終了しました',
'%d process(es) have been killed.' => '%d プロセスを強制終了しました',
'Kill' => '強制終了',
'Parameter name' => '参数名',
'Database schema' => '構造',
'Create procedure' => 'プロシージャの作成',
'Create function' => '関数の作成',
'Routine has been dropped.' => 'ルーチンを作成',
'Routine has been altered.' => 'ルーチンを変更',
'Routine has been created.' => 'ルーチンを作成',
'Routine has been dropped.' => 'ルーチンを作成しました。',
'Routine has been altered.' => 'ルーチンを変更しました。',
'Routine has been created.' => 'ルーチンを作成しました。',
'Alter function' => '関数の変更',
'Alter procedure' => 'プロシージャの変更',
'Return type' => '戻り値の型',
'Add trigger' => 'トリガーの追加',
'Trigger has been dropped.' => 'トリガーを削除しました',
'Trigger has been altered.' => 'トリガーを変更しました',
'Trigger has been created.' => 'トリガーを追加しました',
'Trigger has been dropped.' => 'トリガーを削除しました',
'Trigger has been altered.' => 'トリガーを変更しました',
'Trigger has been created.' => 'トリガーを追加しました',
'Alter trigger' => 'トリガーの変更',
'Create trigger' => 'トリガーの作成',
'Time' => '時間',
'Event' => 'イベント',
'%s version: %s through PHP extension %s' => '%sバージョン%s、 PHP拡張機能 %s',
'%d / ' => '%d / ',
'%d row(s)' => '%d 行',
'Remove' => '除外',
'Are you sure?' => '実行しますか?',
'Privileges' => '権限',
'Create user' => 'ユーザを作成',
'User has been dropped.' => 'ユーザを削除',
'User has been altered.' => 'ユーザを変更',
'User has been created.' => 'ユーザを作成',
'User has been dropped.' => 'ユーザを削除しました。',
'User has been altered.' => 'ユーザを変更しました。',
'User has been created.' => 'ユーザを作成しました。',
'Hashed' => 'Hashed',
'Column' => '列',
'Routine' => 'ルーチン',
'Grant' => '権限の付与',
'Revoke' => '権限の取消し',
'Logged as: %s' => 'ログ:%s',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'POSTデータが大きすぎます。データサイズを小さくするか %s 設定を大きくしてください',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'POSTデータが大きすぎます。データサイズを小さくするか %s 設定を大きくしてください',
'You can upload a big SQL file via FTP and import it from server.' => '大きなSQLファイルは、FTP経由でアップロードしてサーバからインポートしてください。',
'You are offline.' => 'オフライン状態です。',
'Move up' => '上',
'Move down' => '下',
'Export' => 'エクスポート',
@@ -151,9 +174,9 @@ $translations = array(
'Format' => '形式',
'Functions' => '関数',
'Aggregation' => '集合',
'Event has been dropped.' => '削除しました',
'Event has been altered.' => '変更しました',
'Event has been created.' => '作成しました',
'Event has been dropped.' => 'イベントを削除しました',
'Event has been altered.' => 'イベントを変更しました',
'Event has been created.' => 'イベントを作成しました',
'Alter event' => '変更',
'Create event' => '作成',
'Start' => '開始',
@@ -164,8 +187,8 @@ $translations = array(
'Events' => 'イベント',
'Schedule' => 'スケジュール',
'At given time' => '指定時刻',
'Tables have been truncated.' => 'テーブルをtruncateしました',
'Tables have been moved.' => 'テーブルを移動しました',
'Tables have been truncated.' => 'テーブルを空にしました',
'Tables have been moved.' => 'テーブルを移動しました',
'Tables and views' => 'テーブルとビュー',
'Engine' => 'エンジン',
'Collation' => '照合順序',
@@ -177,6 +200,7 @@ $translations = array(
'0123456789' => '0123456789',
'Analyze' => '分析',
'Optimize' => '最適化',
'Vacuum' => '不要領域の回収',
'Check' => 'チェック',
'Repair' => '修復',
'Truncate' => '空にする',
@@ -184,16 +208,18 @@ $translations = array(
'Move' => '移動',
'Save and continue edit' => '保存して継続',
'original' => '元',
'%d item(s) have been affected.' => '%d を更新しました',
'%d item(s) have been affected.' => '%d を更新しました',
'Whole result' => '全結果',
'Tables have been dropped.' => 'テーブルを削除しました',
'Tables have been dropped.' => 'テーブルを削除しました',
'Tables have been optimized.' => 'テーブルを最適化しました。',
'Clone' => 'クローン',
'Maximum number of allowed fields exceeded. Please increase %s.' => '定義可能な最大フィールド数を越えました。%s を増やしてください。',
'Partition by' => 'パーティション',
'Partitions' => 'パーティション',
'Partition name' => 'パーティション名',
'Values' => '値',
'%d row(s) have been imported.' => '%d 行をインポートしました',
'%d row(s) have been imported.' => '%d 行をインポートしました',
'File must be in UTF-8 encoding.' => 'ファイルをUTF-8で保存してください。',
'Show structure' => '構造',
'anywhere' => '任意',
'Import' => 'インポート',
@@ -208,7 +234,7 @@ $translations = array(
'Relations' => '関係',
'Run file' => 'ファイルを実行',
'Clear' => '消去',
'Maximum allowed file size is %sB.' => '最大ファイルサイズ %sB',
'Maximum allowed file size is %sB.' => '最大ファイルサイズ %sB です。',
'Numbers' => '数字',
'Date and time' => '日時',
'Strings' => '文字列',
@@ -219,49 +245,51 @@ $translations = array(
'From' => '差出人',
'Subject' => '題名',
'Send' => '送信',
'%d e-mail(s) have been sent.' => '%d メールを送信しました',
'%d e-mail(s) have been sent.' => '%d メールを送信しました',
'Webserver file %s' => 'Webサーバファイル %s',
'File does not exist.' => 'ファイルは存在しません',
'File does not exist.' => 'ファイルは存在しません',
'%d in total' => '合計 %d',
'Permanent login' => '永続的にログイン',
'Databases have been dropped.' => 'データベースを削除しました',
'Databases have been dropped.' => 'データベースを削除しました',
'Search data in tables' => 'データを検索する',
'Schema' => 'スキーマ',
'Alter schema' => 'スキーマ変更',
'Create schema' => 'スキーマ追加',
'Schema has been dropped.' => 'スキーマを削除しました',
'Schema has been created.' => 'スキーマを追加しました',
'Schema has been altered.' => 'スキーマを変更しました',
'Schema has been dropped.' => 'スキーマを削除しました',
'Schema has been created.' => 'スキーマを追加しました',
'Schema has been altered.' => 'スキーマを変更しました',
'Sequences' => 'シーケンス',
'Create sequence' => 'シーケンス作成',
'Alter sequence' => 'シーケンス変更',
'Sequence has been dropped.' => 'シーケンスを削除しました',
'Sequence has been created.' => 'シーケンスを追加しました',
'Sequence has been altered.' => 'シーケンスを変更しました',
'Sequence has been dropped.' => 'シーケンスを削除しました',
'Sequence has been created.' => 'シーケンスを追加しました',
'Sequence has been altered.' => 'シーケンスを変更しました',
'User types' => 'ユーザー定義型',
'Create type' => 'ユーザー定義型作成',
'Alter type' => 'ユーザー定義型変更',
'Type has been dropped.' => 'ユーザー定義型を削除しました',
'Type has been created.' => 'ユーザー定義型を追加しました',
'Use edit link to modify this value.' => 'リンクを編集する',
'Type has been dropped.' => 'ユーザー定義型を削除しました',
'Type has been created.' => 'ユーザー定義型を追加しました',
'Ctrl+click on a value to modify it.' => 'Ctrl+クリックで値を修正します。',
'Use edit link to modify this value.' => 'この値を修正するとリンクを編集します。',
'last' => '最終',
'From server' => 'サーバーから実行',
'System' => 'データベース種類',
'empty' => '空',
'Network' => 'ネットワーク型',
'Geometry' => 'ジオメトリ型',
'File exists.' => 'ファイルが既に存在します',
'File exists.' => 'ファイルが既に存在します',
'Attachments' => '添付ファイル',
'Item%s has been inserted.' => '%s項目を挿入しました',
'Item%s has been inserted.' => '%s項目を挿入しました',
'now' => '現在の日時',
'%d query(s) executed OK.' => '%d クエリーを実行しました',
'%d query(s) executed OK.' => '%d クエリーを実行しました',
'Show only errors' => 'エラーのみ表示',
'Refresh' => 'リフレッシュ',
'Invalid schema.' => '無効なスキーマ',
'Please use one of the extensions %s.' => 'いずれかの拡張機能を使ってください %s',
'Invalid schema.' => '無効なスキーマです。',
'Please use one of the extensions %s.' => '%s のいずれかの拡張機能を使ってください',
'ltr' => 'ltr',
'Tables have been copied.' => 'テーブルをコピーしました',
'Tables have been copied.' => 'テーブルをコピーしました',
'Copy' => 'コピー',
'overwrite' => '上書き',
'Permanent link' => 'パーマネントリンク',
'Edit all' => 'すべて編集',
'HH:MM:SS' => '時:分:秒',
@@ -275,4 +303,14 @@ $translations = array(
'yes' => 'はい',
'no' => 'いいえ',
'Default value' => '既定値',
// Table check constraints
'Checks' => 'チェック',
'Create check' => 'チェックを作成',
'Alter check' => 'チェックを変更',
'Check has been created.' => 'チェックを作成しました。',
'Check has been altered.' => 'チェックを変更しました。',
'Check has been dropped.' => 'チェックを削除しました。',
);
// run `php ../../lang.php ja` to update this file

View File

@@ -302,3 +302,5 @@ $translations = array(
'Database does not support password.' => 'ბაზაში არაა მხარდაჭერილი პაროლი.',
'Disable %s or enable %s or %s extensions.' => 'გათიშეთ %s ან ჩართეთ %s ან %s გაფართოება.',
);
// run `php ../../lang.php ka` to update this file

View File

@@ -279,3 +279,5 @@ $translations = array(
'You can upload a big SQL file via FTP and import it from server.' => '큰 SQL 파일은 FTP를 통하여 업로드하여 서버에서 가져올 수 있습니다.',
'You have no privileges to update this table.' => '이 테이블을 업데이트할 권한이 없습니다.',
);
// run `php ../../lang.php ko` to update this file

View File

@@ -311,3 +311,5 @@ $translations = array(
'Type has been created.' => 'Tipas sukurtas.',
'Alter type' => 'Keisti tipą',
);
// run `php ../../lang.php lt` to update this file

View File

@@ -243,7 +243,7 @@ $translations = array(
'Type has been dropped.' => 'Tips dzēsts.',
'Type has been created.' => 'Tips izveidots.',
'Ctrl+click on a value to modify it.' => 'Lai izmainītu vērtību, izmanto Ctrl + peles klikšķi.',
'Use edit link to modify this value.' => 'Izmainīt vērtību var tikai ar saiti "Izmainīt".',
'Use edit link to modify this value.' => 'Izmainīt vērtību var tikai ar saiti \'Izmainīt\'.',
'last' => 'pēdējā',
'From server' => 'No servera',
'System' => 'Sistēma',
@@ -302,3 +302,5 @@ $translations = array(
'Unknown error.' => 'Nezināma kļūda.',
'Database does not support password.' => 'Datubāze neatbalsta paroli.',
);
// run `php ../../lang.php lv` to update this file

View File

@@ -339,3 +339,5 @@ $translations = array(
'Type has been created.' => 'Jenis telah dibuat.',
'Alter type' => 'Ubah jenis',
);
// run `php ../../lang.php ms` to update this file

View File

@@ -243,7 +243,7 @@ $translations = array(
'Type has been dropped.' => 'Type verwijderd.',
'Type has been created.' => 'Type aangemaakt.',
'Ctrl+click on a value to modify it.' => 'Ctrl+klik op een waarde om deze te bewerken.',
'Use edit link to modify this value.' => 'Gebruik de link "bewerk" om deze waarde te wijzigen.',
'Use edit link to modify this value.' => 'Gebruik de link \'bewerk\' om deze waarde te wijzigen.',
'last' => 'laatste',
'From server' => 'Van server',
'System' => 'Databasesysteem',
@@ -302,3 +302,5 @@ $translations = array(
'yes' => 'ja',
'no' => 'neen',
);
// run `php ../../lang.php nl` to update this file

View File

@@ -281,3 +281,5 @@ $translations = array(
'Alter type' => 'Endre type',
'Saving' => 'Lagrer',
);
// run `php ../../lang.php no` to update this file

View File

@@ -13,6 +13,9 @@ $translations = array(
'Logged as: %s' => 'Zalogowany jako: %s',
'Logout successful.' => 'Wylogowano pomyślnie.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Dziękujemy za używanie Adminera, rozważ <a href="https://www.adminer.org/pl/donation/">dotację</a>.',
'Loaded plugins' => 'Wczytane wtyczki',
'%s must <a%s>return an array</a>.' => '%s musi <a%s>zwrócić tablicę</a>.',
'<a%s>Configure</a> %s in %s.' => '<a%s>Skonfiguruj</a> %s w %s.',
'Invalid credentials.' => 'Nieprawidłowe dane logowania.',
'There is a space in the input password which might be the cause.' => 'W haśle wejściowym znajduje się spacja, która może być przyczyną.',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Adminer nie obsługuje dostępu do bazy danych bez hasła, <a href="https://www.adminer.org/pl/password/"%s>więcej informacji</a>.',
@@ -356,3 +359,5 @@ $translations = array(
'Check has been altered.' => 'Kontrola została zmieniona.',
'Check has been dropped.' => 'Kontrola została usunięta.',
);
// run `php ../../lang.php pl` to update this file

View File

@@ -262,3 +262,5 @@ $translations = array(
'now' => 'agora',
'ltr' => 'ltr',
);
// run `php ../../lang.php pt-br` to update this file

View File

@@ -262,3 +262,5 @@ $translations = array(
'now' => 'agora',
'ltr' => 'ltr',
);
// run `php ../../lang.php pt` to update this file

View File

@@ -267,3 +267,5 @@ $translations = array(
'Edit all' => 'Editează tot',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php ro` to update this file

View File

@@ -303,3 +303,5 @@ $translations = array(
'Database does not support password.' => 'База данных не поддерживает пароль.',
'Disable %s or enable %s or %s extensions.' => 'Отключите %s или включите расширения %s или %s.',
);
// run `php ../../lang.php ru` to update this file

View File

@@ -285,7 +285,7 @@ $translations = array(
'Default value' => 'Predvolená hodnota',
'Full table scan' => 'Prechod celej tabuľky',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Príliš veľa pokusov o prihlásenie, skúste to znova za %d minutu.', 'Príliš veľa pokusov o prihlásenie, skúste to znova za %d minuty.', 'Príliš veľa pokusov o prihlásenie, skúste to znova za %d minút.'),
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Vďaka za používanie Admineru, <a href="https://www.adminer.org/cs/donation/">prispejte</a> na vývoj.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Vďaka za používanie Admineru, <a href="https://www.adminer.org/sk/donation/">prispejte</a> na vývoj.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Platnosť hlavného hesla vypršala. <a href="https://www.adminer.org/cs/extension/"%s>Implementujte</a> metodu %s, aby platilo natrvalo.',
'The action will be performed after successful login with the same credentials.' => 'Akcia sa vykoná po úspešnom prihlásení s rovnakými prihlasovacími údajmi.',
'Connecting to privileged ports is not allowed.' => 'Pripojenie k privilegovaným portom nie je povolené.',
@@ -302,4 +302,12 @@ $translations = array(
'Disable %s or enable %s or %s extensions.' => 'Zakážte %s alebo povoľte rozšírenie %s alebo %s.',
'yes' => 'áno',
'no' => 'nie',
'Checks' => 'Kontroly',
'Create check' => 'Vytvoriť kontrolu',
'Alter check' => 'Zmeniť kontrolu',
'Check has been created.' => 'Kontrola bola vytvorená.',
'Check has been altered.' => 'Kontrola bola zmenená.',
'Check has been dropped.' => 'Kontrola bola odstránená.',
);
// run `php ../../lang.php sk` to update this file

View File

@@ -306,3 +306,5 @@ $translations = array(
'Type has been created.' => 'Tip je ustvarjen.',
'Alter type' => 'Spremeni tip',
);
// run `php ../../lang.php sl` to update this file

View File

@@ -318,3 +318,5 @@ $translations = array(
'Type has been created.' => 'тип је креиран.',
'Alter type' => 'Уреди тип',
);
// run `php ../../lang.php sr` to update this file

View File

@@ -348,3 +348,5 @@ $translations = array(
'Type has been created.' => 'Typ har skapats.',
'Alter type' => 'Ändra typ',
);
// run `php ../../lang.php sv` to update this file

View File

@@ -266,3 +266,5 @@ $translations = array(
'Edit all' => 'அனைத்தையும் தொகு',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php ta` to update this file

View File

@@ -267,3 +267,5 @@ $translations = array(
'Edit all' => 'แก้ไขทั้งหมด',
'HH:MM:SS' => 'HH:MM:SS',
);
// run `php ../../lang.php th` to update this file

View File

@@ -342,3 +342,5 @@ $translations = array(
'Type has been created.' => 'Tür oluşturuldu.',
'Alter type' => 'Türü değiştir',
);
// run `php ../../lang.php tr` to update this file

View File

@@ -345,3 +345,5 @@ $translations = array(
'Unknown error.' => 'Невідома помилка.',
'Database does not support password.' => 'База даних не підтримує пароль.',
);
// run `php ../../lang.php uk` to update this file

365
adminer/lang/uz.inc.php Normal file
View File

@@ -0,0 +1,365 @@
<?php
namespace Adminer;
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'System' => 'Tizim',
'Server' => 'Server',
'Username' => 'Foydalanuvchi nomi',
'Password' => 'Parol',
'Permanent login' => 'Doimiy kirish',
'Login' => 'Kirish',
'Logout' => 'Chiqish',
'Logged as: %s' => 'Siz kirgansiz: %s',
'Logout successful.' => 'Muvaffaqiyatli chiqdingiz.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Adminer dasturidan foydalanganingiz uchun rahmat, <a href="https://www.adminer.org/en/donation/">xayriya qilishni</a> o\'ylab ko\'ring.',
'Loaded plugins' => 'Yuklangan plaginlar',
'%s must <a%s>return an array</a>.' => '%s <a%s>massiv qaytarishi</a> kerak.',
'<a%s>Configure</a> %s in %s.' => '%s ni %s ichida <a%s>sozlang</a>.',
'Invalid credentials.' => 'Noto\'g\'ri ma\'lumotlar.',
'There is a space in the input password which might be the cause.' => 'Kiritilgan parolda bo\'sh joy bor, bu sabab bo\'lishi mumkin.',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Adminer parolsiz ma\'lumotlar bazasiga kirishni qo\'llab-quvvatlamaydi, <a href="https://www.adminer.org/en/password/"%s>ko\'proq ma\'lumot</a>.',
'Database does not support password.' => 'Ma\'lumotlar bazasi parolni qo\'llab-quvvatlamaydi.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Juda ko\'p muvaffaqiyatsiz urinishlar, %d daqiqadan so\'ng qayta urining.', 'Juda ko\'p muvaffaqiyatsiz urinishlar, %d daqiqadan so\'ng qayta urining.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Asosiy parol muddati tugadi. Uni doimiy qilish uchun %s usulini <a href="https://www.adminer.org/en/extension/"%s>amalga oshiring</a>.',
'Language' => 'Til',
'Invalid CSRF token. Send the form again.' => 'Noto\'g\'ri CSRF belgisi. Shaklni qayta yuboring.',
'If you did not send this request from Adminer then close this page.' => 'Agar bu so\'rovni Adminerdan yuborgan bo\'lmasangiz, ushbu sahifani yoping.',
'No extension' => 'Kengaytma yo\'q',
// %s contains the list of the extensions, e.g. 'mysqli, PDO_MySQL'
'None of the supported PHP extensions (%s) are available.' => 'Qo\'llab-quvvatlanadigan PHP kengaytmalarining (%s) hech biri mavjud emas.',
'Connecting to privileged ports is not allowed.' => 'Imtiyozli portlarga ulanishga ruxsat berilmagan.',
'Disable %s or enable %s or %s extensions.' => '%s ni o\'chiring yoki %s yoki %s kengaytmalarini yoqing.',
'Session support must be enabled.' => 'Sessiya qo\'llab-quvvatlashi yoqilgan bo\'lishi kerak.',
'Session expired, please login again.' => 'Sessiya muddati tugadi, iltimos, qayta kiring.',
'The action will be performed after successful login with the same credentials.' => 'Amal bir xil ma\'lumotlar bilan muvaffaqiyatli kirishdan so\'ng amalga oshiriladi.',
'%s version: %s through PHP extension %s' => '%s versiyasi: %s PHP kengaytmasi %s orqali',
'Refresh' => 'Yangilash',
// text direction - 'ltr' or 'rtl'
'ltr' => 'ltr',
'Privileges' => 'Imtiyozlar',
'Create user' => 'Foydalanuvchi yaratish',
'User has been dropped.' => 'Foydalanuvchi o\'chirildi.',
'User has been altered.' => 'Foydalanuvchi o\'zgartirildi.',
'User has been created.' => 'Foydalanuvchi yaratildi.',
'Hashed' => 'Xeshlangan',
'Column' => 'Ustun',
'Routine' => 'Protsedura',
'Grant' => 'Berish',
'Revoke' => 'Bekor qilish',
'Process list' => 'Jarayonlar ro\'yxati',
'%d process(es) have been killed.' => array('%d jarayon to\'xtatildi.', '%d jarayonlar to\'xtatildi.'),
'Kill' => 'To\'xtatish',
'Variables' => 'O\'zgaruvchilar',
'Status' => 'Holat',
'SQL command' => 'SQL buyrug\'i',
'%d query(s) executed OK.' => array('%d so\'rov muvaffaqiyatli bajarildi.', '%d so\'rovlar muvaffaqiyatli bajarildi.'),
'Query executed OK, %d row(s) affected.' => array('So\'rov muvaffaqiyatli bajarildi, %d qator o\'zgartirildi.', 'So\'rov muvaffaqiyatli bajarildi, %d qatorlar o\'zgartirildi.'),
'No commands to execute.' => 'Bajariladigan buyruqlar yo\'q.',
'Error in query' => 'So\'rovda xatolik',
'Unknown error.' => 'Noma\'lum xatolik.',
'Warnings' => 'Ogohlantirishlar',
'ATTACH queries are not supported.' => 'ATTACH so\'rovlari qo\'llab-quvvatlanmaydi.',
'Execute' => 'Bajarish',
'Stop on error' => 'Xatoda to\'xtash',
'Show only errors' => 'Faqat xatolarni ko\'rsatish',
// sprintf() format for time of the command
'%.3f s' => '%.3f s',
'History' => 'Tarix',
'Clear' => 'Tozalash',
'Edit all' => 'Hammasini tahrirlash',
'File upload' => 'Fayl yuklash',
'From server' => 'Serverdan',
'Webserver file %s' => 'Veb-server fayli %s',
'Run file' => 'Faylni ishga tushirish',
'File does not exist.' => 'Fayl mavjud emas.',
'File uploads are disabled.' => 'Fayl yuklash o\'chirilgan.',
'Unable to upload a file.' => 'Faylni yuklab bo\'lmadi.',
'Maximum allowed file size is %sB.' => 'Maksimal ruxsat etilgan fayl hajmi %sB.',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Juda katta POST ma\'lumotlari. Ma\'lumotlarni kamaytiring yoki %s konfiguratsiya direktivasini oshiring.',
'You can upload a big SQL file via FTP and import it from server.' => 'Katta SQL faylini FTP orqali yuklab, uni serverdan import qilishingiz mumkin.',
'You are offline.' => 'Siz oflayndasiz.',
'Export' => 'Eksport',
'Output' => 'Natija',
'open' => 'ochish',
'save' => 'saqlash',
'Saving' => 'Saqlanmoqda',
'Format' => 'Format',
'Data' => 'Ma\'lumotlar',
'Database' => 'Ma\'lumotlar bazasi',
'DB' => 'MB',
'Use' => 'Foydalanish',
'Select database' => 'Ma\'lumotlar bazasini tanlash',
'Invalid database.' => 'Noto\'g\'ri ma\'lumotlar bazasi.',
'Database has been dropped.' => 'Ma\'lumotlar bazasi o\'chirildi.',
'Databases have been dropped.' => 'Ma\'lumotlar bazalari o\'chirildi.',
'Database has been created.' => 'Ma\'lumotlar bazasi yaratildi.',
'Database has been renamed.' => 'Ma\'lumotlar bazasi qayta nomlandi.',
'Database has been altered.' => 'Ma\'lumotlar bazasi o\'zgartirildi.',
'Alter database' => 'Ma\'lumotlar bazasini o\'zgartirish',
'Create database' => 'Ma\'lumotlar bazasini yaratish',
'Database schema' => 'Ma\'lumotlar bazasi sxemasi',
// link to current database schema layout
'Permanent link' => 'Doimiy havola',
// thousands separator - must contain single byte
',' => ' ',
'0123456789' => '0123456789',
'Engine' => 'Dvigatel',
'Collation' => 'Kodlash',
'Data Length' => 'Ma\'lumotlar hajmi',
'Index Length' => 'Indeks hajmi',
'Data Free' => 'Bo\'sh ma\'lumotlar',
'Rows' => 'Qatorlar',
'%d in total' => 'Jami %d',
'Analyze' => 'Tahlil qilish',
'Optimize' => 'Optimallash',
'Vacuum' => 'Tozalash',
'Check' => 'Tekshirish',
'Repair' => 'Ta\'mirlash',
'Truncate' => 'Bo\'shatish',
'Tables have been truncated.' => 'Jadvallar bo\'shatildi.',
'Move to other database' => 'Boshqa ma\'lumotlar bazasiga ko\'chirish',
'Move' => 'Ko\'chirish',
'Tables have been moved.' => 'Jadvallar ko\'chirildi.',
'Copy' => 'Nusxalash',
'Tables have been copied.' => 'Jadvallar nusxalandi.',
'overwrite' => 'qayta yozish',
'Routines' => 'Protseduralar',
'Routine has been called, %d row(s) affected.' => array('Protsedura chaqirildi, %d qator o\'zgartirildi.', 'Protsedura chaqirildi, %d qatorlar o\'zgartirildi.'),
'Call' => 'Chaqirish',
'Parameter name' => 'Parametr nomi',
'Create procedure' => 'Protsedura yaratish',
'Create function' => 'Funksiya yaratish',
'Routine has been dropped.' => 'Protsedura o\'chirildi.',
'Routine has been altered.' => 'Protsedura o\'zgartirildi.',
'Routine has been created.' => 'Protsedura yaratildi.',
'Alter function' => 'Funksiyani o\'zgartirish',
'Alter procedure' => 'Protseduranni o\'zgartirish',
'Return type' => 'Qaytarish turi',
'Events' => 'Hodisalar',
'Event has been dropped.' => 'Hodisa o\'chirildi.',
'Event has been altered.' => 'Hodisa o\'zgartirildi.',
'Event has been created.' => 'Hodisa yaratildi.',
'Alter event' => 'Hodisani o\'zgartirish',
'Create event' => 'Hodisa yaratish',
'At given time' => 'Belgilangan vaqtda',
'Every' => 'Har bir',
'Schedule' => 'Jadval',
'Start' => 'Boshlash',
'End' => 'Tugatish',
'On completion preserve' => 'Yakunlangandan so\'ng saqlash',
'Tables' => 'Jadvallar',
'Tables and views' => 'Jadvallar va ko\'rinishlar',
'Table' => 'Jadval',
'No tables.' => 'Jadvallar yo\'q.',
'Alter table' => 'Jadvalni o\'zgartirish',
'Create table' => 'Jadval yaratish',
'Table has been dropped.' => 'Jadval o\'chirildi.',
'Tables have been dropped.' => 'Jadvallar o\'chirildi.',
'Tables have been optimized.' => 'Jadvallar optimallashtirildi.',
'Table has been altered.' => 'Jadval o\'zgartirildi.',
'Table has been created.' => 'Jadval yaratildi.',
'Table name' => 'Jadval nomi',
'Show structure' => 'Tuzilishni ko\'rsatish',
'engine' => 'dvigatel',
'collation' => 'kodlash',
'Column name' => 'Ustun nomi',
'Type' => 'Tur',
'Length' => 'Uzunlik',
'Auto Increment' => 'Avto ko\'payish',
'Options' => 'Variantlar',
'Comment' => 'Izoh',
'Default value' => 'Standart qiymat',
'Default values' => 'Standart qiymatlar',
'Drop' => 'O\'chirish',
'Drop %s?' => '%s ni o\'chirasizmi?',
'Are you sure?' => 'Ishonchingiz komilmi?',
'Size' => 'Hajm',
'Compute' => 'Hisoblash',
'Move up' => 'Yuqoriga ko\'chirish',
'Move down' => 'Pastga ko\'chirish',
'Remove' => 'Olib tashlash',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Ruxsat etilgan maydonlar soni oshib ketdi. Iltimos, %s ni oshiring.',
'Partition by' => 'Bo\'lish mezon',
'Partitions' => 'Bo\'limlar',
'Partition name' => 'Bo\'lim nomi',
'Values' => 'Qiymatlar',
'View' => 'Ko\'rinish',
'Materialized view' => 'Moddiy ko\'rinish',
'View has been dropped.' => 'Ko\'rinish o\'chirildi.',
'View has been altered.' => 'Ko\'rinish o\'zgartirildi.',
'View has been created.' => 'Ko\'rinish yaratildi.',
'Alter view' => 'Ko\'rinishni o\'zgartirish',
'Create view' => 'Ko\'rinish yaratish',
'Indexes' => 'Indekslar',
'Indexes have been altered.' => 'Indekslar o\'zgartirildi.',
'Alter indexes' => 'Indekslarni o\'zgartirish',
'Add next' => 'Keyingisini qo\'shish',
'Index Type' => 'Indeks turi',
'length' => 'uzunlik',
'Foreign keys' => 'Tashqi kalitlar',
'Foreign key' => 'Tashqi kalit',
'Foreign key has been dropped.' => 'Tashqi kalit o\'chirildi.',
'Foreign key has been altered.' => 'Tashqi kalit o\'zgartirildi.',
'Foreign key has been created.' => 'Tashqi kalit yaratildi.',
'Target table' => 'Maqsad jadvali',
'Change' => 'O\'zgartirish',
'Source' => 'Manba',
'Target' => 'Maqsad',
'Add column' => 'Ustun qo\'shish',
'Alter' => 'O\'zgartirish',
'Add foreign key' => 'Tashqi kalit qo\'shish',
'ON DELETE' => 'O\'CHIRILGANDA',
'ON UPDATE' => 'YANGILANGANDA',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => 'Manba va maqsad ustunlari bir xil ma\'lumot turiga ega bo\'lishi kerak, maqsad ustunlarda indeks bo\'lishi kerak va havolalar qilingan ma\'lumotlar mavjud bo\'lishi kerak.',
'Triggers' => 'Triggerlar',
'Add trigger' => 'Trigger qo\'shish',
'Trigger has been dropped.' => 'Trigger o\'chirildi.',
'Trigger has been altered.' => 'Trigger o\'zgartirildi.',
'Trigger has been created.' => 'Trigger yaratildi.',
'Alter trigger' => 'Triggerni o\'zgartirish',
'Create trigger' => 'Trigger yaratish',
'Time' => 'Vaqt',
'Event' => 'Hodisa',
'Name' => 'Nomi',
'select' => 'tanlash',
'Select' => 'Tanlash',
'Select data' => 'Ma\'lumotlarni tanlash',
'Functions' => 'Funksiyalar',
'Aggregation' => 'Agregatsiya',
'Search' => 'Qidirish',
'anywhere' => 'hamma joyda',
'Search data in tables' => 'Jadvallarda ma\'lumotlarni qidirish',
'Sort' => 'Saralash',
'descending' => 'kamayish bo\'yicha',
'Limit' => 'Cheklov',
'Limit rows' => 'Qatorlarni cheklash',
'Text length' => 'Matn uzunligi',
'Action' => 'Amal',
'Full table scan' => 'To\'liq jadval skanerlash',
'Unable to select the table' => 'Jadvalni tanlab bo\'lmadi',
'No rows.' => 'Qatorlar yo\'q.',
// used in SQL query limit and it is followed by another number, e.g. '10 / 50 rows' meaning 10 of 50 rows
'%d / ' => '%d / ',
'%d row(s)' => array('%d qator', '%d qatorlar'),
'Page' => 'Sahifa',
'last' => 'oxirgi',
'Load more data' => 'Ko\'proq ma\'lumot yuklash',
'Loading' => 'Yuklanmoqda',
'Whole result' => 'Butun natija',
'%d byte(s)' => array('%d bayt', '%d baytlar'),
'Import' => 'Import',
'%d row(s) have been imported.' => array('%d qator import qilindi.', '%d qatorlar import qilindi.'),
'File must be in UTF-8 encoding.' => 'Fayl UTF-8 kodlashda bo\'lishi kerak.',
// in-place editing in select
'Modify' => 'O\'zgartirish',
'Ctrl+click on a value to modify it.' => 'Qiymatni o\'zgartirish uchun Ctrl+bosing.',
'Use edit link to modify this value.' => 'Bu qiymatni o\'zgartirish uchun tahrir havolasidan foydalaning.',
// %s can contain auto-increment value, e.g. ' 123'
'Item%s has been inserted.' => 'Element%s kiritildi.',
'Item has been deleted.' => 'Element o\'chirildi.',
'Item has been updated.' => 'Element yangilandi.',
'%d item(s) have been affected.' => array('%d element o\'zgartirildi.', '%d elementlar o\'zgartirildi.'),
'New item' => 'Yangi element',
'original' => 'asl',
// label for value '' in enum data type
'empty' => 'bo\'sh',
'edit' => 'tahrirlash',
'Edit' => 'Tahrirlash',
'Insert' => 'Kiritish',
'Save' => 'Saqlash',
'Save and continue edit' => 'Saqlash va tahrirlashni davom ettirish',
'Save and insert next' => 'Saqlash va keyingisini kiritish',
'Selected' => 'Tanlangan',
'Clone' => 'Klonlash',
'Delete' => 'O\'chirish',
'You have no privileges to update this table.' => 'Bu jadvalni yangilash uchun sizda huquqlar yo\'q.',
'E-mail' => 'E-pochta',
'From' => 'Kimdan',
'Subject' => 'Mavzu',
'Attachments' => 'Ilovalar',
'Send' => 'Yuborish',
'%d e-mail(s) have been sent.' => array('%d e-pochta yuborildi.', '%d e-pochtalar yuborildi.'),
// data type descriptions
'Numbers' => 'Raqamlar',
'Date and time' => 'Sana va vaqt',
'Strings' => 'Matnlar',
'Binary' => 'Ikkilik',
'Lists' => 'Ro\'yxatlar',
'Network' => 'Tarmoq',
'Geometry' => 'Geometriya',
'Relations' => 'Munosabatlar',
'Editor' => 'Muharrir',
// date format in Editor: $1 yyyy, $2 yy, $3 mm, $4 m, $5 dd, $6 d
'$1-$3-$5' => '$5.$3.$1',
// hint for date format - use language equivalents for day, month and year shortcuts
'[yyyy]-mm-dd' => 'dd.mm.[yyyy]',
// hint for time format - use language equivalents for hour, minute and second shortcuts
'HH:MM:SS' => 'SS:MM:SS',
'now' => 'hozir',
'yes' => 'ha',
'no' => 'yo\'q',
// general SQLite error in create, drop or rename database
'File exists.' => 'Fayl mavjud.',
'Please use one of the extensions %s.' => 'Iltimos, kengaytmalardan birini %s foydalaning.',
// PostgreSQL and MS SQL schema support
'Alter schema' => 'Sxemani o\'zgartirish',
'Create schema' => 'Sxema yaratish',
'Schema has been dropped.' => 'Sxema o\'chirildi.',
'Schema has been created.' => 'Sxema yaratildi.',
'Schema has been altered.' => 'Sxema o\'zgartirildi.',
'Schema' => 'Sxema',
'Invalid schema.' => 'Noto\'g\'ri sxema.',
// PostgreSQL sequences support
'Sequences' => 'Ketma-ketliklar',
'Create sequence' => 'Ketma-ketlik yaratish',
'Sequence has been dropped.' => 'Ketma-ketlik o\'chirildi.',
'Sequence has been created.' => 'Ketma-ketlik yaratildi.',
'Sequence has been altered.' => 'Ketma-ketlik o\'zgartirildi.',
'Alter sequence' => 'Ketma-ketlikni o\'zgartirish',
// PostgreSQL user types support
'User types' => 'Foydalanuvchi turlari',
'Create type' => 'Tur yaratish',
'Type has been dropped.' => 'Tur o\'chirildi.',
'Type has been created.' => 'Tur yaratildi.',
'Alter type' => 'Turni o\'zgartirish',
// Table check constraints
'Checks' => 'Tekshirishlar',
'Create check' => 'Tekshirish yaratish',
'Alter check' => 'Tekshirishni o\'zgartirish',
'Check has been created.' => 'Tekshirish yaratildi.',
'Check has been altered.' => 'Tekshirish o\'zgartirildi.',
'Check has been dropped.' => 'Tekshirish o\'chirildi.',
);
// run `php ../../lang.php uz` to update this file

View File

@@ -327,3 +327,5 @@ $translations = array(
'Type has been created.' => 'Đã tạo kiểu.',
'Alter type' => 'Sửa kiểu dữ liệu',
);
// run `php ../../lang.php vi` to update this file

View File

@@ -13,6 +13,9 @@ $translations = array(
'Logged as: %s' => 'Xx: %s',
'Logout successful.' => 'Xx.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Xx <a href="https://www.adminer.org/en/donation/">xx</a>.',
'Loaded plugins' => 'Xx',
'%s must <a%s>return an array</a>.' => '%s xx <a%s>xx</a>.',
'<a%s>Configure</a> %s in %s.' => '<a%s>Xx</a> %s xx %s.',
'Invalid credentials.' => 'Xx.',
'There is a space in the input password which might be the cause.' => 'Xx.',
'Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.' => 'Xx, <a href="https://www.adminer.org/en/password/"%s>xx</a>.',
@@ -358,3 +361,5 @@ $translations = array(
'Check has been altered.' => 'Xx.',
'Check has been dropped.' => 'Xx.',
);
// run `php ../../lang.php xx` to update this file

View File

@@ -348,3 +348,5 @@ $translations = array(
'Type has been created.' => '已建立類型。',
'Alter type' => '修改類型',
);
// run `php ../../lang.php zh-tw` to update this file

View File

@@ -348,3 +348,5 @@ $translations = array(
'Type has been created.' => '已创建类型。',
'Alter type' => '修改类型',
);
// run `php ../../lang.php zh` to update this file

View File

@@ -1,44 +0,0 @@
<?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 "../plugins/drivers/simpledb.php";
$plugins = array(
// specify enabled plugins here
new AdminerDatabaseHide(array('information_schema')),
new AdminerDumpJson,
new AdminerDumpBz2,
new AdminerDumpZip,
new AdminerDumpXml,
new AdminerDumpAlter,
//~ new AdminerSqlLog("past-" . rtrim(`git describe --tags --abbrev=0`) . ".sql"),
//~ new AdminerTinymce("../externals/tinymce/jscripts/tiny_mce/tiny_mce_dev.js"),
new AdminerFileUpload(""),
new AdminerJsonColumn,
new AdminerSlugify,
new AdminerTranslation,
new AdminerForeignSystem,
new AdminerEnumOption,
new AdminerTablesFilter,
new AdminerEditForeign,
);
/* 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 (usually named adminer.php)
include "./index.php";

View File

@@ -14,8 +14,8 @@ if (!$result) {
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 input_hidden("db", DB);
echo ($grant ? "" : input_hidden("grant"));
echo "<table class='odds'>\n";
echo "<thead><tr><th>" . lang('Username') . "<th>" . lang('Server') . "<th></thead>\n";

View File

@@ -9,6 +9,11 @@ $row["fields"] = (array) $row["fields"];
if ($_POST && !process_fields($row["fields"]) && !$error) {
$orig = routine($_GET["procedure"], $routine);
$temp_name = "$row[name]_adminer_" . uniqid();
foreach ($row["fields"] as $key => $field) {
if ($field["field"] == "") {
unset($row["fields"][$key]);
}
}
drop_create(
"DROP $routine " . routine_id($PROCEDURE, $orig),
create_routine($routine, $row),
@@ -26,14 +31,19 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
page_header(($PROCEDURE != "" ? (isset($_GET["function"]) ? lang('Alter function') : lang('Alter procedure')) . ": " . h($PROCEDURE) : (isset($_GET["function"]) ? lang('Create function') : lang('Create procedure'))), $error);
if (!$_POST && $PROCEDURE != "") {
$row = routine($_GET["procedure"], $routine);
$row["name"] = $PROCEDURE;
if (!$_POST) {
if ($PROCEDURE == "") {
$row["language"] = "sql";
} else {
$row = routine($_GET["procedure"], $routine);
$row["name"] = $PROCEDURE;
}
}
$collations = get_vals("SHOW CHARACTER SET");
sort($collations);
$routine_languages = routine_languages();
echo ($collations ? "<datalist id='collations'>" . optionlist($collations) . "</datalist>" : "");
?>
<form action="" method="post" id="form">
@@ -58,5 +68,5 @@ if (isset($_GET["function"])) {
<?php if ($PROCEDURE != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $PROCEDURE)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
<?php echo input_token(); ?>
</form>

View File

@@ -56,7 +56,7 @@ if (support("kill")) {
echo ($i + 1) . "/" . lang('%d in total', max_connections());
echo "<p><input type='submit' value='" . lang('Kill') . "'>\n";
}
echo input_token();
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php echo script("tableCheck();"); ?>

View File

@@ -52,9 +52,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; };
var tablePos = {<?php echo implode(",", $table_pos_js) . "\n"; ?>};
var em = qs('#schema').offsetHeight / <?php echo $top; ?>;
qs('#schema').onselectstart = () => false;
const tablePos = {<?php echo implode(",", $table_pos_js) . "\n"; ?>};
const em = qs('#schema').offsetHeight / <?php echo $top; ?>;
document.onmousemove = schemaMousemove;
document.onmouseup = partialArg(schemaMouseup, '<?php echo js_escape(DB); ?>');
</script>
@@ -74,7 +74,9 @@ foreach ($schema as $name => $table) {
$left1 = $left - $table_pos[$name][1];
$i = 0;
foreach ($ref[0] as $source) {
echo "\n<div class='references' title='" . h($target_name) . "' id='refs$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$source]["pos"] . "em; padding-top: .5em;'><div style='border-top: 1px solid Gray; width: " . (-$left1) . "em;'></div></div>";
echo "\n<div class='references' title='" . h($target_name) . "' id='refs$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$source]["pos"] . "em; padding-top: .5em;'>"
. "<div style='border-top: 1px solid gray; width: " . (-$left1) . "em;'></div></div>"
;
}
}
}
@@ -84,8 +86,9 @@ foreach ($schema as $name => $table) {
$left1 = $left - $table_pos[$name][1];
$i = 0;
foreach ($columns as $target) {
echo "\n<div class='references' title='" . h($target_name) . "' id='refd$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$target]["pos"] . "em; height: 1.25em; background: url(../adminer/static/arrow.gif) no-repeat right center;'>"
. "<div style='height: .5em; border-bottom: 1px solid Gray; width: " . (-$left1) . "em;'></div>"
echo "\n<div class='references' title='" . h($target_name) . "' id='refd$left-" . ($i++) . "'"
. " style='left: $left1" . "em; top: " . $table["fields"][$target]["pos"] . "em; height: 1.25em; background: url(../adminer/static/arrow.gif) no-repeat right center;'>"
. "<div style='height: .5em; border-bottom: 1px solid gray; width: " . (-$left1) . "em;'></div>"
. "</div>"
;
}
@@ -106,7 +109,7 @@ foreach ($schema as $name => $table) {
$min_pos = min($min_pos, $pos1, $pos2);
$max_pos = max($max_pos, $pos1, $pos2);
}
echo "<div class='references' id='refl$left' style='left: $left" . "em; top: $min_pos" . "em; padding: .5em 0;'><div style='border-right: 1px solid Gray; margin-top: 1px; height: " . ($max_pos - $min_pos) . "em;'></div></div>\n";
echo "<div class='references' id='refl$left' style='left: $left" . "em; top: $min_pos" . "em; padding: .5em 0;'><div style='border-right: 1px solid gray; margin-top: 1px; height: " . ($max_pos - $min_pos) . "em;'></div></div>\n";
}
}
}

View File

@@ -34,6 +34,6 @@ if (!$row) {
if ($_GET["ns"] != "") {
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $_GET["ns"])) . "\n";
}
echo input_token();
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -25,7 +25,7 @@ if ($_GET["script"] == "db") {
$sums[$key] += ($table_status["Engine"] != "InnoDB" || $key != "Data_free" ? $table_status[$key] : 0);
}
} elseif (array_key_exists($key, $table_status)) {
json_row("$key-$name");
json_row("$key-$name", "?");
}
}
}

View File

@@ -7,7 +7,7 @@ $indexes = indexes($TABLE);
$fields = fields($TABLE);
$foreign_keys = column_foreign_keys($TABLE);
$oid = $table_status["Oid"];
parse_str($_COOKIE["adminer_import"], $adminer_import);
$adminer_import = get_settings("adminer_import");
$rights = array(); // privilege => 0
$columns = array(); // selectable columns
@@ -83,7 +83,7 @@ if ($_POST && !$error) {
}
$where_check = ($where_check ? "\nWHERE " . implode(" AND ", $where_check) : "");
if ($_POST["export"]) {
cookie("adminer_import", "output=" . urlencode($_POST["output"]) . "&format=" . urlencode($_POST["format"]));
save_settings(array("output" => $_POST["output"], "format" => $_POST["format"]), "adminer_import");
dump_headers($TABLE);
$adminer->dumpTable($TABLE, "");
$from = ($select ? implode(", ", $select) : "*")
@@ -100,6 +100,7 @@ if ($_POST && !$error) {
$query = implode(" UNION ALL ", $union);
}
$adminer->dumpData($TABLE, "table", $query);
$adminer->dumpFooter();
exit;
}
@@ -124,11 +125,11 @@ if ($_POST && !$error) {
$result = ($_POST["delete"]
? $driver->delete($TABLE, $where_check)
: ($_POST["clone"]
? queries("INSERT $query$where_check")
? queries("INSERT $query$where_check" . $driver->insertReturning($TABLE))
: $driver->update($TABLE, $set, $where_check)
)
);
$affected = $connection->affected_rows;
$affected = $connection->affected_rows + (is_object($result) ? $result->num_rows : 0); // PostgreSQL with RETURNING fills num_rows
} else {
foreach ((array) $_POST["check"] as $val) {
// where is not unique so OR can't be used
@@ -149,7 +150,7 @@ if ($_POST && !$error) {
}
$message = lang('%d item(s) have been affected.', $affected);
if ($_POST["clone"] && $result && $affected == 1) {
$last_id = last_id();
$last_id = last_id($result);
if ($last_id) {
$message = lang('Item%s has been inserted.', " $last_id");
}
@@ -194,7 +195,7 @@ if ($_POST && !$error) {
} elseif (!preg_match('~~u', $file)) {
$error = lang('File must be in UTF-8 encoding.');
} else {
cookie("adminer_import", "output=" . urlencode($adminer_import["output"]) . "&format=" . urlencode($_POST["separator"]));
save_settings(array("output" => $adminer_import["output"], "format" => $_POST["separator"]), "adminer_import");
$result = true;
$cols = array_keys($fields);
preg_match_all('~(?>"[^"]*"|[^"\r\n]+)+~', $file, $matches);
@@ -257,8 +258,8 @@ if (!$columns && support("table")) {
echo "<form action='' id='form'>\n";
echo "<div style='display: none;'>";
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 (DB != "" ? input_hidden("db", DB) . (isset($_GET["ns"]) ? input_hidden("ns", $_GET["ns"]) : "") : ""); // not used in Editor
echo input_hidden("select", $TABLE);
echo "</div>\n";
$adminer->selectColumnsPrint($select, $columns);
$adminer->selectSearchPrint($where, $search_columns, $indexes);
@@ -451,8 +452,8 @@ if (!$columns && support("table")) {
$id = h("val[$unique_idf][" . bracket_escape($key) . "]");
$value = $_POST["val"][$unique_idf][bracket_escape($key)];
$editable = !is_array($row[$key]) && is_utf8($val) && $rows[$n][$key] == $row[$key] && !$functions[$key] && !$field["generated"];
$text = preg_match('~text|lob~', $field["type"]);
echo "<td id='$id'";
$text = preg_match('~text|json|lob~', $field["type"]);
echo "<td id='$id'" . (preg_match(number_type(), $field["type"]) && is_numeric(strip_tags($val)) ? " class='number'" : "");
if (($_GET["modify"] && $editable) || $value !== null) {
$h_value = h($value !== null ? $value : $row[$key]);
echo ">" . ($text ? "<textarea name='$id' cols='30' rows='" . (substr_count($row[$key], "\n") + 1) . "'>$h_value</textarea>" : "<input name='$id' value='$h_value' size='$lengths[$key]'>");
@@ -490,7 +491,7 @@ if (!$columns && support("table")) {
$found_rows = ($is_group ? false : found_rows($table_status, $where));
if ($found_rows < max(1e4, 2 * ($page + 1) * $limit)) {
// slow with big tables
$found_rows = reset(slow_query(count_rows($TABLE, $where, $is_group, $group)));
$found_rows = first(slow_query(count_rows($TABLE, $where, $is_group, $group)));
} else {
$exact_count = false;
}
@@ -543,7 +544,7 @@ if (!$columns && support("table")) {
echo "<fieldset>";
echo "<legend>" . lang('Whole result') . "</legend>";
$display_rows = ($exact_count ? "" : "~ ") . $found_rows;
$onclick = "var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);";
$onclick = "const checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);";
echo checkbox("all", 1, 0, ($found_rows !== false ? ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) : ""), $onclick) . "\n";
echo "</fieldset>\n";
@@ -587,13 +588,13 @@ if (!$columns && support("table")) {
echo script("qsl('a').onclick = partial(toggle, 'import');", "");
echo "<span id='import'" . ($_POST["import"] ? "" : " class='hidden'") . ">: ";
echo "<input type='file' name='csv_file'> ";
echo html_select("separator", array("csv" => "CSV,", "csv;" => "CSV;", "tsv" => "TSV"), $adminer_import["format"], 1); // 1 - select
echo html_select("separator", array("csv" => "CSV,", "csv;" => "CSV;", "tsv" => "TSV"), $adminer_import["format"]);
echo " <input type='submit' name='import' value='" . lang('Import') . "'>";
echo "</span>";
echo "</div>";
}
echo "<input type='hidden' name='token' value='$token'>\n";
echo input_token();
echo "</form>\n";
echo (!$group && $select ? "" : script("tableCheck();"));
}

View File

@@ -32,6 +32,6 @@ if (!$row) {
if ($SEQUENCE != "") {
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $SEQUENCE)) . "\n";
}
echo input_token();
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -2,9 +2,11 @@
namespace Adminer;
if (!$error && $_POST["export"]) {
save_settings(array("output" => $_POST["output"], "format" => $_POST["format"]), "adminer_import");
dump_headers("sql");
$adminer->dumpTable("", "");
$adminer->dumpData("", "table", $_POST["query"]);
$adminer->dumpFooter();
exit;
}
@@ -30,7 +32,7 @@ if (!$error && $_POST) {
), "rb");
$query = ($fp ? fread($fp, 1e6) : false);
} else {
$query = get_file("sql_file", true);
$query = get_file("sql_file", true, ";");
}
if (is_string($query)) { // get_file() returns error as number, fread() as false
@@ -40,7 +42,7 @@ if (!$error && $_POST) {
if ($query != "" && strlen($query) < 1e6) { // don't add big queries
$q = $query . (preg_match("~;[ \t\r\n]*\$~", $query) ? "" : ";"); //! doesn't work with DELIMITER |
if (!$history || reset(end($history)) != $q) { // no repeated queries
if (!$history || first(end($history)) != $q) { // no repeated queries
restart_session();
$history[] = array($q, time()); //! add elapsed time
set_session("queries", $history_all); // required because reference is unlinked by stop_session()
@@ -63,7 +65,7 @@ if (!$error && $_POST) {
$errors = array();
$parse = '[\'"' . (JUSH == "sql" ? '`#' : (JUSH == "sqlite" ? '`[' : (JUSH == "mssql" ? '[' : ''))) . ']|/\*|-- |$' . (JUSH == "pgsql" ? '|\$[^$]*\$' : '');
$total_start = microtime(true);
parse_str($_COOKIE["adminer_export"], $adminer_export);
$adminer_export = get_settings("adminer_import"); // this doesn't offer SQL export so we match the import/export style at select
$dump_format = $adminer->dumpFormat();
unset($dump_format["sql"]);
@@ -88,8 +90,8 @@ if (!$error && $_POST) {
$pattern = ($found == '/*' ? '\*/'
: ($found == '[' ? ']'
: (preg_match('~^-- |^#~', $found) ? "\n"
: preg_quote($found) . ($c_style_escapes ? "|\\\\." : "")
)));
: preg_quote($found) . ($c_style_escapes ? "|\\\\." : "")))
);
while (preg_match("($pattern|\$)s", $query, $match, PREG_OFFSET_CAPTURE, $offset)) {
$s = $match[0][0];
@@ -157,7 +159,7 @@ if (!$error && $_POST) {
if (!$_POST["only_errors"]) {
echo "<form action='' method='post'>\n";
$num_rows = $result->num_rows;
echo "<p>" . ($num_rows ? ($limit && $num_rows > $limit ? lang('%d / ', $limit) : "") . lang('%d row(s)', $num_rows) : "");
echo "<p class='sql-footer'>" . ($num_rows ? ($limit && $num_rows > $limit ? lang('%d / ', $limit) : "") . lang('%d row(s)', $num_rows) : "");
echo $time;
if ($connection2 && preg_match("~^($space|\\()*+SELECT\\b~i", $q) && ($explain = explain($connection2, $q))) {
echo ", <a href='#$explain_id'>Explain</a>" . script("qsl('a').onclick = partial(toggle, '$explain_id');", "");
@@ -166,8 +168,8 @@ if (!$error && $_POST) {
echo ", <a href='#$id'>" . lang('Export') . "</a>" . script("qsl('a').onclick = partial(toggle, '$id');", "") . "<span id='$id' class='hidden'>: "
. html_select("output", $adminer->dumpOutput(), $adminer_export["output"]) . " "
. html_select("format", $dump_format, $adminer_export["format"])
. "<input type='hidden' name='query' value='" . h($q) . "'>"
. " <input type='submit' name='export' value='" . lang('Export') . "'><input type='hidden' name='token' value='$token'></span>\n"
. input_hidden("query", $q)
. "<input type='submit' name='export' value='" . lang('Export') . "'>" . input_token() . "</span>\n"
. "</form>\n"
;
}
@@ -179,7 +181,7 @@ 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";
echo "<p class='message' title='" . h(isset($connection->info) ? $connection->info : "") . "'>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
}
}
echo ($warnings ? "<div id='$warnings_id' class='hidden'>\n$warnings</div>\n" : "");
@@ -233,7 +235,9 @@ 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 "<p>$execute\n";
echo "<p>";
$adminer->sqlPrintAfter();
echo "$execute\n";
echo lang('Limit rows') . ": <input type='number' name='limit' class='size' value='" . h($_POST ? $_POST["limit"] : $_GET["limit"]) . "'>\n";
} else {
@@ -256,7 +260,7 @@ if (!isset($_GET["import"])) {
echo checkbox("error_stops", 1, ($_POST ? $_POST["error_stops"] : isset($_GET["import"]) || $_GET["error_stops"]), lang('Stop on error')) . "\n";
echo checkbox("only_errors", 1, ($_POST ? $_POST["only_errors"] : isset($_GET["import"]) || $_GET["only_errors"]), lang('Show only errors')) . "\n";
echo "<input type='hidden' name='token' value='$token'>\n";
echo input_token();
if (!isset($_GET["import"]) && $history) {
print_fieldset("history", lang('History'), $_GET["history"] != "");

46
adminer/static/dark.css Normal file
View File

@@ -0,0 +1,46 @@
/** @author Robert Mesaros, https://www.rmsoft.sk */
body { color: #829bb0; background: #002240; }
a { color: #517fa8; }
a:visited { color: #517fa8; }
a:link:hover, a:visited:hover { color: #9bc0e1; }
h1 { border-color: #5e94c1; color: #ffddbf; background: #154269; }
h2 { border-color: #a3bdd3; color: #000; background: #3c678d; }
table, td, th { border-color: #0e416d; }
th { background: #11385a; }
thead td, thead th { color: #a8b05f; background: #011d35; }
thead th a { color: #a8b05f; }
fieldset { border-color: #16548a; }
code { background: #11385a; }
tbody tr:hover td, tbody tr:hover th { background: #133553; }
pre.jush { background: #11385a; }
input.default { box-shadow: 1px 1px 1px #888; }
input.required, input.maxlength { box-shadow: 1px 1px 1px red; }
.version { color: #888; }
.js .column { background: #011d35; }
.error { color: red; background: #efdada; border: 1px solid #e76f6f; }
.error b { background: #efeaea; }
.message { color: #0b860b; background: #efe; border: 1px solid #7fbd7f; }
.message table { color: #829bb0; background: #002240; }
.char { color: #a949a9; }
.date { color: #59c159; }
.enum { color: #d55c5c; }
.binary { color: #9bc0e1; }
.odds tbody tr:nth-child(2n) { background: #042541; }
.js .checkable .checked td, .js .checkable .checked th { background: #10395c; color: #67a4a5; }
.js .checkable .checked:hover td, .js .checkable .checked:hover th { background: #133553; }
.js .checkable .checked a { color: #67a4a5; }
.icon { background-color: #062642; }
.icon:hover { background-color: #d1394e; }
.footer { border-top-color: rgba(0, 34, 64, .7); border-image-source: linear-gradient(rgba(0, 34, 64, 0.2), #002240); }
.footer > div { background: #002240; }
#menu p, #logins, #tables { border-color: #326b9c; }
#logins a, #tables a, #tables span { background: #002240; }
#breadcrumb { background: #154269; }
#h1 { color: #ffddbf; }
#version { color: #d2b397; }
#schema .table { border-color: #093459; }
#help { border-color: #666; background: #c7e4fe; }
#schema div.table a { color: #3c7bb3; }
#menu .active { color: #398c8d; }
#edit-fields tbody tr:hover td, #edit-fields tbody tr:hover th { background: #3b6f9d; }

View File

@@ -1,4 +1,5 @@
/** @author Ondrej Valka, http://valka.info */
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; min-width: fit-content; }
a { color: blue; text-decoration: none; }
a:visited { color: navy; }
@@ -10,27 +11,29 @@ h2 { font-size: 150%; margin: 0 0 20px -18px; padding: .8em 1em; border-bottom:
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; }
table { margin: 1em 20px 0 0; font-size: 90%; border-spacing: 0; border-width: 1px 0 0 1px; }
table, td, th { border-color: #999; border-style: solid; }
td, th { border-width: 0 1px 1px 0; padding: .2em .3em; margin: 0; }
th { background: #eee; text-align: left; }
thead { position: sticky; top: 0; }
thead th { text-align: center; padding: .2em .5em; }
thead td, thead th { background: #ddf; } /* position: sticky; causes Firefox to lose borders */
thead td, thead th { background: #ddf; }
fieldset { display: inline; vertical-align: top; padding: .5em .8em; margin: .8em .5em 0 0; border: 1px solid #999; }
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; }
td pre { margin: 0; }
pre, textarea { font: 100%/1.25 monospace; }
pre, textarea { font: 110%/1.25 monospace; }
pre.jush { background: #fff; }
pre code { display: block; font-size: 100%; }
input, textarea { box-sizing: border-box; }
input, select { vertical-align: middle; }
input[type="radio"] { vertical-align: text-bottom; }
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.required, input.maxlength { box-shadow: 1px 1px 1px red; }
input.wayoff { left: -1000px; position: absolute; }
.block { display: block; }
.version { color: #777; font-size: 62%; }
@@ -47,17 +50,16 @@ input.wayoff { left: -1000px; position: absolute; }
.date { color: #7F007F; }
.enum { color: #007F7F; }
.binary { color: red; }
.odds tbody tr:nth-child(2n) td { background: #F5F5F5; }
.odds tbody tr:nth-child(2n) { background: #F5F5F5; }
.js .checkable .checked td, .js .checkable .checked th { background: #ddf; }
.time { color: silver; font-size: 70%; }
.function { text-align: right; }
.number { text-align: right; }
.datetime { text-align: right; }
.type { width: 15ex; width: auto\9; }
.options select { width: 20ex; width: auto\9; }
.function, .number, .datetime { text-align: right; }
.type { width: 15ex; }
.options select, .options input { width: 20ex; }
.view { font-style: italic; }
.active { font-weight: bold; }
.sqlarea { width: 98%; }
.sql-footer { margin-bottom: 2.5em; }
.explain table { white-space: pre; }
.icon { width: 18px; height: 18px; background-color: navy; }
.icon:hover { background-color: red; }
@@ -98,7 +100,7 @@ input.wayoff { left: -1000px; position: absolute; }
@media all and (max-width: 880px) {
.pages { left: auto; }
.logout { position: static; padding: 0 1em 1em; }
.logout { position: static; padding: 1em; }
#menu { position: static; width: auto; }
#content { margin-left: 10px; }
#lang { position: static; }

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