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

Compare commits

..

516 Commits

Author SHA1 Message Date
Jakub Vrana
32955f7802 Release 4.7.3 2019-08-27 17:58:21 +02:00
Jakub Vrana
5ffec58a8f Fix blocking of concurrent instances in PHP >7.2 (bug #703) 2019-08-27 13:03:03 +02:00
František Hána
34a0bfd939 setup Mongo authSource by ENV 2019-08-22 09:43:46 +02:00
Jakub Vrana
b07908282b Reset table after changing DB 2019-08-21 15:09:47 +02:00
Jakub Vrana
bce0e8d54a Move <p> after a possible error 2019-08-21 15:05:02 +02:00
Jakub Vrana
c6fc6b63e8 Allow editing foreign keys pointing to tables in other database/schema (bug #694) 2019-08-21 15:00:11 +02:00
Jakub Vrana
03961bbe1b MS SQL: Support foreign keys to other DB 2019-08-21 14:33:17 +02:00
Jakub Vrana
f37a878b62 Do not display error for foreign keys to other databases 2019-08-21 14:19:48 +02:00
Jakub Vrana
021e3f900d Save bytes 2019-08-21 14:13:08 +02:00
Jakub Vokoun
3d32470b87 MSSQL: use textarea in edit form for Memo type (#357)
Signed-off-by: Jakub Vokoun <jakub.vokoun@gmail.com>
2019-08-21 13:13:16 +02:00
Jakub Vrana
f692b6498f MySQL: Support STORED GENERATED 2019-08-21 12:23:08 +02:00
Jakub Vrana
3b056fe308 SQLite: Skip renaming when recreating table if not necessary 2019-08-21 12:06:32 +02:00
Jakub Vrana
d6ec4ca0b3 SQLite: Preserve auto increment when recreating table 2019-08-21 11:54:07 +02:00
Jakub Vrana
903de0e889 SQLite: Allow setting auto increment for empty tables 2019-08-21 11:46:38 +02:00
Jakub Vrana
48f33f6255 Remove extra space in alter table command 2019-08-21 11:28:33 +02:00
Jakub Vrana
1b33729110 SQLite: Handle error in altering table (bug #697) 2019-08-21 11:21:17 +02:00
Troy Olson
788d383609 init mancave-hever design 2019-08-20 18:01:41 +02:00
Jakub Vrana
364e032b69 MySQL: Allow editing rows identified by negative floats (bug #695) 2019-08-20 17:58:54 +02:00
Troy Olson
b7641a2d13 added floating footer css for adminer-theme-mancave2-2.1.alpha 2019-08-20 17:42:23 +02:00
Jakub Vrana
5f4af56f68 Add a comment (bug #691) 2019-08-20 16:24:33 +02:00
Jakub Vrana
95a92ceb95 Use is_numeric() 2019-08-20 09:47:01 +02:00
Jakub Vrana
306e8733e7 Support MariaDB virtual columns 2019-08-19 18:38:57 +02:00
Jakub Vrana
67b84d1167 MySQL: Speed up displaying tables in large databases (bug #700) 2019-08-19 18:29:05 +02:00
Jakub Vrana
ab76024da7 Support unquoted floats in export 2019-08-19 17:18:56 +02:00
Jakub Vrana
4a27882a97 SQLite: Quote strings stored in integer columns in export (bug #696) 2019-08-19 17:14:27 +02:00
Malte Riesch
00d36efcf1 MySQL: Skip editing generated columns 2019-08-19 16:51:28 +02:00
Jakub Vrana
92d443dac0 Add AdminerLoginIp 2019-07-19 14:36:42 +02:00
Jakub Vrana
d71cb127cf Close </ul> of logins 2019-07-19 13:52:24 +02:00
Jakub Vrana
fd1691cb1d Release 4.7.2 2019-07-18 08:56:37 +02:00
Jakub Vrana
d5bf51b2a7 MySQL: Fix getting foreign keys 2019-07-18 08:50:52 +02:00
Jakub Vrana
b7b4157bcb Fix table status in PostgreSQL 12 (bug #683) 2019-07-15 13:37:10 +02:00
Jakub Vrana
10b00e13b1 Fix displaying SQL command after Save and continue edit 2019-07-15 13:16:24 +02:00
Jakub Vrana
45caae1660 PostgreSQL: Display definitions of materialized views (bug #682) 2019-07-15 13:03:57 +02:00
Michal Adamec
36e9a4d6e1 Support for viewing and editing of column comments in mssql driver 2019-07-15 12:45:39 +02:00
Jakub Vrana
9b58ecf925 PostgreSQL: Fix setting column comments on new table 2019-07-15 12:21:17 +02:00
Jakub Vrana
36ade4e197 MySQL: Fix displaying multi-columns foreign keys (bug #675) 2019-07-14 19:53:41 +02:00
grass@dionera.com
6a5b0abbb4 Check if PDO SSL Attributes are set within config, and only set them in PDO Options. otherwise Mysql PDO throws errors if attribute is set and empty 2019-07-14 19:20:13 +02:00
Bohuslav Simek
33234fef19 Elasticsearch: Show executed query as a json 2019-07-14 19:11:17 +02:00
Bohuslav Simek
4b6833ba65 MongoDB: number of records should be count on provide rows 2019-07-14 19:10:16 +02:00
Inge Brattaas
d846eac97e Keep font size in all tables.
Prevent CSS rule "table { font-size: 90% }" from making nested tables
unreadable.
2019-07-14 18:58:07 +02:00
Adam Žurek
0eab60c338 travis: test on php 5.6-7.3 (#330) 2019-07-14 17:22:32 +02:00
Jonathon Sim
7f32e26759 Cache busting for adminer.css 2019-05-18 17:29:33 +02:00
Dennis Stolmeijer
327041874e Always pass the SRID part of a geometry property with the GeomFromText function 2019-05-18 17:24:35 +02:00
Jakub Vrana
37a3dd6c6b Update rmsoft designs 2019-05-18 17:24:35 +02:00
Mario Wenzel
02f5cbdc4d Allow bruteForceKey to be overwritten (#342)
As per Documentation (https://www.adminer.org/en/extension/#api) bruteForceKey can be overwritten by plugins. This change actually allows for that to happen.
2019-05-14 10:49:52 +02:00
Jakub Vrana
deea21dd2d Allow overwriting tables when copying them 2019-05-14 09:56:29 +02:00
Jakub Vrana
f00f7a0e19 Update rmsoft design 2019-05-14 09:43:58 +02:00
Jakub Vrana
48292b70e8 Stretch footer over the whole table width (bug #624) 2019-05-14 09:31:51 +02:00
Jakub Vrana
15900301ee Do not attempt logging in without password (bug #676) 2019-05-14 09:07:51 +02:00
Jakub Vrana
0e6f1972e9 Fix typo in translation (bug #673) 2019-03-21 08:38:57 +01:00
Christoph Thelen
4e91550b14 missing translation DE
added missing translation for donation link
2019-01-29 10:02:39 +01:00
0x1793d1
333da64cdb Fix too small #lang margin on pepa-linha design 2019-01-28 13:55:21 +01:00
Jakub Vrana
a2ec51e948 Fix creating users and changing password in MySQL 8 (bug #663) 2019-01-28 13:47:53 +01:00
0x1793d1
d114535911 Fix #tables margin (#326) 2019-01-25 10:00:26 +01:00
Jakub Vrana
7247f801bd Release 4.7.1 2019-01-24 15:57:17 +01:00
Jakub Vrana
21f0481a1d Remember visible columns in Create Table form (bug #493) 2019-01-22 13:24:15 +01:00
Jakub Vrana
7defb7787d Editor: Allow disabling boolean fields in PostgreSQL (bug #640) 2019-01-22 12:04:08 +01:00
Jan
659003e07f fix: haeckel adminer.css (#323)
- fix: broken menu layout on Firefox 64+
 - add: option to hide "new version" link (commented out)
 - add: author credits for changes made in 2018
2019-01-22 10:39:52 +01:00
Jakub Vrana
2cb426b464 SQLite: Hide server field in login form 2019-01-16 14:57:21 +01:00
Jakub Vrana
2117f224b6 Improve MariaDB status variables link (bug #658) 2019-01-16 12:49:24 +01:00
popcorner
7ea6266482 Update zh-tw.inc.php 2019-01-16 12:26:58 +01:00
popcorner
edb79998a9 Update zh.inc.php 2019-01-16 12:26:58 +01:00
Jakub Vrana
41043f8dad Display the tables scrollbar (bug #647) 2019-01-16 12:16:51 +01:00
Jakub Vrana
31bbadb479 Document change 2018-12-18 16:20:34 +01:00
Tim Düsterhus
a2fbcbe28e Fix PHP 7.3 compatibility (#318) 2018-12-18 16:17:21 +01:00
Edgar Barrantes
a623cd69de Position of the background database image changed. (#316) 2018-12-18 16:07:53 +01:00
alekseymvt
ed346be313 Fix mvt theme (#315) 2018-12-18 15:52:43 +01:00
Peter Knut
7eaa57fc0b Use <ul> list for logins (#314) 2018-12-18 15:45:04 +01:00
Jakub Vrana
c275362c30 Add missing Japanese translations (thanks to Shirai Takashi) 2018-12-18 14:45:46 +01:00
Peter Knut
b2606cda0e Change '...' to horizontal ellipsis character 2018-12-18 14:45:37 +01:00
helix84
da76e6b9b8 php <5.4 compat: array syntax (#313) 2018-12-18 14:21:23 +01:00
Jakub Vrana
83fe083f2f Add autocomplete attributes to login form 2018-12-12 16:13:14 +01:00
Jakub Vrana
85e6f2ac9e Release 4.7.0 2018-11-24 14:13:01 +01:00
Jakub Vrana
e148db4b0f Fix whitespace 2018-11-24 12:16:12 +01:00
Jakub Vrana
660703e422 Clarify change description 2018-11-24 12:08:02 +01:00
Lucas Sandery
55f11df052 Updated theme for v4.7 (#310)
Signed-off-by: Lucas Sandery <lucas-sandery@users.noreply.github.com>
2018-11-24 11:09:47 +01:00
Winnie Lin
ea6370ef77 Update zh-tw.inc.php (#299)
Fix some typo and add white spaces for readability
2018-11-01 07:03:53 +01:00
Jakub Vrana
0ad6a1e578 Fix a typo 2018-10-29 11:46:04 +01:00
Jakub Vrana
e546b483a1 Delete copy/pasted code 2018-10-29 11:43:45 +01:00
Jakub Vrana
5b443a4e7d Change inline style to class name 2018-10-27 21:21:20 +02:00
kPherox
e4837a0564 Wrap table.nowrap with div[style="overflow-x: auto"] 2018-10-27 21:16:57 +02:00
Jakub Vrana
83a0776e8d Fix MariaDB link to numeric types 2018-10-27 20:13:55 +02:00
Jakub Vrana
5bebb439a1 MySQL: Descending indexes in MySQL 8 (bug #643) 2018-10-27 20:05:04 +02:00
sartor
9f0ee9cf41 PostgreSQL: Support for GENERATED BY DEFAULT AS IDENTITY 2018-10-27 19:42:01 +02:00
Jakub Vrana
c002009bfe Fix style 2018-10-27 19:38:43 +02:00
sartor
a592ad52f1 ClickHouse: support for decimal types, SQL operator 2018-10-27 19:32:52 +02:00
sartor
3127c0d95e ClickHouse: Fix for drop multiple tables and views 2018-10-27 19:32:10 +02:00
sartor
9447d97a6a ClickHouse ALTER DELETE and ALTER UPDATE support 2018-10-27 19:31:35 +02:00
sartor
c8e41ee649 ClickHouse fix select-like queries format postfix 2018-10-27 19:30:33 +02:00
Jakub Vrana
b327a76fc0 Avoid overwriting existing tables when copying tables (bug #642) 2018-10-27 18:50:50 +02:00
Jakub Vrana
7f2dd73670 PostgreSQL: Export DESC indexes (bug #639) 2018-10-27 18:14:00 +02:00
Jakub Vrana
c8975a151c Recognize current_timestamp() in edit (bug #638) 2018-10-27 18:06:20 +02:00
ilessiivi
150841e5d7 Hide import from server if no path 2018-10-01 18:07:51 +02:00
Jakub Vrana
ae03bdd4c4 Simplify storing executed SQL queries to bookmarks 2018-10-01 17:08:58 +02:00
alekseymvt
01e08cc053 fix editor theme (#302) 2018-09-19 16:42:22 +02:00
Jakub Vrana
a426fefd40 Remove unused code 2018-09-19 11:16:21 +02:00
Jakub Vrana
90df1b14f0 MySQL: Recognize ON UPDATE current_timestamp() (bug #632) 2018-09-19 10:08:41 +02:00
Jakub Vrana
cd3231b4af PostgreSQL: Quote array values in export (bug #621) 2018-09-19 09:49:56 +02:00
Christopher CHEN
65c52735fb Add plugin pretty-json-column
(cherry picked from commit 9b8612a49c43ff170837dbf84f8c08a0e85386a8)
2018-09-18 18:59:24 +02:00
Jakub Vrana
93ccc7502b Update translation 2018-09-18 15:47:22 +02:00
Christopher CHEN
84e86cf572 DOM not ready when restoring adminer_tables_filter (#289)
Uncaught TypeError: Cannot set property 'value' of null
2018-09-18 15:38:13 +02:00
Jakub Vrana
1ce5b5ad31 Add Georgian translation 2018-09-18 15:34:09 +02:00
Aleksey M
941bf22e52 Update mvt design 2018-09-18 13:40:58 +02:00
Jakub Vrana
a5c54563c6 Fix design (thanks to apmuthu) 2018-09-18 13:32:26 +02:00
Jakub Vrana
0234fe4a66 ClickHouse: Fix escaping 2018-09-18 13:13:34 +02:00
Sartor
1883e250ff ClickHouse support alpha version 2018-09-18 13:09:46 +02:00
Huy Cat, Hoang
56d8b89bee Fix typo in Vietnamese translation 2018-09-18 12:20:21 +02:00
Peter Knut
4d66e42817 Add class 'layout' to all non-data tables 2018-09-18 12:08:19 +02:00
harryxu
94f6a45a2a Set default db to sqlsrv connection 2018-09-18 11:44:02 +02:00
Jakub Vrana
0f08592bc0 Warn when using password with leading or trailing spaces 2018-09-13 16:08:57 +02:00
Jakub Vrana
a5cbad504c Update donation link 2018-09-06 17:22:56 +02:00
Jakub Vrana
d581f3dedb Make maxlength in all fields a soft limit 2018-07-15 21:05:26 +02:00
Jakub Vrana
e8e4934e97 Increase username maxlength to 80 (bug #623) 2018-07-15 21:01:38 +02:00
Jared Brandt
e959e46fa5 Fixes foreign key pattern in MySQL
Foreign keys are not displaying in MySQL when ANSI_QUOTES is enabled because the preg_match_all() is looking specifically for backticks. This fix allows for double quotes as well, so foreign keys are recognized even when ANSI_QUOTES is enabled.
2018-07-15 20:51:09 +02:00
Jakub Vrana
bb3d2957e1 Fix function change with set data type (thanks to osoba hrdelnata) 2018-07-15 20:37:47 +02:00
Aleksey M
ea408aa530 Adminer theme 2018-07-15 20:12:07 +02:00
Jakub Vrana
df90d9f68c Reset event handlers after cloning (thanks to Salko) 2018-07-15 20:10:13 +02:00
Jakub Vrana
cf76ad529b Fix inline editing of empty cells 2018-07-09 16:52:10 +02:00
Jakub Vrana
3d84dcf859 Release 4.6.3 2018-06-28 21:58:29 +02:00
Jakub Vrana
4b9d88545e Fix typo 2018-06-28 20:35:19 +02:00
Jakub Vrana
26a39ac243 Revert "PgSQL search operator "SQL" added"
This reverts commit af7ac6f06a.
2018-06-27 22:23:56 +02:00
Jakub Vrana
3676b7fb71 Add TODO 2018-06-27 08:55:19 +02:00
Jakub Vrana
c564a8ef50 MySQL: Disallow LOAD DATA LOCAL INFILE 2018-06-26 08:53:12 +02:00
Jakub Vrana
2780eb01f5 PostgreSQL: Export false as 0 in PDO (bug #619) 2018-06-09 12:45:17 +02:00
Gintautas Miselis
b98d0bcc55 mssql: ignore serverproperty error
This change allows connection to Sybase ASE 15
2018-06-09 12:25:24 +02:00
Jakub Vrana
e856e28892 Add spaces 2018-06-09 12:24:18 +02:00
Petr Sedlacek
8f269d66b0 Fix table list in sidebar in designs/pokorny (#278) 2018-06-09 12:23:15 +02:00
Peter Knut
3de94b67ca Allow AdminerTablesFilter plugin to be used with third-party table list plugins (#275) 2018-05-13 09:49:09 +02:00
Jakub Vrana
a9a7488454 Recommend inlining the hash 2018-05-07 12:23:13 +02:00
Jakub Vrana
36f13031f7 Improve error message 2018-05-07 12:22:52 +02:00
Jakub Vrana
6f25b1b5cf Escape \ in enum edit 2018-05-06 19:21:58 +02:00
Jakub Vrana
659c34f7c5 Improve enum parsing 2018-05-06 19:21:58 +02:00
Jakub Vrana
11f24a52e4 Order database names in MySQL 8(bug #613) 2018-05-06 18:11:03 +02:00
Franklin Tse
3c3d861f41 Respect 'session.cookie_secure' if it is On 2018-05-06 17:49:39 +02:00
Jakub Vrana
7b60b03e6a Copy triggers when copying table 2018-05-06 17:36:52 +02:00
Jakub Vrana
84c65fcca6 MS SQL: Support port with sqlsrc 2018-05-06 11:46:36 +02:00
Jakub Vrana
733fe9e430 PostgreSQL: Do not cast uuid searches to text (bug #608) 2018-05-06 11:41:59 +02:00
Jakub Vrana
5c3fb875e1 Editor: Do not check boolean checkboxes with false in PostgreSQL (bug #607) 2018-05-06 11:26:43 +02:00
Jakub Vrana
60d1b7b3b4 Disallow using password-less databases 2018-05-04 16:52:41 +02:00
Jakub Vrana
db11fa4c1a MongoDB: Consolidate code 2018-05-04 16:39:21 +02:00
Jakub Vrana
c3cfc0e69b MongoDB: Consolidate code 2018-05-04 16:38:24 +02:00
Jakub Vrana
5f4d407f2e MongoDB: Consolidate code 2018-05-04 16:37:36 +02:00
Jakub Vrana
70afe70b72 MongoDB: Report version 2018-05-04 15:37:29 +02:00
Jakub Vrana
75f43a4454 Document that Elasticsearch requires allow_url_fopen 2018-05-04 15:26:57 +02:00
Matěj Humpál
78f4513d9d PostgreSQL: Do not cast boolean to text on search (#264) 2018-03-18 14:34:54 +01:00
Jakub Vrana
89c66ccabe PostgreSQL: Do not cast number searches to text 2018-03-13 14:09:53 +01:00
Jakub Vrana
6ba77b7899 PostgreSQL: Fix editing data in views (bug #605) 2018-03-11 16:41:04 +01:00
Jakub Vrana
d271d0b481 Elasticsearch: Fix PHP warning 2018-03-11 16:07:54 +01:00
Sartor
af7ac6f06a PgSQL search operator "SQL" added 2018-03-11 15:48:42 +01:00
Jakub Vrana
19034c35fe PostgreSQL: Fix slow query 2018-03-10 17:16:07 +01:00
Jakub Vrana
88438cd607 Update JUSH 2018-03-10 17:15:55 +01:00
Jakub Vrana
34c792bb59 Display that *.gz files are supported in file upload 2018-03-09 18:21:44 +01:00
Jakub Vrana
6ed94f1f6d Save bytes 2018-03-09 18:19:14 +01:00
Jakub Vrana
8c4726bb61 Stay on import page when switching database 2018-03-09 18:19:14 +01:00
Jakub Vrana
8ab2c7e03b Decrease timeout for running slow queries from 5 seconds to 2 seconds 2018-03-09 18:19:14 +01:00
Jakub Vrana
665fafb297 Simplify running slow queries 2018-03-09 18:19:14 +01:00
Jakub Vrana
67c2a91c67 Remove unused argument 2018-03-09 18:19:14 +01:00
Jakub Vrana
78b8707bd0 Update JUSH 2018-03-09 18:19:14 +01:00
Jakub Vrana
7c15940be8 Use JUSH from GitHub 2018-03-02 09:38:58 +01:00
Jakub Vrana
8c5603a822 Clarify changelog 2018-03-01 13:08:58 +01:00
Jakub Vrana
4e7c31a589 Display missing database in navigation 2018-03-01 12:09:10 +01:00
David Sinquin
cf9cad66e2 MongoDB driver: Add create_database methods.
MongoDB databases are created on the fly when some data is written in
the database, so this method does not need to do anything.
2018-03-01 11:48:02 +01:00
Jakub Vrana
26a3967cf9 Fix comment 2018-03-01 11:46:23 +01:00
Pero Brbora
6c63c2f91e Add $driver to global variables 2018-03-01 11:46:12 +01:00
Pero Brbora
acee5c0011 Add $driver to global variables 2018-03-01 11:30:13 +01:00
Jakub Vrana
36b75b4203 Use $adminer->operators 2018-03-01 11:29:04 +01:00
Jakub Vrana
4a24ee7672 PostgreSQL: Do not cast time search 2018-03-01 11:23:01 +01:00
Matěj Humpál
e21ddd9767 Do not cast date/timestamp exact searches in PostgreSQL to text 2018-03-01 11:21:50 +01:00
Matěj Humpál
f844fc499e Do not cast date/timestamp exact searches in PostgreSQL to text 2018-03-01 11:06:12 +01:00
Jakub Vrana
52d7c38ef1 MySQL: Use CONVERT() only when searching for non-ASCII (bug #603) 2018-03-01 11:01:35 +01:00
Jakub Vrana
53dd78f5af Remove optional submodule 2018-03-01 09:54:20 +01:00
Róbert Mesároš
ea1dad584b Update adminer-design (rmsoft) to version 4.6.2.1 2018-02-23 08:12:11 +01:00
Jakub Vrana
910bb39424 Wrap lines 2018-02-23 08:09:21 +01:00
Jakub Vrana
14db884471 Fix displaying info about non-alphabetical objects (bug #599) 2018-02-22 16:47:30 +01:00
Jakub Vrana
3410836c12 Allow connecting to different drivers in login-servers 2018-02-22 12:38:22 +01:00
Jakub Vrana
cd503f6a0d Wrap long line 2018-02-22 11:39:09 +01:00
Jakub Vrana
00721402e0 Add login-otp plugin 2018-02-22 11:36:11 +01:00
Jakub Vrana
4355aaa96f Update translation 2018-02-21 21:36:55 +01:00
Jakub Vrana
b1cdc7902b Comment 2018-02-21 00:28:59 +01:00
Jakub Vrana
3f4f3454f8 Centralize stopping session 2018-02-20 23:14:36 +01:00
Jakub Vrana
846435aef8 Stop session before connecting (thanks to Kareem Zidane) 2018-02-20 23:11:05 +01:00
Jakub Vrana
d7982e0b29 Update design (thanks to Jan) 2018-02-20 22:44:10 +01:00
Jakub Vrana
7b35ebd82e PDO: Support binary fields download 2018-02-20 22:40:20 +01:00
Jakub Vrana
5b359263eb Don't try to check missing checkboxes 2018-02-20 22:09:47 +01:00
Jakub Vrana
6ebbd8c719 Use file caching only in non-dev 2018-02-20 22:08:52 +01:00
Jakub Vrana
8bb51bec36 Editor: Delete images from compiled version 2018-02-20 16:53:53 +01:00
Jakub Vrana
fc5ddddf92 Remove driver from file URLs (stored in path) 2018-02-20 16:40:14 +01:00
Jakub Vrana
d3a429314a Fix image in compiled version 2018-02-20 16:35:34 +01:00
Jakub Vrana
b4392b3f91 Use single \ in ' strings 2018-02-20 16:27:40 +01:00
Jakub Vrana
2021ea8fd7 &nbsp; is not needed with border-collapse 2018-02-20 16:02:25 +01:00
Jakub Vrana
7cb3e768bb Release 4.6.2 2018-02-20 09:20:42 +01:00
Jakub Vrana
baf7225602 Fix test 2018-02-20 09:17:13 +01:00
Jakub Vrana
0cfc68e6c6 Fix typo 2018-02-20 00:00:47 +01:00
Jakub Vrana
03dfea2943 Comment 2018-02-20 00:00:00 +01:00
Jakub Vrana
54f6806339 Use function after declaring it 2018-02-19 23:48:51 +01:00
Jakub Vrana
ee4f7db641 Remove test server 2018-02-19 23:38:32 +01:00
Jakub Vrana
b53762ae5f Make test works with MariaDB 2018-02-19 23:37:19 +01:00
Jakub Vrana
866d109a9b Make test work on wide screen 2018-02-19 23:25:43 +01:00
Jakub Vrana
37c57c386a Editor: Fix displaying of true boolean values 2018-02-19 23:09:46 +01:00
Jakub Vrana
1f5ca321b6 Comment 2018-02-19 23:04:27 +01:00
Jakub Vrana
059d6266e2 Store current version before authentication and in Editor 2018-02-19 23:02:39 +01:00
Jakub Vrana
0e1d8c67fc Update design (thanks to Jan) 2018-02-19 14:07:11 +01:00
Jakub Vrana
a113a25123 Add missing fullstop 2018-02-15 22:25:45 +01:00
Róbert Mesároš
49a865d106 Version 4.6.1.1 (#254)
Update to Version 4.6.1.1
2018-02-15 22:25:16 +01:00
Nuri Akman
026b362e7d Turkish language file updated. 2018-02-15 22:20:58 +01:00
Jakub Vrana
7c32360c67 Align Whole result 2018-02-14 06:46:59 +01:00
Jakub Vrana
8a94bc6f41 Always hide import 2018-02-14 06:42:07 +01:00
Jakub Vrana
3f901cfe30 Print email only with rows or page 2018-02-14 06:41:44 +01:00
Jakub Vrana
c8fd73d70a Move import out of footer 2018-02-13 22:24:59 +01:00
Jakub Vrana
30d0060b96 Move pagination to fieldset 2018-02-13 22:17:59 +01:00
Jakub Vrana
8b157a673e Update readme 2018-02-10 01:58:14 +01:00
Jakub Vrana
ce381aaf48 Make Login test work with jush-textarea 2018-02-10 01:56:48 +01:00
Jakub Vrana
d3eac979d4 Add SQLite test 2018-02-10 01:51:03 +01:00
Jakub Vrana
f19e23c98b Test warnings 2018-02-10 01:47:29 +01:00
Jakub Vrana
705d3a910f Convert tests to Katalon 2018-02-10 01:24:14 +01:00
Jakub Vrana
d18c7b3587 Promote MongoDB, demote Oracle and MS SQL 2018-02-10 00:09:07 +01:00
Jakub Vrana
1f12ea4e4a Capitalize Whole result 2018-02-09 23:45:53 +01:00
Jakub Vrana
71a6a1269d Fill footer to the right 2018-02-09 23:36:53 +01:00
Jakub Vrana
6a3bce1174 Make footer smaller 2018-02-09 23:33:46 +01:00
Jakub Vrana
28acee861f Move pagination outside footer 2018-02-09 23:28:19 +01:00
Jakub Vrana
42b15654c4 Wrap more into if (!is_ajax) 2018-02-09 23:09:05 +01:00
Jakub Vrana
e2d858d638 Move <p> 2018-02-09 23:05:21 +01:00
Jakub Vrana
879963dec1 PostgreSQL: Add IF EXISTS to DROP SEQUENCE in export (bug #595) 2018-02-09 22:11:27 +01:00
Jakub Vrana
daa19b0a6e Make footer border more obvious 2018-02-09 22:05:11 +01:00
Jakub Vrana
d27ee7a388 Make footer margin not transparent 2018-02-09 21:55:18 +01:00
Jakub Vrana
1ec4637ade Centralize oninput 2018-02-09 21:23:42 +01:00
Jakub Vrana
ea1ff7e902 Speed up alter table
Alter table mysql.user takes 0.9 instead of 1.5 seconds.
2018-02-09 21:11:12 +01:00
Jakub Vrana
2761f44cf4 Use Unicode arrows in alt 2018-02-09 17:54:52 +01:00
Jakub Vrana
557b8b178e Avoid hiding column only to show it later 2018-02-09 17:50:25 +01:00
Jakub Vrana
07d1bc4291 Respect unchecked Default values 2018-02-09 17:45:50 +01:00
Jakub Vrana
7ac96dd0b2 Update UI when coming from history 2018-02-09 17:35:17 +01:00
Jakub Vrana
eeb7ce1939 PostgreSQL: Fix exporting string default values (thanks to PotatoPangolin) 2018-02-09 15:29:54 +01:00
Jakub Vrana
ea4ac5c8f3 Semi-transparent border on table actions 2018-02-09 15:14:10 +01:00
Jakub Vrana
3906231dc5 Fix exporting sequences in PostgreSQL 10 2018-02-09 14:43:25 +01:00
Jakub Vrana
fad20d1065 Do not append empty values 2018-02-09 13:48:50 +01:00
Jakub Vrana
ffb4ee3a61 Shorten JSON values in select (bug #594) 2018-02-09 13:48:33 +01:00
Jakub Vrana
34d338b185 Fix id in databases list 2018-02-09 13:34:46 +01:00
Jakub Vrana
1b148bc08c Suggest updating Git submodules 2018-02-09 11:09:49 +01:00
Jakub Vrana
f4983dfd5f Declare MariaDB support 2018-02-09 09:24:12 +01:00
Jakub Vrana
800fbb9b9e Release 4.6.1 2018-02-09 00:20:58 +01:00
Jakub Vrana
4b1960f498 Round 9.2 to 9.2 2018-02-08 23:58:09 +01:00
Jakub Vrana
e299e9d82d MariaDB: Links to documentation in syntax highlighting 2018-02-08 23:47:16 +01:00
Jakub Vrana
cf7fe88990 Display notification about performing action after relogin 2018-02-08 16:49:56 +01:00
Jakub Vrana
60e5d24116 Reorder changes 2018-02-08 14:34:43 +01:00
Jakub Vrana
a1927d5b71 Allow specifying server name displayed in breadcrumbs 2018-02-08 14:32:21 +01:00
Jakub Vrana
76d7560d27 MariaDB: Links to documentation 2018-02-08 13:56:22 +01:00
Jakub Vrana
f0b7d8ccd0 Reorder changes 2018-02-08 12:10:37 +01:00
Jakub Vrana
d322e0165b Remove .lcZ from timeFormat (bug #593) 2018-02-08 11:52:11 +01:00
Jakub Vrana
4009ede3ee Add todo 2018-02-08 11:26:21 +01:00
Jakub Vrana
cddd61c214 Add more system tables help links 2018-02-08 11:21:33 +01:00
Jakub Vrana
8b8cfd9f04 Respect empty tableName in tablesPrint 2018-02-08 10:35:54 +01:00
Jakub Vrana
99d7b88341 Use tableName() in table.inc.php 2018-02-08 10:34:43 +01:00
Jakub Vrana
2db1c74310 Avoid qsl in a loop 2018-02-08 09:52:23 +01:00
Jakub Vrana
fb2d34f739 Support Shift+click in server export 2018-02-08 09:47:15 +01:00
Jakub Vrana
6e2f681faa Avoid qsl in a loop 2018-02-08 09:30:16 +01:00
Jakub Vrana
686865bc10 Sticky position of table actions 2018-02-08 00:14:32 +01:00
Jakub Vrana
996ebf61d7 Document regression 2018-02-07 21:08:24 +01:00
Jakub Vrana
6a7ee5a2f3 Avoid qsl in check[]
Table with 1000 rows rendered in 1.8 instead of 7.5 seconds.
2018-02-07 18:55:28 +01:00
Jakub Vrana
4b45722fad Avoid qsl in a loop
Table with 500 rows rendered in 1.5 instead of 5.5 seconds.
2018-02-07 18:55:16 +01:00
Jakub Vrana
14998e12b6 Mark optional parameter 2018-02-07 18:14:00 +01:00
Jakub Vrana
718f9d3791 SQLite: Support ` in PRIMARY KEY 2018-02-07 16:43:21 +01:00
Jakub Vrana
964a988fef Avoid Invalid credentials with no credentials 2018-02-07 16:29:57 +01:00
Jakub Vrana
66e7ec56bb SQLite: Allow deleting PRIMARY KEY from tables with auto increment 2018-02-07 14:47:29 +01:00
Jakub Vrana
ca336427f5 Do not wrap alter table thead 2018-02-07 14:22:58 +01:00
Jakub Vrana
8a75cbc630 Add version() to use in plugins 2018-02-07 12:49:53 +01:00
Jakub Vrana
c8bb112a5d Select original if nothing else is selected 2018-02-07 12:46:43 +01:00
Jakub Vrana
06660882b5 Remove nested array 2018-02-07 12:42:46 +01:00
Jakub Vrana
42eec7d728 Support connecting to MySQL via SSL 2018-02-07 12:13:58 +01:00
Jakub Vrana
cac523402a Display Invalid credentials if connection error is empty 2018-02-07 11:37:53 +01:00
Jakub Vrana
02cd416093 Delete unused functions 2018-02-06 16:33:47 +01:00
Jakub Vrana
33f0023d37 Ignore functions in Min_Driver 2018-02-06 16:32:56 +01:00
Jakub Vrana
f09d26a51d Remove unnecessary quotes 2018-02-06 16:25:58 +01:00
Jakub Vrana
b500a46f9a Add truncate_sql to PostgreSQL 2018-02-06 16:24:12 +01:00
Jakub Vrana
19653de764 PostgreSQL: Unescape bytea fields 2018-02-06 16:05:50 +01:00
Jakub Vrana
29c127e94a Save bytes 2018-02-06 15:54:19 +01:00
Jakub Vrana
4417a8b220 Add missing function to compile.php 2018-02-06 15:52:48 +01:00
Jakub Vrana
17b110f0d5 PostgreSQL: Upload binary files to bytea fields 2018-02-06 15:42:14 +01:00
Jakub Vrana
b649fb2f3f Allow using number_type() as pattern 2018-02-06 14:52:12 +01:00
Jakub Vrana
d3914ea58e Translate thousands separator in JS 2018-02-06 14:47:43 +01:00
Jakub Vrana
31d8803db2 Editor: Use type=search for Search tables 2018-02-06 14:13:51 +01:00
Jakub Vrana
d43b773214 Move tableCheck() below </form> 2018-02-06 13:53:15 +01:00
Jakub Vrana
f09a04ed09 Pass operator from db.inc.php 2018-02-06 13:51:56 +01:00
Jakub Vrana
d7f9b6b5de PostgreSQL: Cast to string when searching using LIKE (bug #325) 2018-02-06 13:51:53 +01:00
Jakub Vrana
197abdcb70 MySQL: Support non-utf8 charset in search in column 2018-02-06 13:51:23 +01:00
Jakub Vrana
c2de3b8ec1 Use ST_GeomFromText in MySQL 8 (bug #574) 2018-02-06 13:50:40 +01:00
Jakub Vrana
c52fb951b0 Do not modify $_GET["where"] 2018-02-06 13:00:17 +01:00
Jakub Vrana
14429ff355 Display empty operator as LIKE %% 2018-02-06 12:56:18 +01:00
Jakub Vrana
a7632fd9fd Fix whitespace 2018-02-06 12:50:44 +01:00
Jakub Vrana
967d5c64a3 Avoid deprecated each() 2018-02-06 12:49:39 +01:00
Jakub Vrana
c34ada5368 PostgreSQL: Fix condition for selecting no rows 2018-02-06 12:43:10 +01:00
Jakub Vrana
2d7bda4d1e Fix error display in Search tables 2018-02-06 12:40:28 +01:00
Jakub Vrana
6cfb3676a7 PostgreSQL: Don't treat interval type as number (bug #474) 2018-02-06 12:17:01 +01:00
Jakub Vrana
11a7fc0277 Pass required parameter 2018-02-06 12:00:22 +01:00
Jakub Vrana
de539cf0c7 Use existing variable 2018-02-06 11:57:02 +01:00
Jakub Vrana
880902da17 Add class to use in designs 2018-02-06 08:47:28 +01:00
Jakub Vrana
89ceb06208 Use primary key instead of LIMIT 1 if available 2018-02-05 11:21:19 +01:00
Jakub Vrana
d2ed0f7810 Release 4.6.0 2018-02-05 09:30:33 +01:00
Jakub Vrana
7b0c58af32 Fix affected rows after getting warnings 2018-02-05 09:23:07 +01:00
Jakub Vrana
d3cdfc17de Fix number of affected rows after getting warnings 2018-02-05 09:09:41 +01:00
Jakub Vrana
f097817386 Fix test 2018-02-05 08:43:31 +01:00
Jakub Vrana
3b55c4c0f7 Fix 5.1 being displayed as 5.09999... 2018-02-05 08:42:25 +01:00
Jakub Vrana
6636434378 PRIMARY KEY in SQLite 2018-02-05 08:32:51 +01:00
Jakub Vrana
dd3e57086b Add design Esterka 2018-02-02 09:18:38 +01:00
Jakub Vrana
473b60361b Disable autocompleting password on create user page 2018-02-02 08:52:15 +01:00
Jakub Vrana
f128c2d1ea Use primary key to edit rows even if not selected 2018-02-01 23:09:40 +01:00
Jakub Vrana
c75096f173 Space between DB and Use 2018-02-01 22:22:29 +01:00
Jakub Vrana
c0b2c506bc Translate DB 2018-02-01 22:20:56 +01:00
Jakub Vrana
0ebf710d41 Select converted fields only once 2018-02-01 22:03:48 +01:00
Jakub Vrana
fa41126c37 Don't count rows if we reached the end 2018-02-01 20:59:05 +01:00
Jakub Vrana
09920e0056 Fix count_rows with more than one group by column 2018-02-01 20:45:49 +01:00
Jakub Vrana
685bf29abc Use separator in limit1 2018-02-01 18:53:53 +01:00
Jakub Vrana
0866c79afb SQLite: Limit rows in data manipulation without unique key 2018-02-01 18:47:57 +01:00
Jakub Vrana
e8e3ced948 Document that tests don't work with oninput 2018-02-01 17:04:50 +01:00
Jakub Vrana
52d98e16fa PostgreSQL: Limit rows in data manipulation without unique key 2018-02-01 16:58:01 +01:00
Jakub Vrana
763e66a148 Don't use ctid as it's not stable 2018-02-01 16:45:31 +01:00
Jakub Vrana
8868b48e4c Move variables close to their usage 2018-02-01 16:40:58 +01:00
Jakub Vrana
4961588f7d Limit non-unique where updates 2018-02-01 16:25:30 +01:00
Jakub Vrana
f4625da53d Use Oid as the name of the column 2018-02-01 16:15:36 +01:00
Jakub Vrana
dc94b2ec38 Save bytes 2018-02-01 16:00:40 +01:00
Jakub Vrana
f8af8c9cbf Update rmsoft design 2018-02-01 15:38:15 +01:00
Jakub Vrana
e55f0d7cb2 MySQL: Add FIND_IN_SET search operator 2018-02-01 15:25:38 +01:00
Jakub Vrana
5b7f2d9086 Add rmsoft design 2018-02-01 14:54:18 +01:00
Jakub Vrana
6d55395d9e MySQL: Add floor and ceil functions 2018-02-01 14:32:01 +01:00
Jakub Vrana
2e6190fdf1 Fix links to PostgreSQL 10 documentation 2018-02-01 14:02:25 +01:00
Jakub Vrana
b9ad864b75 Delete unused variable 2018-02-01 13:57:46 +01:00
Jakub Vrana
7296f017fb Display options for timestamp columns when creating a new table (thanks to Robert Vlach) 2018-02-01 13:55:11 +01:00
Jakub Vrana
ae91088cb3 Don't display warnings for failed queries 2018-02-01 13:16:37 +01:00
Jakub Vrana
51a574926d Fix variable name 2018-02-01 13:08:28 +01:00
Jakub Vrana
532a4ee083 Reorder variables 2018-02-01 12:27:22 +01:00
Jakub Vrana
6b9c0dee14 Use pg_last_notice only with pgsql 2018-02-01 12:03:11 +01:00
Jakub Vrana
be75939344 Print warnings in call 2018-02-01 11:58:04 +01:00
Jakub Vrana
d667f585e0 Pass start time to selectQuery 2018-02-01 11:54:56 +01:00
Jakub Vrana
ebb23a7a88 PostgreSQL: Display warnings 2018-02-01 11:50:15 +01:00
Jakub Vrana
e9add6d985 Return string from warnings() 2018-02-01 11:43:44 +01:00
Jakub Vrana
e3346fb0bc Display warnings in messages 2018-02-01 09:21:50 +01:00
Jakub Vrana
ae2ea56681 Show select warnings 2018-02-01 08:59:46 +01:00
Colin Mollenhour
080fd0f374 Support X-Forwarded-Prefix (e.g. Traefik PathPrefixStrip feature) 2018-01-31 20:38:14 +01:00
Jakub Vrana
e32f90f8ff Lowercase EXPLAIN but don't translate it 2018-01-31 20:25:41 +01:00
Jakub Vrana
7ad09d2cb4 Move explain below warnings 2018-01-31 20:25:11 +01:00
Jakub Vrana
40038d4210 Fix return type 2018-01-31 18:29:01 +01:00
Jakub Vrana
2adc174541 MySQL: Display warnings in SQL command 2018-01-31 17:28:12 +01:00
Jakub Vrana
2fb2d208c0 Quote default values not starting with a letter 2018-01-31 16:46:50 +01:00
Jakub Vrana
4de6e3180d Stop redirecting links via adminer.org 2018-01-31 11:11:34 +01:00
Jakub Vrana
8829ccdf93 Fix min_version use 2018-01-30 23:53:04 +01:00
Jakub Vrana
0320bcdda6 Quote dates in default value 2018-01-30 17:00:34 +01:00
Jakub Vrana
851700516d Fully support functions in default values 2018-01-30 16:50:37 +01:00
Jakub Vrana
d542843fdd Fix min_version use 2018-01-30 16:42:13 +01:00
Jakub Vrana
4bb2f806b1 PostgreSQL: Allow now() as default value (bug #525) 2018-01-30 16:24:31 +01:00
Jakub Vrana
cc31a69b65 Fix edit_type after 1f21cd43 2018-01-30 16:21:04 +01:00
Jakub Vrana
78f0a1152e PostgreSQL: Allow editing views with uppercase letters (bug #467) 2018-01-30 16:03:13 +01:00
Jakub Vrana
1f21cd4329 PostgreSQL: Allow creating trigger functions 2018-01-30 15:55:50 +01:00
Jakub Vrana
9f69160797 Add placeholders 2018-01-30 15:24:01 +01:00
Jakub Vrana
e81334ef87 PostgreSQL: Support functions 2018-01-30 15:18:26 +01:00
Jakub Vrana
6c3e1e2768 Add min_version to compile.php 2018-01-30 14:47:22 +01:00
Jakub Vrana
92739f48ce SimpleDB: Document that allow_url_fopen is required (bug #340) 2018-01-30 13:19:21 +01:00
Jakub Vrana
d28d01e76c Focus correct field in selectSearch 2018-01-29 21:19:11 +01:00
Jakub Vrana
75450548b3 Support JSON since MariaDB 10.2 (bug #590) 2018-01-29 21:08:38 +01:00
Jakub Vrana
c3b4208853 Use min_version 2018-01-29 20:54:24 +01:00
Jakub Vrana
d38c673e2a Add min_version 2018-01-29 19:34:26 +01:00
Jakub Vrana
93686eab65 Save bytes 2018-01-29 18:33:26 +01:00
Pisyek
224ddb5a33 add malay translation 2018-01-29 18:25:58 +01:00
Radosław Kowalewski
4db23fd471 Added and translated missing keys in polish translation 2018-01-29 18:13:50 +01:00
Steven Adger
a003866a55 Update compatibility with TinyMCE v4 (#247) 2018-01-29 18:09:35 +01:00
Jakub Vrana
0d90f1f1dd Fix elastic after ef5a7639 2018-01-27 11:08:56 +01:00
helix84
ef5a76392d fix elastic.inc.php to work on PHP 5.2
Without this change, I get the following syntax error on PHP 5.2.6:
PHP Parse error:  syntax error, unexpected ':' in /var/www/adminer/adminer/drivers/elastic.inc.php on line 415

I haven't actually tested the alter_table() method.
2018-01-26 16:48:34 +01:00
Jakub Vrana
8d0cbb6eb4 Fix counting selected rows after going back to select page 2018-01-26 08:52:12 +01:00
Jakub Vrana
536999d4dc Release 4.5.0 2018-01-24 21:55:47 +01:00
Jakub Vrana
827a2b8a54 Fix tests after 95d02bb9 2018-01-24 20:52:44 +01:00
Jakub Vrana
a954f7d4b4 Simplify drop object confirmation questions 2018-01-24 18:36:19 +01:00
Jakub Vrana
a137f248f7 Translate message added in 4.4.0 2018-01-24 18:22:20 +01:00
Jakub Vrana
95d02bb924 Display name of the object in confirmation when dropping it 2018-01-24 18:13:05 +01:00
Jakub Vrana
921e57b9aa Display error when getting row to edit 2018-01-24 17:37:35 +01:00
Jakub Vrana
25f9655a38 Avoid CONVERT() except in MySQL (bug #509) 2018-01-24 17:37:14 +01:00
Jakub Vrana
919204dd38 Bump version 2018-01-24 16:51:53 +01:00
Jakub Vrana
34f25afe90 MySQL: Support routines with comments in parameters (bug #460) 2018-01-24 16:37:38 +01:00
Jakub Vrana
8b29ae910f Verify if adminer.version was created on www.adminer.org 2018-01-24 15:10:44 +01:00
Jakub Vrana
6c96b060e7 Store current Adminer version server-side to avoid excessive requests 2018-01-24 15:09:11 +01:00
Jakub Vrana
f4662d5e27 Send token as last param 2018-01-24 13:44:31 +01:00
Jakub Vrana
b15618fcfd Allow using adminer.invalid by other users in a group 2018-01-24 12:11:26 +01:00
Jakub Vrana
03e3f517a8 Extract file_open_lock and file_write_unlock 2018-01-24 12:04:53 +01:00
Jakub Vrana
f0d2af329a Display boolean values as code (bug #562) 2018-01-24 10:53:25 +01:00
Jakub Vrana
452b9ad7f1 MariaDB: Support fulltext and spatial indexes in InnoDB (bug #583) 2018-01-24 09:18:19 +01:00
Jakub Vrana
fb18e814de PostgreSQL: Display foreign tables (bug #576) 2018-01-23 15:03:53 +01:00
Jakub Vrana
75413c56d2 Add designs.php 2018-01-23 14:36:32 +01:00
Jakub Vrana
c3d83d5412 Fix compiled version after 5cc831c1 2018-01-23 14:10:21 +01:00
Jakub Vrana
b14aa75a98 Hide window.opener from pages opened in a new window (bug #561) 2018-01-23 12:53:22 +01:00
Jakub Vrana
dbc76a2b1e Fix GPL version 2018-01-23 12:21:42 +01:00
Jakub Vrana
6d774794c8 Add plugin for switching designs 2018-01-23 12:15:38 +01:00
Jakub Vrana
81be5edb97 Display bold parts of error (bug #565) 2018-01-23 11:16:28 +01:00
Jakub Vrana
e30e5dd059 Add bottom border to last cells 2018-01-23 11:11:41 +01:00
Jakub Vrana
0cdd8beab1 Editor: Fix displaying of false values in PostgreSQL (bug #568) 2018-01-23 11:02:15 +01:00
Jakub Vrana
7b9d5a29aa Decrease float precision (bug #578) 2018-01-23 10:52:57 +01:00
Andrea Giacobino
5cc831c1e1 Add ability to override file name (path) when loading dump from webserver 2018-01-23 09:24:57 +01:00
Jakub Vrana
72aa3c5127 Support current_timestamp() as default of time fields (bug #572) 2018-01-23 08:36:11 +01:00
Jakub Vrana
43ccfcef8f Display newlines in column comments (bug #573) 2018-01-22 21:05:56 +01:00
Jakub Vrana
c789c147b7 MySQL: Support geometry in MySQL 8 (bug #574) 2018-01-22 20:56:35 +01:00
Uherkovich Péter
a2adb67d2f MSSQL driver fixed for freetds drivers. See bug #167, #291 2018-01-22 18:35:08 +01:00
Jakub Vrana
34e2f47761 Fix search focus (regression from 4.4.0) 2018-01-22 18:34:16 +01:00
Jakub Vrana
0d2b232bd7 Compatibility with PHP < 5.3 2018-01-22 17:30:12 +01:00
Jakub Vrana
83e16e059f Add mongodb as a possible driver 2018-01-22 17:12:48 +01:00
Jakub Vrana
6e4dc3911f Save bytes 2018-01-22 17:05:49 +01:00
Vladimir Goncharov
2a08a11e89 php7 support with minimal changes of original code 2018-01-22 16:59:55 +01:00
Jakub Vrana
993dce398d PostgreSQL: Export DROP SEQUENCE if dropping table 2018-01-22 14:33:21 +01:00
Jakub Vrana
eee9a62c8f PostgreSQL: Do not export triggers if not requested 2018-01-22 14:25:27 +01:00
Jakub Vrana
ce17b6cf46 Ignore removed CREATE+ALTER mode in trigger_sql() 2018-01-22 14:14:42 +01:00
Jakub Vrana
923c0ffc87 Fix whitespace 2018-01-22 13:51:47 +01:00
Jakub Vrana
48ed20323f CSP: Allow any CSS 2018-01-22 12:22:25 +01:00
Troy
9a4cd8936d adminer-theme-mancave2-2.0.alpha 2018-01-22 12:20:33 +01:00
Jáchym Toušek
019ada8da5 Fix NULL value in edit form with Postgres 2018-01-22 12:06:15 +01:00
Jakub Vrana
6a95b71164 Do not warn about MySQL specific functions 2018-01-22 12:00:38 +01:00
Jakub Vrana
3b4ce4a0b4 Fix single driver non-MySQL compiled versions (regression from 150301ed) 2018-01-22 11:42:17 +01:00
Jakub Vrana
a414896885 Hide driver selection in single-driver version (regression from e762a6aa) 2018-01-22 11:34:25 +01:00
Peter Knut
47734d8ff4 Unify HTML for list of tables in Editor according to Adminer 2018-01-22 10:57:20 +01:00
Peter Knut
fef1808288 Encapsulate fulltext part in search box into <div> 2018-01-22 10:53:50 +01:00
Fabio Montefuscolo
d2c82fdeca Enhance ElasticSearch integration 2018-01-19 18:32:41 +01:00
Jakub Vrana
e657cdbc3a Allow PHP 5.6 in Travis 2018-01-19 18:20:02 +01:00
Jakub Vrana
bc14e8432f Select numeric database name in DB list (bug #580) 2018-01-19 17:39:27 +01:00
Jakub Vrana
34b03ef835 SQLite: Enable foreign key checks 2018-01-19 14:57:58 +01:00
Jakub Vrana
329b7de9cc CSP: Allow any images, media and fonts, disallow base-uri 2018-01-19 11:05:26 +01:00
Jakub Vrana
2dcad1f284 Define JS functions in AdminerTablesFilter sooner 2018-01-19 10:55:51 +01:00
Jakub Vrana
1b98a10100 Adminer: Fix Search data in tables 2018-01-19 10:46:35 +01:00
Jakub Vrana
187dd56b1c Release 4.4.0 2018-01-17 12:41:38 +01:00
Jakub Vrana
ba9099f084 Allow sending multiple CSP headers 2018-01-17 11:05:59 +01:00
Jakub Vrana
16e05167a4 Use __construct for constructor 2018-01-16 20:05:07 +01:00
Jakub Vrana
756e304c92 Set session cache limiter only without session.auto_start (bug #586) 2018-01-16 16:56:14 +01:00
Jakub Vrana
e762a6aa95 Add missing newline 2018-01-16 16:44:49 +01:00
Jakub Vrana
b3d5c9affe Require specifying credentials in login-sqlite plugin 2018-01-16 16:37:59 +01:00
Jakub Vrana
0268aba85a Avoid count(null) 2018-01-16 16:22:24 +01:00
Jakub Vrana
9ca92309a1 Disallow PHP 5.3 in Travis 2018-01-16 13:51:02 +01:00
Jakub Vrana
0fae40fb61 Disallow connecting to privileged ports (thanks to hyp3rlinx) 2018-01-16 11:18:32 +01:00
Jakub Vrana
0e5df34ea8 Rate limit password-less login attempts from the same IP address (thanks to hyp3rlinx) 2018-01-16 11:17:25 +01:00
Jakub Vrana
f3938c1a66 Use HTTPS 2018-01-14 11:03:54 +01:00
Jakub Vrana
07aa80048a Use HTTPS in doc_link() 2018-01-14 10:38:01 +01:00
Jakub Vrana
c57e7ac3e3 Do not set '' for empty enum 2018-01-14 10:19:56 +01:00
Jakub Vrana
6d14b47d02 Fix select function onchange 2018-01-14 10:18:38 +01:00
Jakub Vrana
ef3b468626 Clone all event handlers in cloneNode() 2018-01-14 10:04:53 +01:00
Jakub Vrana
4d38c09db5 Use border-collapse to prevent unnecessary wrapping in Chrome 2018-01-14 09:35:13 +01:00
Jakub Vrana
3ba99a1c2a Fix whitespace 2018-01-14 08:52:22 +01:00
Jakub Vrana
9cbdb6262b Fix selectCount() in information_schema 2018-01-14 08:36:10 +01:00
Jakub Vrana
cc268428b8 Fix SQL command toggle 2018-01-14 00:10:42 +01:00
Jakub Vrana
80d030f51a Disallow scripts without nonce 2018-01-13 22:19:16 +01:00
Jakub Vrana
e23da5da0e Fix wrapping in Create table 2018-01-13 17:40:21 +01:00
Jakub Vrana
9d532fc0a1 Use script_src for <script src> 2018-01-13 16:25:11 +01:00
Jakub Vrana
144c7de27f Fix typo in script() 2018-01-13 15:23:47 +01:00
Jakub Vrana
b7fcebfba8 Do not send empty CSP 2018-01-13 14:21:54 +01:00
Jakub Vrana
d39a6e59c7 Move inline event handlers to <script> 2018-01-13 09:34:01 +01:00
Jakub Vrana
fc559a1cf6 Move inline event handlers to <script> 2018-01-13 09:21:21 +01:00
Jakub Vrana
f457053d85 Use the fact that we handle oninput in whisper() 2018-01-13 09:07:35 +01:00
Jakub Vrana
e255ba9aa4 Move inline event handlers to <script> 2018-01-13 08:58:01 +01:00
Jakub Vrana
3fe0d88f98 Editor: Fix Search data in tables 2018-01-12 23:59:04 +01:00
Jakub Vrana
68c6b1c942 Move inline event handlers to <script> 2018-01-12 23:42:20 +01:00
Jakub Vrana
001c37e240 Use <script> instead of inline event handler for skipping original 2018-01-12 23:27:14 +01:00
Jakub Vrana
b6cc584f48 Move inline event handlers to <script> 2018-01-12 22:46:16 +01:00
Jakub Vrana
af1ad47a64 Return false from editingMoveRow() 2018-01-12 22:35:05 +01:00
Jakub Vrana
2eaac2e94e Move inline event handlers to <script> 2018-01-12 22:25:38 +01:00
Jakub Vrana
40abffe8de Use oninput instead of onchange 2018-01-12 22:18:54 +01:00
Jakub Vrana
259a465125 Move inline event handlers to <script> 2018-01-12 21:57:54 +01:00
Jakub Vrana
6c1fbf13c6 Fix fieldChange() after 6353a898 2018-01-12 21:49:45 +01:00
Jakub Vrana
6353a89816 Use oninput instead of onkeyup 2018-01-12 18:46:44 +01:00
Jakub Vrana
38aac7ada2 Move inline event handlers to <script> 2018-01-12 18:34:19 +01:00
Jakub Vrana
24245867d7 Use <script> instead of inline event handler in on_help() 2018-01-12 18:11:00 +01:00
Jakub Vrana
1459df56bc Move inline event handlers to <script> 2018-01-12 17:59:46 +01:00
Jakub Vrana
dc3a0e1a32 Clone onchange in cloneNode() 2018-01-12 17:33:23 +01:00
Jakub Vrana
0411495d20 Move inline event handlers to <script> 2018-01-12 17:19:47 +01:00
Jakub Vrana
3d69fbf5f7 Allow searching data in tables by Ctrl+Enter 2018-01-12 17:11:29 +01:00
Jakub Vrana
5e9df49fd1 Move inline event handlers to <script> 2018-01-12 17:11:29 +01:00
Jakub Vrana
565a5ca0eb Fix selectors in schema after 58b2904d 2018-01-12 17:11:29 +01:00
Jakub Vrana
9061583538 Rely on event always passed to handlers 2018-01-12 17:11:29 +01:00
Jakub Vrana
35b1db6974 Move inline event handlers to <script> 2018-01-12 17:11:29 +01:00
Jakub Vrana
068ee71bf7 Return false from editingRemoveRow 2018-01-12 17:11:29 +01:00
Jakub Vrana
efcf37d162 Move inline event handlers to <script> 2018-01-12 17:11:29 +01:00
Jakub Vrana
e645693147 Use script() for <script> 2018-01-12 17:10:33 +01:00
Jakub Vrana
12fbfc9847 Move inline event handlers to <script> 2018-01-12 17:09:41 +01:00
Jakub Vrana
6b2ba65084 Use <script> instead of inline event handler in print_fieldset() 2018-01-12 17:09:41 +01:00
Jakub Vrana
a5ee3451ac Use <script> instead of inline event handler in confirm() 2018-01-12 17:09:41 +01:00
Jakub Vrana
da671df728 Move inline event handlers to <script> 2018-01-12 17:09:41 +01:00
Jakub Vrana
650221357d Return false from ajaxSetHtml() 2018-01-12 17:09:41 +01:00
Jakub Vrana
d996b48cfa Move inline event handlers to <script> 2018-01-12 17:09:41 +01:00
Jakub Vrana
22b4322710 Revert using @this in formChecked 2018-01-12 17:09:41 +01:00
Jakub Vrana
36edd445a6 Move inline event handlers to <script> 2018-01-12 17:09:41 +01:00
Jakub Vrana
7305783c21 Return false from toggle() 2018-01-12 17:09:41 +01:00
Jakub Vrana
ee3a88d574 onchange='selectFieldChange 2018-01-12 17:09:41 +01:00
Jakub Vrana
e5c52589ec Use @this in selectFieldChange 2018-01-12 17:09:41 +01:00
Jakub Vrana
3b0e1cf289 Move inline event handlers to <script> 2018-01-12 17:09:41 +01:00
Jakub Vrana
767fc0e47e Fix indexesAddColumn after 14778165 2018-01-12 17:09:41 +01:00
Jakub Vrana
63581af0f6 Move inline event handlers to <script> 2018-01-12 17:09:35 +01:00
Jakub Vrana
813ada6661 Revert using @this in formChecked 2018-01-11 18:58:00 +01:00
Jakub Vrana
4be72a2a0d Allow customizing CSP 2018-01-11 18:39:49 +01:00
Jakub Vrana
541c3c1fed Allow img-src data: common in skins 2018-01-11 18:39:49 +01:00
Jakub Vrana
3408d4ad78 Use JSON.parse if available 2018-01-11 18:39:49 +01:00
Jakub Vrana
e614ae08c4 Add Content Security Policy 2018-01-11 18:39:49 +01:00
Jakub Vrana
552d2a6be4 Always send security headers in customization 2018-01-11 18:39:49 +01:00
Jakub Vrana
415253b1b1 Add nosniff header 2018-01-11 18:39:22 +01:00
Jakub Vrana
d07b7e3773 Use Referrer-Policy instead of <meta name="referrer">
To make securityheaders.io happy.

Also fix a typo in the value (https://lists.w3.org/Archives/Public/public-webappsec/2015May/0059.html).
2018-01-11 18:38:15 +01:00
Jakub Vrana
3de101dff4 Editor: Fix doubleclick on database page 2018-01-11 17:24:57 +01:00
Jakub Vrana
48dacd1e97 Fix a typo from 9cb28186 2018-01-11 17:05:37 +01:00
Jakub Vrana
14778165a8 Use @this in JavaScript (prepares for removing inline event handlers) 2018-01-11 17:01:29 +01:00
Jakub Vrana
72b199378a Prevent PHP 7.1 warning about non-numeric values 2018-01-11 16:22:29 +01:00
Jakub Vrana
329fa55af5 Unindent doc-comments 2018-01-11 15:14:05 +01:00
Jakub Vrana
ecf34769ad Delete type="text/css" from <style> as it is the default in HTML5 2018-01-11 14:14:15 +01:00
Jakub Vrana
dc85ba2d86 Delete type="text/javascript" from <script> as it is the default in HTML5 2018-01-11 14:13:43 +01:00
Jakub Vrana
741b76fbd4 Replace getElementsByTagName by shortcut for querySelectorAll 2018-01-11 14:00:04 +01:00
Jakub Vrana
58b2904d62 Use querySelector 2018-01-11 13:55:48 +01:00
Jakub Vrana
9cb281868f Replace getElementById by shortcut for querySelector (requires IE8) 2018-01-11 13:51:32 +01:00
Jakub Vrana
67f6aea77f Fix skin for Chrome 61 (thanks to Dominik Ulrich) 2017-10-28 15:05:07 +02:00
Jakub Vrana
7bcba262df Editor: Display field comment's text inside [] only in edit form 2017-10-01 08:45:17 -07:00
Itamar Schen
75c0786d2e Fix hebrew typos (#228) 2017-09-29 09:25:32 +02:00
Jakub Vrana
c4f6cbb32e Add new Hebrew translations 2017-09-11 13:25:49 +02:00
Jakub Vrana
b10e9e127e Add Hebrew translation 2017-09-09 12:06:14 +02:00
Lukas Tribus
32f1e856ad Editor: Don't set time zone from PHP
Current implementation checks the delta between the local time and
UTC, and applies the delta as time zone for MySQL.

This assumption is wrong if the current time is DST enabled, but the
time that is converted isn't - and vice versa.

For example, Europe/Prague is "CET-1CEST,M3.5.0,M10.5.0/3", when
the MySQL connections is setup now (September, DST enabled) and
we are reading a TIMESTAMP from November, then MySQL applies +0200
instead of +0100 to that timestamp even though November is supposed
to be DST disabled.

There is no reliable and portable way in PHP to understand the
time zone, especially since PHP >= 5.4.0 ignores environment
variable and OS settings [1].

MySQL needs to be properly setup (TZ data loaded [2] and default
TZ set [3]), then everything will work just fine.

The current implementation however causes wrong data 50% of the
time, even when OS/MySQL/PHP is properly setup. As a MySQL
connection will converte timestamps from both DST enabled and
DST disabled dates, a static UTC offset must never be set at
connection level (set time_zone = ...).

This change removes the current implementation, therefor maintaining
OS/MySQL defaults, fixing the DST issue in properly configured
environments.

[1] http://php.net/manual/en/function.date-default-timezone-get.php
[2] https://dev.mysql.com/doc/refman/5.5/en/mysql-tzinfo-to-sql.html
[3] https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html
2017-09-09 11:44:42 +02:00
Jonathan Vollebregt
17e45e9a9c Make sure all sidebar elements are pushed down, not just the form.
This was breaking the #logins block at the log in screen.
2017-09-09 11:39:47 +02:00
Jonathan Vollebregt
e1f43da8df Update AdminerTablesFilter to produce li as per c9801e2e24 2017-05-19 11:23:35 +02:00
Jakub Vrana
70aef8a55a MySQL: Remove dedicated view for replication status 2017-05-19 11:11:44 +02:00
Jakub Vrana
0b824dad29 Sort table names (bug #552) 2017-05-19 10:57:20 +02:00
Alfonso Montero
65fa4b4e31 Update es.inc.php 2017-04-22 10:07:55 +02:00
Jakub Vrana
c0a3f30060 Add a donate link 2017-04-16 10:42:27 +02:00
202 changed files with 10476 additions and 4391 deletions

7
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "jush"]
path = externals/jush
url = git://git.code.sf.net/p/jush/git
[submodule "wymeditor"]
path = externals/wymeditor
url = git://github.com/wymeditor/wymeditor.git
url = git://github.com/vrana/jush
[submodule "JsShrink"]
path = externals/JsShrink
url = git://github.com/vrana/JsShrink.git
url = git://github.com/vrana/JsShrink

View File

@@ -1,5 +1,7 @@
language: php
php:
- '5.3'
- '7.1'
- 5.6
- 7.1
- 7.2
- 7.3
script: git diff --name-only $TRAVIS_COMMIT_RANGE | grep '\.php$' | xargs -n1 -P8 php -l | grep -v 'No syntax errors'; test $? -eq 1

View File

@@ -1,8 +1,8 @@
<?php
$PROCEDURE = $_GET["call"];
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["call"]);
page_header(lang('Call') . ": " . h($PROCEDURE), $error);
$routine = routine($PROCEDURE, (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
$routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
$in = array();
$out = array();
foreach ($routine["fields"] as $i => $field) {
@@ -30,9 +30,12 @@ if (!$error && $_POST) {
}
$query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")";
echo "<p><code class='jush-$jush'>" . h($query) . "</code> <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>\n";
$start = microtime(true);
$result = $connection->multi_query($query);
$affected = $connection->affected_rows; // getting warnigns overwrites this
echo $adminer->selectQuery($query, $start, !$result);
if (!$connection->multi_query($query)) {
if (!$result) {
echo "<p class='error'>" . error() . "\n";
} else {
$connection2 = connect();
@@ -45,7 +48,7 @@ if (!$error && $_POST) {
if (is_object($result)) {
select($result, $connection2);
} else {
echo "<p class='message'>" . lang('Routine has been called, %d row(s) affected.', $connection->affected_rows) . "\n";
echo "<p class='message'>" . lang('Routine has been called, %d row(s) affected.', $affected) . "\n";
}
} while ($connection->next_result());
@@ -59,7 +62,7 @@ if (!$error && $_POST) {
<form action="" method="post">
<?php
if ($in) {
echo "<table cellspacing='0'>\n";
echo "<table cellspacing='0' class='layout'>\n";
foreach ($in as $key) {
$field = $routine["fields"][$key];
$name = $field["field"];

View File

@@ -27,6 +27,10 @@ if ($row["auto_increment_col"]) {
$row["fields"][$row["auto_increment_col"]]["auto_increment"] = true;
}
if ($_POST) {
set_adminer_settings(array("comments" => $_POST["comments"], "defaults" => $_POST["defaults"]));
}
if ($_POST && !process_fields($row["fields"]) && !$error) {
if ($_POST["drop"]) {
queries_redirect(substr(ME, 0, -1), lang('Table has been dropped.'), drop_tables(array($TABLE)));
@@ -120,7 +124,7 @@ page_header(($TABLE != "" ? lang('Alter table') : lang('Create table')), $error,
if (!$_POST) {
$row = array(
"Engine" => $_COOKIE["adminer_engine"],
"fields" => array(array("field" => "", "type" => (isset($types["int"]) ? "int" : (isset($types["integer"]) ? "integer" : "")))),
"fields" => array(array("field" => "", "type" => (isset($types["int"]) ? "int" : (isset($types["integer"]) ? "integer" : "")), "on_update" => "")),
"partition_names" => array(""),
);
@@ -162,49 +166,41 @@ foreach ($engines as $engine) {
<form action="" method="post" id="form">
<p>
<?php if (support("columns") || $TABLE == "") { ?>
<?php echo lang('Table name'); ?>: <input name="name" maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php if ($TABLE == "" && !$_POST) { ?><script type='text/javascript'>focus(document.getElementById('form')['name']);</script><?php } ?>
<?php echo ($engines ? "<select name='Engine' onchange='helpClose();'" . on_help("getTarget(event).value", 1) . ">" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" : ""); ?>
<?php echo lang('Table name'); ?>: <input name="name" data-maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php if ($TABLE == "" && !$_POST) { echo script("focus(qs('#form')['name']);"); } ?>
<?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?php 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")) { ?>
<div class="scrollable">
<table cellspacing="0" id="edit-fields" class="nowrap">
<?php
$comments = ($_POST ? $_POST["comments"] : $row["Comment"] != "");
if (!$_POST && !$comments) {
foreach ($row["fields"] as $field) {
if ($field["comment"] != "") {
$comments = true;
break;
}
}
}
edit_fields($row["fields"], $collations, "TABLE", $foreign_keys, $comments);
edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
?>
</table>
</div>
<p>
<?php echo lang('Auto Increment'); ?>: <input type="number" name="Auto_increment" size="6" value="<?php echo h($row["Auto_increment"]); ?>">
<?php echo checkbox("defaults", 1, true, lang('Default values'), "columnShow(this.checked, 5)", "jsonly"); ?>
<?php if (!$_POST["defaults"]) { ?><script type="text/javascript">editingHideDefaults()</script><?php } ?>
<?php echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : adminer_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly"); ?>
<?php echo (support("comment")
? "<label><input type='checkbox' name='comments' value='1' class='jsonly' onclick=\"columnShow(this.checked, 6); toggle('Comment'); if (this.checked) this.form['Comment'].focus();\"" . ($comments ? " checked" : "") . ">" . lang('Comment') . "</label>"
. ' <input name="Comment" id="Comment" value="' . h($row["Comment"]) . '" maxlength="' . ($connection->server_info >= 5.5 ? 2048 : 60) . '"' . ($comments ? '' : ' class="hidden"') . '>'
? checkbox("comments", 1, ($_POST ? $_POST["comments"] : adminer_setting("comments")), lang('Comment'), "editingCommentsClick(this, true);", "jsonly")
. ' <input name="Comment" value="' . h($row["Comment"]) . '" data-maxlength="' . (min_version(5.5) ? 2048 : 60) . '">'
: '')
; ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?>
<?php if ($TABLE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?php if ($TABLE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $TABLE)); ?><?php } ?>
<?php
if (support("partitioning")) {
$partition_table = preg_match('~RANGE|LIST~', $row["partition_by"]);
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
<p>
<?php echo "<select name='partition_by' onchange='partitionByChange(this);'" . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . ">" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>"; ?>
<?php echo "<select name='partition_by'>" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>" . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); ?>
(<input name="partition" value="<?php echo h($row["partition"]); ?>">)
<?php echo lang('Partitions'); ?>: <input type="number" name="partitions" class="size<?php echo ($partition_table || !$row["partition_by"] ? " hidden" : ""); ?>" value="<?php echo h($row["partitions"]); ?>">
<table cellspacing="0" id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>
@@ -212,7 +208,8 @@ if (support("partitioning")) {
<?php
foreach ($row["partition_names"] as $key => $val) {
echo '<tr>';
echo '<td><input name="partition_names[]" value="' . h($val) . '"' . ($key == count($row["partition_names"]) - 1 ? ' onchange="partitionNameChange(this);"' : '') . ' autocapitalize="off">';
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]) . '">';
}
?>
@@ -223,3 +220,4 @@ foreach ($row["partition_names"] as $key => $val) {
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php echo script("qs('#form')['defaults'].onclick();" . (support("comment") ? " editingCommentsClick(qs('#form')['comments']);" : "")); ?>

View File

@@ -47,7 +47,7 @@ if ($_POST) {
} elseif ($jush == "sql") {
// propose database name with limited privileges
foreach (get_vals("SHOW GRANTS") as $grant) {
if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\\.\\*)?~', $grant, $match) && $match[1]) {
if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\.\*)?~', $grant, $match) && $match[1]) {
$name = stripcslashes(idf_unescape("`$match[2]`"));
break;
}
@@ -60,17 +60,18 @@ if ($_POST) {
<?php
echo ($_POST["add_x"] || strpos($name, "\n")
? '<textarea id="name" name="name" rows="10" cols="40">' . h($name) . '</textarea><br>'
: '<input name="name" id="name" value="' . h($name) . '" maxlength="64" autocapitalize="off">'
: '<input name="name" id="name" value="' . h($name) . '" data-maxlength="64" autocapitalize="off">'
) . "\n" . ($collations ? html_select("collation", array("" => "(" . lang('collation') . ")") + $collations, $row["collation"]) . doc_link(array(
'sql' => "charset-charsets.html",
'mariadb' => "supported-character-sets-and-collations/",
'mssql' => "ms187963.aspx",
)) : "");
echo script("focus(qs('#name'));");
?>
<script type='text/javascript'>focus(document.getElementById('name'));</script>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php
if (DB != "") {
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'" . confirm() . ">\n";
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', DB)) . "\n";
} 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";
}

View File

@@ -4,7 +4,7 @@ $tables_views = array_merge((array) $_POST["tables"], (array) $_POST["views"]);
if ($tables_views && !$error && !$_POST["search"]) {
$result = true;
$message = "";
if ($jush == "sql" && count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"] || $_POST["copy"])) {
if ($jush == "sql" && $_POST["tables"] && count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"] || $_POST["copy"])) {
queries("SET foreign_key_checks = 0"); // allows to truncate or drop several tables at once
}
@@ -56,22 +56,28 @@ if ($adminer->homepage()) {
echo "<form action='' method='post'>\n";
if (support("table")) {
echo "<fieldset><legend>" . lang('Search data in tables') . " <span id='selected2'></span></legend><div>";
echo "<input type='search' name='query' value='" . h($_POST["query"]) . "'> <input type='submit' name='search' value='" . lang('Search') . "'>\n";
echo "<input type='search' name='query' value='" . h($_POST["query"]) . "'>";
echo script("qsl('input').onkeydown = partialArg(bodyKeydown, 'search');", "");
echo " <input type='submit' name='search' value='" . lang('Search') . "'>\n";
echo "</div></fieldset>\n";
if ($_POST["search"] && $_POST["query"] != "") {
$_GET["where"][0]["op"] = "LIKE %%";
search_tables();
}
}
$doc_link = doc_link(array('sql' => 'show-table-status.html'));
echo "<table cellspacing='0' class='nowrap checkable' onclick='tableClick(event);' ondblclick='tableClick(event, true);'>\n";
echo '<thead><tr class="wrap"><td><input id="check-all" type="checkbox" onclick="formCheck(this, /^(tables|views)\[/);" class="jsonly">';
echo "<div class='scrollable'>\n";
echo "<table cellspacing='0' class='nowrap checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo '<thead><tr class="wrap">';
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("qs('#check-all').onclick = partial(formCheck, /^(tables|views)\[/);", "");
echo '<th>' . lang('Table');
echo '<td>' . lang('Engine') . doc_link(array('sql' => 'storage-engines.html'));
echo '<td>' . lang('Collation') . doc_link(array('sql' => 'charset-mysql.html'));
echo '<td>' . lang('Collation') . doc_link(array('sql' => 'charset-charsets.html', 'mariadb' => 'supported-character-sets-and-collations/'));
echo '<td>' . lang('Data Length') . $doc_link;
echo '<td>' . lang('Index Length') . $doc_link;
echo '<td>' . lang('Data Free') . $doc_link;
echo '<td>' . lang('Auto Increment') . doc_link(array('sql' => 'example-auto-increment.html'));
echo '<td>' . lang('Auto Increment') . doc_link(array('sql' => 'example-auto-increment.html', 'mariadb' => 'auto_increment/'));
echo '<td>' . lang('Rows') . $doc_link;
echo (support("comment") ? '<td>' . lang('Comment') . $doc_link : '');
echo "</thead>\n";
@@ -80,7 +86,7 @@ if ($adminer->homepage()) {
foreach ($tables_list as $name => $type) {
$view = ($type !== null && !preg_match('~table~i', $type));
$id = h("Table-" . $name);
echo '<tr' . odd() . '><td>' . checkbox(($view ? "views[]" : "tables[]"), $name, in_array($name, $tables_views, true), "", "formUncheck('check-all');", "", $id);
echo '<tr' . odd() . '><td>' . checkbox(($view ? "views[]" : "tables[]"), $name, in_array($name, $tables_views, true), "", "", "", $id);
echo '<th>' . (support("table") || support("indexes") ? "<a href='" . h(ME) . "table=" . urlencode($name) . "' title='" . lang('Show structure') . "' id='$id'>" . h($name) . '</a>' : h($name));
if ($view) {
echo '<td colspan="6"><a href="' . h(ME) . "view=" . urlencode($name) . '" title="' . lang('Alter view') . '">' . (preg_match('~materialized~i', $type) ? lang('Materialized view') : lang('View')) . '</a>';
@@ -99,48 +105,52 @@ if ($adminer->homepage()) {
echo ($link ? "<td align='right'>" . (support("table") || $key == "Rows" || (support("indexes") && $key != "Data_length")
? "<a href='" . h(ME . "$link[0]=") . urlencode($name) . "'$id title='$link[1]'>?</a>"
: "<span$id>?</span>"
) : "<td id='$key-" . h($name) . "'>&nbsp;");
) : "<td id='$key-" . h($name) . "'>");
}
$tables++;
}
echo (support("comment") ? "<td id='Comment-" . h($name) . "'>&nbsp;" : "");
echo (support("comment") ? "<td id='Comment-" . h($name) . "'>" : "");
}
echo "<tr><td>&nbsp;<th>" . lang('%d in total', count($tables_list));
echo "<td>" . nbsp($jush == "sql" ? $connection->result("SELECT @@storage_engine") : "");
echo "<td>" . nbsp(db_collation(DB, collations()));
echo "<tr><td><th>" . lang('%d in total', count($tables_list));
echo "<td>" . h($jush == "sql" ? $connection->result("SELECT @@storage_engine") : "");
echo "<td>" . h(db_collation(DB, collations()));
foreach (array("Data_length", "Index_length", "Data_free") as $key) {
echo "<td align='right' id='sum-$key'>&nbsp;";
echo "<td align='right' id='sum-$key'>";
}
echo "</table>\n";
echo "</div>\n";
if (!information_schema(DB)) {
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'" . on_help("'VACUUM'") . "> ";
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'" . on_help($jush == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'") . "> ";
echo "<div class='footer'><div>\n";
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . on_help("'VACUUM'");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . on_help($jush == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'");
echo "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>"
. ($jush == "sqlite" ? $vacuum
: ($jush == "pgsql" ? $vacuum . $optimize
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'" . on_help("'ANALYZE TABLE'") . "> " . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'" . on_help("'CHECK TABLE'") . "> "
. "<input type='submit' name='repair' value='" . lang('Repair') . "'" . on_help("'REPAIR TABLE'") . "> "
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . on_help("'ANALYZE TABLE'") . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'CHECK TABLE'")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . on_help("'REPAIR TABLE'")
: "")))
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'" . confirm() . on_help($jush == "sqlite" ? "'DELETE'" : "'TRUNCATE" . ($jush == "pgsql" ? "'" : " TABLE'")) . "> "
. "<input type='submit' name='drop' value='" . lang('Drop') . "'" . confirm() . on_help("'DROP TABLE'") . ">\n";
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . on_help($jush == "sqlite" ? "'DELETE'" : "'TRUNCATE" . ($jush == "pgsql" ? "'" : " TABLE'")) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . on_help("'DROP TABLE'") . confirm() . "\n";
$databases = (support("scheme") ? $adminer->schemas() : $adminer->databases());
if (count($databases) != 1 && $jush != "sqlite") {
$db = (isset($_POST["target"]) ? $_POST["target"] : (support("scheme") ? $_GET["ns"] : DB));
echo "<p>" . lang('Move to other database') . ": ";
echo ($databases ? html_select("target", $databases, $db) : '<input name="target" value="' . h($db) . '" autocapitalize="off">');
echo " <input type='submit' name='move' value='" . lang('Move') . "'>";
echo (support("copy") ? " <input type='submit' name='copy' value='" . lang('Copy') . "'>" : "");
echo (support("copy") ? " <input type='submit' name='copy' value='" . lang('Copy') . "'> " . checkbox("overwrite", 1, $_POST["overwrite"], lang('overwrite')) : "");
echo "\n";
}
echo "<input type='hidden' name='all' value='' onclick=\"selectCount('selected', formChecked(this, /^(tables|views)\[/));" . (support("table") ? " selectCount('selected2', formChecked(this, /^tables\[/) || $tables);" : "") . "\">\n"; // used by trCheck()
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 "</div></fieldset>\n";
echo "</div></div>\n";
}
echo "</form>\n";
echo "<script type='text/javascript'>tableCheck();</script>\n";
echo script("tableCheck();");
}
echo '<p class="links"><a href="' . h(ME) . 'create=">' . lang('Create table') . "</a>\n";
@@ -151,14 +161,15 @@ if ($adminer->homepage()) {
$routines = routines();
if ($routines) {
echo "<table cellspacing='0'>\n";
echo '<thead><tr><th>' . lang('Name') . '<td>' . lang('Type') . '<td>' . lang('Return type') . "<td>&nbsp;</thead>\n";
echo '<thead><tr><th>' . lang('Name') . '<td>' . lang('Type') . '<td>' . lang('Return type') . "<td></thead>\n";
odd('');
foreach ($routines as $row) {
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"])); // not computed on the pages to be able to print the header first
echo '<tr' . odd() . '>';
echo '<th><a href="' . h(ME) . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["ROUTINE_NAME"]) . '">' . h($row["ROUTINE_NAME"]) . '</a>';
echo '<th><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . h($row["ROUTINE_NAME"]) . '</a>';
echo '<td>' . h($row["ROUTINE_TYPE"]);
echo '<td>' . h($row["DTD_IDENTIFIER"]);
echo '<td><a href="' . h(ME) . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["ROUTINE_NAME"]) . '">' . lang('Alter') . "</a>";
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a>";
}
echo "</table>\n";
}
@@ -221,7 +232,7 @@ if ($adminer->homepage()) {
}
if ($tables_list) {
echo "<script type='text/javascript'>ajaxSetHtml('" . js_escape(ME) . "script=db');</script>\n";
echo script("ajaxSetHtml('" . js_escape(ME) . "script=db');");
}
}
}

14
adminer/designs.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
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);
}
return new AdminerPlugin(array(
new AdminerDesigns($designs),
));
}
include "./index.php";

View File

@@ -6,5 +6,5 @@ header("Content-Disposition: attachment; filename=" . friendly_url("$TABLE-" . i
$select = array(idf_escape($_GET["field"]));
$result = $driver->select($TABLE, $select, array(where($_GET, $fields)), $select);
$row = ($result ? $result->fetch_row() : array());
echo $row[0];
echo $driver->value($row[0], $fields[$_GET["field"]]);
exit; // don't output footer

View File

@@ -0,0 +1,354 @@
<?php
$drivers["clickhouse"] = "ClickHouse (alpha)";
if (isset($_GET["clickhouse"])) {
define("DRIVER", "clickhouse");
class Min_DB {
var $extension = "JSON", $server_info, $errno, $_result, $error, $_url;
var $_db = 'default';
function rootQuery($db, $query) {
@ini_set('track_errors', 1); // @ - may be disabled
$file = @file_get_contents("$this->_url/?database=$db", false, stream_context_create(array('http' => array(
'method' => 'POST',
'content' => $this->isQuerySelectLike($query) ? "$query FORMAT JSONCompact" : $query,
'header' => 'Content-type: application/x-www-form-urlencoded',
'ignore_errors' => 1, // available since PHP 5.2.10
))));
if ($file === false) {
$this->error = $php_errormsg;
return $file;
}
if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
$this->error = $file;
return false;
}
$return = json_decode($file, true);
if ($return === null) {
$this->errno = json_last_error();
if (function_exists('json_last_error_msg')) {
$this->error = json_last_error_msg();
} else {
$constants = get_defined_constants(true);
foreach ($constants['json'] as $name => $value) {
if ($value == $this->errno && preg_match('~^JSON_ERROR_~', $name)) {
$this->error = $name;
break;
}
}
}
}
return new Min_Result($return);
}
function isQuerySelectLike($query) {
return (bool) preg_match('~^(select|show)~i', $query);
}
function query($query) {
return $this->rootQuery($this->_db, $query);
}
function connect($server, $username, $password) {
preg_match('~^(https?://)?(.*)~', $server, $match);
$this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]";
$return = $this->query('SELECT 1');
return (bool) $return;
}
function select_db($database) {
$this->_db = $database;
return true;
}
function quote($string) {
return "'" . addcslashes($string, "\\'") . "'";
}
function multi_query($query) {
return $this->_result = $this->query($query);
}
function store_result() {
return $this->_result;
}
function next_result() {
return false;
}
function result($query, $field = 0) {
$result = $this->query($query);
return $result['data'];
}
}
class Min_Result {
var $num_rows, $_rows, $columns, $meta, $_offset = 0;
function __construct($result) {
$this->num_rows = $result['rows'];
$this->_rows = $result['data'];
$this->meta = $result['meta'];
$this->columns = array_column($this->meta, 'name');
reset($this->_rows);
}
function fetch_assoc() {
$row = current($this->_rows);
next($this->_rows);
return $row === false ? false : array_combine($this->columns, $row);
}
function fetch_row() {
$row = current($this->_rows);
next($this->_rows);
return $row;
}
function fetch_field() {
$column = $this->_offset++;
$return = new stdClass;
if ($column < count($this->columns)) {
$return->name = $this->meta[$column]['name'];
$return->orgname = $return->name;
$return->type = $this->meta[$column]['type'];
}
return $return;
}
}
class Min_Driver extends Min_SQL {
function delete($table, $queryWhere, $limit = 0) {
return queries("ALTER TABLE " . table($table) . " DELETE $queryWhere");
}
function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") {
$values = array();
foreach ($set as $key => $val) {
$values[] = "$key = $val";
}
$query = $separator . implode(",$separator", $values);
return queries("ALTER TABLE " . table($table) . " UPDATE $query$queryWhere");
}
}
function idf_escape($idf) {
return "`" . str_replace("`", "``", $idf) . "`";
}
function table($idf) {
return idf_escape($idf);
}
function explain($connection, $query) {
return '';
}
function found_rows($table_status, $where) {
$rows = get_vals("SELECT COUNT(*) FROM " . idf_escape($table_status["Name"]) . ($where ? " WHERE " . implode(" AND ", $where) : ""));
return empty($rows) ? false : $rows[0];
}
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
foreach ($fields as $field) {
if ($field[1][2] === " NULL") {
$field[1][1] = " Nullable({$field[1][1]})";
}
unset($field[1][2]);
}
}
function truncate_tables($tables) {
return apply_queries("TRUNCATE TABLE", $tables);
}
function drop_views($views) {
return drop_tables($views);
}
function drop_tables($tables) {
return apply_queries("DROP TABLE", $tables);
}
function connect() {
global $adminer;
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
return $connection;
}
return $connection->error;
}
function get_databases($flush) {
global $connection;
$result = get_rows('SHOW DATABASES');
$return = array();
foreach ($result as $row) {
$return[] = $row['name'];
}
sort($return);
return $return;
}
function limit($query, $where, $limit, $offset = 0, $separator = " ") {
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? ", $offset" : "") : "");
}
function limit1($table, $query, $where, $separator = "\n") {
return limit($query, $where, 1, 0, $separator);
}
function db_collation($db, $collations) {
}
function engines() {
return array('MergeTree');
}
function logged_user() {
global $adminer;
$credentials = $adminer->credentials();
return $credentials[1];
}
function tables_list() {
$result = get_rows('SHOW TABLES');
$return = array();
foreach ($result as $row) {
$return[$row['name']] = 'table';
}
ksort($return);
return $return;
}
function count_tables($databases) {
return array();
}
function table_status($name = "", $fast = false) {
global $connection;
$return = array();
$tables = get_rows("SELECT name, engine FROM system.tables WHERE database = " . q($connection->_db));
foreach ($tables as $table) {
$return[$table['name']] = array(
'Name' => $table['name'],
'Engine' => $table['engine'],
);
if ($name === $table['name']) {
return $return[$table['name']];
}
}
return $return;
}
function is_view($table_status) {
return false;
}
function fk_support($table_status) {
return false;
}
function convert_field($field) {
}
function unconvert_field($field, $return) {
if (in_array($field['type'], array("Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Float32", "Float64"))) {
return "to$field[type]($return)";
}
return $return;
}
function fields($table) {
$return = array();
$result = get_rows("SELECT name, type, default_expression FROM system.columns WHERE " . idf_escape('table') . " = " . q($table));
foreach($result as $row) {
$type = trim($row['type']);
$nullable = strpos($type, 'Nullable(') === 0;
$return[trim($row['name'])] = array(
"field" => trim($row['name']),
"full_type" => $type,
"type" => $type,
"default" => trim($row['default_expression']),
"null" => $nullable,
"auto_increment" => '0',
"privileges" => array("insert" => 1, "select" => 1, "update" => 0),
);
}
return $return;
}
function indexes($table, $connection2 = null) {
return array();
}
function foreign_keys($table) {
return array();
}
function collations() {
return array();
}
function information_schema($db) {
return false;
}
function error() {
global $connection;
return h($connection->error);
}
function types() {
return array();
}
function schemas() {
return array();
}
function get_schema() {
return "";
}
function set_schema($schema) {
return true;
}
function auto_increment() {
return '';
}
function last_id() {
return 0; // ClickHouse doesn't have it
}
function support($feature) {
return preg_match("~^(columns|sql|status|table)$~", $feature);
}
$jush = "clickhouse";
$types = array();
$structured_types = array();
foreach (array( //! arrays
lang('Numbers') => array("Int8" => 3, "Int16" => 5, "Int32" => 10, "Int64" => 19, "UInt8" => 3, "UInt16" => 5, "UInt32" => 10, "UInt64" => 20, "Float32" => 7, "Float64" => 16, 'Decimal' => 38, 'Decimal32' => 9, 'Decimal64' => 18, 'Decimal128' => 38),
lang('Date and time') => array("Date" => 13, "DateTime" => 20),
lang('Strings') => array("String" => 0),
lang('Binary') => array("FixedString" => 0),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
$unsigned = array();
$operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL");
$functions = array();
$grouping = array("avg", "count", "count distinct", "max", "min", "sum");
$edit_functions = array();
}

View File

@@ -2,10 +2,10 @@
$drivers["elastic"] = "Elasticsearch (beta)";
if (isset($_GET["elastic"])) {
$possible_drivers = array("json");
$possible_drivers = array("json + allow_url_fopen");
define("DRIVER", "elastic");
if (function_exists('json_decode')) {
if (function_exists('json_decode') && ini_bool('allow_url_fopen')) {
class Min_DB {
var $extension = "JSON", $server_info, $errno, $error, $_url;
@@ -17,9 +17,10 @@ if (isset($_GET["elastic"])) {
*/
function rootQuery($path, $content = array(), $method = 'GET') {
@ini_set('track_errors', 1); // @ - may be disabled
$file = @file_get_contents($this->_url . '/' . ltrim($path, '/'), false, stream_context_create(array('http' => array(
$file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
'method' => $method,
'content' => json_encode($content),
'content' => $content === null ? $content : json_encode($content),
'header' => 'Content-Type: application/json',
'ignore_errors' => 1, // available since PHP 5.2.10
))));
if (!$file) {
@@ -60,7 +61,7 @@ if (isset($_GET["elastic"])) {
function connect($server, $username, $password) {
preg_match('~^(https?://)?(.*)~', $server, $match);
$this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]/";
$this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]";
$return = $this->query('');
if ($return) {
$this->server_info = $return['version']['number'];
@@ -83,7 +84,7 @@ if (isset($_GET["elastic"])) {
var $num_rows, $_rows;
function __construct($rows) {
$this->num_rows = count($this->_rows);
$this->num_rows = count($rows);
$this->_rows = $rows;
reset($this->_rows);
}
@@ -128,7 +129,7 @@ if (isset($_GET["elastic"])) {
}
}
foreach ($where as $val) {
list($col,$op,$val) = explode(" ",$val,3);
list($col, $op, $val) = explode(" ", $val, 3);
if ($col == "_id") {
$data["query"]["ids"]["values"][] = $val;
}
@@ -147,7 +148,7 @@ if (isset($_GET["elastic"])) {
$start = microtime(true);
$search = $this->_conn->query($query, $data);
if ($print) {
echo $adminer->selectQuery("$query: " . print_r($data, true), format_time($start));
echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search);
}
if (!$search) {
return false;
@@ -156,7 +157,7 @@ if (isset($_GET["elastic"])) {
foreach ($search['hits']['hits'] as $hit) {
$row = array();
if ($select == array("*")) {
$row["_id"] = $hit["_id"];
$row["_id"] = $hit["_id"];
}
$fields = $hit['_source'];
if ($select != array("*")) {
@@ -176,6 +177,49 @@ if (isset($_GET["elastic"])) {
return new Min_Result($return);
}
function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
//! use $limit
$parts = preg_split('~ *= *~', $queryWhere);
if (count($parts) == 2) {
$id = trim($parts[1]);
$query = "$type/$id";
return $this->_conn->query($query, $record, 'POST');
}
return false;
}
function insert($type, $record) {
$id = ""; //! user should be able to inform _id
$query = "$type/$id";
$response = $this->_conn->query($query, $record, 'POST');
$this->_conn->last_id = $response['_id'];
return $response['created'];
}
function delete($type, $queryWhere, $limit = 0) {
//! use $limit
$ids = array();
if (is_array($_GET["where"]) && $_GET["where"]["_id"]) {
$ids[] = $_GET["where"]["_id"];
}
if (is_array($_POST['check'])) {
foreach ($_POST['check'] as $check) {
$parts = preg_split('~ *= *~', $check);
if (count($parts) == 2) {
$ids[] = trim($parts[1]);
}
}
}
$this->_conn->affected_rows = 0;
foreach ($ids as $id) {
$query = "{$type}/{$id}";
$response = $this->_conn->query($query, '{}', 'DELETE');
if (is_array($response) && $response['found'] == true) {
$this->_conn->affected_rows++;
}
}
return $this->_conn->affected_rows;
}
}
@@ -183,8 +227,11 @@ if (isset($_GET["elastic"])) {
function connect() {
global $adminer;
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
list($server, $username, $password) = $adminer->credentials();
if ($password != "" && $connection->connect($server, $username, "")) {
return lang('Database does not support password.');
}
if ($connection->connect($server, $username, $password)) {
return $connection;
}
return $connection->error;
@@ -223,9 +270,14 @@ if (isset($_GET["elastic"])) {
function count_tables($databases) {
global $connection;
$return = $connection->query('_mapping');
if ($return) {
$return = array_map('count', $return);
$return = array();
$result = $connection->query('_stats');
if ($result && $result['indices']) {
$indices = $result['indices'];
foreach ($indices as $indice => $stats) {
$indexing = $stats['total']['indexing'];
$return[$indice] = $indexing['index_total'];
}
}
return $return;
}
@@ -241,24 +293,26 @@ if (isset($_GET["elastic"])) {
function table_status($name = "", $fast = false) {
global $connection;
$search = $connection->query("_search?search_type=count", array(
"facets" => array(
$search = $connection->query("_search", array(
"size" => 0,
"aggregations" => array(
"count_by_type" => array(
"terms" => array(
"field" => "_type",
"field" => "_type"
)
)
)
), "POST");
$return = array();
if ($search) {
foreach ($search["facets"]["count_by_type"]["terms"] as $table) {
$return[$table["term"]] = array(
"Name" => $table["term"],
$tables = $search["aggregations"]["count_by_type"]["buckets"];
foreach ($tables as $table) {
$return[$table["key"]] = array(
"Name" => $table["key"],
"Engine" => "table",
"Rows" => $table["count"],
"Rows" => $table["doc_count"],
);
if ($name != "" && $name == $table["term"]) {
if ($name != "" && $name == $table["key"]) {
return $return[$name];
}
}
@@ -336,16 +390,16 @@ if (isset($_GET["elastic"])) {
return null;
}
/** Create database
/** Create index
* @param string
* @return mixed
*/
function create_database($db) {
global $connection;
return $connection->rootQuery(urlencode($db), array(), 'PUT');
return $connection->rootQuery(urlencode($db), null, 'PUT');
}
/** Drop databases
/** Remove index
* @param array
* @return mixed
*/
@@ -354,7 +408,27 @@ if (isset($_GET["elastic"])) {
return $connection->rootQuery(urlencode(implode(',', $databases)), array(), 'DELETE');
}
/** Drop tables
/** Alter type
* @param array
* @return mixed
*/
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
global $connection;
$properties = array();
foreach ($fields as $f) {
$field_name = trim($f[1][0]);
$field_type = trim($f[1][1] ? $f[1][1] : "text");
$properties[$field_name] = array(
'type' => $field_type
);
}
if (!empty($properties)) {
$properties = array('properties' => $properties);
}
return $connection->query("_mapping/{$name}", $properties, 'PUT');
}
/** Drop types
* @param array
* @return bool
*/
@@ -367,9 +441,25 @@ if (isset($_GET["elastic"])) {
return $return;
}
function last_id() {
global $connection;
return $connection->last_id;
}
$jush = "elastic";
$operators = array("=", "query");
$functions = array();
$grouping = array();
$edit_functions = array(array("json"));
$types = array(); ///< @var array ($type => $maximum_unsigned_length, ...)
$structured_types = array(); ///< @var array ($description => array($type, ...), ...)
foreach (array(
lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21),
lang('Date and time') => array("date" => 10),
lang('Strings') => array("string" => 65535, "text" => 65535),
lang('Binary') => array("binary" => 255),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
}

View File

@@ -147,8 +147,8 @@ if (isset($_GET["firebird"])) {
return $return;
}
function limit1($query, $where) {
return limit($query, $where, 1);
function limit1($table, $query, $where, $separator = "\n") {
return limit($query, $where, 1, 0, $separator);
}
function db_collation($db, $collations) {

View File

@@ -1,32 +1,16 @@
<?php
$drivers["mongo"] = "MongoDB (beta)";
$drivers["mongo"] = "MongoDB";
if (isset($_GET["mongo"])) {
$possible_drivers = array("mongo");
$possible_drivers = array("mongo", "mongodb");
define("DRIVER", "mongo");
if (class_exists('MongoDB')) {
class Min_DB {
var $extension = "Mongo", $error, $last_id, $_link, $_db;
var $extension = "Mongo", $server_info = MongoClient::VERSION, $error, $last_id, $_link, $_db;
function connect($server, $username, $password) {
global $adminer;
$db = $adminer->database();
$options = array();
if ($username != "") {
$options["username"] = $username;
$options["password"] = $password;
}
if ($db != "") {
$options["db"] = $db;
}
try {
$this->_link = @new MongoClient("mongodb://$server", $options);
return true;
} catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
function connect($uri, $options) {
return @new MongoClient($uri, $options);
}
function query($query) {
@@ -109,97 +93,481 @@ if (isset($_GET["mongo"])) {
}
}
}
class Min_Driver extends Min_SQL {
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$select = ($select == array("*")
? array()
: array_fill_keys($select, true)
);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
class Min_Driver extends Min_SQL {
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$select = ($select == array("*")
? array()
: array_fill_keys($select, true)
);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
}
return new Min_Result($this->_conn->_db->selectCollection($table)
->find(array(), $select)
->sort($sort)
->limit($limit != "" ? +$limit : 0)
->skip($page * $limit)
);
}
function insert($table, $set) {
try {
$return = $this->_conn->_db->selectCollection($table)->insert($set);
$this->_conn->errno = $return['code'];
$this->_conn->error = $return['err'];
$this->_conn->last_id = $set['_id'];
return !$return['err'];
} catch (Exception $ex) {
$this->_conn->error = $ex->getMessage();
return false;
}
}
return new Min_Result($this->_conn->_db->selectCollection($table)
->find(array(), $select)
->sort($sort)
->limit(+$limit)
->skip($page * $limit)
);
}
function insert($table, $set) {
try {
$return = $this->_conn->_db->selectCollection($table)->insert($set);
$this->_conn->errno = $return['code'];
$this->_conn->error = $return['err'];
$this->_conn->last_id = $set['_id'];
return !$return['err'];
} catch (Exception $ex) {
$this->_conn->error = $ex->getMessage();
function get_databases($flush) {
global $connection;
$return = array();
$dbs = $connection->_link->listDBs();
foreach ($dbs['databases'] as $db) {
$return[] = $db['name'];
}
return $return;
}
function count_tables($databases) {
global $connection;
$return = array();
foreach ($databases as $db) {
$return[$db] = count($connection->_link->selectDB($db)->getCollectionNames(true));
}
return $return;
}
function tables_list() {
global $connection;
return array_fill_keys($connection->_db->getCollectionNames(true), 'table');
}
function drop_databases($databases) {
global $connection;
foreach ($databases as $db) {
$response = $connection->_link->selectDB($db)->drop();
if (!$response['ok']) {
return false;
}
}
return true;
}
function indexes($table, $connection2 = null) {
global $connection;
$return = array();
foreach ($connection->_db->selectCollection($table)->getIndexInfo() as $index) {
$descs = array();
foreach ($index["key"] as $column => $type) {
$descs[] = ($type == -1 ? '1' : null);
}
$return[$index["name"]] = array(
"type" => ($index["name"] == "_id_" ? "PRIMARY" : ($index["unique"] ? "UNIQUE" : "INDEX")),
"columns" => array_keys($index["key"]),
"lengths" => array(),
"descs" => $descs,
);
}
return $return;
}
function fields($table) {
return fields_from_edit();
}
function found_rows($table_status, $where) {
global $connection;
//! don't call count_rows()
return $connection->_db->selectCollection($_GET["select"])->count($where);
}
$operators = array("=");
} elseif (class_exists('MongoDB\Driver\Manager')) {
class Min_DB {
var $extension = "MongoDB", $server_info = MONGODB_VERSION, $error, $last_id;
/** @var MongoDB\Driver\Manager */
var $_link;
var $_db, $_db_name;
function connect($uri, $options) {
$class = 'MongoDB\Driver\Manager';
return new $class($uri, $options);
}
function query($query) {
return false;
}
function select_db($database) {
$this->_db_name = $database;
return true;
}
function quote($string) {
return $string;
}
}
}
class Min_Result {
var $num_rows, $_rows = array(), $_offset = 0, $_charset = array();
function __construct($result) {
foreach ($result as $item) {
$row = array();
foreach ($item as $key => $val) {
if (is_a($val, 'MongoDB\BSON\Binary')) {
$this->_charset[$key] = 63;
}
$row[$key] =
(is_a($val, 'MongoDB\BSON\ObjectID') ? 'MongoDB\BSON\ObjectID("' . strval($val) . '")' :
(is_a($val, 'MongoDB\BSON\UTCDatetime') ? $val->toDateTime()->format('Y-m-d H:i:s') :
(is_a($val, 'MongoDB\BSON\Binary') ? $val->bin : //! allow downloading
(is_a($val, 'MongoDB\BSON\Regex') ? strval($val) :
(is_object($val) ? json_encode($val, 256) : // 256 = JSON_UNESCAPED_UNICODE
$val // MongoMinKey, MongoMaxKey
)))));
}
$this->_rows[] = $row;
foreach ($row as $key => $val) {
if (!isset($this->_rows[0][$key])) {
$this->_rows[0][$key] = null;
}
}
}
$this->num_rows = $result->count;
}
function fetch_assoc() {
$row = current($this->_rows);
if (!$row) {
return $row;
}
$return = array();
foreach ($this->_rows[0] as $key => $val) {
$return[$key] = $row[$key];
}
next($this->_rows);
return $return;
}
function fetch_row() {
$return = $this->fetch_assoc();
if (!$return) {
return $return;
}
return array_values($return);
}
function fetch_field() {
$keys = array_keys($this->_rows[0]);
$name = $keys[$this->_offset++];
return (object) array(
'name' => $name,
'charsetnr' => $this->_charset[$name],
);
}
function connect() {
global $adminer;
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
return $connection;
}
return $connection->error;
}
function error() {
global $connection;
return h($connection->error);
}
function logged_user() {
global $adminer;
$credentials = $adminer->credentials();
return $credentials[1];
}
class Min_Driver extends Min_SQL {
public $primary = "_id";
function get_databases($flush) {
global $connection;
$return = array();
$dbs = $connection->_link->listDBs();
foreach ($dbs['databases'] as $db) {
$return[] = $db['name'];
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
global $connection;
$select = ($select == array("*")
? array()
: array_fill_keys($select, 1)
);
if (count($select) && !isset($select['_id'])) {
$select['_id'] = 0;
}
$where = where_to_query($where);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
}
if (isset($_GET['limit']) && is_numeric($_GET['limit']) && $_GET['limit'] > 0) {
$limit = $_GET['limit'];
}
$limit = min(200, max(1, (int) $limit));
$skip = $page * $limit;
$class = 'MongoDB\Driver\Query';
$query = new $class($where, array('projection' => $select, 'limit' => $limit, 'skip' => $skip, 'sort' => $sort));
$results = $connection->_link->executeQuery("$connection->_db_name.$table", $query);
return new Min_Result($results);
}
function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
if (isset($set['_id'])) {
unset($set['_id']);
}
$removeFields = array();
foreach ($set as $key => $value) {
if ($value == 'NULL') {
$removeFields[$key] = 1;
unset($set[$key]);
}
}
$update = array('$set' => $set);
if (count($removeFields)) {
$update['$unset'] = $removeFields;
}
$bulk->update($where, $update, array('upsert' => false));
$results = $connection->_link->executeBulkWrite("$db.$table", $bulk);
$connection->affected_rows = $results->getModifiedCount();
return true;
}
function delete($table, $queryWhere, $limit = 0) {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
$bulk->delete($where, array('limit' => $limit));
$results = $connection->_link->executeBulkWrite("$db.$table", $bulk);
$connection->affected_rows = $results->getDeletedCount();
return true;
}
function insert($table, $set) {
global $connection;
$db = $connection->_db_name;
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
if (isset($set['_id']) && empty($set['_id'])) {
unset($set['_id']);
}
$bulk->insert($set);
$results = $connection->_link->executeBulkWrite("$db.$table", $bulk);
$connection->affected_rows = $results->getInsertedCount();
return true;
}
}
return $return;
}
function collations() {
return array();
}
function db_collation($db, $collations) {
}
function count_tables($databases) {
global $connection;
$return = array();
foreach ($databases as $db) {
$return[$db] = count($connection->_link->selectDB($db)->getCollectionNames(true));
function get_databases($flush) {
/** @var Min_DB */
global $connection;
$return = array();
$class = 'MongoDB\Driver\Command';
$command = new $class(array('listDatabases' => 1));
$results = $connection->_link->executeCommand('admin', $command);
foreach ($results as $dbs) {
foreach ($dbs->databases as $db) {
$return[] = $db->name;
}
}
return $return;
}
return $return;
function count_tables($databases) {
$return = array();
return $return;
}
function tables_list() {
global $connection;
$class = 'MongoDB\Driver\Command';
$command = new $class(array('listCollections' => 1));
$results = $connection->_link->executeCommand($connection->_db_name, $command);
$collections = array();
foreach ($results as $result) {
$collections[$result->name] = 'table';
}
return $collections;
}
function drop_databases($databases) {
return false;
}
function indexes($table, $connection2 = null) {
global $connection;
$return = array();
$class = 'MongoDB\Driver\Command';
$command = new $class(array('listIndexes' => $table));
$results = $connection->_link->executeCommand($connection->_db_name, $command);
foreach ($results as $index) {
$descs = array();
$columns = array();
foreach (get_object_vars($index->key) as $column => $type) {
$descs[] = ($type == -1 ? '1' : null);
$columns[] = $column;
}
$return[$index->name] = array(
"type" => ($index->name == "_id_" ? "PRIMARY" : (isset($index->unique) ? "UNIQUE" : "INDEX")),
"columns" => $columns,
"lengths" => array(),
"descs" => $descs,
);
}
return $return;
}
function fields($table) {
$fields = fields_from_edit();
if (!count($fields)) {
global $driver;
$result = $driver->select($table, array("*"), null, null, array(), 10);
while ($row = $result->fetch_assoc()) {
foreach ($row as $key => $val) {
$row[$key] = null;
$fields[$key] = array(
"field" => $key,
"type" => "string",
"null" => ($key != $driver->primary),
"auto_increment" => ($key == $driver->primary),
"privileges" => array(
"insert" => 1,
"select" => 1,
"update" => 1,
),
);
}
}
}
return $fields;
}
function found_rows($table_status, $where) {
global $connection;
$where = where_to_query($where);
$class = 'MongoDB\Driver\Command';
$command = new $class(array('count' => $table_status['Name'], 'query' => $where));
$results = $connection->_link->executeCommand($connection->_db_name, $command);
$toArray = $results->toArray();
return $toArray[0]->n;
}
function sql_query_where_parser($queryWhere) {
$queryWhere = trim(preg_replace('/WHERE[\s]?[(]?\(?/', '', $queryWhere));
$queryWhere = preg_replace('/\)\)\)$/', ')', $queryWhere);
$wheres = explode(' AND ', $queryWhere);
$wheresOr = explode(') OR (', $queryWhere);
$where = array();
foreach ($wheres as $whereStr) {
$where[] = trim($whereStr);
}
if (count($wheresOr) == 1) {
$wheresOr = array();
} elseif (count($wheresOr) > 1) {
$where = array();
}
return where_to_query($where, $wheresOr);
}
function where_to_query($whereAnd = array(), $whereOr = array()) {
global $adminer;
$data = array();
foreach (array('and' => $whereAnd, 'or' => $whereOr) as $type => $where) {
if (is_array($where)) {
foreach ($where as $expression) {
list($col, $op, $val) = explode(" ", $expression, 3);
if ($col == "_id") {
$val = str_replace('MongoDB\BSON\ObjectID("', "", $val);
$val = str_replace('")', "", $val);
$class = 'MongoDB\BSON\ObjectID';
$val = new $class($val);
}
if (!in_array($op, $adminer->operators)) {
continue;
}
if (preg_match('~^\(f\)(.+)~', $op, $match)) {
$val = (float) $val;
$op = $match[1];
} elseif (preg_match('~^\(date\)(.+)~', $op, $match)) {
$dateTime = new DateTime($val);
$class = 'MongoDB\BSON\UTCDatetime';
$val = new $class($dateTime->getTimestamp() * 1000);
$op = $match[1];
}
switch ($op) {
case '=':
$op = '$eq';
break;
case '!=':
$op = '$ne';
break;
case '>':
$op = '$gt';
break;
case '<':
$op = '$lt';
break;
case '>=':
$op = '$gte';
break;
case '<=':
$op = '$lte';
break;
case 'regex':
$op = '$regex';
break;
default:
continue 2;
}
if ($type == 'and') {
$data['$and'][] = array($col => array($op => $val));
} elseif ($type == 'or') {
$data['$or'][] = array($col => array($op => $val));
}
}
}
}
return $data;
}
$operators = array(
"=",
"!=",
">",
"<",
">=",
"<=",
"regex",
"(f)=",
"(f)!=",
"(f)>",
"(f)<",
"(f)>=",
"(f)<=",
"(date)=",
"(date)!=",
"(date)>",
"(date)<",
"(date)>=",
"(date)<=",
);
}
function tables_list() {
global $connection;
return array_fill_keys($connection->_db->getCollectionNames(true), 'table');
function table($idf) {
return $idf;
}
function idf_escape($idf) {
return $idf;
}
function table_status($name = "", $fast = false) {
@@ -213,43 +581,100 @@ if (isset($_GET["mongo"])) {
return $return;
}
function information_schema() {
function create_database($db, $collation) {
return true;
}
function is_view($table_status) {
}
function drop_databases($databases) {
function last_id() {
global $connection;
foreach ($databases as $db) {
$response = $connection->_link->selectDB($db)->drop();
if (!$response['ok']) {
return $connection->last_id;
}
function error() {
global $connection;
return h($connection->error);
}
function collations() {
return array();
}
function logged_user() {
global $adminer;
$credentials = $adminer->credentials();
return $credentials[1];
}
function connect() {
global $adminer;
$connection = new Min_DB;
list($server, $username, $password) = $adminer->credentials();
$options = array();
if ($username . $password != "") {
$options["username"] = $username;
$options["password"] = $password;
}
$db = $adminer->database();
if ($db != "") {
$options["db"] = $db;
}
if (($auth_source = getenv("MONGO_AUTH_SOURCE"))) {
$options["authSource"] = $auth_source;
}
try {
$connection->_link = $connection->connect("mongodb://$server", $options);
if ($password != "") {
$options["password"] = "";
try {
$connection->connect("mongodb://$server", $options);
return lang('Database does not support password.');
} catch (Exception $ex) {
// this is what we want
}
}
return $connection;
} catch (Exception $ex) {
return $ex->getMessage();
}
}
function alter_indexes($table, $alter) {
global $connection;
foreach ($alter as $val) {
list($type, $name, $set) = $val;
if ($set == "DROP") {
$return = $connection->_db->command(array("deleteIndexes" => $table, "index" => $name));
} else {
$columns = array();
foreach ($set as $column) {
$column = preg_replace('~ DESC$~', '', $column, 1, $count);
$columns[$column] = ($count ? -1 : 1);
}
$return = $connection->_db->selectCollection($table)->ensureIndex($columns, array(
"unique" => ($type == "UNIQUE"),
"name" => $name,
//! "sparse"
));
}
if ($return['errmsg']) {
$connection->error = $return['errmsg'];
return false;
}
}
return true;
}
function indexes($table, $connection2 = null) {
global $connection;
$return = array();
foreach ($connection->_db->selectCollection($table)->getIndexInfo() as $index) {
$descs = array();
foreach ($index["key"] as $column => $type) {
$descs[] = ($type == -1 ? '1' : null);
}
$return[$index["name"]] = array(
"type" => ($index["name"] == "_id_" ? "PRIMARY" : ($index["unique"] ? "UNIQUE" : "INDEX")),
"columns" => array_keys($index["key"]),
"lengths" => array(),
"descs" => $descs,
);
}
return $return;
function support($feature) {
return preg_match("~database|indexes|descidx~", $feature);
}
function fields($table) {
return fields_from_edit();
function db_collation($db, $collations) {
}
function information_schema() {
}
function is_view($table_status) {
}
function convert_field($field) {
@@ -270,12 +695,6 @@ if (isset($_GET["mongo"])) {
return array();
}
function found_rows($table_status, $where) {
global $connection;
//! don't call count_rows()
return $connection->_db->selectCollection($_GET["select"])->count($where);
}
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
global $connection;
if ($table == "") {
@@ -306,51 +725,7 @@ if (isset($_GET["mongo"])) {
return true;
}
function alter_indexes($table, $alter) {
global $connection;
foreach ($alter as $val) {
list($type, $name, $set) = $val;
if ($set == "DROP") {
$return = $connection->_db->command(array("deleteIndexes" => $table, "index" => $name));
} else {
$columns = array();
foreach ($set as $column) {
$column = preg_replace('~ DESC$~', '', $column, 1, $count);
$columns[$column] = ($count ? -1 : 1);
}
$return = $connection->_db->selectCollection($table)->ensureIndex($columns, array(
"unique" => ($type == "UNIQUE"),
"name" => $name,
//! "sparse"
));
}
if ($return['errmsg']) {
$connection->error = $return['errmsg'];
return false;
}
}
return true;
}
function last_id() {
global $connection;
return $connection->last_id;
}
function table($idf) {
return $idf;
}
function idf_escape($idf) {
return $idf;
}
function support($feature) {
return preg_match("~database|indexes~", $feature);
}
$jush = "mongo";
$operators = array("=");
$functions = array();
$grouping = array();
$edit_functions = array(array("json"));

View File

@@ -5,7 +5,7 @@
* @author Jakub Vrana
*/
$drivers["mssql"] = "MS SQL";
$drivers["mssql"] = "MS SQL (beta)";
if (isset($_GET["mssql"])) {
$possible_drivers = array("SQLSRV", "MSSQL", "PDO_DBLIB");
@@ -24,7 +24,13 @@ if (isset($_GET["mssql"])) {
}
function connect($server, $username, $password) {
$this->_link = @sqlsrv_connect($server, array("UID" => $username, "PWD" => $password, "CharacterSet" => "UTF-8"));
global $adminer;
$db = $adminer->database();
$connection_info = array("UID" => $username, "PWD" => $password, "CharacterSet" => "UTF-8");
if ($db != "") {
$connection_info["Database"] = $db;
}
$this->_link = @sqlsrv_connect(preg_replace('~:~', ',', $server), $connection_info);
if ($this->_link) {
$info = sqlsrv_server_info($this->_link);
$this->server_info = $info['SQLServerVersion'];
@@ -147,8 +153,10 @@ if (isset($_GET["mssql"])) {
$this->_link = @mssql_connect($server, $username, $password);
if ($this->_link) {
$result = $this->query("SELECT SERVERPROPERTY('ProductLevel'), SERVERPROPERTY('Edition')");
$row = $result->fetch_row();
$this->server_info = $this->result("sp_server_info 2", 2) . " [$row[0]] $row[1]";
if ($result) {
$row = $result->fetch_row();
$this->server_info = $this->result("sp_server_info 2", 2) . " [$row[0]] $row[1]";
}
} else {
$this->error = mssql_get_last_message();
}
@@ -239,7 +247,7 @@ if (isset($_GET["mssql"])) {
var $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);
$this->dsn("dblib:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password);
return true;
}
@@ -308,13 +316,13 @@ if (isset($_GET["mssql"])) {
return ($limit !== null ? " TOP (" . ($limit + $offset) . ")" : "") . " $query$where"; // seek later
}
function limit1($query, $where) {
return limit($query, $where, 1);
function limit1($table, $query, $where, $separator = "\n") {
return limit($query, $where, 1, 0, $separator);
}
function db_collation($db, $collations) {
global $connection;
return $connection->result("SELECT collation_name FROM sys.databases WHERE name = " . q($db));
return $connection->result("SELECT collation_name FROM sys.databases WHERE name = " . q($db));
}
function engines() {
@@ -342,7 +350,7 @@ if (isset($_GET["mssql"])) {
function table_status($name = "") {
$return = array();
foreach (get_rows("SELECT name AS Name, type_desc AS Engine FROM sys.all_objects WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row) {
foreach (get_rows("SELECT ao.name AS Name, ao.type_desc AS Engine, (SELECT value FROM fn_listextendedproperty(default, 'SCHEMA', schema_name(schema_id), 'TABLE', ao.name, null, null)) AS Comment FROM sys.all_objects AS ao WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row) {
if ($name != "") {
return $row;
}
@@ -360,8 +368,9 @@ if (isset($_GET["mssql"])) {
}
function fields($table) {
$comments = get_key_vals("SELECT objname, cast(value as varchar) FROM fn_listextendedproperty('MS_DESCRIPTION', 'schema', " . q(get_schema()) . ", 'table', " . q($table) . ", 'column', NULL)");
$return = array();
foreach (get_rows("SELECT c.*, t.name type, d.definition [default]
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]
FROM sys.all_columns c
JOIN sys.all_objects o ON c.object_id = o.object_id
JOIN sys.types t ON c.user_type_id = t.user_type_id
@@ -381,6 +390,7 @@ WHERE o.schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND o.type IN ('S', 'U',
"collation" => $row["collation_name"],
"privileges" => array("insert" => 1, "select" => 1, "update" => 1),
"primary" => $row["is_identity"], //! or indexes.is_primary_key
"comment" => $comments[$row["name"]],
);
}
return $return;
@@ -406,7 +416,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
function view($name) {
global $connection;
return array("select" => preg_replace('~^(?:[^[]|\\[[^]]*])*\\s+AS\\s+~isU', '', $connection->result("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = SCHEMA_NAME() AND TABLE_NAME = " . q($name))));
return array("select" => preg_replace('~^(?:[^[]|\[[^]]*])*\s+AS\s+~isU', '', $connection->result("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = SCHEMA_NAME() AND TABLE_NAME = " . q($name))));
}
function collations() {
@@ -423,7 +433,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
function error() {
global $connection;
return nl_br(h(preg_replace('~^(\\[[^]]*])+~m', '', $connection->error)));
return nl_br(h(preg_replace('~^(\[[^]]*])+~m', '', $connection->error)));
}
function create_database($db, $collation) {
@@ -448,13 +458,16 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
$alter = array();
$comments = array();
foreach ($fields as $field) {
$column = idf_escape($field[0]);
$val = $field[1];
if (!$val) {
$alter["DROP"][] = " COLUMN $column";
} else {
$val[1] = preg_replace("~( COLLATE )'(\\w+)'~", "\\1\\2", $val[1]);
$val[1] = preg_replace("~( COLLATE )'(\\w+)'~", '\1\2', $val[1]);
$comments[$field[0]] = $val[5];
unset($val[5]);
if ($field[0] == "") {
$alter["ADD"][] = "\n " . implode("", $val) . ($table == "" ? substr($foreign[$val[0]], 16 + strlen($val[0])) : ""); // 16 - strlen(" FOREIGN KEY ()")
} else {
@@ -480,6 +493,11 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
return false;
}
}
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));
}
return true;
}
@@ -524,6 +542,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
$return = array();
foreach (get_rows("EXEC sp_fkeys @fktable_name = " . q($table)) as $row) {
$foreign_key = &$return[$row["FK_NAME"]];
$foreign_key["db"] = $row["PKTABLE_QUALIFIER"];
$foreign_key["table"] = $row["PKTABLE_NAME"];
$foreign_key["source"][] = $row["FKCOLUMN_NAME"];
$foreign_key["target"][] = $row["PKCOLUMN_NAME"];
@@ -561,7 +580,7 @@ WHERE s.xtype = 'TR' AND s.name = " . q($name)
); // triggers are not schema-scoped
$return = reset($rows);
if ($return) {
$return["Statement"] = preg_replace('~^.+\\s+AS\\s+~isU', '', $return["text"]); //! identifiers, comments
$return["Statement"] = preg_replace('~^.+\s+AS\s+~isU', '', $return["text"]); //! identifiers, comments
}
return $return;
}
@@ -624,7 +643,7 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
}
function support($feature) {
return preg_match('~^(columns|database|drop_col|indexes|scheme|sql|table|trigger|view|view_trigger)$~', $feature); //! routine|
return preg_match('~^(comment|columns|database|drop_col|indexes|descidx|scheme|sql|table|trigger|view|view_trigger)$~', $feature); //! routine|
}
$jush = "mssql";

View File

@@ -14,16 +14,23 @@ if (!defined("DRIVER")) {
}
function connect($server = "", $username = "", $password = "", $database = null, $port = null, $socket = null) {
global $adminer;
mysqli_report(MYSQLI_REPORT_OFF); // stays between requests, not required since PHP 5.3.4
list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
$ssl = $adminer->connectSsl();
if ($ssl) {
$this->ssl_set($ssl['key'], $ssl['cert'], $ssl['ca'], '', '');
}
$return = @$this->real_connect(
($server != "" ? $host : ini_get("mysqli.default_host")),
($server . $username != "" ? $username : ini_get("mysqli.default_user")),
($server . $username . $password != "" ? $password : ini_get("mysqli.default_pw")),
$database,
(is_numeric($port) ? $port : ini_get("mysqli.default_port")),
(!is_numeric($port) ? $port : $socket)
(!is_numeric($port) ? $port : $socket),
($ssl ? 64 : 0) // 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16)
);
$this->options(MYSQLI_OPT_LOCAL_INFILE, false);
return $return;
}
@@ -50,7 +57,7 @@ if (!defined("DRIVER")) {
}
}
} elseif (extension_loaded("mysql") && !(ini_get("sql.safe_mode") && extension_loaded("pdo_mysql"))) {
} elseif (extension_loaded("mysql") && !((ini_bool("sql.safe_mode") || ini_bool("mysql.allow_local_infile")) && extension_loaded("pdo_mysql"))) {
class Min_DB {
var
$extension = "MySQL", ///< @var string extension name
@@ -68,6 +75,10 @@ if (!defined("DRIVER")) {
* @return bool
*/
function connect($server, $username, $password) {
if (ini_bool("mysql.allow_local_infile")) {
$this->error = lang('Disable %s or enable %s or %s extensions.', "'mysql.allow_local_infile'", "MySQLi", "PDO_MySQL");
return false;
}
$this->_link = @mysql_connect(
($server != "" ? $server : ini_get("mysql.default_host")),
("$server$username" != "" ? $username : ini_get("mysql.default_user")),
@@ -223,7 +234,26 @@ if (!defined("DRIVER")) {
var $extension = "PDO_MySQL";
function connect($server, $username, $password) {
$this->dsn("mysql:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\\d)~', ';port=\\1', $server)), $username, $password);
global $adminer;
$options = array(PDO::MYSQL_ATTR_LOCAL_INFILE => false);
$ssl = $adminer->connectSsl();
if ($ssl) {
if (!empty($ssl['key'])) {
$options[PDO::MYSQL_ATTR_SSL_KEY] = $ssl['key'];
}
if (!empty($ssl['cert'])) {
$options[PDO::MYSQL_ATTR_SSL_CERT] = $ssl['cert'];
}
if (!empty($ssl['ca'])) {
$options[PDO::MYSQL_ATTR_SSL_CA] = $ssl['ca'];
}
}
$this->dsn(
"mysql:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)),
$username,
$password,
$options
);
return true;
}
@@ -276,6 +306,42 @@ if (!defined("DRIVER")) {
}
return queries($prefix . implode(",\n", $values) . $suffix);
}
function slowQuery($query, $timeout) {
if (min_version('5.7.8', '10.1.2')) {
if (preg_match('~MariaDB~', $this->_conn->server_info)) {
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]";
}
}
}
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) . ")"
: $idf
);
}
function 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
return ob_get_clean();
}
}
function tableHelp($name) {
$maria = preg_match('~MariaDB~', $this->_conn->server_info);
if (information_schema(DB)) {
return strtolower(($maria ? "information-schema-$name-table/" : str_replace("_", "-", $name) . "-table.html"));
}
if (DB == "mysql") {
return ($maria ? "mysql$name-table/" : "system-database.html"); //! more precise link
}
}
}
@@ -307,7 +373,7 @@ if (!defined("DRIVER")) {
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
$connection->set_charset(charset($connection)); // available in MySQLi since PHP 5.0.5
$connection->query("SET sql_quote_show_create = 1, autocommit = 1");
if (version_compare($connection->server_info, '5.7.8') >= 0) {
if (min_version('5.7.8', 10.2, $connection)) {
$structured_types[lang('Strings')][] = "json";
$types["json"] = 4294967295;
}
@@ -325,12 +391,11 @@ if (!defined("DRIVER")) {
* @return array
*/
function get_databases($flush) {
global $connection;
// SHOW DATABASES can take a very long time so it is cached
$return = get_session("dbs");
if ($return === null) {
$query = ($connection->server_info >= 5
? "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA"
$query = (min_version(5)
? "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA ORDER BY SCHEMA_NAME"
: "SHOW DATABASES"
); // SHOW DATABASES can be disabled by skip_show_database
$return = ($flush ? slow_query($query) : get_vals($query));
@@ -354,12 +419,14 @@ if (!defined("DRIVER")) {
}
/** Formulate SQL modification query with limit 1
* @param string
* @param string everything after UPDATE or DELETE
* @param string
* @param string
* @return string
*/
function limit1($query, $where) {
return limit($query, $where, 1);
function limit1($table, $query, $where, $separator = "\n") {
return limit($query, $where, 1, 0, $separator);
}
/** Get database collation
@@ -405,8 +472,7 @@ if (!defined("DRIVER")) {
* @return array array($name => $type)
*/
function tables_list() {
global $connection;
return get_key_vals($connection->server_info >= 5
return get_key_vals(min_version(5)
? "SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME"
: "SHOW TABLES"
);
@@ -430,15 +496,14 @@ if (!defined("DRIVER")) {
* @return array array($name => array("Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => )) or only inner array with $name
*/
function table_status($name = "", $fast = false) {
global $connection;
$return = array();
foreach (get_rows($fast && $connection->server_info >= 5
foreach (get_rows($fast && min_version(5)
? "SELECT TABLE_NAME AS Name, ENGINE AS Engine, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name")
: "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "")
) as $row) {
if ($row["Engine"] == "InnoDB") {
// ignore internal comment, unnecessary since MySQL 5.1.21
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["Comment"]);
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\1', $row["Comment"]);
}
if (!isset($row["Engine"])) {
$row["Comment"] = "";
@@ -464,9 +529,8 @@ if (!defined("DRIVER")) {
* @return bool
*/
function fk_support($table_status) {
global $connection;
return preg_match('~InnoDB|IBMDB2I~i', $table_status["Engine"])
|| (preg_match('~NDB~i', $table_status["Engine"]) && version_compare($connection->server_info, '5.6') >= 0);
|| (preg_match('~NDB~i', $table_status["Engine"]) && min_version(5.6));
}
/** Get information about fields
@@ -476,7 +540,7 @@ if (!defined("DRIVER")) {
function fields($table) {
$return = array();
foreach (get_rows("SHOW FULL COLUMNS FROM " . table($table)) as $row) {
preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~', $row["Type"], $match);
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $row["Type"], $match);
$return[$row["Field"]] = array(
"field" => $row["Field"],
"full_type" => $row["Type"],
@@ -491,6 +555,8 @@ if (!defined("DRIVER")) {
"privileges" => array_flip(preg_split('~, *~', $row["Privileges"])),
"comment" => $row["Comment"],
"primary" => ($row["Key"] == "PRI"),
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186
"generated" => preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $row["Extra"]),
);
}
return $return;
@@ -519,7 +585,7 @@ if (!defined("DRIVER")) {
*/
function foreign_keys($table) {
global $connection, $on_actions;
static $pattern = '`(?:[^`]|``)+`';
static $pattern = '(?:`(?:[^`]|``)+`|"(?:[^"]|"")+")';
$return = array();
$create_table = $connection->result("SHOW CREATE TABLE " . table($table), 1);
if ($create_table) {
@@ -546,7 +612,7 @@ if (!defined("DRIVER")) {
*/
function view($name) {
global $connection;
return array("select" => preg_replace('~^(?:[^`]|`[^`]*`)*\\s+AS\\s+~isU', '', $connection->result("SHOW CREATE VIEW " . table($name), 1)));
return array("select" => preg_replace('~^(?:[^`]|`[^`]*`)*\s+AS\s+~isU', '', $connection->result("SHOW CREATE VIEW " . table($name), 1)));
}
/** Get sorted grouped list of collations
@@ -573,9 +639,8 @@ if (!defined("DRIVER")) {
* @return bool
*/
function information_schema($db) {
global $connection;
return ($connection->server_info >= 5 && $db == "information_schema")
|| ($connection->server_info >= 5.5 && $db == "performance_schema");
return (min_version(5) && $db == "information_schema")
|| (min_version(5.5) && $db == "performance_schema");
}
/** Get escaped error message
@@ -751,19 +816,24 @@ if (!defined("DRIVER")) {
queries("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'");
foreach ($tables as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
if (!queries("\nDROP TABLE IF EXISTS $name")
if (($_POST["overwrite"] && !queries("\nDROP TABLE IF EXISTS $name"))
|| !queries("CREATE TABLE $name LIKE " . table($table))
|| !queries("INSERT INTO $name SELECT * FROM " . table($table))
) {
return false;
}
foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_\\"))) as $row) {
$trigger = $row["Trigger"];
if (!queries("CREATE TRIGGER " . ($target == DB ? idf_escape("copy_$trigger") : idf_escape($target) . "." . idf_escape($trigger)) . " $row[Timing] $row[Event] ON $name FOR EACH ROW\n$row[Statement];")) {
return false;
}
}
}
foreach ($views as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
$view = view($table);
if (!queries("DROP VIEW IF EXISTS $name")
|| !queries("CREATE VIEW $name AS $view[select]") //! USE to avoid db.table
) {
if (($_POST["overwrite"] && !queries("DROP VIEW IF EXISTS $name"))
|| !queries("CREATE VIEW $name AS $view[select]")) { //! USE to avoid db.table
return false;
}
}
@@ -813,8 +883,9 @@ if (!defined("DRIVER")) {
function routine($name, $type) {
global $connection, $enum_length, $inout, $types;
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum_length)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$pattern = "\\s*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
$fields = array();
@@ -825,7 +896,7 @@ if (!defined("DRIVER")) {
"field" => $name,
"type" => strtolower($param[5]),
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
"unsigned" => strtolower(preg_replace('~\\s+~', ' ', trim("$param[8] $param[7]"))),
"unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))),
"null" => 1,
"full_type" => $param[4],
"inout" => strtoupper($param[1]),
@@ -844,10 +915,10 @@ if (!defined("DRIVER")) {
}
/** Get list of routines
* @return array ("ROUTINE_TYPE" => , "ROUTINE_NAME" => , "DTD_IDENTIFIER" => )
* @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => )
*/
function routines() {
return get_rows("SELECT ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
}
/** Get list of available routine languages
@@ -857,6 +928,15 @@ if (!defined("DRIVER")) {
return array(); // "SQL" not required
}
/** Get routine signature
* @param string
* @param array result of routine()
* @return string
*/
function routine_id($name, $row) {
return idf_escape($name);
}
/** Get last auto increment ID
* @return string
*/
@@ -871,7 +951,7 @@ if (!defined("DRIVER")) {
* @return Min_Result
*/
function explain($connection, $query) {
return $connection->query("EXPLAIN " . ($connection->server_info >= 5.1 ? "PARTITIONS " : "") . $query);
return $connection->query("EXPLAIN " . (min_version(5.1) ? "PARTITIONS " : "") . $query);
}
/** Get approximate number of rows
@@ -915,13 +995,14 @@ if (!defined("DRIVER")) {
/** Get SQL command to create table
* @param string
* @param bool
* @param string
* @return string
*/
function create_sql($table, $auto_increment) {
function create_sql($table, $auto_increment, $style) {
global $connection;
$return = $connection->result("SHOW CREATE TABLE " . table($table), 1);
if (!$auto_increment) {
$return = preg_replace('~ AUTO_INCREMENT=\\d+~', '', $return); //! skip comments
$return = preg_replace('~ AUTO_INCREMENT=\d+~', '', $return); //! skip comments
}
return $return;
}
@@ -944,14 +1025,12 @@ if (!defined("DRIVER")) {
/** Get SQL commands to create triggers
* @param string
* @param string
* @return string
*/
function trigger_sql($table, $style) {
function trigger_sql($table) {
$return = "";
foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_\\")), null, "-- ") as $row) {
$return .= "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "")
. "CREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . table($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n";
$return .= "\nCREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . table($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n";
}
return $return;
}
@@ -977,14 +1056,6 @@ if (!defined("DRIVER")) {
return get_key_vals("SHOW STATUS");
}
/** Get replication status of master or slave
* @param string
* @return array ($name => $value)
*/
function replication_status($type) {
return get_rows("SHOW $type STATUS");
}
/** Convert field in select and edit
* @param array one element from fields()
* @return string
@@ -997,7 +1068,7 @@ if (!defined("DRIVER")) {
return "BIN(" . idf_escape($field["field"]) . " + 0)"; // + 0 is required outside MySQLnd
}
if (preg_match("~geometry|point|linestring|polygon~", $field["type"])) {
return "AsWKT(" . idf_escape($field["field"]) . ")";
return (min_version(8) ? "ST_" : "") . "AsWKT(" . idf_escape($field["field"]) . ")";
}
}
@@ -1014,18 +1085,17 @@ if (!defined("DRIVER")) {
$return = "CONV($return, 2, 10) + 0";
}
if (preg_match("~geometry|point|linestring|polygon~", $field["type"])) {
$return = "GeomFromText($return)";
$return = (min_version(8) ? "ST_" : "") . "GeomFromText($return, SRID($field[field]))";
}
return $return;
}
/** Check whether a feature is supported
* @param string "comment", "copy", "database", "drop_col", "dump", "event", "kill", "materializedview", "partitioning", "privileges", "procedure", "processlist", "routine", "scheme", "sequence", "status", "table", "trigger", "type", "variables", "view", "view_trigger"
* @param string "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) {
global $connection;
return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . ($connection->server_info < 5.1 ? "|event|partitioning" . ($connection->server_info < 5 ? "|routine|trigger|view" : "") : "") . "~", $feature);
return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . (min_version(8) ? "" : "|descidx" . (min_version(5.1) ? "" : "|event|partitioning" . (min_version(5) ? "" : "|routine|trigger|view"))) . "~", $feature);
}
function kill_process($val) {
@@ -1056,16 +1126,16 @@ if (!defined("DRIVER")) {
$structured_types[$key] = array_keys($val);
}
$unsigned = array("unsigned", "zerofill", "unsigned zerofill"); ///< @var array number variants
$operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"); ///< @var array operators used in select
$functions = array("char_length", "date", "from_unixtime", "lower", "round", "sec_to_time", "time_to_sec", "upper"); ///< @var array functions used in select
$operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"); ///< @var array operators used in select
$functions = array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper"); ///< @var array functions used in select
$grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"); ///< @var array grouping functions used in select
$edit_functions = array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only
array(
"char" => "md5/sha1/password/encrypt/uuid", //! JavaScript for disabling maxlength
"char" => "md5/sha1/password/encrypt/uuid",
"binary" => "md5/sha1",
"date|time" => "now",
), array(
"(^|[^o])int|float|double|decimal" => "+/-", // not point
number_type() => "+/-",
"date" => "+ interval/- interval",
"time" => "addtime/subtime",
"char|text" => "concat",

View File

@@ -1,5 +1,5 @@
<?php
$drivers["oracle"] = "Oracle";
$drivers["oracle"] = "Oracle (beta)";
if (isset($_GET["oracle"])) {
$possible_drivers = array("OCI8", "PDO_OCI");
@@ -175,8 +175,8 @@ if (isset($_GET["oracle"])) {
));
}
function limit1($query, $where) {
return " $query$where";
function limit1($table, $query, $where, $separator = "\n") {
return " $query$where"; //! limit
}
function db_collation($db, $collations) {
@@ -398,7 +398,7 @@ ORDER BY PROCESS
}
function support($feature) {
return preg_match('~^(columns|database|drop_col|indexes|processlist|scheme|sql|status|table|variables|view|view_trigger)$~', $feature); //!
return preg_match('~^(columns|database|drop_col|indexes|descidx|processlist|scheme|sql|status|table|variables|view|view_trigger)$~', $feature); //!
}
$jush = "oracle";

View File

@@ -6,7 +6,7 @@ if (isset($_GET["pgsql"])) {
define("DRIVER", "pgsql");
if (extension_loaded("pgsql")) {
class Min_DB {
var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error;
var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error, $timeout;
function _error($errno, $error) {
if (ini_bool("html_errors")) {
@@ -37,7 +37,15 @@ if (isset($_GET["pgsql"])) {
}
function quote($string) {
return "'" . pg_escape_string($this->_link, $string) . "'"; //! bytea
return "'" . pg_escape_string($this->_link, $string) . "'";
}
function value($val, $field) {
return ($field["type"] == "bytea" ? pg_unescape_bytea($val) : $val);
}
function quoteBinary($string) {
return "'" . pg_escape_bytea($this->_link, $string) . "'";
}
function select_db($database) {
@@ -61,12 +69,18 @@ if (isset($_GET["pgsql"])) {
$this->error = "";
if (!$result) {
$this->error = pg_last_error($this->_link);
return false;
$return = false;
} elseif (!pg_num_fields($result)) {
$this->affected_rows = pg_affected_rows($result);
return true;
$return = true;
} else {
$return = new Min_Result($result);
}
return new Min_Result($result);
if ($this->timeout) {
$this->timeout = 0;
$this->query("RESET statement_timeout");
}
return $return;
}
function multi_query($query) {
@@ -89,6 +103,10 @@ if (isset($_GET["pgsql"])) {
}
return pg_fetch_result($result->_result, 0, $field);
}
function warnings() {
return h(pg_last_notice($this->_link)); // second parameter is available since PHP 7.1.0
}
}
class Min_Result {
@@ -127,7 +145,7 @@ if (isset($_GET["pgsql"])) {
} elseif (extension_loaded("pdo_pgsql")) {
class Min_DB extends Min_PDO {
var $extension = "PDO_PgSQL";
var $extension = "PDO_PgSQL", $timeout;
function connect($server, $username, $password) {
global $adminer;
@@ -143,6 +161,23 @@ 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) {
$this->timeout = 0;
parent::query("RESET statement_timeout");
}
return $return;
}
function warnings() {
return ''; // not implemented in PDO_PgSQL as of PHP 7.2.1
}
function close() {
}
}
@@ -173,6 +208,40 @@ if (isset($_GET["pgsql"])) {
return true;
}
function slowQuery($query, $timeout) {
$this->_conn->query("SET statement_timeout = " . (1000 * $timeout));
$this->_conn->timeout = 1000 * $timeout;
return $query;
}
function convertSearch($idf, $val, $field) {
return (preg_match('~char|text'
. (!preg_match('~LIKE~', $val["op"]) ? '|date|time(stamp)?|boolean|uuid|' . number_type() : '')
. '~', $field["type"])
? $idf
: "CAST($idf AS text)"
);
}
function quoteBinary($s) {
return $this->_conn->quoteBinary($s);
}
function warnings() {
return $this->_conn->warnings();
}
function tableHelp($name) {
$links = array(
"information_schema" => "infoschema",
"pg_catalog" => "catalog",
);
$link = $links[$_GET["ns"]];
if ($link) {
return "$link-" . str_replace("_", "-", $name) . ".html";
}
}
}
@@ -190,12 +259,12 @@ if (isset($_GET["pgsql"])) {
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
if ($connection->server_info >= 9) {
if (min_version(9, 0, $connection)) {
$connection->query("SET application_name = 'Adminer'");
if ($connection->server_info >= 9.2) {
if (min_version(9.2, 0, $connection)) {
$structured_types[lang('Strings')][] = "json";
$types["json"] = 4294967295;
if ($connection->server_info >= 9.4) {
if (min_version(9.4, 0, $connection)) {
$structured_types[lang('Strings')][] = "jsonb";
$types["jsonb"] = 4294967295;
}
@@ -214,8 +283,11 @@ if (isset($_GET["pgsql"])) {
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
}
function limit1($query, $where) {
return " $query$where";
function limit1($table, $query, $where, $separator = "\n") {
return (preg_match('~^INTO~', $query)
? limit($query, $where, 1, 0, $separator)
: " $query" . (is_view(table_status1($table)) ? $where : " WHERE ctid = (SELECT ctid FROM " . table($table) . $where . $separator . "LIMIT 1)")
);
}
function db_collation($db, $collations) {
@@ -252,11 +324,11 @@ ORDER BY 1";
function table_status($name = "") {
$return = array();
foreach (get_rows("SELECT c.relname AS \"Name\", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\", pg_relation_size(c.oid) AS \"Data_length\", pg_total_relation_size(c.oid) - pg_relation_size(c.oid) AS \"Index_length\", obj_description(c.oid, 'pg_class') AS \"Comment\", c.relhasoids::int AS \"Oid\", c.reltuples as \"Rows\", n.nspname
foreach (get_rows("SELECT c.relname AS \"Name\", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\", pg_relation_size(c.oid) AS \"Data_length\", pg_total_relation_size(c.oid) - pg_relation_size(c.oid) AS \"Index_length\", obj_description(c.oid, 'pg_class') AS \"Comment\", " . (min_version(12) ? "''" : "CASE WHEN c.relhasoids THEN 'oid' ELSE '' END") . " AS \"Oid\", c.reltuples as \"Rows\", n.nspname
FROM pg_class c
JOIN pg_namespace n ON(n.nspname = current_schema() AND n.oid = c.relnamespace)
WHERE relkind IN ('r', 'm', 'v')
" . ($name != "" ? "AND relname = " . q($name) : "ORDER BY c.oid")
WHERE relkind IN ('r', 'm', 'v', 'f')
" . ($name != "" ? "AND relname = " . q($name) : "ORDER BY relname")
) as $row) { //! Index_length, Auto_increment
$return[$row["Name"]] = $row;
}
@@ -277,7 +349,10 @@ WHERE relkind IN ('r', 'm', 'v')
'timestamp without time zone' => 'timestamp',
'timestamp with time zone' => 'timestamptz',
);
foreach (get_rows("SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, d.adsrc AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment
$identity_column = min_version(10) ? "(a.attidentity = 'd')::int" : '0';
foreach (get_rows("SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, d.adsrc AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment, $identity_column AS identity
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_attribute a ON c.oid = a.attrelid
@@ -300,11 +375,14 @@ ORDER BY a.attnum"
$row["type"] = $type;
$row["full_type"] = $row["type"] . $length . $addon . $array;
}
if ($row['identity']) {
$row['default'] = 'GENERATED BY DEFAULT AS IDENTITY';
}
$row["null"] = !$row["attnotnull"];
$row["auto_increment"] = preg_match('~^nextval\\(~i', $row["default"]);
$row["auto_increment"] = $row['identity'] || preg_match('~^nextval\(~i', $row["default"]);
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1);
if (preg_match('~(.+)::[^)]+(.*)~', $row["default"], $match)) {
$row["default"] = ($match[1][0] == "'" ? idf_unescape($match[1]) : $match[1]) . $match[2];
$row["default"] = ($match[1] == "NULL" ? null : (($match[1][0] == "'" ? idf_unescape($match[1]) : $match[1]) . $match[2]));
}
$return[$row["field"]] = $row;
}
@@ -360,7 +438,7 @@ ORDER BY conkey, conname") as $row) {
function view($name) {
global $connection;
return array("select" => trim($connection->result("SELECT pg_get_viewdef(" . q($name) . ")")));
return array("select" => trim($connection->result("SELECT pg_get_viewdef(" . $connection->result("SELECT oid FROM pg_class WHERE relname = " . q($name)) . ")")));
}
function collations() {
@@ -375,8 +453,8 @@ ORDER BY conkey, conname") as $row) {
function error() {
global $connection;
$return = h($connection->error);
if (preg_match('~^(.*\\n)?([^\\n]*)\\n( *)\\^(\\n.*)?$~s', $return, $match)) {
$return = $match[1] . preg_replace('~((?:[^&]|&[^;]*;){' . strlen($match[3]) . '})(.*)~', '\\1<b>\\2</b>', $match[2]) . $match[4];
if (preg_match('~^(.*\n)?([^\n]*)\n( *)\^(\n.*)?$~s', $return, $match)) {
$return = $match[1] . preg_replace('~((?:[^&]|&[^;]*;){' . strlen($match[3]) . '})(.*)~', '\1<b>\2</b>', $match[2]) . $match[4];
}
return nl_br($return);
}
@@ -403,6 +481,9 @@ ORDER BY conkey, conname") as $row) {
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
$alter = array();
$queries = array();
if ($table != "" && $table != $name) {
$queries[] = "ALTER TABLE " . table($table) . " RENAME TO " . table($name);
}
foreach ($fields as $field) {
$column = idf_escape($field[0]);
$val = $field[1];
@@ -418,7 +499,7 @@ ORDER BY conkey, conname") as $row) {
$alter[] = ($table != "" ? "ADD " : " ") . implode($val);
} else {
if ($column != $val[0]) {
$queries[] = "ALTER TABLE " . table($table) . " RENAME $column TO $val[0]";
$queries[] = "ALTER TABLE " . table($name) . " RENAME $column TO $val[0]";
}
$alter[] = "ALTER $column TYPE$val[1]";
if (!$val[6]) {
@@ -427,7 +508,7 @@ ORDER BY conkey, conname") as $row) {
}
}
if ($field[0] != "" || $val5 != "") {
$queries[] = "COMMENT ON COLUMN " . table($table) . ".$val[0] IS " . ($val5 != "" ? substr($val5, 9) : "''");
$queries[] = "COMMENT ON COLUMN " . table($name) . ".$val[0] IS " . ($val5 != "" ? substr($val5, 9) : "''");
}
}
}
@@ -437,9 +518,6 @@ ORDER BY conkey, conname") as $row) {
} elseif ($alter) {
array_unshift($queries, "ALTER TABLE " . table($table) . "\n" . implode(",\n", $alter));
}
if ($table != "" && $table != $name) {
$queries[] = "ALTER TABLE " . table($table) . " RENAME TO " . table($name);
}
if ($table != "" || $comment != "") {
$queries[] = "COMMENT ON TABLE " . table($name) . " IS " . q($comment);
}
@@ -541,30 +619,36 @@ ORDER BY conkey, conname") as $row) {
);
}
/*
function routine($name, $type) {
//! there can be more functions with the same name differing only in parameters, it must be also passed to DROP FUNCTION
//! no procedures, only functions
//! different syntax of CREATE FUNCTION
$rows = get_rows('SELECT pg_catalog.format_type(p.prorettype, NULL) AS "returns", p.prosrc AS "definition"
FROM pg_catalog.pg_namespace n
JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid
WHERE n.nspname = current_schema() AND p.proname = ' . q($name));
$rows[0]["fields"] = array(); //!
return $rows[0];
$rows = get_rows('SELECT routine_definition AS definition, LOWER(external_language) AS language, *
FROM information_schema.routines
WHERE routine_schema = current_schema() AND specific_name = ' . q($name));
$return = $rows[0];
$return["returns"] = array("type" => $return["type_udt_name"]);
$return["fields"] = get_rows('SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, parameter_mode AS inout
FROM information_schema.parameters
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
ORDER BY ordinal_position');
return $return;
}
*/
function routines() {
return get_rows('SELECT p.proname AS "ROUTINE_NAME", p.proargtypes AS "ROUTINE_TYPE", pg_catalog.format_type(p.prorettype, NULL) AS "DTD_IDENTIFIER"
FROM pg_catalog.pg_namespace n
JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid
WHERE n.nspname = current_schema()
ORDER BY p.proname');
return get_rows('SELECT specific_name AS "SPECIFIC_NAME", routine_type AS "ROUTINE_TYPE", routine_name AS "ROUTINE_NAME", type_udt_name AS "DTD_IDENTIFIER"
FROM information_schema.routines
WHERE routine_schema = current_schema()
ORDER BY SPECIFIC_NAME');
}
function routine_languages() {
return get_vals("SELECT langname FROM pg_catalog.pg_language");
return get_vals("SELECT LOWER(lanname) FROM pg_catalog.pg_language");
}
function routine_id($name, $row) {
$return = array();
foreach ($row["fields"] as $field) {
$return[] = $field["type"];
}
return idf_escape($name) . "(" . implode(", ", $return) . ")";
}
function last_id() {
@@ -617,12 +701,7 @@ AND typelem = 0"
return $return;
}
/** Get SQL command to create table
* @param string
* @param bool
* @return string
*/
function create_sql($table, $auto_increment) {
function create_sql($table, $auto_increment, $style) {
global $connection;
$return = '';
$return_parts = array();
@@ -634,7 +713,6 @@ AND typelem = 0"
ksort($indexes);
$fkeys = foreign_keys($table);
ksort($fkeys);
$triggers = triggers($table);
if (!$status || empty($fields)) {
return false;
@@ -645,15 +723,19 @@ AND typelem = 0"
// fields' definitions
foreach ($fields as $field_name => $field) {
$part = idf_escape($field['field']) . ' ' . $field['full_type']
. (is_null($field['default']) ? "" : " DEFAULT $field[default]")
. default_value($field)
. ($field['attnotnull'] ? " NOT NULL" : "");
$return_parts[] = $part;
// sequences for fields
if (preg_match('~nextval\(\'([^\']+)\'\)~', $field['default'], $matches)) {
$sequence_name = $matches[1];
$sq = reset(get_rows("SELECT * FROM $sequence_name"));
$sequences[] = "CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value] START " . ($auto_increment ? $sq['last_value'] : 1) . " CACHE $sq[cache_value];";
$sq = reset(get_rows(min_version(10)
? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q($sequence_name)
: "SELECT * FROM $sequence_name"
));
$sequences[] = ($style == "DROP+CREATE" ? "DROP SEQUENCE IF EXISTS $sequence_name;\n" : "")
. "CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value] START " . ($auto_increment ? $sq['last_value'] : 1) . " CACHE $sq[cache_value];";
}
}
@@ -680,7 +762,11 @@ AND typelem = 0"
// "basic" indexes after table definition
foreach ($indexes as $index_name => $index) {
if ($index['type'] == 'INDEX') {
$return .= "\n\nCREATE INDEX " . idf_escape($index_name) . " ON " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " USING btree (" . implode(', ', array_map('idf_escape', $index['columns'])) . ");";
$columns = array();
foreach ($index['columns'] as $key => $val) {
$columns[] = idf_escape($val) . ($index['descs'][$key] ? " DESC" : "");
}
$return .= "\n\nCREATE INDEX " . idf_escape($index_name) . " ON " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " USING btree (" . implode(', ', $columns) . ");";
}
}
@@ -695,30 +781,21 @@ AND typelem = 0"
}
}
// triggers
foreach ($triggers as $trg_id => $trg) {
$trigger = trigger($trg_id, $status['Name']);
$return .= "\n\nCREATE TRIGGER " . idf_escape($trigger['Trigger']) . " $trigger[Timing] $trigger[Events] ON " . idf_escape($status["nspname"]) . "." . idf_escape($status['Name']) . " $trigger[Type] $trigger[Statement];";
}
return rtrim($return, ';');
}
/** Get SQL commands to create triggers
* @param string
* @param string
* @return string
*/
//@TODO
function trigger_sql($table, $style) {
$return = "";
//foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_\\")), null, "-- ") as $row) {
// $return .= "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "")
// . "CREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . table($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n";
//}
//return $return;
function truncate_sql($table) {
return "TRUNCATE " . table($table);
}
return false;
function trigger_sql($table) {
$status = table_status($table);
$return = "";
foreach (triggers($table) as $trg_id => $trg) {
$trigger = trigger($trg_id, $status['Name']);
$return .= "\nCREATE TRIGGER " . idf_escape($trigger['Trigger']) . " $trigger[Timing] $trigger[Events] ON " . idf_escape($status["nspname"]) . "." . idf_escape($status['Name']) . " $trigger[Type] $trigger[Statement];;\n";
}
return $return;
}
@@ -731,8 +808,7 @@ AND typelem = 0"
}
function process_list() {
global $connection;
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . ($connection->server_info < 9.2 ? "procpid" : "pid"));
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid"));
}
function show_status() {
@@ -746,8 +822,7 @@ AND typelem = 0"
}
function support($feature) {
global $connection;
return preg_match('~^(database|table|columns|sql|indexes|comment|view|' . ($connection->server_info >= 9.3 ? 'materializedview|' : '') . 'scheme|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature); //! routine|
return preg_match('~^(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);
}
function kill_process($val) {
@@ -778,7 +853,7 @@ AND typelem = 0"
$structured_types[$key] = array_keys($val);
}
$unsigned = array();
$operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // no "SQL" to avoid SQL injection
$operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // no "SQL" to avoid CSRF
$functions = array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper");
$grouping = array("avg", "count", "count distinct", "max", "min", "sum");
$edit_functions = array(
@@ -786,7 +861,7 @@ AND typelem = 0"
"char" => "md5",
"date|time" => "now",
), array(
"int|numeric|real|money" => "+/-",
number_type() => "+/-",
"date|time" => "+ interval/- interval", //! escape
"char|text" => "||",
)

View File

@@ -2,10 +2,10 @@
$drivers["simpledb"] = "SimpleDB";
if (isset($_GET["simpledb"])) {
$possible_drivers = array("SimpleXML");
$possible_drivers = array("SimpleXML + allow_url_fopen");
define("DRIVER", "simpledb");
if (class_exists('SimpleXMLElement')) {
if (class_exists('SimpleXMLElement') && ini_bool('allow_url_fopen')) {
class Min_DB {
var $extension = "SimpleXML", $server_info = '2009-04-15', $error, $timeout, $next, $affected_rows, $_result;
@@ -19,6 +19,7 @@ if (isset($_GET["simpledb"])) {
$params['NextToken'] = $this->next;
}
$result = sdb_request_all('Select', 'Item', $params, $this->timeout); //! respect $unbuffered
$this->timeout = 0;
if ($result === false) {
return $result;
}
@@ -236,12 +237,22 @@ if (isset($_GET["simpledb"])) {
function rollback() {
return false;
}
function slowQuery($query, $timeout) {
$this->_conn->timeout = $timeout;
return $query;
}
}
function connect() {
global $adminer;
list(, , $password) = $adminer->credentials();
if ($password != "") {
return lang('Database does not support password.');
}
return new Min_DB;
}

View File

@@ -152,7 +152,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function fetch_field() {
$name = $this->_result->fieldName($this->_offset++);
$pattern = '(\\[.*]|"(?:[^"]|"")*"|(.+))';
$pattern = '(\[.*]|"(?:[^"]|"")*"|(.+))';
if (preg_match("~^($pattern\\.)?$pattern\$~", $name, $match)) {
$table = ($match[3] != "" ? $match[3] : idf_unescape($match[2]));
$name = ($match[5] != "" ? $match[5] : idf_unescape($match[4]));
@@ -184,11 +184,13 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function __construct() {
parent::__construct(":memory:");
$this->query("PRAGMA foreign_keys = 1");
}
function select_db($filename) {
if (is_readable($filename) && $this->query("ATTACH " . $this->quote(preg_match("~(^[/\\\\]|:)~", $filename) ? $filename : dirname($_SERVER["SCRIPT_FILENAME"]) . "/$filename") . " AS a")) { // is_readable - SQLite 3
parent::__construct($filename);
$this->query("PRAGMA foreign_keys = 1");
return true;
}
return false;
@@ -216,6 +218,15 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return queries("REPLACE INTO " . table($table) . " (" . implode(", ", array_keys(reset($rows))) . ") VALUES\n" . implode(",\n", $values));
}
function tableHelp($name) {
if ($name == "sqlite_sequence") {
return "fileformat2.html#seqtab";
}
if ($name == "sqlite_master") {
return "fileformat2.html#$name";
}
}
}
@@ -229,6 +240,11 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
}
function connect() {
global $adminer;
list(, , $password) = $adminer->credentials();
if ($password != "") {
return lang('Database does not support password.');
}
return new Min_DB;
}
@@ -240,9 +256,12 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
}
function limit1($query, $where) {
function limit1($table, $query, $where, $separator = "\n") {
global $connection;
return ($connection->result("SELECT sqlite_compileoption_used('ENABLE_UPDATE_DELETE_LIMIT')") ? limit($query, $where, 1) : " $query$where");
return (preg_match('~^INTO~', $query) || $connection->result("SELECT sqlite_compileoption_used('ENABLE_UPDATE_DELETE_LIMIT')")
? limit($query, $where, 1, 0, $separator)
: " $query WHERE rowid = (SELECT rowid FROM " . table($table) . $where . $separator . "LIMIT 1)" //! use primary key in tables with WITHOUT rowid
);
}
function db_collation($db, $collations) {
@@ -259,7 +278,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
}
function tables_list() {
return get_key_vals("SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY (name = 'sqlite_sequence'), name", 1);
return get_key_vals("SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY (name = 'sqlite_sequence'), name");
}
function count_tables($databases) {
@@ -269,9 +288,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function table_status($name = "") {
global $connection;
$return = array();
foreach (get_rows("SELECT name AS Name, type AS Engine FROM sqlite_master WHERE type IN ('table', 'view') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row) {
$row["Oid"] = 1;
$row["Auto_increment"] = "";
foreach (get_rows("SELECT name AS Name, type AS Engine, 'rowid' AS Oid, '' AS Auto_increment FROM sqlite_master WHERE type IN ('table', 'view') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row) {
$row["Rows"] = $connection->result("SELECT COUNT(*) FROM " . idf_escape($row["Name"]));
$return[$row["Name"]] = $row;
}
@@ -334,9 +351,9 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
}
$return = array();
$sql = $connection2->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table));
if (preg_match('~\bPRIMARY\s+KEY\s*\((([^)"]+|"[^"]*")++)~i', $sql, $match)) {
if (preg_match('~\bPRIMARY\s+KEY\s*\((([^)"]+|"[^"]*"|`[^`]*`)++)~i', $sql, $match)) {
$return[""] = array("type" => "PRIMARY", "columns" => array(), "lengths" => array(), "descs" => array());
preg_match_all('~((("[^"]*+")+)|(\S+))(\s+(ASC|DESC))?(,\s*|$)~i', $match[1], $matches, PREG_SET_ORDER);
preg_match_all('~((("[^"]*+")+|(?:`[^`]*+`)+)|(\S+))(\s+(ASC|DESC))?(,\s*|$)~i', $match[1], $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$return[""]["columns"][] = idf_unescape($match[2]) . $match[4];
$return[""]["descs"][] = (preg_match('~DESC~i', $match[5]) ? '1' : null);
@@ -390,7 +407,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function view($name) {
global $connection;
return array("select" => preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\\s+~iU', '', $connection->result("SELECT sql FROM sqlite_master WHERE name = " . q($name)))); //! identifiers may be inside []
return array("select" => preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\s+~iU', '', $connection->result("SELECT sql FROM sqlite_master WHERE name = " . q($name)))); //! identifiers may be inside []
}
function collations() {
@@ -465,6 +482,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
}
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
global $connection;
$use_all_fields = ($table == "" || $foreign);
foreach ($fields as $field) {
if ($field[0] != "" || !$field[1] || $field[2]) {
@@ -491,19 +509,28 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
if ($table != $name && !queries("ALTER TABLE " . table($table) . " RENAME TO " . table($name))) {
return false;
}
} elseif (!recreate_table($table, $name, $alter, $originals, $foreign)) {
} elseif (!recreate_table($table, $name, $alter, $originals, $foreign, $auto_increment)) {
return false;
}
if ($auto_increment) {
queries("BEGIN");
queries("UPDATE sqlite_sequence SET seq = $auto_increment WHERE name = " . q($name)); // ignores error
if (!$connection->affected_rows) {
queries("INSERT INTO sqlite_sequence (name, seq) VALUES (" . q($name) . ", $auto_increment)");
}
queries("COMMIT");
}
return true;
}
function recreate_table($table, $name, $fields, $originals, $foreign, $indexes = array()) {
function recreate_table($table, $name, $fields, $originals, $foreign, $auto_increment, $indexes = array()) {
global $connection;
if ($table != "") {
if (!$fields) {
foreach (fields($table) as $key => $field) {
if ($indexes) {
$field["auto_increment"] = 0;
}
$fields[] = process_field($field, $field);
$originals[$key] = idf_escape($key);
}
@@ -558,12 +585,13 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
$fields[$key] = " " . implode($field);
}
$fields = array_merge($fields, array_filter($foreign));
if (!queries("CREATE TABLE " . table($table != "" ? "adminer_$name" : $name) . " (\n" . implode(",\n", $fields) . "\n)")) {
$temp_name = ($table == $name ? "adminer_$name" : $name);
if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $fields) . "\n)")) {
// implicit ROLLBACK to not overwrite $connection->error
return false;
}
if ($table != "") {
if ($originals && !queries("INSERT INTO " . table("adminer_$name") . " (" . implode(", ", $originals) . ") SELECT " . implode(", ", array_map('idf_escape', array_keys($originals))) . " FROM " . table($table))) {
if ($originals && !queries("INSERT INTO " . table($temp_name) . " (" . implode(", ", $originals) . ") SELECT " . implode(", ", array_map('idf_escape', array_keys($originals))) . " FROM " . table($table))) {
return false;
}
$triggers = array();
@@ -571,12 +599,15 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
$trigger = trigger($trigger_name);
$triggers[] = "CREATE TRIGGER " . idf_escape($trigger_name) . " " . implode(" ", $timing_event) . " ON " . table($name) . "\n$trigger[Statement]";
}
if (!queries("DROP TABLE " . table($table))) { // drop before creating indexes and triggers to allow using old names
$auto_increment = $auto_increment ? 0 : $connection->result("SELECT seq FROM sqlite_sequence WHERE name = " . q($table)); // if $auto_increment is set then it will be updated later
if (!queries("DROP TABLE " . table($table)) // drop before creating indexes and triggers to allow using old names
|| ($table == $name && !queries("ALTER TABLE " . table($temp_name) . " RENAME TO " . table($name)))
|| !alter_indexes($name, $indexes)
) {
return false;
}
queries("ALTER TABLE " . table("adminer_$name") . " RENAME TO " . table($name));
if (!alter_indexes($name, $indexes)) {
return false;
if ($auto_increment) {
queries("UPDATE sqlite_sequence SET seq = $auto_increment WHERE name = " . q($name)); // ignores error
}
foreach ($triggers as $trigger) {
if (!queries($trigger)) {
@@ -599,7 +630,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function alter_indexes($table, $alter) {
foreach ($alter as $primary) {
if ($primary[0] == "PRIMARY") {
return recreate_table($table, $table, array(), array(), array(), $alter);
return recreate_table($table, $table, array(), array(), array(), 0, $alter);
}
}
foreach (array_reverse($alter) as $val) {
@@ -634,7 +665,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
if ($name == "") {
return array("Statement" => "BEGIN\n\t;\nEND");
}
$idf = '(?:[^`"\\s]+|`[^`]*`|"[^"]*")+';
$idf = '(?:[^`"\s]+|`[^`]*`|"[^"]*")+';
$trigger_options = trigger_options();
preg_match(
"~^CREATE\\s+TRIGGER\\s*$idf\\s*(" . implode("|", $trigger_options["Timing"]) . ")\\s+([a-z]+)(?:\\s+OF\\s+($idf))?\\s+ON\\s*$idf\\s*(?:FOR\\s+EACH\\s+ROW\\s)?(.*)~is",
@@ -655,7 +686,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
$return = array();
$trigger_options = trigger_options();
foreach (get_rows("SELECT * FROM sqlite_master WHERE type = 'trigger' AND tbl_name = " . q($table)) as $row) {
preg_match('~^CREATE\\s+TRIGGER\\s*(?:[^`"\\s]+|`[^`]*`|"[^"]*")+\\s*(' . implode("|", $trigger_options["Timing"]) . ')\\s*(.*)\\s+ON\\b~iU', $row["sql"], $match);
preg_match('~^CREATE\s+TRIGGER\s*(?:[^`"\s]+|`[^`]*`|"[^"]*")+\s*(' . implode("|", $trigger_options["Timing"]) . ')\s*(.*?)\s+ON\b~i', $row["sql"], $match);
$return[$row["name"]] = array($match[1], $match[2]);
}
return $return;
@@ -669,18 +700,6 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
);
}
function routine($name, $type) {
// not supported by SQLite
}
function routines() {
// not supported by SQLite
}
function routine_languages() {
// not supported by SQLite
}
function begin() {
return queries("BEGIN");
}
@@ -713,7 +732,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return true;
}
function create_sql($table, $auto_increment) {
function create_sql($table, $auto_increment, $style) {
global $connection;
$return = $connection->result("SELECT sql FROM sqlite_master WHERE type IN ('table', 'view') AND name = " . q($table));
foreach (indexes($table) as $name => $index) {
@@ -732,7 +751,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function use_sql($database) {
}
function trigger_sql($table, $style) {
function trigger_sql($table) {
return implode(get_vals("SELECT sql || ';;\n' FROM sqlite_master WHERE type = 'trigger' AND tbl_name = " . q($table)));
}
@@ -762,7 +781,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
}
function support($feature) {
return preg_match('~^(columns|database|drop_col|dump|indexes|move_col|sql|status|table|trigger|variables|view|view_trigger)$~', $feature);
return preg_match('~^(columns|database|drop_col|dump|indexes|descidx|move_col|sql|status|table|trigger|variables|view|view_trigger)$~', $feature);
}
$jush = "sqlite";

View File

@@ -92,7 +92,7 @@ SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
$fields = fields($name);
$adminer->dumpData($name, $_POST["data_style"], "SELECT *" . convert_fields($fields, $fields) . " FROM " . table($name));
}
if ($is_sql && $_POST["triggers"] && $table && ($triggers = trigger_sql($name, $_POST["table_style"]))) {
if ($is_sql && $_POST["triggers"] && $table && ($triggers = trigger_sql($name))) {
echo "\nDELIMITER ;;\n$triggers\nDELIMITER ;\n";
}
@@ -126,7 +126,7 @@ page_header(lang('Export'), $error, ($_GET["export"] != "" ? array("table" => $_
?>
<form action="" method="post">
<table cellspacing="0">
<table cellspacing="0" class="layout">
<?php
$db_style = array('', 'USE', 'DROP+CREATE', 'CREATE');
$table_style = array('', 'DROP+CREATE', 'CREATE');
@@ -165,12 +165,13 @@ echo "<tr><th>" . lang('Data') . "<td>" . html_select('data_style', $data_style,
<table cellspacing="0">
<?php
echo script("qsl('table').onclick = dumpClick;");
$prefixes = array();
if (DB != "") {
$checked = ($TABLE != "" ? "" : " checked");
echo "<thead><tr>";
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked onclick='formCheck(this, /^tables\\[/);'>" . lang('Tables') . "</label>";
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked onclick='formCheck(this, /^data\\[/);'></label>";
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked>" . lang('Tables') . "</label>" . script("qs('#check-tables').onclick = partial(formCheck, /^tables\\[/);", "");
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked></label>" . script("qs('#check-data').onclick = partial(formCheck, /^data\\[/);", "");
echo "</thead>\n";
$views = "";
@@ -178,28 +179,31 @@ if (DB != "") {
foreach ($tables_list as $name => $type) {
$prefix = preg_replace('~_.*~', '', $name);
$checked = ($TABLE == "" || $TABLE == (substr($TABLE, -1) == "%" ? "$prefix%" : $name)); //! % may be part of table name
$print = "<tr><td>" . checkbox("tables[]", $name, $checked, $name, "checkboxClick(event, this); formUncheck('check-tables');", "block");
$print = "<tr><td>" . checkbox("tables[]", $name, $checked, $name, "", "block");
if ($type !== null && !preg_match('~table~i', $type)) {
$views .= "$print\n";
} else {
echo "$print<td align='right'><label class='block'><span id='Rows-" . h($name) . "'></span>" . checkbox("data[]", $name, $checked, "", "checkboxClick(event, this); formUncheck('check-data');") . "</label>\n";
echo "$print<td align='right'><label class='block'><span id='Rows-" . h($name) . "'></span>" . checkbox("data[]", $name, $checked) . "</label>\n";
}
$prefixes[$prefix]++;
}
echo $views;
if ($tables_list) {
echo "<script type='text/javascript'>ajaxSetHtml('" . js_escape(ME) . "script=db');</script>\n";
echo script("ajaxSetHtml('" . js_escape(ME) . "script=db');");
}
} else {
echo "<thead><tr><th style='text-align: left;'><label class='block'><input type='checkbox' id='check-databases'" . ($TABLE == "" ? " checked" : "") . " onclick='formCheck(this, /^databases\\[/);'>" . lang('Database') . "</label></thead>\n";
echo "<thead><tr><th style='text-align: left;'>";
echo "<label class='block'><input type='checkbox' id='check-databases'" . ($TABLE == "" ? " checked" : "") . ">" . lang('Database') . "</label>";
echo script("qs('#check-databases').onclick = partial(formCheck, /^databases\\[/);", "");
echo "</thead>\n";
$databases = $adminer->databases();
if ($databases) {
foreach ($databases as $db) {
if (!information_schema($db)) {
$prefix = preg_replace('~_.*~', '', $db);
echo "<tr><td>" . checkbox("databases[]", $db, $TABLE == "" || $TABLE == "$prefix%", $db, "formUncheck('check-databases');", "block") . "\n";
echo "<tr><td>" . checkbox("databases[]", $db, $TABLE == "" || $TABLE == "$prefix%", $db, "", "block") . "\n";
$prefixes[$prefix]++;
}
}

View File

@@ -1,10 +1,10 @@
<?php
$TABLE = $_GET["edit"];
$fields = fields($TABLE);
$where = (isset($_GET["select"]) ? (count($_POST["check"]) == 1 ? where_check($_POST["check"][0], $fields) : "") : where($_GET, $fields));
$where = (isset($_GET["select"]) ? ($_POST["check"] && count($_POST["check"]) == 1 ? where_check($_POST["check"][0], $fields) : "") : where($_GET, $fields));
$update = (isset($_GET["select"]) ? $_POST["edit"] : $where);
foreach ($fields as $name => $field) {
if (!isset($field["privileges"][$update ? "update" : "insert"]) || $adminer->fieldName($field) == "") {
if (!isset($field["privileges"][$update ? "update" : "insert"]) || $adminer->fieldName($field) == "" || $field["generated"]) {
unset($fields[$name]);
}
}
@@ -82,9 +82,13 @@ if ($_POST["save"]) {
}
if ($select) {
$result = $driver->select($TABLE, $select, array($where), $select, array(), (isset($_GET["select"]) ? 2 : 1));
$row = $result->fetch_assoc();
if (!$row) { // MySQLi returns null
$row = false;
if (!$result) {
$error = error();
} else {
$row = $result->fetch_assoc();
if (!$row) { // MySQLi returns null
$row = false;
}
}
if (isset($_GET["select"]) && (!$row || $result->fetch_assoc())) { // $result->num_rows != 1 isn't available in all drivers
$row = null;

View File

@@ -35,18 +35,18 @@ if (!$row && $EVENT != "") {
?>
<form action="" method="post">
<table cellspacing="0">
<tr><th><?php echo lang('Name'); ?><td><input name="EVENT_NAME" value="<?php echo h($row["EVENT_NAME"]); ?>" maxlength="64" autocapitalize="off">
<table cellspacing="0" class="layout">
<tr><th><?php echo lang('Name'); ?><td><input name="EVENT_NAME" value="<?php echo h($row["EVENT_NAME"]); ?>" data-maxlength="64" autocapitalize="off">
<tr><th title="datetime"><?php echo lang('Start'); ?><td><input name="STARTS" value="<?php echo h("$row[EXECUTE_AT]$row[STARTS]"); ?>">
<tr><th title="datetime"><?php echo lang('End'); ?><td><input name="ENDS" value="<?php echo h($row["ENDS"]); ?>">
<tr><th><?php echo lang('Every'); ?><td><input type="number" name="INTERVAL_VALUE" value="<?php echo h($row["INTERVAL_VALUE"]); ?>" class="size"> <?php echo html_select("INTERVAL_FIELD", $intervals, $row["INTERVAL_FIELD"]); ?>
<tr><th><?php echo lang('Status'); ?><td><?php echo html_select("STATUS", $statuses, $row["STATUS"]); ?>
<tr><th><?php echo lang('Comment'); ?><td><input name="EVENT_COMMENT" value="<?php echo h($row["EVENT_COMMENT"]); ?>" maxlength="64">
<tr><th>&nbsp;<td><?php echo checkbox("ON_COMPLETION", "PRESERVE", $row["ON_COMPLETION"] == "PRESERVE", lang('On completion preserve')); ?>
<tr><th><?php echo lang('Comment'); ?><td><input name="EVENT_COMMENT" value="<?php echo h($row["EVENT_COMMENT"]); ?>" data-maxlength="64">
<tr><th><td><?php echo checkbox("ON_COMPLETION", "PRESERVE", $row["ON_COMPLETION"] == "PRESERVE", lang('On completion preserve')); ?>
</table>
<p><?php textarea("EVENT_DEFINITION", $row["EVENT_DEFINITION"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($EVENT != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?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; ?>">
</form>

View File

@@ -1,12 +1,5 @@
<?php
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");
// caching headers added in compile.php
if ($_GET["file"] == "favicon.ico") {
header("Content-Type: image/x-icon");

View File

@@ -48,17 +48,33 @@ if ($_POST) {
$row["table"] = $TABLE;
$row["source"] = array("");
}
$source = array_keys(fields($TABLE)); //! no text and blob
$target = ($TABLE === $row["table"] ? $source : array_keys(fields($row["table"])));
$referencable = array_keys(array_filter(table_status('', true), 'fk_support'));
?>
<form action="" method="post">
<p>
<?php if ($row["db"] == "" && $row["ns"] == "") { ?>
<?php echo lang('Target table'); ?>:
<?php echo html_select("table", $referencable, $row["table"], "this.form['change-js'].value = '1'; this.form.submit();"); ?>
<?php
$source = array_keys(fields($TABLE)); //! no text and blob
if ($row["db"] != "") {
$connection->select_db($row["db"]);
}
if ($row["ns"] != "") {
set_schema($row["ns"]);
}
$referencable = array_keys(array_filter(table_status('', true), 'fk_support'));
$target = ($TABLE === $row["table"] ? $source : array_keys(fields(in_array($row["table"], $referencable) ? $row["table"] : reset($referencable))));
$onchange = "this.form['change-js'].value = '1'; this.form.submit();";
echo "<p>" . lang('Target table') . ": " . html_select("table", $referencable, $row["table"], $onchange) . "\n";
if ($jush == "pgsql") {
echo lang('Schema') . ": " . html_select("ns", $adminer->schemas(), $row["ns"] != "" ? $row["ns"] : $_GET["ns"], $onchange);
} elseif ($jush != "sqlite") {
$dbs = array();
foreach ($adminer->databases() as $db) {
if (!information_schema($db)) {
$dbs[] = $db;
}
}
echo lang('DB') . ": " . html_select("db", $dbs, $row["db"] != "" ? $row["db"] : $_GET["db"], $onchange);
}
?>
<input type="hidden" name="change-js" value="">
<noscript><p><input type="submit" name="change" value="<?php echo lang('Change'); ?>"></noscript>
<table cellspacing="0">
@@ -67,7 +83,7 @@ $referencable = array_keys(array_filter(table_status('', true), 'fk_support'));
$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(this);" : 1), "label-source");
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");
$j++;
}
@@ -78,6 +94,7 @@ foreach ($row["source"] as $key => $val) {
<?php echo lang('ON UPDATE'); ?>: <?php echo html_select("on_update", array(-1 => "") + explode("|", $on_actions), $row["on_update"]); ?>
<?php echo doc_link(array(
'sql' => "innodb-foreign-key-constraints.html",
'mariadb' => "foreign-keys/",
'pgsql' => "sql-createtable.html#SQL-CREATETABLE-REFERENCES",
'mssql' => "ms174979.aspx",
'oracle' => "clauses002.htm#sthref2903",
@@ -85,7 +102,6 @@ foreach ($row["source"] as $key => $val) {
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<noscript><p><input type="submit" name="add" value="<?php echo lang('Add column'); ?>"></noscript>
<?php } ?>
<?php if ($name != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?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; ?>">
</form>

View File

@@ -9,7 +9,7 @@ class Adminer {
* @return string HTML code
*/
function name() {
return "<a href='https://www.adminer.org/' target='_blank' id='h1'>Adminer</a>";
return "<a href='https://www.adminer.org/'" . target_blank() . " id='h1'>Adminer</a>";
}
/** Connection parameters
@@ -19,6 +19,12 @@ class Adminer {
return array(SERVER, $_GET["username"], get_password());
}
/** Get SSL connection options
* @return array array("key" => filename, "cert" => filename, "ca" => filename) or null
*/
function connectSsl() {
}
/** Get key used for permanent login
* @param bool
* @return string cryptic string which gets combined with password or false in case of an error
@@ -33,6 +39,14 @@ class Adminer {
function bruteForceKey() {
return $_SERVER["REMOTE_ADDR"];
}
/** Get server name displayed in breadcrumbs
* @param string
* @return string HTML code or null
*/
function serverName($server) {
return h($server);
}
/** Identifier of selected database
* @return string
@@ -61,18 +75,24 @@ class Adminer {
* @return float number of seconds
*/
function queryTimeout() {
return 5;
return 2;
}
/** Headers to send before HTML output
* @return bool true to send security headers
* @return null
*/
function headers() {
return true;
}
/** Get Content Security Policy headers
* @return array of arrays with directive name in key, allowed sources in value
*/
function csp() {
return csp();
}
/** Print HTML code inside <head>
* @return bool true to link adminer.css if exists
* @return bool true to link favicon.ico and adminer.css if exists
*/
function head() {
?>
@@ -81,26 +101,43 @@ class Adminer {
return true;
}
/** Get URLs of the CSS files
* @return array of strings
*/
function css() {
$return = array();
$filename = "adminer.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
}
return $return;
}
/** Print login form
* @return null
*/
function loginForm() {
global $drivers;
?>
<table cellspacing="0">
<tr><th><?php echo lang('System'); ?><td><?php echo html_select("auth[driver]", $drivers, DRIVER); ?>
<tr><th><?php echo lang('Server'); ?><td><input name="auth[server]" value="<?php echo h(SERVER); ?>" title="hostname[:port]" placeholder="localhost" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="auth[username]" id="username" value="<?php echo h($_GET["username"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input type="password" name="auth[password]">
<tr><th><?php echo lang('Database'); ?><td><input name="auth[db]" value="<?php echo h($_GET["db"]); ?>" autocapitalize="off">
</table>
<script type="text/javascript">
focus(document.getElementById('username'));
</script>
<?php
echo "<table cellspacing='0' class='layout'>\n";
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);") . "\n");
echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">' . "\n");
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(qs('#username')); qs('#username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">' . "\n");
echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">' . "\n");
echo "</table>\n";
echo "<p><input type='submit' value='" . lang('Login') . "'>\n";
echo checkbox("auth[permanent]", 1, $_COOKIE["adminer_permanent"], lang('Permanent login')) . "\n";
}
/** Get login form field
* @param string
* @param string HTML
* @param string HTML
* @return string
*/
function loginFormField($name, $heading, $value) {
return $heading . $value;
}
/** Authorize the user
* @param string
@@ -108,9 +145,8 @@ focus(document.getElementById('username'));
* @return mixed true for success, string for error message, false for unknown error
*/
function login($login, $password) {
global $jush;
if ($jush == "sqlite") {
return lang('<a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to use SQLite.', '<code>login()</code>');
if ($password == "") {
return lang('Adminer does not support accessing a database without a password, <a href="https://www.adminer.org/en/password/"%s>more information</a>.', target_blank());
}
return true;
}
@@ -138,6 +174,7 @@ focus(document.getElementById('username'));
* @return null
*/
function selectLinks($tableStatus, $set = "") {
global $jush, $driver;
echo '<p class="links">';
$links = array("select" => lang('Select data'));
if (support("table") || support("indexes")) {
@@ -153,9 +190,11 @@ focus(document.getElementById('username'));
if ($set !== null) {
$links["edit"] = lang('New item');
}
$name = $tableStatus["Name"];
foreach ($links as $key => $val) {
echo " <a href='" . h(ME) . "$key=" . urlencode($tableStatus["Name"]) . ($key == "edit" ? $set : "") . "'" . bold(isset($_GET[$key])) . ">$val</a>";
echo " <a href='" . h(ME) . "$key=" . urlencode($name) . ($key == "edit" ? $set : "") . "'" . bold(isset($_GET[$key])) . ">$val</a>";
}
echo doc_link(array($jush => $driver->tableHelp($name)), "?");
echo "\n";
}
@@ -186,14 +225,22 @@ focus(document.getElementById('username'));
/** Query printed in select before execution
* @param string query to be executed
* @param string elapsed time
* @param float start time of the query
* @param bool
* @return string
*/
function selectQuery($query, $time) {
global $jush;
return "<p><code class='jush-$jush'>" . h(str_replace("\n", " ", $query)) . "</code> <span class='time'>($time)</span>"
function selectQuery($query, $start, $failed = false) {
global $jush, $driver;
$return = "</p>\n"; // required for IE9 inline edit
if (!$failed && ($warnings = $driver->warnings())) {
$id = "warnings";
$return = ", <a href='#$id'>" . lang('Warnings') . "</a>" . script("qsl('a').onclick = partial(toggle, '$id');", "")
. "$return<div id='$id' class='hidden'>\n$warnings</div>\n"
;
}
return "<p><code class='jush-$jush'>" . h(str_replace("\n", " ", $query)) . "</code> <span class='time'>(" . format_time($start) . ")</span>"
. (support("sql") ? " <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>" : "")
. "</p>" // </p> - required for IE9 inline edit
. $return
;
}
@@ -239,14 +286,14 @@ focus(document.getElementById('username'));
* @return string
*/
function selectVal($val, $link, $field, $original) {
$return = ($val === null ? "<i>NULL</i>" : (preg_match("~char|binary~", $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>" : $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) ? " rel='noreferrer'" : "") . ">$return</a>" : $return);
return ($link ? "<a href='" . h($link) . "'" . (is_url($link) ? target_blank() : "") . ">$return</a>" : $return);
}
/** Value conversion used in select and edit
@@ -263,7 +310,8 @@ focus(document.getElementById('username'));
* @return null
*/
function tableStructurePrint($fields) {
echo "<table cellspacing='0'>\n";
echo "<div class='scrollable'>\n";
echo "<table cellspacing='0' class='nowrap'>\n";
echo "<thead><tr><th>" . lang('Column') . "<td>" . lang('Type') . (support("comment") ? "<td>" . lang('Comment') : "") . "</thead>\n";
foreach ($fields as $field) {
echo "<tr" . odd() . "><th>" . h($field["field"]);
@@ -271,10 +319,11 @@ focus(document.getElementById('username'));
echo ($field["null"] ? " <i>NULL</i>" : "");
echo ($field["auto_increment"] ? " <i>" . lang('Auto Increment') . "</i>" : "");
echo (isset($field["default"]) ? " <span title='" . lang('Default value') . "'>[<b>" . h($field["default"]) . "</b>]</span>" : "");
echo (support("comment") ? "<td>" . nbsp($field["comment"]) : "");
echo (support("comment") ? "<td>" . h($field["comment"]) : "");
echo "\n";
}
echo "</table>\n";
echo "</div>\n";
}
/** Print list of indexes on table in tabular format
@@ -309,9 +358,16 @@ focus(document.getElementById('username'));
$select[""] = array();
foreach ($select as $key => $val) {
$val = $_GET["columns"][$key];
$column = select_input(" name='columns[$i][col]' onchange='" . ($key !== "" ? "selectFieldChange(this.form)" : "selectAddRow(this)") . ";'", $columns, $val["col"]);
echo "<div>" . ($functions || $grouping ? "<select name='columns[$i][fun]' onchange='helpClose();" . ($key !== "" ? "" : " this.nextSibling.nextSibling.onchange();") . "'"
. on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1) . ">" . optionlist(array(-1 => "") + array_filter(array(lang('Functions') => $functions, lang('Aggregation') => $grouping)), $val["fun"]) . "</select>"
$column = select_input(
" name='columns[$i][col]'",
$columns,
$val["col"],
($key !== "" ? "selectFieldChange" : "selectAddRow")
);
echo "<div>" . ($functions || $grouping ? "<select name='columns[$i][fun]'>"
. optionlist(array(-1 => "") + array_filter(array(lang('Functions') => $functions, lang('Aggregation') => $grouping)), $val["fun"]) . "</select>"
. on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1)
. script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "")
. "($column)" : $column) . "</div>\n";
$i++;
}
@@ -328,21 +384,27 @@ focus(document.getElementById('username'));
print_fieldset("search", lang('Search'), $where);
foreach ($indexes as $i => $index) {
if ($index["type"] == "FULLTEXT") {
echo "(<i>" . implode("</i>, <i>", array_map('h', $index["columns"])) . "</i>) AGAINST";
echo " <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "' onchange='selectFieldChange(this.form);'>";
echo "<div>(<i>" . implode("</i>, <i>", array_map('h', $index["columns"])) . "</i>) AGAINST";
echo " <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "'>";
echo script("qsl('input').oninput = selectFieldChange;", "");
echo checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL");
echo "<br>\n";
echo "</div>\n";
}
}
$_GET["where"] = (array) $_GET["where"];
reset($_GET["where"]);
$change_next = "this.nextSibling.onchange();";
for ($i = 0; $i <= count($_GET["where"]); $i++) {
list(, $val) = each($_GET["where"]);
$change_next = "this.parentNode.firstChild.onchange();";
foreach (array_merge((array) $_GET["where"], array(array())) as $i => $val) {
if (!$val || ("$val[col]$val[val]" != "" && in_array($val["op"], $this->operators))) {
echo "<div>" . select_input(" name='where[$i][col]' onchange='$change_next'", $columns, $val["col"], "(" . lang('anywhere') . ")");
echo "<div>" . select_input(
" name='where[$i][col]'",
$columns,
$val["col"],
($val ? "selectFieldChange" : "selectAddRow"),
"(" . lang('anywhere') . ")"
);
echo html_select("where[$i][op]", $this->operators, $val["op"], $change_next);
echo "<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "' onchange='" . ($val ? "selectFieldChange(this.form)" : "selectAddRow(this)") . ";' onkeydown='selectSearchKeydown(this, event);' onsearch='selectSearchSearch(this);'></div>\n";
echo "<input type='search' name='where[$i][val]' value='" . h($val["val"]) . "'>";
echo script("mixin(qsl('input'), {oninput: function () { $change_next }, onkeydown: selectSearchKeydown, onsearch: selectSearchSearch});", "");
echo "</div>\n";
}
}
echo "</div></fieldset>\n";
@@ -359,12 +421,12 @@ focus(document.getElementById('username'));
$i = 0;
foreach ((array) $_GET["order"] as $key => $val) {
if ($val != "") {
echo "<div>" . select_input(" name='order[$i]' onchange='selectFieldChange(this.form);'", $columns, $val);
echo "<div>" . select_input(" name='order[$i]'", $columns, $val, "selectFieldChange");
echo checkbox("desc[$i]", 1, isset($_GET["desc"][$key]), lang('descending')) . "</div>\n";
$i++;
}
}
echo "<div>" . select_input(" name='order[$i]' onchange='selectAddRow(this);'", $columns);
echo "<div>" . select_input(" name='order[$i]'", $columns, "", "selectAddRow");
echo checkbox("desc[$i]", 1, false, lang('descending')) . "</div>\n";
echo "</div></fieldset>\n";
}
@@ -375,7 +437,8 @@ focus(document.getElementById('username'));
*/
function selectLimitPrint($limit) {
echo "<fieldset><legend>" . lang('Limit') . "</legend><div>"; // <div> for easy styling
echo "<input type='number' name='limit' class='size' value='" . h($limit) . "' onchange='selectFieldChange(this.form);'>";
echo "<input type='number' name='limit' class='size' value='" . h($limit) . "'>";
echo script("qsl('input').oninput = selectFieldChange;", "");
echo "</div></fieldset>\n";
}
@@ -399,7 +462,7 @@ focus(document.getElementById('username'));
echo "<fieldset><legend>" . lang('Action') . "</legend><div>";
echo "<input type='submit' value='" . lang('Select') . "'>";
echo " <span id='noindex' title='" . lang('Full table scan') . "'></span>";
echo "<script type='text/javascript'>\n";
echo "<script" . nonce() . ">\n";
echo "var indexColumns = ";
$columns = array();
foreach ($indexes as $index) {
@@ -413,7 +476,7 @@ focus(document.getElementById('username'));
json_row($key);
}
echo ";\n";
echo "selectFieldChange(document.getElementById('form'));\n";
echo "selectFieldChange.call(qs('#form')['select']);\n";
echo "</script>\n";
echo "</div></fieldset>\n";
}
@@ -466,15 +529,16 @@ focus(document.getElementById('username'));
* @return array expressions to join by AND
*/
function selectSearchProcess($fields, $indexes) {
global $connection, $jush;
global $connection, $driver;
$return = array();
foreach ($indexes as $i => $index) {
if ($index["type"] == "FULLTEXT" && $_GET["fulltext"][$i] != "") {
$return[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST (" . q($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")";
}
}
foreach ((array) $_GET["where"] as $val) {
foreach ((array) $_GET["where"] as $key => $val) {
if ("$val[col]$val[val]" != "" && in_array($val["op"], $this->operators)) {
$prefix = "";
$cond = " $val[op]";
if (preg_match('~IN$~', $val["op"])) {
$in = process_length($val["val"]);
@@ -485,24 +549,25 @@ focus(document.getElementById('username'));
$cond = " LIKE " . $this->processInput($fields[$val["col"]], "%$val[val]%");
} elseif ($val["op"] == "ILIKE %%") {
$cond = " ILIKE " . $this->processInput($fields[$val["col"]], "%$val[val]%");
} elseif ($val["op"] == "FIND_IN_SET") {
$prefix = "$val[op](" . q($val["val"]) . ", ";
$cond = ")";
} elseif (!preg_match('~NULL$~', $val["op"])) {
$cond .= " " . $this->processInput($fields[$val["col"]], $val["val"]);
}
if ($val["col"] != "") {
$return[] = idf_escape($val["col"]) . $cond;
$return[] = $prefix . $driver->convertSearch(idf_escape($val["col"]), $val, $fields[$val["col"]]) . $cond;
} else {
// find anywhere
$cols = array();
foreach ($fields as $name => $field) {
$is_text = preg_match('~char|text|enum|set~', $field["type"]);
if ((is_numeric($val["val"]) || !preg_match('~(^|[^o])int|float|double|decimal|bit~', $field["type"]))
&& (!preg_match("~[\x80-\xFF]~", $val["val"]) || $is_text)
if ((preg_match('~^[-\d.' . (preg_match('~IN$~', $val["op"]) ? ',' : '') . ']+$~', $val["val"]) || !preg_match('~' . number_type() . '|bit~', $field["type"]))
&& (!preg_match("~[\x80-\xFF]~", $val["val"]) || preg_match('~char|text|enum|set~', $field["type"]))
) {
$name = idf_escape($name);
$cols[] = ($jush == "sql" && $is_text && !preg_match("~^utf8_~", $field["collation"]) ? "CONVERT($name USING " . charset($connection) . ")" : $name);
$cols[] = $prefix . $driver->convertSearch(idf_escape($name), $val, $field) . $cond;
}
}
$return[] = ($cols ? "(" . implode("$cond OR ", $cols) . "$cond)" : "0");
$return[] = ($cols ? "(" . implode(" OR ", $cols) . ")" : "1 = 0");
}
}
}
@@ -518,7 +583,7 @@ focus(document.getElementById('username'));
$return = array();
foreach ((array) $_GET["order"] as $key => $val) {
if ($val != "") {
$return[] = (preg_match('~^((COUNT\\(DISTINCT |[A-Z0-9_]+\\()(`(?:[^`]|``)+`|"(?:[^"]|"")+")\\)|COUNT\\(\\*\\))$~', $val) ? $val : idf_escape($val)) //! MS SQL uses []
$return[] = (preg_match('~^((COUNT\(DISTINCT |[A-Z0-9_]+\()(`(?:[^`]|``)+`|"(?:[^"]|"")+")\)|COUNT\(\*\))$~', $val) ? $val : idf_escape($val)) //! MS SQL uses []
. (isset($_GET["desc"][$key]) ? " DESC" : "")
;
}
@@ -565,19 +630,28 @@ focus(document.getElementById('username'));
/** Query printed after execution in the message
* @param string executed query
* @param string elapsed time
* @param bool
* @return string
*/
function messageQuery($query, $time) {
global $jush;
function messageQuery($query, $time, $failed = false) {
global $jush, $driver;
restart_session();
$history = &get_session("queries");
$id = "sql-" . count($history[$_GET["db"]]);
if (!$history[$_GET["db"]]) {
$history[$_GET["db"]] = array();
}
if (strlen($query) > 1e6) {
$query = preg_replace('~[\x80-\xFF]+$~', '', substr($query, 0, 1e6)) . "\n..."; // [\x80-\xFF] - valid UTF-8, \n - can end by one-line comment
$query = preg_replace('~[\x80-\xFF]+$~', '', substr($query, 0, 1e6)) . "\n"; // [\x80-\xFF] - valid UTF-8, \n - can end by one-line comment
}
$history[$_GET["db"]][] = array($query, time(), $time); // not DB - $_GET["db"] is changed in database.inc.php //! respect $_GET["ns"]
return " <span class='time'>" . @date("H:i:s") . "</span> <a href='#$id' onclick=\"return !toggle('$id');\">" . lang('SQL command') . "</a>" // @ - time zone may be not set
. "<div id='$id' class='hidden'><pre><code class='jush-$jush'>" . shorten_utf8($query, 1000) . '</code></pre>'
$sql_id = "sql-" . count($history[$_GET["db"]]);
$return = "<a href='#$sql_id' class='toggle'>" . lang('SQL command') . "</a>\n";
if (!$failed && ($warnings = $driver->warnings())) {
$id = "warnings-" . count($history[$_GET["db"]]);
$return = "<a href='#$id' class='toggle'>" . lang('Warnings') . "</a>, $return<div id='$id' class='hidden'>\n$warnings</div>\n";
}
return " <span class='time'>" . @date("H:i:s") . "</span>" // @ - time zone may be not set
. " $return<div id='$sql_id' class='hidden'><pre><code class='jush-$jush'>" . shorten_utf8($query, 1000) . "</code></pre>"
. ($time ? " <span class='time'>($time)</span>" : '')
. (support("sql") ? '<p><a href="' . h(str_replace("db=" . urlencode(DB), "db=" . urlencode($_GET["db"]), ME) . 'sql=&history=' . (count($history[$_GET["db"]]) - 1)) . '">' . lang('Edit') . '</a>' : '')
. '</div>'
@@ -626,6 +700,16 @@ focus(document.getElementById('username'));
return "";
}
/** Get hint for edit field
* @param string table name
* @param array single field from fields()
* @param string
* @return string
*/
function editHint($table, $field, $value) {
return "";
}
/** Process sent input
* @param array single field from fields()
* @param string
@@ -642,10 +726,10 @@ focus(document.getElementById('username'));
$return = "$function()";
} elseif (preg_match('~^current_(date|timestamp)$~', $function)) {
$return = $function;
} elseif (preg_match('~^([+-]|\\|\\|)$~', $function)) {
} elseif (preg_match('~^([+-]|\|\|)$~', $function)) {
$return = idf_escape($name) . " $function $return";
} elseif (preg_match('~^[+-] interval$~', $function)) {
$return = idf_escape($name) . " $function " . (preg_match("~^(\\d+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : $return);
$return = idf_escape($name) . " $function " . (preg_match("~^(\\d+|'[0-9.: -]') [A-Z_]+\$~i", $value) ? $value : $return);
} elseif (preg_match('~^(addtime|subtime|concat)$~', $function)) {
$return = "$function(" . idf_escape($name) . ", $return)";
} elseif (preg_match('~^(md5|sha1|password|encrypt)$~', $function)) {
@@ -699,7 +783,7 @@ focus(document.getElementById('username'));
}
$create = "CREATE TABLE " . table($table) . " (" . implode(", ", $fields) . ")";
} else {
$create = create_sql($table, $_POST["auto_increment"]);
$create = create_sql($table, $_POST["auto_increment"], $style);
}
set_utf8mb4($create);
if ($style && $create) {
@@ -761,7 +845,7 @@ focus(document.getElementById('username'));
foreach ($row as $key => $val) {
$field = $fields[$key];
$row[$key] = ($val !== null
? unconvert_field($field, preg_match('~(^|[^o])int|float|double|decimal~', $field["type"]) && $val != '' ? $val : q($val))
? unconvert_field($field, preg_match(number_type(), $field["type"]) && !preg_match('~\[~', $field["full_type"]) && is_numeric($val) ? $val : q(($val === false ? 0 : $val)))
: "NULL"
);
}
@@ -812,6 +896,13 @@ focus(document.getElementById('username'));
return $ext;
}
/** Set the path of the file for webserver load
* @return string path of the sql dump file
*/
function importServerPath() {
return "adminer.sql";
}
/** Print homepage
* @return bool whether to print default homepage
*/
@@ -832,42 +923,39 @@ focus(document.getElementById('username'));
?>
<h1>
<?php echo $this->name(); ?> <span class="version"><?php echo $VERSION; ?></span>
<a href="https://www.adminer.org/#download" target="_blank" id="version"><?php echo (version_compare($VERSION, $_COOKIE["adminer_version"]) < 0 ? h($_COOKIE["adminer_version"]) : ""); ?></a>
<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>
</h1>
<?php
if ($missing == "auth") {
$first = true;
$output = "";
foreach ((array) $_SESSION["pwds"] as $vendor => $servers) {
foreach ($servers as $server => $usernames) {
foreach ($usernames as $username => $password) {
if ($password !== null) {
if ($first) {
echo "<p id='logins' onmouseover='menuOver(this, event);' onmouseout='menuOut(this);'>\n";
$first = false;
}
$dbs = $_SESSION["db"][$vendor][$server][$username];
foreach (($dbs ? array_keys($dbs) : array("")) as $db) {
echo "<a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>($drivers[$vendor]) " . h($username . ($server != "" ? "@$server" : "") . ($db != "" ? " - $db" : "")) . "</a><br>\n";
$output .= "<li><a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>($drivers[$vendor]) " . h($username . ($server != "" ? "@" . $this->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "</a>\n";
}
}
}
}
}
if ($output) {
echo "<ul id='logins'>\n$output</ul>\n" . script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});");
}
} else {
if ($_GET["ns"] !== "" && !$missing && DB != "") {
$connection->select_db(DB);
$tables = table_status('', true);
}
?>
<script type="text/javascript" src="../externals/jush/modules/jush.js"></script>
<script type="text/javascript" src="../externals/jush/modules/jush-textarea.js"></script>
<script type="text/javascript" src="../externals/jush/modules/jush-txt.js"></script>
<script type="text/javascript" src="../externals/jush/modules/jush-js.js"></script>
<?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");
?>
<script type="text/javascript" src="../externals/jush/modules/jush-<?php echo $jush; ?>.js"></script>
<script type="text/javascript">
<script<?php echo nonce(); ?>>
<?php
if ($tables) {
$links = array();
@@ -879,8 +967,9 @@ focus(document.getElementById('username'));
echo "jushLinks.$val = jushLinks.$jush;\n";
}
}
$server_info = $connection->server_info;
?>
bodyLoad('<?php echo (is_object($connection) ? substr($connection->server_info, 0, 3) : ""); ?>');
bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $server_info) : ""); ?>'<?php echo (preg_match('~MariaDB~', $server_info) ? ", true" : ""); ?>);
</script>
<?php
}
@@ -909,30 +998,34 @@ bodyLoad('<?php echo (is_object($connection) ? substr($connection->server_info,
function databasesPrint($missing) {
global $adminer, $connection;
$databases = $this->databases();
if ($databases && !in_array(DB, $databases)) {
array_unshift($databases, DB);
}
?>
<form action="">
<p id="dbs">
<?php
hidden_fields_get();
$db_events = " onmousedown='dbMouseDown(event, this);' onchange='dbChange(this);'";
echo "<span title='" . lang('database') . "'>DB</span>: " . ($databases
? "<select name='db'$db_events>" . optionlist(array("" => "") + $databases, DB) . "</select>"
: '<input name="db" value="' . h(DB) . '" autocapitalize="off">'
$db_events = script("mixin(qsl('select'), {onmousedown: dbMouseDown, onchange: dbChange});");
echo "<span title='" . lang('database') . "'>" . lang('DB') . "</span>: " . ($databases
? "<select name='db'>" . optionlist(array("" => "") + $databases, DB) . "</select>$db_events"
: "<input name='db' value='" . h(DB) . "' autocapitalize='off'>\n"
);
echo "<input type='submit' value='" . lang('Use') . "'" . ($databases ? " class='hidden'" : "") . ">\n";
if ($missing != "db" && DB != "" && $connection->select_db(DB)) {
if (support("scheme")) {
echo "<br>" . lang('Schema') . ": <select name='ns'$db_events>" . optionlist(array("" => "") + $adminer->schemas(), $_GET["ns"]) . "</select>";
echo "<br>" . lang('Schema') . ": <select name='ns'>" . optionlist(array("" => "") + $adminer->schemas(), $_GET["ns"]) . "</select>$db_events";
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
}
}
}
echo (isset($_GET["sql"]) ? '<input type="hidden" name="sql" value="">'
: (isset($_GET["schema"]) ? '<input type="hidden" name="schema" value="">'
: (isset($_GET["dump"]) ? '<input type="hidden" name="dump" value="">'
: (isset($_GET["privileges"]) ? '<input type="hidden" name="privileges" value="">'
: ""))));
foreach (array("import", "sql", "schema", "dump", "privileges") as $val) {
if (isset($_GET[$val])) {
echo "<input type='hidden' name='$val' value=''>";
break;
}
}
echo "</p></form>\n";
}
@@ -941,16 +1034,18 @@ bodyLoad('<?php echo (is_object($connection) ? substr($connection->server_info,
* @return null
*/
function tablesPrint($tables) {
echo "<ul id='tables' onmouseover='menuOver(this, event);' onmouseout='menuOut(this);'>\n";
echo "<ul id='tables'>" . script("mixin(qs('#tables'), {onmouseover: menuOver, onmouseout: menuOut});");
foreach ($tables as $table => $status) {
echo '<li><a href="' . h(ME) . 'select=' . urlencode($table) . '"' . bold($_GET["select"] == $table || $_GET["edit"] == $table, "select") . ">" . lang('select') . "</a> ";
$name = $this->tableName($status);
echo (support("table") || support("indexes")
? '<a href="' . h(ME) . 'table=' . urlencode($table) . '"'
. bold(in_array($table, array($_GET["table"], $_GET["create"], $_GET["indexes"], $_GET["foreign"], $_GET["trigger"])), (is_view($status) ? "view" : "structure"))
. " title='" . lang('Show structure') . "'>$name</a>"
: "<span>$name</span>"
) . "\n";
if ($name != "") {
echo '<li><a href="' . h(ME) . 'select=' . urlencode($table) . '"' . bold($_GET["select"] == $table || $_GET["edit"] == $table, "select") . ">" . lang('select') . "</a> ";
echo (support("table") || support("indexes")
? '<a href="' . h(ME) . 'table=' . urlencode($table) . '"'
. bold(in_array($table, array($_GET["table"], $_GET["create"], $_GET["indexes"], $_GET["foreign"], $_GET["trigger"])), (is_view($status) ? "view" : "structure"))
. " title='" . lang('Show structure') . "'>$name</a>"
: "<span>$name</span>"
) . "\n";
}
}
echo "</ul>\n";
}

View File

@@ -17,15 +17,10 @@ if ($_COOKIE["adminer_permanent"]) {
function add_invalid_login() {
global $adminer;
$filename = get_temp_dir() . "/adminer.invalid";
$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;
}
$fp = file_open_lock(get_temp_dir() . "/adminer.invalid");
if (!$fp) {
return;
}
flock($fp, LOCK_EX);
$invalids = unserialize(stream_get_contents($fp));
$time = time();
if ($invalids) {
@@ -40,22 +35,21 @@ function add_invalid_login() {
$invalid = array($time + 30*60, 0); // active for 30 minutes
}
$invalid[1]++;
$serialized = serialize($invalids);
rewind($fp);
fwrite($fp, $serialized);
ftruncate($fp, strlen($serialized));
flock($fp, LOCK_UN);
fclose($fp);
file_write_unlock($fp, serialize($invalids));
}
function check_invalid_login() {
global $adminer;
$invalids = unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
$invalid = $invalids[$adminer->bruteForceKey()];
$next_attempt = ($invalid[1] > 29 ? $invalid[0] - time() : 0); // allow 30 invalid attempts
if ($next_attempt > 0) { //! do the same with permanent login
auth_error(lang('Too many unsuccessful logins, try again in %d minute(s).', ceil($next_attempt / 60)));
}
}
$auth = $_POST["auth"];
if ($auth) {
$invalids = unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
$invalid = $invalids[$adminer->bruteForceKey()];
$next_attempt = ($invalid[1] > 30 ? $invalid[0] - time() : 0); // allow 30 invalid attempts
if ($next_attempt > 0) { //! do the same with permanent login
auth_error(lang('Too many unsuccessful logins, try again in %d minute(s).', ceil($next_attempt / 60)));
}
session_regenerate_id(); // defense against session fixation
$vendor = $auth["driver"];
$server = $auth["server"];
@@ -89,7 +83,7 @@ if ($auth) {
set_session($key, null);
}
unset_permanent();
redirect(substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1), lang('Logout successful.'));
redirect(substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1), lang('Logout successful.') . ' ' . lang('Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.'));
}
} elseif ($permanent && !$_SESSION["pwds"]) {
@@ -126,11 +120,12 @@ function auth_error($error) {
if (($_COOKIE[$session_name] || $_GET[$session_name]) && !$has_token) {
$error = lang('Session expired, please login again.');
} else {
restart_session();
add_invalid_login();
$password = get_password();
if ($password !== null) {
if ($password === false) {
$error .= '<br>' . lang('Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.', '<code>permanentLogin()</code>');
$error .= '<br>' . lang('Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.', target_blank(), '<code>permanentLogin()</code>');
}
set_password(DRIVER, SERVER, $_GET["username"], null);
}
@@ -144,30 +139,41 @@ function auth_error($error) {
cookie("adminer_key", ($_COOKIE["adminer_key"] ? $_COOKIE["adminer_key"] : rand_string()), $params["lifetime"]);
page_header(lang('Login'), $error, null);
echo "<form action='' method='post'>\n";
$adminer->loginForm();
echo "<div>";
hidden_fields($_POST, array("auth")); // expired session
if (hidden_fields($_POST, array("auth"))) { // expired session
echo "<p class='message'>" . lang('The action will be performed after successful login with the same credentials.') . "\n";
}
echo "</div>\n";
$adminer->loginForm();
echo "</form>\n";
page_footer("auth");
exit;
}
if (isset($_GET["username"])) {
if (!class_exists("Min_DB")) {
unset($_SESSION["pwds"][DRIVER]);
unset_permanent();
page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.', implode(", ", $possible_drivers)), false);
page_footer("auth");
exit;
}
$connection = connect();
if (isset($_GET["username"]) && !class_exists("Min_DB")) {
unset($_SESSION["pwds"][DRIVER]);
unset_permanent();
page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.', implode(", ", $possible_drivers)), false);
page_footer("auth");
exit;
}
$driver = new Min_Driver($connection);
stop_session(true);
if (isset($_GET["username"]) && is_string(get_password())) {
list($host, $port) = explode(":", SERVER, 2);
if (is_numeric($port) && $port < 1024) {
auth_error(lang('Connecting to privileged ports is not allowed.'));
}
check_invalid_login();
$connection = connect();
$driver = new Min_Driver($connection);
}
$login = null;
if (!is_object($connection) || ($login = $adminer->login($_GET["username"], get_password())) !== true) {
auth_error((is_string($connection) ? h($connection) : (is_string($login) ? $login : lang('Invalid credentials.'))));
$error = (is_string($connection) ? h($connection) : (is_string($login) ? $login : lang('Invalid credentials.')));
auth_error($error . (preg_match('~^ | $~', get_password()) ? '<br>' . lang('There is a space in the input password which might be the cause.') : ''));
}
if ($auth && $_POST["token"]) {

View File

@@ -18,14 +18,22 @@ if (function_exists("mb_internal_encoding")) {
mb_internal_encoding("8bit");
}
include "../adminer/include/functions.inc.php";
// used only in compiled file
if (isset($_GET["file"])) {
include "../adminer/file.inc.php";
}
include "../adminer/include/functions.inc.php";
if ($_GET["script"] == "version") {
$fp = file_open_lock(get_temp_dir() . "/adminer.version");
if ($fp) {
file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
}
exit;
}
global $adminer, $connection, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
global $adminer, $connection, $driver, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function
if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
$_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"];
@@ -33,13 +41,16 @@ if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
if (!strpos($_SERVER["REQUEST_URI"], '?') && $_SERVER["QUERY_STRING"] != "") { // IIS 7 compatibility
$_SERVER["REQUEST_URI"] .= "?$_SERVER[QUERY_STRING]";
}
$HTTPS = $_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off");
if ($_SERVER["HTTP_X_FORWARDED_PREFIX"]) {
$_SERVER["REQUEST_URI"] = $_SERVER["HTTP_X_FORWARDED_PREFIX"] . $_SERVER["REQUEST_URI"];
}
$HTTPS = ($_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")) || ini_bool("session.cookie_secure"); // session.cookie_secure could be set on HTTP if we are behind a reverse proxy
@ini_set("session.use_trans_sid", false); // protect links in export, @ - may be disabled
session_cache_limiter(""); // to allow restarting session and to not send Cache-Control: no-store
if (!defined("SID")) {
session_cache_limiter(""); // to allow restarting session
session_name("adminer_sid"); // use specific session name to get own namespace
$params = array(0, preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"]), "", $HTTPS);
$params = array(0, preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"]), "", $HTTPS);
if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
$params[] = true; // HttpOnly
}
@@ -54,7 +65,7 @@ if (get_magic_quotes_runtime()) {
}
@set_time_limit(0); // @ - can be disabled
@ini_set("zend.ze1_compatibility_mode", false); // @ - deprecated
@ini_set("precision", 20); // @ - can be disabled
@ini_set("precision", 15); // @ - can be disabled, 15 - internal PHP precision
include "../adminer/include/lang.inc.php";
include "../adminer/lang/$LANG.inc.php";
@@ -68,11 +79,12 @@ include "../adminer/drivers/firebird.inc.php";
include "../adminer/drivers/simpledb.inc.php";
include "../adminer/drivers/mongo.inc.php";
include "../adminer/drivers/elastic.inc.php";
include "../adminer/drivers/clickhouse.inc.php";
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
define("SERVER", $_GET[DRIVER]); // read from pgsql=localhost
define("DB", $_GET["db"]); // for the sake of speed and size
define("ME", preg_replace('~^[^?]*/([^?]*).*~', '\\1', $_SERVER["REQUEST_URI"]) . '?'
define("ME", preg_replace('~^[^?]*/([^?]*).*~', '\1', $_SERVER["REQUEST_URI"]) . '?'
. (sid() ? SID . '&' : '')
. (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '')
. (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
@@ -84,11 +96,6 @@ include "./include/adminer.inc.php";
include "../adminer/include/design.inc.php";
include "../adminer/include/xxtea.inc.php";
include "../adminer/include/auth.inc.php";
if (!ini_bool("session.use_cookies") || @ini_set("session.use_cookies", false) !== false) { // @ - may be disabled
session_write_close(); // improves concurrency if a user opens several pages at once, may be restarted later
}
include "./include/editing.inc.php";
include "./include/connect.inc.php";

View File

@@ -17,7 +17,6 @@ function connect_error() {
'processlist' => lang('Process list'),
'variables' => lang('Variables'),
'status' => lang('Status'),
'replication' => lang('Replication'),
) as $key => $val) {
if (support($key)) {
echo "<a href='" . h(ME) . "$key='>$val</a>\n";
@@ -30,13 +29,14 @@ function connect_error() {
$scheme = support("scheme");
$collations = collations();
echo "<form action='' method='post'>\n";
echo "<table cellspacing='0' class='checkable' onclick='tableClick(event);' ondblclick='tableClick(event, true);'>\n";
echo "<table cellspacing='0' class='checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo "<thead><tr>"
. (support("database") ? "<td>&nbsp;" : "")
. (support("database") ? "<td>" : "")
. "<th>" . lang('Database') . " - <a href='" . h(ME) . "refresh=1'>" . lang('Refresh') . "</a>"
. "<td>" . lang('Collation')
. "<td>" . lang('Tables')
. "<td>" . lang('Size') . " - <a href='" . h(ME) . "dbsize=1' onclick=\"return !ajaxSetHtml('" . h(js_escape(ME)) . "script=connect');\">" . lang('Compute') . "</a>"
. "<td>" . lang('Size') . " - <a href='" . h(ME) . "dbsize=1'>" . lang('Compute') . "</a>" . script("qsl('a').onclick = partial(ajaxSetHtml, '" . js_escape(ME) . "script=connect');", "")
. "</thead>\n"
;
@@ -46,8 +46,8 @@ function connect_error() {
$root = h(ME) . "db=" . urlencode($db);
$id = h("Db-" . $db);
echo "<tr" . odd() . ">" . (support("database") ? "<td>" . checkbox("db[]", $db, in_array($db, (array) $_POST["db"]), "", "", "", $id) : "");
echo "<th><a href='$root' id='$db'>" . h($db) . "</a>";
$collation = nbsp(db_collation($db, $collations));
echo "<th><a href='$root' id='$id'>" . h($db) . "</a>";
$collation = h(db_collation($db, $collations));
echo "<td>" . (support("database") ? "<a href='$root" . ($scheme ? "&amp;ns=" : "") . "&amp;database=' title='" . lang('Alter database') . "'>$collation</a>" : $collation);
echo "<td align='right'><a href='$root&amp;schema=' id='tables-" . h($db) . "' title='" . lang('Database schema') . "'>" . ($_GET["dbsize"] ? $tables : "?") . "</a>";
echo "<td align='right' id='size-" . h($db) . "'>" . ($_GET["dbsize"] ? db_size($db) : "?");
@@ -56,15 +56,17 @@ function connect_error() {
echo "</table>\n";
echo (support("database")
? "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>\n"
. "<input type='hidden' name='all' value='' onclick=\"selectCount('selected', formChecked(this, /^db/));\">\n" // used by trCheck()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'" . confirm() . ">\n"
? "<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 type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm() . "\n"
. "</div></fieldset>\n"
. "</div></div>\n"
: ""
);
echo "<script type='text/javascript'>tableCheck();</script>\n";
echo "<input type='hidden' name='token' value='$token'>\n";
echo "</form>\n";
echo script("tableCheck();");
}
}
@@ -78,7 +80,7 @@ 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["replication"]) || 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);

View File

@@ -19,28 +19,50 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
<!DOCTYPE html>
<html lang="<?php echo $LANG; ?>" dir="<?php echo lang('ltr'); ?>">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta name="robots" content="noindex">
<meta name="referrer" content="origin-when-crossorigin">
<title><?php echo $title_page; ?></title>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css">
<script type="text/javascript" src="../adminer/static/functions.js"></script>
<script type="text/javascript" src="static/editing.js"></script>
<?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 if (file_exists("adminer.css")) { ?>
<link rel="stylesheet" type="text/css" href="adminer.css">
<?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" onkeydown="bodyKeydown(event);" onclick="bodyClick(event);"<?php echo (isset($_COOKIE["adminer_version"]) ? "" : " onload=\"verifyVersion('$VERSION');\""); ?>>
<script type="text/javascript">
<body class="<?php echo lang('ltr'); ?> nojs">
<?php
$filename = get_temp_dir() . "/adminer.version";
if (!$_COOKIE["adminer_version"] && function_exists('openssl_verify') && file_exists($filename) && filemtime($filename) + 86400 > time()) { // 86400 - 1 day in seconds
$version = unserialize(file_get_contents($filename));
$public = "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwqWOVuF5uw7/+Z70djoK
RlHIZFZPO0uYRezq90+7Amk+FDNd7KkL5eDve+vHRJBLAszF/7XKXe11xwliIsFs
DFWQlsABVZB3oisKCBEuI71J4kPH8dKGEWR9jDHFw3cWmoH3PmqImX6FISWbG3B8
h7FIx3jEaw5ckVPVTeo5JRm/1DZzJxjyDenXvBQ/6o9DgZKeNDgxwKzH+sw9/YCO
jHnq1cFpOIISzARlrHMa/43YfeNRAm/tsBXjSxembBPo7aQZLAWHmaj5+K19H10B
nCpz9Y++cipkVEiKRGih4ZEvjoFysEOdRLj6WiD/uUNky4xGeA6LaJqh5XpkFkcQ
fQIDAQAB
-----END PUBLIC KEY-----
";
if (openssl_verify($version["version"], base64_decode($version["signature"]), $public) == 1) {
$_COOKIE["adminer_version"] = $version["version"]; // doesn't need to send to the browser
}
}
?>
<script<?php echo nonce(); ?>>
mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick<?php
echo (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '$VERSION', '" . js_escape(ME) . "', '" . get_token() . "')"); // $token may be empty in auth.inc.php
?>});
document.body.className = document.body.className.replace(/ nojs/, ' js');
var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
</script>
<div id="help" class="jush-<?php echo $jush; ?> jsonly hidden" onmouseover="helpOpen = 1;" onmouseout="helpMouseout(this, event);"></div>
<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
@@ -48,7 +70,8 @@ var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
$link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1);
echo '<p id="breadcrumb"><a href="' . h($link ? $link : ".") . '">' . $drivers[DRIVER] . '</a> &raquo; ';
$link = substr(preg_replace('~\b(db|ns)=[^&]*&~', '', ME), 0, -1);
$server = (SERVER != "" ? h(SERVER) : lang('Server'));
$server = $adminer->serverName(SERVER);
$server = ($server != "" ? $server : lang('Server'));
if ($breadcrumb === false) {
echo "$server\n";
} else {
@@ -89,10 +112,45 @@ function page_headers() {
global $adminer;
header("Content-Type: text/html; charset=utf-8");
header("Cache-Control: no-cache");
if ($adminer->headers()) {
header("X-Frame-Options: deny"); // ClickJacking protection in IE8, Safari 4, Chrome 2, Firefox 3.6.9
header("X-XSS-Protection: 0"); // prevents introducing XSS in IE8 by removing safe parts of the page
header("X-Frame-Options: deny"); // ClickJacking protection in IE8, Safari 4, Chrome 2, Firefox 3.6.9
header("X-XSS-Protection: 0"); // prevents introducing XSS in IE8 by removing safe parts of the page
header("X-Content-Type-Options: nosniff");
header("Referrer-Policy: origin-when-cross-origin");
foreach ($adminer->csp() as $csp) {
$header = array();
foreach ($csp as $key => $val) {
$header[] = "$key $val";
}
header("Content-Security-Policy: " . implode("; ", $header));
}
$adminer->headers();
}
/** Get Content Security Policy headers
* @return array of arrays with directive name in key, allowed sources in value
*/
function csp() {
return array(
array(
"script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'", // 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
"connect-src" => "'self'",
"frame-src" => "https://www.adminer.org",
"object-src" => "'none'",
"base-uri" => "'none'",
"form-action" => "'self'",
),
);
}
/** Get a CSP nonce
* @return string Base64 value
*/
function get_nonce() {
static $nonce;
if (!$nonce) {
$nonce = base64_encode(rand_string());
}
return $nonce;
}
/** Print flash and error messages
@@ -103,7 +161,7 @@ function page_messages($error) {
$uri = preg_replace('~^[^?]*~', '', $_SERVER["REQUEST_URI"]);
$messages = $_SESSION["messages"][$uri];
if ($messages) {
echo "<div class='message'>" . implode("</div>\n<div class='message'>", $messages) . "</div>\n";
echo "<div class='message'>" . implode("</div>\n<div class='message'>", $messages) . "</div>" . script("messagesPrint();");
unset($_SESSION["messages"][$uri]);
}
if ($error) {
@@ -132,6 +190,6 @@ function page_footer($missing = "") {
<div id="menu">
<?php $adminer->navigation($missing); ?>
</div>
<script type="text/javascript">setupSubmitHighlight(document);</script>
<?php
echo script("setupSubmitHighlight(document);");
}

View File

@@ -27,7 +27,7 @@
$query = $adminer->selectQueryBuild($select, $where, $group, $order, $limit, $page);
if (!$query) {
$query = "SELECT" . limit(
($_GET["page"] != "last" && +$limit && $group && $is_group && $jush == "sql" ? "SQL_CALC_FOUND_ROWS " : "") . implode(", ", $select) . "\nFROM " . table($table),
($_GET["page"] != "last" && $limit != "" && $group && $is_group && $jush == "sql" ? "SQL_CALC_FOUND_ROWS " : "") . implode(", ", $select) . "\nFROM " . table($table),
($where ? "\nWHERE " . implode(" AND ", $where) : "") . ($group && $is_group ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : ""),
($limit != "" ? +$limit : null),
($page ? $limit * $page : 0),
@@ -37,7 +37,7 @@
$start = microtime(true);
$return = $this->_conn->query($query);
if ($print) {
echo $adminer->selectQuery($query, format_time($start));
echo $adminer->selectQuery($query, $start, !$return);
}
return $return;
}
@@ -50,7 +50,7 @@
*/
function delete($table, $queryWhere, $limit = 0) {
$query = "FROM " . table($table);
return queries("DELETE" . ($limit ? limit1($query, $queryWhere) : " $query$queryWhere"));
return queries("DELETE" . ($limit ? limit1($table, $query, $queryWhere) : " $query$queryWhere"));
}
/** Update data in table
@@ -67,7 +67,7 @@
$values[] = "$key = $val";
}
$query = table($table) . " SET$separator" . implode(",$separator", $values);
return queries("UPDATE" . ($limit ? limit1($query, $queryWhere) : " $query$queryWhere"));
return queries("UPDATE" . ($limit ? limit1($table, $query, $queryWhere, $separator) : " $query$queryWhere"));
}
/** Insert data into table
@@ -99,12 +99,70 @@
return queries("BEGIN");
}
/** Commit transaction
* @return bool
*/
function commit() {
return queries("COMMIT");
}
/** Rollback transaction
* @return bool
*/
function rollback() {
return queries("ROLLBACK");
}
/** Return query with a timeout
* @param string
* @param int seconds
* @return string or null if the driver doesn't support query timeouts
*/
function slowQuery($query, $timeout) {
}
/** Convert column to be searchable
* @param string escaped column name
* @param array array("op" => , "val" => )
* @param array
* @return string
*/
function convertSearch($idf, $val, $field) {
return $idf;
}
/** Convert value returned by database to actual value
* @param string
* @param array
* @return string
*/
function value($val, $field) {
return (method_exists($this->_conn, 'value')
? $this->_conn->value($val, $field)
: (is_resource($val) ? stream_get_contents($val) : $val)
);
}
/** Quote binary string
* @param string
* @return string
*/
function quoteBinary($s) {
return q($s);
}
/** Get warnings about the last command
* @return string HTML
*/
function warnings() {
return '';
}
/** Get help link for table
* @param string
* @return string relative URL or null
*/
function tableHelp($name) {
}
}

View File

@@ -17,6 +17,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
odd(''); // reset odd for each result
for ($i=0; (!$limit || $i < $limit) && ($row = $result->fetch_row()); $i++) {
if (!$i) {
echo "<div class='scrollable'>\n";
echo "<table cellspacing='0' class='nowrap'>\n";
echo "<thead><tr>";
for ($j=0; $j < count($row); $j++) {
@@ -50,7 +51,10 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
}
$types[$j] = $field->type;
echo "<th" . ($orgtable != "" || $field->name != $orgname ? " title='" . h(($orgtable != "" ? "$orgtable." : "") . $orgname) . "'" : "") . ">" . h($name)
. ($orgtables ? doc_link(array('sql' => "explain-output.html#explain_" . strtolower($name))) : "")
. ($orgtables ? doc_link(array(
'sql' => "explain-output.html#explain_" . strtolower($name),
'mariadb' => "explain/#the-columns-in-explain-select",
)) : "")
;
}
echo "</thead>\n";
@@ -61,8 +65,6 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
$val = "<i>NULL</i>";
} elseif ($blobs[$key] && !is_utf8($val)) {
$val = "<i>" . lang('%d byte(s)', strlen($val)) . "</i>"; //! link to download
} elseif (!strlen($val)) { // strlen - SQLite can return int
$val = "&nbsp;"; // some content to print a border
} else {
$val = h($val);
if ($types[$key] == 254) { // 254 - char
@@ -84,7 +86,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
echo "<td>$val";
}
}
echo ($i ? "</table>" : "<p class='message'>" . lang('No rows.')) . "\n";
echo ($i ? "</table>\n</div>" : "<p class='message'>" . lang('No rows.')) . "\n";
return $return;
}
@@ -110,6 +112,31 @@ 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
@@ -135,25 +162,28 @@ function textarea($name, $value, $rows = 10, $cols = 80) {
* @param array
* @param array
* @param array returned by referencable_primary()
* @param array extra types to prepend
* @return null
*/
function edit_type($key, $field, $collations, $foreign_keys = array()) {
function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_types = array()) {
global $structured_types, $types, $unsigned, $on_actions;
$type = $field["type"];
?>
<td><select name="<?php echo h($key); ?>[type]" class="type" onfocus="lastType = selectValue(this);" onchange="editingTypeChange(this);"<?php echo on_help("getTarget(event).value", 1); ?> aria-labelledby="label-type"><?php
if ($type && !isset($types[$type]) && !isset($foreign_keys[$type])) {
array_unshift($structured_types, $type);
<td><select name="<?php echo h($key); ?>[type]" class="type" aria-labelledby="label-type"><?php
if ($type && !isset($types[$type]) && !isset($foreign_keys[$type]) && !in_array($type, $extra_types)) {
$extra_types[] = $type;
}
if ($foreign_keys) {
$structured_types[lang('Foreign keys')] = $foreign_keys;
}
echo optionlist($structured_types, $type);
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" onfocus="editingLengthFocus(this);"<?php echo (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : ""); ?> onchange="editingLengthChange(this);" onkeyup="this.onchange();" aria-labelledby="label-length"><td class="options"><?php //! type="number" with enabled JavaScript
<?php echo on_help("getTarget(event).value", 1); ?>
<?php echo script("mixin(qsl('select'), {onfocus: function () { lastType = selectValue(this); }, onchange: editingTypeChange});", ""); ?>
<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"><?php echo script("mixin(qsl('input'), {onfocus: editingLengthFocus, oninput: editingLengthChange});", ""); ?><td class="options"><?php
echo "<select name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . '><option value="">(' . lang('collation') . ')' . optionlist($collations, $field["collation"]) . '</select>';
echo ($unsigned ? "<select name='" . h($key) . "[unsigned]'" . (!$type || preg_match('~((^|[^o])int|float|double|decimal)$~', $type) ? "" : " class='hidden'") . '><option>' . optionlist($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"), $field["on_update"]) . '</select>' : '');
echo ($unsigned ? "<select name='" . h($key) . "[unsigned]'" . (!$type || preg_match(number_type(), $type) ? "" : " class='hidden'") . '><option>' . optionlist($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("|", $on_actions), $field["on_delete"]) . "</select> " : " "); // space for IE
}
@@ -178,7 +208,7 @@ function process_type($field, $collate = "COLLATE") {
global $unsigned;
return " $field[type]"
. process_length($field["length"])
. (preg_match('~(^|[^o])int|float|double|decimal~', $field["type"]) && in_array($field["unsigned"], $unsigned) ? " $field[unsigned]" : "")
. (preg_match(number_type(), $field["type"]) && in_array($field["unsigned"], $unsigned) ? " $field[unsigned]" : "")
. (preg_match('~char|text|enum|set~', $field["type"]) && $field["collation"] ? " $collate " . q($field["collation"]) : "")
;
}
@@ -189,24 +219,26 @@ function process_type($field, $collate = "COLLATE") {
* @return array array("field", "type", "NULL", "DEFAULT", "ON UPDATE", "COMMENT", "AUTO_INCREMENT")
*/
function process_field($field, $type_field) {
global $jush;
$default = $field["default"];
return array(
idf_escape(trim($field["field"])),
process_type($type_field),
($field["null"] ? " NULL" : " NOT NULL"), // NULL for timestamp
(isset($default) ? " DEFAULT " . (
(preg_match('~time~', $field["type"]) && preg_match('~^CURRENT_TIMESTAMP$~i', $default))
|| ($jush == "sqlite" && preg_match('~^CURRENT_(TIME|TIMESTAMP|DATE)$~i', $default))
|| ($field["type"] == "bit" && preg_match("~^([0-9]+|b'[0-1]+')\$~", $default))
|| ($jush == "pgsql" && preg_match("~^[a-z]+\\(('[^']*')+\\)\$~", $default))
? $default : q($default)) : ""),
default_value($field),
(preg_match('~timestamp|datetime~', $field["type"]) && $field["on_update"] ? " ON UPDATE $field[on_update]" : ""),
(support("comment") && $field["comment"] != "" ? " COMMENT " . q($field["comment"]) : ""),
($field["auto_increment"] ? auto_increment() : null),
);
}
/** Get default value clause
* @param array
* @return string
*/
function default_value($field) {
$default = $field["default"];
return ($default === null ? "" : " DEFAULT " . (preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default) ? q($default) : $default));
}
/** Get type class to use in CSS
* @param string
* @return string class=''
@@ -229,34 +261,35 @@ function type_class($type) {
* @param array
* @param string TABLE or PROCEDURE
* @param array returned by referencable_primary()
* @param bool display comments column
* @return null
*/
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array(), $comments = false) {
global $connection, $inout;
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
global $inout;
$fields = array_values($fields);
?>
<thead><tr class="wrap">
<?php if ($type == "PROCEDURE") { ?><td>&nbsp;<?php } ?>
<thead><tr>
<?php if ($type == "PROCEDURE") { ?><td><?php } ?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;" onblur="editingLengthBlur(this);"></textarea>
<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=""><acronym id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</acronym><?php echo doc_link(array(
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype.html#DATATYPE-SERIAL",
'mssql' => "ms186775.aspx",
)); ?>
<td id="label-default"><?php echo lang('Default value'); ?>
<?php echo (support("comment") ? "<td id='label-comment'" . ($comments ? "" : " class='hidden'") . ">" . lang('Comment') : ""); ?>
<?php echo (support("comment") ? "<td id='label-comment'>" . 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 type="text/javascript">row_count = <?php echo count($fields); ?>;</script>
<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 onkeydown="return editingKeydown(event);">
<tbody>
<?php
echo script("mixin(qsl('tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput});");
foreach ($fields as $i => $field) {
$i++;
$orig = $field[($_POST ? "orig" : "field")];
@@ -264,24 +297,22 @@ function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = arra
?>
<tr<?php echo ($display ? "" : " style='display: none;'"); ?>>
<?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $inout), $field["inout"]) : ""); ?>
<th><?php if ($display) { ?><input name="fields[<?php echo $i; ?>][field]" value="<?php echo h($field["field"]); ?>" onchange="editingNameChange(this);<?php echo ($field["field"] != "" || count($fields) > 1 ? '' : ' editingAddRow(this);" onkeyup="if (this.value) editingAddRow(this);'); ?>" maxlength="64" autocapitalize="off" aria-labelledby="label-name"><?php } ?>
<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 echo script("qsl('input').oninput = function () { editingNameChange.call(this);" . ($field["field"] != "" || count($fields) > 1 ? "" : " editingAddRow.call(this);") . " };", ""); ?><?php } ?>
<input type="hidden" name="fields[<?php echo $i; ?>][orig]" value="<?php echo h($orig); ?>">
<?php edit_type("fields[$i]", $field, $collations, $foreign_keys); ?>
<?php if ($type == "TABLE") { ?>
<td><?php echo checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null"); ?>
<td><label class="block"><input type="radio" name="auto_increment_col" value="<?php echo $i; ?>"<?php if ($field["auto_increment"]) { ?> checked<?php } ?> onclick="var field = this.form['fields[' + this.value + '][field]']; if (!field.value) { field.value = 'id'; field.onchange(); }" aria-labelledby="label-ai"></label><td><?php
echo checkbox("fields[$i][has_default]", 1, $field["has_default"], "", "", "", "label-default"); ?><input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" onkeyup="keyupChange.call(this);" onchange="this.previousSibling.checked = true;" aria-labelledby="label-default">
<?php echo (support("comment") ? "<td" . ($comments ? "" : " class='hidden'") . "><input name='fields[$i][comment]' value='" . h($field["comment"]) . "' maxlength='" . ($connection->server_info >= 5.5 ? 1024 : 255) . "' aria-labelledby='label-comment'>" : ""); ?>
<?php } ?>
<?php
<td><label class="block"><input type="radio" name="auto_increment_col" value="<?php echo $i; ?>"<?php if ($field["auto_increment"]) { ?> checked<?php } ?> aria-labelledby="label-ai"></label><td><?php
echo checkbox("fields[$i][has_default]", 1, $field["has_default"], "", "", "", "label-default"); ?><input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" aria-labelledby="label-default"><?php
echo (support("comment") ? "<td><input name='fields[$i][comment]' value='" . h($field["comment"]) . "' data-maxlength='" . (min_version(5.5) ? 1024 : 255) . "' aria-labelledby='label-comment'>" : "");
}
echo "<td>";
echo (support("move_col") ?
"<input type='image' class='icon' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "' onclick='return !editingAddRow(this, 1);'>&nbsp;"
. "<input type='image' class='icon' name='up[$i]' src='../adminer/static/up.gif' alt='^' title='" . lang('Move up') . "' onclick='return !editingMoveRow(this, 1);'>&nbsp;"
. "<input type='image' class='icon' name='down[$i]' src='../adminer/static/down.gif' alt='v' title='" . lang('Move down') . "' onclick='return !editingMoveRow(this, 0);'>&nbsp;"
"<input type='image' class='icon' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'> "
. "<input type='image' class='icon' name='up[$i]' src='../adminer/static/up.gif' alt='' title='" . lang('Move up') . "'> "
. "<input type='image' class='icon' name='down[$i]' src='../adminer/static/down.gif' alt='' title='" . lang('Move down') . "'> "
: "");
echo ($orig == "" || support("drop_col") ? "<input type='image' class='icon' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "' onclick=\"return !editingRemoveRow(this, 'fields\$1[field]');\">" : "");
echo "\n";
echo ($orig == "" || support("drop_col") ? "<input type='image' class='icon' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "'>" : "");
}
}
@@ -352,7 +383,7 @@ function grant($grant, $privileges, $columns, $on) {
: queries("$grant ALL PRIVILEGES$on") && queries("$grant GRANT OPTION$on")
);
}
return queries("$grant " . preg_replace('~(GRANT OPTION)\\([^)]*\\)~', '\\1', implode("$columns, ", $privileges) . $columns) . $on);
return queries("$grant " . preg_replace('~(GRANT OPTION)\([^)]*\)~', '\1', implode("$columns, ", $privileges) . $columns) . $on);
}
/** Drop old object and create a new one
@@ -411,7 +442,7 @@ function create_trigger($on, $row) {
* @return string
*/
function create_routine($routine, $row) {
global $inout;
global $inout, $jush;
$set = array();
$fields = (array) $row["fields"];
ksort($fields); // enforce fields order
@@ -420,13 +451,13 @@ function create_routine($routine, $row) {
$set[] = (preg_match("~^($inout)\$~", $field["inout"]) ? "$field[inout] " : "") . idf_escape($field["field"]) . process_type($field, "CHARACTER SET");
}
}
$definition = rtrim("\n$row[definition]", ";");
return "CREATE $routine "
. idf_escape(trim($row["name"]))
. " (" . implode(", ", $set) . ")"
. (isset($_GET["function"]) ? " RETURNS" . process_type($row["returns"], "CHARACTER SET") : "")
. ($row["language"] ? " LANGUAGE $row[language]" : "")
. rtrim("\n$row[definition]", ";")
. ";"
. ($jush == "pgsql" ? " AS " . q($definition) : "$definition;")
;
}
@@ -435,16 +466,21 @@ function create_routine($routine, $row) {
* @return string
*/
function remove_definer($query) {
return preg_replace('~^([A-Z =]+) DEFINER=`' . preg_replace('~@(.*)~', '`@`(%|\\1)', logged_user()) . '`~', '\\1', $query); //! proper escaping of user
return preg_replace('~^([A-Z =]+) DEFINER=`' . preg_replace('~@(.*)~', '`@`(%|\1)', logged_user()) . '`~', '\1', $query); //! proper escaping of user
}
/** Format foreign key to use in SQL query
* @param array ("table" => string, "source" => array, "target" => array, "on_delete" => one of $on_actions, "on_update" => one of $on_actions)
* @param array ("db" => string, "ns" => string, "table" => string, "source" => array, "target" => array, "on_delete" => one of $on_actions, "on_update" => one of $on_actions)
* @return string
*/
function format_foreign_key($foreign_key) {
global $on_actions;
return " FOREIGN KEY (" . implode(", ", array_map('idf_escape', $foreign_key["source"])) . ") REFERENCES " . table($foreign_key["table"])
$db = $foreign_key["db"];
$ns = $foreign_key["ns"];
return " FOREIGN KEY (" . implode(", ", array_map('idf_escape', $foreign_key["source"])) . ") REFERENCES "
. ($db != "" && $db != $_GET["db"] ? idf_escape($db) . "." : "")
. ($ns != "" && $ns != $_GET["ns"] ? idf_escape($ns) . "." : "")
. table($foreign_key["table"])
. " (" . implode(", ", array_map('idf_escape', $foreign_key["target"])) . ")" //! reuse $name - check in older MySQL versions
. (preg_match("~^($on_actions)\$~", $foreign_key["on_delete"]) ? " ON DELETE $foreign_key[on_delete]" : "")
. (preg_match("~^($on_actions)\$~", $foreign_key["on_update"]) ? " ON UPDATE $foreign_key[on_update]" : "")
@@ -485,18 +521,25 @@ function ini_bytes($ini) {
/** Create link to database documentation
* @param array $jush => $path
* @param string HTML code
* @return string HTML code
*/
function doc_link($paths) {
function doc_link($paths, $text = "<sup>?</sup>") {
global $jush, $connection;
$server_info = $connection->server_info;
$version = preg_replace('~^(\d\.?\d).*~s', '\1', $server_info); // two most significant digits
$urls = array(
'sql' => "http://dev.mysql.com/doc/refman/" . substr($connection->server_info, 0, 3) . "/en/",
'sqlite' => "http://www.sqlite.org/",
'pgsql' => "http://www.postgresql.org/docs/" . substr($connection->server_info, 0, 3) . "/static/",
'mssql' => "http://msdn.microsoft.com/library/",
'oracle' => "http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/",
'sql' => "https://dev.mysql.com/doc/refman/$version/en/",
'sqlite' => "https://www.sqlite.org/",
'pgsql' => "https://www.postgresql.org/docs/$version/static/",
'mssql' => "https://msdn.microsoft.com/library/",
'oracle' => "https://download.oracle.com/docs/cd/B19306_01/server.102/b14200/",
);
return ($paths[$jush] ? "<a href='$urls[$jush]$paths[$jush]' target='_blank' rel='noreferrer'><sup>?</sup></a>" : "");
if (preg_match('~MariaDB~', $server_info)) {
$urls['sql'] = "https://mariadb.com/kb/en/library/";
$paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql']));
}
return ($paths[$jush] ? "<a href='$urls[$jush]$paths[$jush]'" . target_blank() . ">$text</a>" : "");
}
/** Wrap gzencode() for usage in ob_start()
@@ -529,7 +572,7 @@ function db_size($db) {
* @return null
*/
function set_utf8mb4($create) {
global $connection;
global $connection;
static $set = false;
if (!$set && preg_match('~\butf8mb4~i', $create)) { // possible false positive
$set = true;

View File

@@ -16,6 +16,14 @@ function adminer() {
return $adminer;
}
/** Get Adminer version
* @return string
*/
function version() {
global $VERSION;
return $VERSION;
}
/** Unescape database identifier
* @param string text inside ``
* @return string
@@ -38,7 +46,14 @@ function escape_string($val) {
* @return string
*/
function number($val) {
return preg_replace('~[^0-9]+~', '', $val);
return preg_replace('~[^0-9]+~', '', $val);
}
/** Get regular expression to match numeric types
* @return string
*/
function number_type() {
return '((?<!o)int(?!er)|numeric|real|float|double|decimal|money)'; // not point, not interval
}
/** Disable magic_quotes_gpc
@@ -73,12 +88,62 @@ function bracket_escape($idf, $back = false) {
return strtr($idf, ($back ? array_flip($trans) : $trans));
}
/** Check if connection has at least the given version
* @param string required version
* @param string required MariaDB version
* @param Min_DB defaults to $connection
* @return bool
*/
function min_version($version, $maria_db = "", $connection2 = null) {
global $connection;
if (!$connection2) {
$connection2 = $connection;
}
$server_info = $connection2->server_info;
if ($maria_db && preg_match('~([\d.]+)-MariaDB~', $server_info, $match)) {
$server_info = $match[1];
$version = $maria_db;
}
return (version_compare($server_info, $version) >= 0);
}
/** Get connection charset
* @param Min_DB
* @return string
*/
function charset($connection) {
return (version_compare($connection->server_info, "5.5.3") >= 0 ? "utf8mb4" : "utf8"); // SHOW CHARSET would require an extra query
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
@@ -89,14 +154,6 @@ function h($string) {
return str_replace("\0", "&#0;", htmlspecialchars($string, ENT_QUOTES, 'utf-8'));
}
/** Escape for TD
* @param string
* @return string
*/
function nbsp($string) {
return (trim($string) != "" ? h($string) : "&nbsp;");
}
/** Convert \n to <br>
* @param string
* @return string
@@ -119,8 +176,8 @@ function checkbox($name, $value, $checked, $label = "", $onclick = "", $class =
$return = "<input type='checkbox' name='$name' value='" . h($value) . "'"
. ($checked ? " checked" : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ($onclick ? ' onclick="' . h($onclick) . '"' : '')
. ">"
. ($onclick ? script("qsl('input').onclick = function () { $onclick };", "") : "")
;
return ($label != "" || $class ? "<label" . ($class ? " class='$class'" : "") . ">$return" . h($label) . "</label>" : $return);
}
@@ -160,9 +217,10 @@ function optionlist($options, $selected = null, $use_keys = false) {
function html_select($name, $options, $value = "", $onchange = true, $labelled_by = "") {
if ($onchange) {
return "<select name='" . h($name) . "'"
. (is_string($onchange) ? ' onchange="' . h($onchange) . '"' : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">" . optionlist($options, $value) . "</select>";
. ">" . optionlist($options, $value) . "</select>"
. (is_string($onchange) ? script("qsl('select').onchange = function () { $onchange };", "") : "")
;
}
$return = "";
foreach ($options as $key => $val) {
@@ -172,35 +230,42 @@ function html_select($name, $options, $value = "", $onchange = true, $labelled_b
}
/** Generate HTML <select> or <input> if $options are empty
* @param string
* @param array
* @param string
* @param string
* @return string
*/
function select_input($attrs, $options, $value = "", $placeholder = "") {
return ($options
? "<select$attrs><option value=''>$placeholder" . optionlist($options, $value, true) . "</select>"
: "<input$attrs size='10' value='" . h($value) . "' placeholder='$placeholder'>"
);
* @param string
* @param array
* @param string
* @param string
* @param string
* @return string
*/
function select_input($attrs, $options, $value = "", $onchange = "", $placeholder = "") {
$tag = ($options ? "select" : "input");
return "<$tag$attrs" . ($options
? "><option value=''>$placeholder" . optionlist($options, $value, true) . "</select>"
: " size='10' value='" . h($value) . "' placeholder='$placeholder'>"
) . ($onchange ? script("qsl('$tag').onchange = $onchange;", "") : ""); //! use oninput for input
}
/** Get onclick confirmation
* @param string
* @param string
* @return string
*/
function confirm() {
return " onclick=\"return confirm('" . lang('Are you sure?') . "');\"";
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
* @param string
* @return null
*/
function print_fieldset($id, $legend, $visible = false, $onclick = "") {
echo "<fieldset><legend><a href='#fieldset-$id' onclick=\"" . h($onclick) . "return !toggle('fieldset-$id');\">$legend</a></legend><div id='fieldset-$id'" . ($visible ? "" : " class='hidden'") . ">\n";
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
@@ -286,7 +351,7 @@ function set_password($vendor, $server, $username, $password) {
}
/** Get password from session
* @return string
* @return string or null for missing password or false for expired password
*/
function get_password() {
$return = get_session("pwds");
@@ -328,21 +393,23 @@ function get_vals($query, $column = 0) {
/** Get keys from first column and values from second
* @param string
* @param Min_DB
* @param float
* @param bool
* @return array
*/
function get_key_vals($query, $connection2 = null, $timeout = 0) {
function get_key_vals($query, $connection2 = null, $set_keys = true) {
global $connection;
if (!is_object($connection2)) {
$connection2 = $connection;
}
$return = array();
$connection2->timeout = $timeout;
$result = $connection2->query($query);
$connection2->timeout = 0;
if (is_object($result)) {
while ($row = $result->fetch_row()) {
$return[$row[0]] = $row[1];
if ($set_keys) {
$return[$row[0]] = $row[1];
} else {
$return[] = $row[0];
}
}
}
return $return;
@@ -352,7 +419,7 @@ function get_key_vals($query, $connection2 = null, $timeout = 0) {
* @param string
* @param Min_DB
* @param string
* @return array associative
* @return array of associative arrays
*/
function get_rows($query, $connection2 = null, $error = "<p class='error'>") {
global $connection;
@@ -412,10 +479,10 @@ function where($where, $fields = array()) {
$key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key);
$return[] = $column
. ($jush == "sql" && preg_match('~^[0-9]*\\.[0-9]*$~', $val) ? " LIKE " . q(addcslashes($val, "%_\\"))
: ($jush == "mssql" ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val))
. ($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))
)) // LIKE because of floats but slow with ints, in MS SQL because of text
))
; //! enum and set
if ($jush == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
@@ -479,7 +546,7 @@ function cookie($name, $value, $lifetime = 2592000) { // 2592000 - 30 days
global $HTTPS;
return header("Set-Cookie: $name=" . urlencode($value)
. ($lifetime ? "; expires=" . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT" : "")
. "; path=" . preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"])
. "; path=" . preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"])
. ($HTTPS ? "; secure" : "")
. "; HttpOnly; SameSite=lax",
false);
@@ -494,12 +561,17 @@ function restart_session() {
}
}
/** Stop session if it would be possible to restart it later
/** Stop session if possible
* @param bool
* @return null
*/
function stop_session() {
if (!ini_bool("session.use_cookies")) {
session_write_close();
function stop_session($force = false) {
$use_cookies = ini_bool("session.use_cookies");
if (!$use_cookies || $force) {
session_write_close(); // improves concurrency if a user opens several pages at once, may be restarted later
if ($use_cookies && @ini_set("session.use_cookies", false) === false) { // @ - may be disabled
session_start();
}
}
}
@@ -529,7 +601,7 @@ 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);
preg_match('~([^?]*)\??(.*)~', remove_from_uri(implode("|", array_keys($drivers)) . "|username|" . ($db !== null ? "db|" : "") . session_name()), $match);
return "$match[1]?"
. (sid() ? SID . "&" : "")
. ($vendor != "server" || $server != "" ? urlencode($vendor) . "=" . urlencode($server) . "&" : "")
@@ -584,10 +656,10 @@ function query_redirect($query, $location, $message, $redirect = true, $execute
}
$sql = "";
if ($query) {
$sql = $adminer->messageQuery($query, $time);
$sql = $adminer->messageQuery($query, $time, $failed);
}
if ($failed) {
$error = error() . $sql;
$error = error() . $sql . script("messagesPrint();");
return false;
}
if ($redirect) {
@@ -689,7 +761,7 @@ function get_file($key, $decompress = false) {
}
$name = $file["name"][$key];
$tmp_name = $file["tmp_name"][$key];
$content = file_get_contents($decompress && preg_match('~\\.gz$~', $name)
$content = file_get_contents($decompress && preg_match('~\.gz$~', $name)
? "compress.zlib://$tmp_name"
: $tmp_name
); //! may not be reachable because of open_basedir
@@ -734,7 +806,7 @@ function repeat_pattern($pattern, $length) {
*/
function is_utf8($val) {
// don't print control chars except \t\r\n
return (preg_match('~~u', $val) && !preg_match('~[\\0-\\x8\\xB\\xC\\xE-\\x1F]~', $val));
return (preg_match('~~u', $val) && !preg_match('~[\0-\x8\xB\xC\xE-\x1F]~', $val));
}
/** Shorten UTF-8 string
@@ -747,7 +819,7 @@ function shorten_utf8($string, $length = 80, $suffix = "") {
if (!preg_match("(^(" . repeat_pattern("[\t\r\n -\x{10FFFF}]", $length) . ")($)?)u", $string, $match)) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
preg_match("(^(" . repeat_pattern("[\t\r\n -~]", $length) . ")($)?)", $string, $match);
}
return h($match[1]) . $suffix . (isset($match[2]) ? "" : "<i>...</i>");
return h($match[1]) . $suffix . (isset($match[2]) ? "" : "<i></i>");
}
/** Format decimal number
@@ -755,7 +827,7 @@ function shorten_utf8($string, $length = 80, $suffix = "") {
* @return string
*/
function format_number($val) {
return strtr(number_format($val, 0, ".", lang(',')), preg_split('~~u', lang('0123456789'), -1, PREG_SPLIT_NO_EMPTY));
return strtr(number_format($val, 0, ".", lang(',')), preg_split('~~u', lang('0123456789'), -1, PREG_SPLIT_NO_EMPTY));
}
/** Generate friendly URL
@@ -770,9 +842,10 @@ function friendly_url($val) {
/** Print hidden fields
* @param array
* @param array
* @return null
* @return bool
*/
function hidden_fields($process, $ignore = array()) {
$return = false;
while (list($key, $val) = each($process)) {
if (!in_array($key, $ignore)) {
if (is_array($val)) {
@@ -780,10 +853,12 @@ function hidden_fields($process, $ignore = array()) {
$process[$key . "[$k]"] = $v;
}
} else {
$return = true;
echo '<input type="hidden" name="' . h($key) . '" value="' . h($val) . '">';
}
}
}
return $return;
}
/** Print hidden fields for GET forms
@@ -847,7 +922,7 @@ function enum_input($type, $attrs, $field, $value, $empty = null) {
* @return null
*/
function input($field, $value, $function) {
global $connection, $types, $adminer, $jush;
global $types, $adminer, $jush;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
@@ -865,38 +940,31 @@ function input($field, $value, $function) {
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$attrs = " name='fields[$name]'";
if ($field["type"] == "enum") {
echo nbsp($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
} else {
$first = 0;
foreach ($functions as $key => $val) {
if ($key === "" || !$val) {
break;
}
$first++;
}
$onchange = ($first ? " onchange=\"var f = this.form['function[" . h(js_escape(bracket_escape($field["field"]))) . "]']; if ($first > f.selectedIndex) f.selectedIndex = $first;\" onkeyup='keyupChange.call(this);'" : "");
$attrs .= $onchange;
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]' onchange='functionChange(this);'" . on_help("getTarget(event).value.replace(/^SQL\$/, '')", 1) . ">" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
: nbsp(reset($functions))
? "<select name='function[$name]'>" . 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'" . (in_array(strtolower($value), array('1', 't', 'true', 'y', 'yes', 'on')) ? " checked='checked'" : "") . "$attrs value='1'>";
"<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' : '') . "$onchange>" . h($adminer->editVal($val, $field)) . '</label>';
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'$onchange>";
} elseif (($text = preg_match('~text|lob~', $field["type"])) || preg_match("~\n~", $value)) {
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 {
@@ -908,18 +976,30 @@ function input($field, $value, $function) {
echo "<textarea$attrs cols='50' rows='12' class='jush-js'>" . h($value) . '</textarea>';
} else {
// int(3) is only a display hint
$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' && $connection->server_info >= 5.6 && preg_match('~time~', $field["type"])) {
$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~', $field["type"]) && !preg_match('~\[\]~', $field["full_type"]) ? " type='number'" : "")
. ((!$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(); }});");
}
}
}
@@ -928,7 +1008,7 @@ function input($field, $value, $function) {
* @return string or false to leave the original value
*/
function process_input($field) {
global $adminer;
global $adminer, $driver;
$idf = bracket_escape($field["field"]);
$function = $_POST["function"][$idf];
$value = $_POST["fields"][$idf];
@@ -945,7 +1025,7 @@ function process_input($field) {
return null;
}
if ($function == "orig") {
return ($field["on_update"] == "CURRENT_TIMESTAMP" ? idf_escape($field["field"]) : false);
return (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? idf_escape($field["field"]) : false);
}
if ($function == "NULL") {
return "NULL";
@@ -966,7 +1046,7 @@ function process_input($field) {
if (!is_string($file)) {
return false; //! report errors
}
return q($file);
return $driver->quoteBinary($file);
}
return $adminer->processInput($field, $value, $function);
}
@@ -1003,25 +1083,20 @@ function fields_from_edit() {
*/
function search_tables() {
global $adminer, $connection;
$_GET["where"][0]["op"] = "LIKE %%";
$_GET["where"][0]["val"] = $_POST["query"];
$found = false;
$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()) {
if (!$found) {
echo "<ul>\n";
$found = true;
}
echo "<li>" . ($result
? "<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>\n"
: "$name: <span class='error'>" . error() . "</span>\n");
$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 ($found ? "</ul>" : "<p class='message'>" . lang('No tables.')) . "\n";
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/** Send headers for export
@@ -1084,6 +1159,35 @@ function get_temp_dir() {
return $return;
}
/** Open and exclusively lock a file
* @param string
* @return resource or null for error
*/
function file_open_lock($filename) {
$fp = @fopen($filename, "r+"); // @ - may not exist
if (!$fp) { // c+ is available since PHP 5.2.6
$fp = @fopen($filename, "w"); // @ - may not be writable
if (!$fp) {
return;
}
chmod($filename, 0660);
}
flock($fp, LOCK_EX);
return $fp;
}
/** Write and unlock a file
* @param resource
* @param string
*/
function file_write_unlock($fp, $data) {
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, strlen($data));
flock($fp, LOCK_UN);
fclose($fp);
}
/** 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
@@ -1119,7 +1223,7 @@ function rand_string() {
* @return string HTML
*/
function select_value($val, $link, $field, $text_length) {
global $adminer, $HTTPS;
global $adminer;
if (is_array($val)) {
$return = "";
foreach ($val as $k => $v) {
@@ -1137,18 +1241,13 @@ function select_value($val, $link, $field, $text_length) {
if (is_mail($val)) {
$link = "mailto:$val";
}
if ($protocol = is_url($val)) {
$link = (($protocol == "http" && $HTTPS) || preg_match('~WebKit|Firefox~i', $_SERVER["HTTP_USER_AGENT"]) // WebKit supports noreferrer since 2009, Firefox since version 38
? $val // HTTP links from HTTPS pages don't receive Referer automatically
: "https://www.adminer.org/redirect/?url=" . urlencode($val) // intermediate page to hide Referer
);
if (is_url($val)) {
$link = $val; // IE 11 and all modern browsers hide referrer
}
}
$return = $adminer->editVal($val, $field);
if ($return !== null) {
if ($return === "") { // === - may be int
$return = "&nbsp;";
} elseif (!is_utf8($return)) {
if (!is_utf8($return)) {
$return = "\0"; // htmlspecialchars of binary data returns an empty string
} elseif ($text_length != "" && is_shortable($field)) {
$return = shorten_utf8($return, max(0, +$text_length)); // usage of LEFT() would reduce traffic but complicate query - expected average speedup: .001 s VS .01 s on local network
@@ -1172,11 +1271,11 @@ function is_mail($email) {
/** Check whether the string is URL address
* @param string
* @return string "http", "https" or ""
* @return bool
*/
function is_url($string) {
$domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component //! IDN
return (preg_match("~^(https?)://($domain?\\.)+$domain(:\\d+)?(/.*)?(\\?.*)?(#.*)?\$~i", $string, $match) ? strtolower($match[1]) : ""); //! restrict path, query and fragment characters
return preg_match("~^(https?)://($domain?\\.)+$domain(:\\d+)?(/.*)?(\\?.*)?(#.*)?\$~i", $string); //! restrict path, query and fragment characters
}
/** Check if field should be shortened
@@ -1184,7 +1283,7 @@ function is_url($string) {
* @return bool
*/
function is_shortable($field) {
return preg_match('~char|text|lob|geometry|point|linestring|polygon|string|bytea~', $field["type"]);
return preg_match('~char|text|json|lob|geometry|point|linestring|polygon|string|bytea~', $field["type"]);
}
/** Get query to compute number of found rows
@@ -1199,7 +1298,7 @@ function count_rows($table, $where, $is_group, $group) {
$query = " FROM " . table($table) . ($where ? " WHERE " . implode(" AND ", $where) : "");
return ($is_group && ($jush == "sql" || count($group) == 1)
? "SELECT COUNT(DISTINCT " . implode(", ", $group) . ")$query"
: "SELECT COUNT(*)" . ($is_group ? " FROM (SELECT 1$query$group_by) x" : $query)
: "SELECT COUNT(*)" . ($is_group ? " FROM (SELECT 1$query GROUP BY " . implode(", ", $group) . ") x" : $query)
);
}
@@ -1208,16 +1307,17 @@ function count_rows($table, $where, $is_group, $group) {
* @return array of strings
*/
function slow_query($query) {
global $adminer, $token;
global $adminer, $token, $driver;
$db = $adminer->database();
$timeout = $adminer->queryTimeout();
if (support("kill") && is_object($connection2 = connect()) && ($db == "" || $connection2->select_db($db))) {
$slow_query = $driver->slowQuery($query, $timeout);
if (!$slow_query && support("kill") && is_object($connection2 = connect()) && ($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 type="text/javascript">
<script<?php echo nonce(); ?>>
var timeout = setTimeout(function () {
ajax('<?php echo js_escape(ME); ?>script=kill', function () {
}, 'token=<?php echo $token; ?>&kill=<?php echo $kill; ?>');
}, 'kill=<?php echo $kill; ?>&token=<?php echo $token; ?>');
}, <?php echo 1000 * $timeout; ?>);
</script>
<?php
@@ -1226,13 +1326,13 @@ var timeout = setTimeout(function () {
}
ob_flush();
flush();
$return = @get_key_vals($query, $connection2, $timeout); // @ - may be killed
$return = @get_key_vals(($slow_query ? $slow_query : $query), $connection2, false); // @ - may be killed
if ($connection2) {
echo "<script type='text/javascript'>clearTimeout(timeout);</script>\n";
echo script("clearTimeout(timeout);");
ob_flush();
flush();
}
return array_keys($return);
return $return;
}
/** Generate BREACH resistant CSRF token
@@ -1295,7 +1395,7 @@ function lzw_decompress($binary) {
* @return string
*/
function on_help($command, $side = 0) {
return " onmouseover='helpMouseover(this, event, " . h($command) . ", $side);' onmouseout='helpMouseout(this, event);'";
return script("mixin(qsl('select, input'), {onmouseover: function (event) { helpMouseover.call(this, event, $command, $side) }, onmouseout: helpMouseout});", "");
}
/** Print edit data form
@@ -1323,7 +1423,7 @@ function edit_form($TABLE, $fields, $row, $update) {
if (!$fields) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else {
echo "<table cellspacing='0' onkeydown='return editingKeydown(event);'>\n";
echo "<table cellspacing='0' class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field);
@@ -1349,12 +1449,12 @@ function edit_form($TABLE, $fields, $row, $update) {
}
$function = ($_POST["save"]
? (string) $_POST["function"][$name]
: ($update && $field["on_update"] == "CURRENT_TIMESTAMP"
: ($update && preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"])
? "now"
: ($value === false ? null : ($value !== null ? '' : 'NULL'))
)
);
if (preg_match("~time~", $field["type"]) && $value == "CURRENT_TIMESTAMP") {
if (preg_match("~time~", $field["type"]) && preg_match('~^CURRENT_TIMESTAMP~i', $value)) {
$value = "";
$function = "now";
}
@@ -1363,7 +1463,8 @@ function edit_form($TABLE, $fields, $row, $update) {
}
if (!support("table")) {
echo "<tr>"
. "<th><input name='field_keys[]' onkeyup='keyupChange.call(this);' onchange='fieldChange(this);' value=''>" // needs empty value for keyupChange()
. "<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"
@@ -1376,13 +1477,14 @@ function edit_form($TABLE, $fields, $row, $update) {
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') . "' onclick='return !ajaxForm(this.form, \"" . lang('Saving') . '...", this)'
? 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 type='text/javascript'>focus(document.getElementById('form').getElementsByTagName('td')[1].firstChild);</script>\n")
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[1].firstChild);"))
);
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));

View File

@@ -2,13 +2,13 @@
// not used in a single language version
$langs = array(
'en' => 'English', // Jakub Vrána - http://www.vrana.cz
'en' => 'English', // Jakub Vrána - https://www.vrana.cz
'ar' => 'العربية', // Y.M Amine - Algeria - nbr7@live.fr
'bg' => 'Български', // Deyan Delchev
'bn' => 'বাংলা', // Dipak Kumar - dipak.ndc@gmail.com
'bs' => 'Bosanski', // Emir Kurtovic
'ca' => 'Català', // Joan Llosas
'cs' => 'Čeština', // Jakub Vrána - http://www.vrana.cz
'cs' => 'Čeština', // Jakub Vrána - https://www.vrana.cz
'da' => 'Dansk', // Jarne W. Beutnagel - jarne@beutnagel.dk
'de' => 'Deutsch', // Klemens Häckel - http://clickdimension.wordpress.com
'el' => 'Ελληνικά', // Dimitrios T. Tanis - jtanis@tanisfood.gr
@@ -18,12 +18,15 @@ $langs = array(
'fi' => 'Suomi', // Finnish - Kari Eveli - http://www.lexitec.fi/
'fr' => 'Français', // Francis Gagné, Aurélien Royer
'gl' => 'Galego', // Eduardo Penabad Ramos
'he' => 'עברית', // Binyamin Yawitz - https://stuff-group.com/
'hu' => 'Magyar', // Borsos Szilárd (Borsosfi) - http://www.borsosfi.hu, info@borsosfi.hu
'id' => 'Bahasa Indonesia', // Ivan Lanin - http://ivan.lanin.org
'it' => 'Italiano', // Alessandro Fiorotto, Paolo Asperti
'ja' => '日本語', // Hitoshi Ozawa - http://sourceforge.jp/projects/oss-ja-jpn/releases/
'ka' => 'ქართული', // Saba Khmaladze skhmaladze@uglt.org
'ko' => '한국어', // dalli - skcha67@gmail.com
'lt' => 'Lietuvių', // Paulius Leščinskas - http://www.lescinskas.lt
'ms' => 'Bahasa Melayu', // Pisyek
'nl' => 'Nederlands', // Maarten Balliauw - http://blog.maartenballiauw.be
'no' => 'Norsk', // Iver Odin Kvello, mupublishing.com
'pl' => 'Polski', // Radosław Kowalewski - http://srsbiz.pl/
@@ -35,7 +38,7 @@ $langs = array(
'sl' => 'Slovenski', // Matej Ferlan - www.itdinamik.com, matej.ferlan@itdinamik.com
'sr' => 'Српски', // Nikola Radovanović - cobisimo@gmail.com
'ta' => 'த‌மிழ்', // G. Sampath Kumar, Chennai, India, sampathkumar11@gmail.com
'th' => 'ภาษาไทย', // Panya Saraphi, elect.tu@gmail.com - http://www.opencart2u.com/
'th' => 'ภาษาไทย', // Panya Saraphi, elect.tu@gmail.com - http://www.opencart2u.com/
'tr' => 'Türkçe', // Bilgehan Korkmaz - turktron.com
'uk' => 'Українська', // Valerii Kryzhov
'vi' => 'Tiếng Việt', // Giang Manh @ manhgd google mail

View File

@@ -12,9 +12,9 @@ if (extension_loaded('pdo')) {
}
}
function dsn($dsn, $username, $password) {
function dsn($dsn, $username, $password, $options = array()) {
try {
parent::__construct($dsn, $username, $password);
parent::__construct($dsn, $username, $password, $options);
} catch (Exception $ex) {
auth_error(h($ex->getMessage()));
}
@@ -29,6 +29,9 @@ if (extension_loaded('pdo')) {
$this->error = "";
if (!$result) {
list(, $this->errno, $this->error) = $this->errorInfo();
if (!$this->error) {
$this->error = lang('Unknown error.');
}
return false;
}
$this->store_result($result);

View File

@@ -1,2 +1,2 @@
<?php
$VERSION = "4.3.1";
$VERSION = "4.7.3";

View File

@@ -3,8 +3,8 @@
* @link https://www.adminer.org/
* @author Jakub Vrana, https://www.vrana.cz/
* @copyright 2007 Jakub Vrana
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
* @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)
*/
include "./include/bootstrap.inc.php";
@@ -65,8 +65,6 @@ if (isset($_GET["download"])) {
include "./user.inc.php";
} elseif (isset($_GET["processlist"])) {
include "./processlist.inc.php";
} elseif (isset($_GET["replication"])) {
include "./replication.inc.php";
} elseif (isset($_GET["select"])) {
include "./select.inc.php";
} elseif (isset($_GET["variables"])) {

View File

@@ -2,10 +2,10 @@
$TABLE = $_GET["indexes"];
$index_types = array("PRIMARY", "UNIQUE", "INDEX");
$table_status = table_status($TABLE, true);
if (preg_match('~MyISAM|M?aria' . ($connection->server_info >= 5.6 ? '|InnoDB' : '') . '~i', $table_status["Engine"])) {
if (preg_match('~MyISAM|M?aria' . (min_version(5.6, '10.0.5') ? '|InnoDB' : '') . '~i', $table_status["Engine"])) {
$index_types[] = "FULLTEXT";
}
if (preg_match('~MyISAM|M?aria' . ($connection->server_info >= 5.7 ? '|InnoDB' : '') . '~i', $table_status["Engine"])) {
if (preg_match('~MyISAM|M?aria' . (min_version(5.7, '10.2.2') ? '|InnoDB' : '') . '~i', $table_status["Engine"])) {
$index_types[] = "SPATIAL";
}
$indexes = indexes($TABLE);
@@ -94,12 +94,13 @@ if (!$row) {
?>
<form action="" method="post">
<div class="scrollable">
<table cellspacing="0" class="nowrap">
<thead><tr>
<th id="label-type"><?php echo lang('Index Type'); ?>
<th><input type="submit" class="wayoff"><?php echo lang('Column (length)'); ?>
<th id="label-name"><?php echo lang('Name'); ?>
<th><noscript><input type='image' class='icon' name='add[0]' src='../adminer/static/plus.gif' alt='+' title='<?php echo lang('Add next'); ?>'></noscript>&nbsp;
<th><noscript><?php echo "<input type='image' class='icon' name='add[0]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>"; ?></noscript>
</thead>
<?php
if ($primary) {
@@ -113,30 +114,32 @@ 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(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);" : 1), "label-type");
echo "<td>";
ksort($index["columns"]);
$i = 1;
foreach ($index["columns"] as $key => $column) {
echo "<span>" . select_input(
" name='indexes[$j][columns][$i]' onchange=\"" . ($i == count($index["columns"]) ? "indexesAddColumn" : "indexesChangeColumn") . "(this, '" . h(js_escape($jush == "sql" ? "" : $_GET["indexes"] . "_")) . "');\" title='" . lang('Column') . "'",
" name='indexes[$j][columns][$i]' title='" . lang('Column') . "'",
($fields ? array_combine($fields, $fields) : $fields),
$column
$column,
"partial(" . ($i == count($index["columns"]) ? "indexesAddColumn" : "indexesChangeColumn") . ", '" . js_escape($jush == "sql" ? "" : $_GET["indexes"] . "_") . "')"
);
echo ($jush == "sql" || $jush == "mssql" ? "<input type='number' name='indexes[$j][lengths][$i]' class='size' value='" . h($index["lengths"][$key]) . "' title='" . lang('Length') . "'>" : "");
echo ($jush != "sql" ? checkbox("indexes[$j][descs][$i]", 1, $index["descs"][$key], lang('descending')) : "");
echo (support("descidx") ? checkbox("indexes[$j][descs][$i]", 1, $index["descs"][$key], lang('descending')) : "");
echo " </span>";
$i++;
}
echo "<td><input name='indexes[$j][name]' value='" . h($index["name"]) . "' autocapitalize='off' aria-labelledby='label-name'>\n";
echo "<td><input type='image' class='icon' name='drop_col[$j]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "' onclick=\"return !editingRemoveRow(this, 'indexes\$1[type]');\">\n";
echo "<td><input type='image' class='icon' name='drop_col[$j]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "'>" . script("qsl('input').onclick = partial(editingRemoveRow, 'indexes\$1[type]');");
}
$j++;
}
?>
</table>
</div>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">

View File

@@ -184,7 +184,7 @@ $translations = array(
'Move to other database' => 'نقل إلى قاعدة بيانات أخرى',
'Move' => 'نقل',
'%d item(s) have been affected.' => 'عدد العناصر المعدلة هو %d.',
'whole result' => 'نتيجة كاملة',
'Whole result' => 'نتيجة كاملة',
'Clone' => 'نسخ',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'لقد تجاوزت العدد الأقصى للحقول. يرجى الرفع من %s.',
'Partition by' => 'مقسم بواسطة',

View File

@@ -12,7 +12,7 @@ $translations = array(
'Logout successful.' => 'Излизането е успешно.',
'Invalid credentials.' => 'Невалидни потребителски данни.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Прекалено много неуспешни опити за вход, опитайте пак след %d минута.', 'Прекалено много неуспешни опити за вход, опитайте пак след %d минути.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Главната парола вече е невалидна. <a href="https://www.adminer.org/en/extension/" target="_blank">Изберете</a> %s метод, за да я направите постоянна.',
'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 метод, за да я направите постоянна.',
'Language' => 'Език',
'Invalid CSRF token. Send the form again.' => 'Невалиден шифроващ ключ. Попълнете и изпратете формуляра отново.',
'If you did not send this request from Adminer then close this page.' => 'Ако не сте изпратили тази заявка през Adminer, затворете тази страница.',
@@ -245,7 +245,7 @@ $translations = array(
'last' => 'последен',
'Load more data' => 'Зареждане на повече данни',
'Loading' => 'Зареждане',
'whole result' => 'пълен резултат',
'Whole result' => 'Пълен резултат',
'%d byte(s)' => array('%d байт', '%d байта'),
'Import' => 'Импорт',

View File

@@ -186,7 +186,7 @@ $translations = array(
'original' => 'প্রকৃত',
'Tables have been dropped.' => 'টেবিলসমূহ মুছে ফেলা হয়েছে।',
'%d item(s) have been affected.' => '%d টি বিষয়বস্তু প্রভাবিত হয়েছে',
'whole result' => 'সম্পূর্ণ ফলাফল',
'Whole result' => 'সম্পূর্ণ ফলাফল',
'Clone' => 'ক্লোন',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'অনুমোদিত ফিল্ড এর সর্বাধিক সংখ্যা অতিক্রম করে গেছে। অনুগ্রহপূর্বক %s বৃদ্ধি করুন।',
'Partition by' => 'পার্টিশন যার মাধ্যমে',

View File

@@ -234,7 +234,7 @@ $translations = array(
'last' => 'poslijednja',
'Loading' => 'Učitavam',
'Load more data' => 'Učitavam još podataka',
'whole result' => 'ceo rezultat',
'Whole result' => 'Ceo rezultat',
'%d byte(s)' => array('%d bajt', '%d bajta', '%d bajtova'),
'Import' => 'Uvoz',

View File

@@ -185,7 +185,7 @@ $translations = array(
'Save and continue edit' => 'Desa i segueix editant',
'original' => 'original',
'%d item(s) have been affected.' => array('S\'ha modificat %d element.', 'S\'han modificat %d elements.'),
'whole result' => 'tots els resultats',
'Whole result' => 'Tots els resultats',
'Tables have been dropped.' => 'S\'han suprimit les taules.',
'Clone' => 'Clona',
'Partition by' => 'Fes particions segons',

View File

@@ -10,17 +10,23 @@ $translations = array(
'Logout' => 'Odhlásit',
'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.',
'Invalid credentials.' => 'Neplatné přihlašovací údaje.',
'<a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to use SQLite.' => 'Pro přihlášení k SQLite <a href="https://www.adminer.org/cs/extension/" target="_blank">implementujte</a> metodu %s.',
'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>.',
'Database does not support password.' => 'Databáze nepodporuje heslo.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Příliš mnoho pokusů o přihlášení, zkuste to znovu za %d minutu.', 'Příliš mnoho pokusů o přihlášení, zkuste to znovu za %d minuty.', 'Příliš mnoho pokusů o přihlášení, zkuste to znovu za %d minut.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Platnost hlavního hesla vypršela. <a href="https://www.adminer.org/cs/extension/" target="_blank">Implementujte</a> metodu %s, aby platilo stále.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Platnost hlavního hesla vypršela. <a href="https://www.adminer.org/cs/extension/"%s>Implementujte</a> metodu %s, aby platilo stále.',
'Language' => 'Jazyk',
'Invalid CSRF token. Send the form again.' => 'Neplatný token CSRF. Odešlete formulář znovu.',
'If you did not send this request from Adminer then close this page.' => 'Pokud jste tento požadavek neposlali z Adminera, tak tuto stránku zavřete.',
'No extension' => 'Žádné rozšíření',
'None of the supported PHP extensions (%s) are available.' => 'Není dostupné žádné z podporovaných PHP rozšíření (%s).',
'Connecting to privileged ports is not allowed.' => 'Připojování k privilegovaným portům není povoleno.',
'Disable %s or enable %s or %s extensions.' => 'Zakažte %s nebo povolte extenze %s nebo %s.',
'Session support must be enabled.' => 'Session proměnné musí být povolené.',
'Session expired, please login again.' => 'Session vypršela, přihlašte se prosím znovu.',
'The action will be performed after successful login with the same credentials.' => 'Akce bude provedena po úspěšném přihlášení se stejnými přihlašovacími údaji.',
'%s version: %s through PHP extension %s' => 'Verze %s: %s přes PHP rozšíření %s',
'Refresh' => 'Obnovit',
@@ -45,15 +51,13 @@ $translations = array(
'Variables' => 'Proměnné',
'Status' => 'Stav',
'Replication' => 'Replikace',
'Master status' => 'Master status',
'Slave status' => 'Slave status',
'SQL command' => 'SQL příkaz',
'%d query(s) executed OK.' => array('%d příkaz proběhl v pořádku.', '%d příkazy proběhly v pořádku.', '%d příkazů proběhlo v pořádku.'),
'Query executed OK, %d row(s) affected.' => array('Příkaz proběhl v pořádku, byl změněn %d záznam.', 'Příkaz proběhl v pořádku, byly změněny %d záznamy.', 'Příkaz proběhl v pořádku, bylo změněno %d záznamů.'),
'No commands to execute.' => 'Žádné příkazy k vykonání.',
'Error in query' => 'Chyba v dotazu',
'Unknown error.' => 'Neznámá chyba.',
'Warnings' => 'Varování',
'ATTACH queries are not supported.' => 'Dotazy ATTACH nejsou podporované.',
'Execute' => 'Provést',
'Stop on error' => 'Zastavit při chybě',
@@ -85,6 +89,7 @@ $translations = array(
'Database' => 'Databáze',
'database' => 'databáze',
'DB' => 'DB',
'Use' => 'Vybrat',
'Select database' => 'Vybrat databázi',
'Invalid database.' => 'Nesprávná databáze.',
@@ -122,6 +127,7 @@ $translations = array(
'Tables have been moved.' => 'Tabulky byly přesunuty.',
'Copy' => 'Zkopírovat',
'Tables have been copied.' => 'Tabulky byly zkopírovány.',
'overwrite' => 'přepsat',
'Routines' => 'Procedury a funkce',
'Routine has been called, %d row(s) affected.' => array('Procedura byla zavolána, byl změněn %d záznam.', 'Procedura byla zavolána, byly změněny %d záznamy.', 'Procedura byla zavolána, bylo změněno %d záznamů.'),
@@ -173,6 +179,7 @@ $translations = array(
'Default value' => 'Výchozí hodnota',
'Default values' => 'Výchozí hodnoty',
'Drop' => 'Odstranit',
'Drop %s?' => 'Odstranit %s?',
'Are you sure?' => 'Opravdu?',
'Size' => 'Velikost',
'Compute' => 'Spočítat',
@@ -251,7 +258,7 @@ $translations = array(
'last' => 'poslední',
'Load more data' => 'Nahrát další data',
'Loading' => 'Nahrává se',
'whole result' => 'celý výsledek',
'Whole result' => 'Celý výsledek',
'%d byte(s)' => array('%d bajt', '%d bajty', '%d bajtů'),
'Import' => 'Import',
@@ -339,8 +346,4 @@ $translations = array(
'Type has been dropped.' => 'Typ byl odstraněn.',
'Type has been created.' => 'Typ byl vytvořen.',
'Alter type' => 'Pozměnit typ',
'Replication' => null,
'Master status' => null,
'Slave status' => null,
);

View File

@@ -10,7 +10,7 @@ $translations = array(
'Logged as: %s' => 'Logget ind som: %s',
'Logout successful.' => 'Log af vellykket.',
'Invalid credentials.' => 'Ugyldige log ind oplysninger.',
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Master-kodeordet er udløbet. <a href="https://www.adminer.org/en/extension/" target="_blank">Implementer</a> en metode for %s for at gøre det permanent.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Master-kodeordet er udløbet. <a href="https://www.adminer.org/en/extension/"%s>Implementer</a> en metode for %s for at gøre det permanent.',
'Language' => 'Sprog',
'Invalid CSRF token. Send the form again.' => 'Ugyldigt CSRF-token - Genindsend formen.',
'No extension' => 'Ingen udvidelse',
@@ -212,7 +212,7 @@ $translations = array(
'last' => 'sidste',
'Load more data' => 'Indlæs mere data',
'Loading' => 'Indlæser',
'whole result' => 'hele resultatet',
'Whole result' => 'Hele resultatet',
'%d byte(s)' => array('%d byte', '%d bytes'),
'Import' => 'Importer',
'%d row(s) have been imported.' => array('%d række er importeret.', '%d rækker er importeret.'),

View File

@@ -2,6 +2,7 @@
$translations = array(
'Login' => 'Login',
'Logout successful.' => 'Abmeldung erfolgreich.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Danke, dass Sie Adminer genutzt haben. <a href="https://www.adminer.org/de/donation/">Spenden willkommen!</a>',
'Invalid credentials.' => 'Ungültige Anmelde-Informationen.',
'Server' => 'Server',
'Username' => 'Benutzer',
@@ -186,7 +187,7 @@ $translations = array(
'original' => 'Original',
'Tables have been dropped.' => 'Tabellen wurden entfernt (drop).',
'%d item(s) have been affected.' => '%d Artikel betroffen.',
'whole result' => 'Gesamtergebnis',
'Whole result' => 'Gesamtergebnis',
'Clone' => 'Klonen',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Die maximal erlaubte Anzahl der Felder ist überschritten. Bitte %s erhöhen.',
'Partition by' => 'Partitionieren um',
@@ -283,6 +284,6 @@ $translations = array(
'Saving' => 'Speichere',
'yes' => 'ja',
'no' => 'nein',
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Das Master-Passwort ist abgelaufen. <a href="https://www.adminer.org/de/extension/" target="_blank">Implementieren</a> Sie die %s Methode, um es permanent zu machen.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Das Master-Passwort ist abgelaufen. <a href="https://www.adminer.org/de/extension/"%s>Implementieren</a> Sie die %s Methode, um es permanent zu machen.',
'%d / ' => '%d / ',
);

View File

@@ -12,7 +12,7 @@ $translations = array(
'Logout successful.' => 'Αποσυνδεθήκατε με επιτυχία.',
'Invalid credentials.' => 'Εσφαλμένα Διαπιστευτήρια.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Επανηλημμένες ανεπιτυχείς προσπάθειες σύνδεσης, δοκιμάστε ξανά σε %s λεπτό.', 'Επανηλημμένες ανεπιτυχείς προσπάθειες σύνδεσης, δοκιμάστε ξανά σε %s λεπτά.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Έλειξε ο Κύριος Κωδικός. <a href="https://www.adminer.org/en/extension/" target="_blank">Ενεργοποιήστε</a> τη μέθοδο %s για να τον κάνετε μόνιμο.',
'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 για να τον κάνετε μόνιμο.',
'Language' => 'Γλώσσα',
'Invalid CSRF token. Send the form again.' => 'Άκυρο κουπόνι CSRF. Στείλτε τη φόρμα ξανά.',
'If you did not send this request from Adminer then close this page.' => 'Αν δε στείλατε αυτό το αίτημα από το Adminer, τότε κλείστε αυτή τη σελίδα.',
@@ -149,7 +149,7 @@ $translations = array(
'Table' => 'Πίνακας',
'No tables.' => 'Χωρίς πίνακες.',
'Alter table' => 'Τροποποίηση πίνακα',
'Create table' => 'Δημιουργία πίνακα',
'Create table' => 'Δημιουργία πίνακα',
'Table has been dropped.' => 'Ο πίνακας διαγράφηκε.',
'Tables have been dropped.' => 'Οι πινακες διαγράφηκαν.',
'Tables have been optimized.' => 'Οι πίνακες βελτιστοποιήθηκαν.',
@@ -246,7 +246,7 @@ $translations = array(
'last' => 'τελευταία',
'Load more data' => 'Φόρτωση κι άλλων δεδομένων',
'Loading' => 'Φορτώνει',
'whole result' => 'όλο το αποτέλεσμα',
'Whole result' => 'Όλο το αποτέλεσμα',
'%d byte(s)' => array('%d byte', '%d bytes'),
'Import' => 'Εισαγωγή',

View File

@@ -44,9 +44,9 @@ $translations = array(
'Delete' => 'Eliminar',
'Database' => 'Base de datos',
'Routines' => 'Procedimientos',
'Indexes have been altered.' => 'Indices actualizados.',
'Indexes' => 'Indices',
'Alter indexes' => 'Modificar indices',
'Indexes have been altered.' => 'Índices actualizados.',
'Indexes' => 'Índices',
'Alter indexes' => 'Modificar índices',
'Add next' => 'Agregar',
'Language' => 'Idioma',
'Select' => 'Mostrar',
@@ -77,7 +77,7 @@ $translations = array(
'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.'),
'Call' => 'Llamar',
'No extension' => 'No hay extension',
'No extension' => 'No hay extensión',
'None of the supported PHP extensions (%s) are available.' => 'Ninguna de las extensiones PHP soportadas (%s) está disponible.',
'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.',
@@ -113,7 +113,7 @@ $translations = array(
'Routine has been dropped.' => 'Procedimiento eliminado.',
'Routine has been altered.' => 'Procedimiento modificado.',
'Routine has been created.' => 'Procedimiento creado.',
'Alter function' => 'Modificar Función',
'Alter function' => 'Modificar función',
'Alter procedure' => 'Modificar procedimiento',
'Return type' => 'Tipo de valor de vuelta',
'Add trigger' => 'Agregar disparador',
@@ -127,7 +127,7 @@ $translations = array(
'%s version: %s through PHP extension %s' => 'Versión %s: %s a través de la extensión de PHP %s',
'%d row(s)' => array('%d registro', '%d registros'),
'Remove' => 'Eliminar',
'Are you sure?' => 'Está seguro?',
'Are you sure?' => '¿Está seguro?',
'Privileges' => 'Privilegios',
'Create user' => 'Crear Usuario',
'User has been dropped.' => 'Usuario eliminado.',
@@ -139,7 +139,7 @@ $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.',
'Logged as: %s' => 'Logeado como: %s',
'Logged as: %s' => 'Logueado como: %s',
'Move up' => 'Mover arriba',
'Move down' => 'Mover abajo',
'Functions' => 'Funciones',
@@ -186,12 +186,12 @@ $translations = array(
'original' => 'original',
'Tables have been dropped.' => 'Tablas eliminadas.',
'%d item(s) have been affected.' => array('%d elemento afectado.', '%d elementos afectados.'),
'whole result' => 'resultado completo',
'Whole result' => 'Resultado completo',
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Excedida la cantidad máxima de campos permitidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
'Partitions' => 'Particiones',
'Partition name' => 'Nombre de Partición',
'Partition name' => 'Nombre de partición',
'Values' => 'Valores',
'%d row(s) have been imported.' => array('%d registro importado.', '%d registros importados.'),
'anywhere' => 'donde sea',
@@ -248,16 +248,16 @@ $translations = array(
'System' => 'Motor de base de datos',
'Select data' => 'Visualizar contenido',
'Show structure' => 'Mostrar estructura',
'empty' => 'ningúno',
'empty' => 'ninguno',
'Network' => 'Red',
'Geometry' => 'Geometría',
'File exists.' => 'Ese archivo ya existe.',
'Attachments' => 'Adjuntos',
'%d query(s) executed OK.' => array('%d sentencia sql ejecutada correctamente.', '%d sentencias sql ejecutadas correctamente.'),
'%d query(s) executed OK.' => array('%d sentencia SQL ejecutada correctamente.', '%d sentencias SQL ejecutadas correctamente.'),
'Show only errors' => 'Mostrar solamente errores',
'Refresh' => 'Refrescar',
'Invalid schema.' => 'Esquema inválido.',
'Please use one of the extensions %s.' => 'Por favor use una de las extensiones %s.',
'Please use one of the extensions %s.' => 'Por favor, use una de las extensiones %s.',
'now' => 'ahora',
'ltr' => 'ltr',
'Tables have been copied.' => 'Tablas copiadas.',

View File

@@ -186,7 +186,7 @@ $translations = array(
'Move to other database' => 'Liiguta teise andmebaasi',
'Move' => 'Liiguta',
'%d item(s) have been affected.' => 'Mõjutatud kirjeid: %d.',
'whole result' => 'Täielikud tulemused',
'Whole result' => 'Täielikud tulemused',
'Clone' => 'Kloon',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maksimaalne väljade arv ületatud. Palun suurendage %s.',
'Partition by' => 'Partitsiooni',

View File

@@ -12,7 +12,7 @@ $translations = array(
'Logout successful.' => 'با موفقیت خارج شدید.',
'Invalid credentials.' => 'اعتبار سنجی نامعتبر.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('ورودهای ناموفق بیش از حد، %d دقیقه دیگر تلاش نمایید.', 'ورودهای ناموفق بیش از حد، %d دقیقه دیگر تلاش نمایید.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'رمز اصلی باطل شده است. روش %s را <a href="https://www.adminer.org/en/extension/" target="_blank">پیاده سازی</a> کرده تا آن را دائمی سازید.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'رمز اصلی باطل شده است. روش %s را <a href="https://www.adminer.org/en/extension/"%s>پیاده سازی</a> کرده تا آن را دائمی سازید.',
'Language' => 'زبان',
'Invalid CSRF token. Send the form again.' => 'CSRF token نامعتبر است. دوباره سعی کنید.',
'No extension' => 'پسوند نامعتبر',
@@ -244,7 +244,7 @@ $translations = array(
'last' => 'آخری',
'Load more data' => 'بارگزاری اطلاعات بیشتر',
'Loading' => 'در حال بارگزاری',
'whole result' => 'همه نتایج',
'Whole result' => 'همه نتایج',
'%d byte(s)' => array('%d بایت', '%d بایت'),
'Import' => 'وارد کردن',

View File

@@ -12,7 +12,7 @@ $translations = array(
'Logout successful.' => 'Uloskirjautuminen onnistui.',
'Invalid credentials.' => 'Virheelliset kirjautumistiedot.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Liian monta epäonnistunutta sisäänkirjautumisyritystä, kokeile uudestaan %d minuutin kuluttua.', 'Liian monta epäonnistunutta sisäänkirjautumisyritystä, kokeile uudestaan %d minuutin kuluttua.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Master-salasana ei ole enää voimassa. <a href="https://www.adminer.org/en/extension/" target="_blank">Toteuta</a> %s-metodi sen tekemiseksi pysyväksi.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Master-salasana ei ole enää voimassa. <a href="https://www.adminer.org/en/extension/"%s>Toteuta</a> %s-metodi sen tekemiseksi pysyväksi.',
'Language' => 'Kieli',
'Invalid CSRF token. Send the form again.' => 'Virheellinen CSRF-vastamerkki. Lähetä lomake uudelleen.',
'If you did not send this request from Adminer then close this page.' => 'Jollet lähettänyt tämä pyyntö Adminerista, sulje tämä sivu.',
@@ -246,7 +246,7 @@ $translations = array(
'last' => 'viimeinen',
'Load more data' => 'Lataa lisää dataa',
'Loading' => 'Ladataan',
'whole result' => 'koko tulos',
'Whole result' => 'Koko tulos',
'%d byte(s)' => array('%d tavu', '%d tavua'),
'Import' => 'Tuonti',

View File

@@ -184,7 +184,7 @@ $translations = array(
'Move to other database' => 'Déplacer vers une autre base de données',
'Move' => 'Déplacer',
'%d item(s) have been affected.' => array('%d élément a été modifié.', '%d éléments ont été modifiés.'),
'whole result' => 'résultat entier',
'Whole result' => 'Résultat entier',
'Clone' => 'Cloner',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Le nombre maximum de champs est dépassé. Veuillez augmenter %s.',
'Partition by' => 'Partitionner par',
@@ -274,7 +274,7 @@ $translations = array(
'File must be in UTF-8 encoding.' => 'Les fichiers doivent être encodés en UTF-8.',
'Full table scan' => 'Scan de toute la table',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Trop de connexions échouées, essayez à nouveau dans %d minute.', 'Trop de connexions échouées, essayez à nouveau dans %d minutes.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Le mot de passe a expiré. <a href="https://www.adminer.org/en/extension/" target="_blank">Implémentez</a> la méthode %s afin de le rendre permanent.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Le mot de passe a expiré. <a href="https://www.adminer.org/en/extension/"%s>Implémentez</a> la méthode %s afin de le rendre permanent.',
'You can upload a big SQL file via FTP and import it from server.' => 'Vous pouvez uploader un gros fichier SQL par FTP et ensuite l\'importer depuis le serveur.',
'Size' => 'Taille',
'Compute' => 'Calcul',

View File

@@ -186,7 +186,7 @@ $translations = array(
'original' => 'orixinal',
'Tables have been dropped.' => 'Elimináronse as táboas.',
'%d item(s) have been affected.' => array('%d elemento afectado.', '%d elementos afectados.'),
'whole result' => 'resultado completo',
'Whole result' => 'Resultado completo',
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Excedida o número máximo de campos permitidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',
@@ -278,7 +278,7 @@ $translations = array(
'Default value' => 'Valor por defecto',
'Full table scan' => 'Escaneo completo da táboa',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Demasiados intentos de conexión, intentao de novo en %d minuto', 'Demasiados intentos de conexión, intentao de novo en %d minutos'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'O contrasinal principal caducou. <a href="https://www.adminer.org/en/extension/" target="_blank">Implementa</a> o método %s para facelo permanente.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'O contrasinal principal caducou. <a href="https://www.adminer.org/en/extension/"%s>Implementa</a> o método %s para facelo permanente.',
'If you did not send this request from Adminer then close this page.' => 'Se non enviaches esta petición dende o Adminer entón pecha esta páxina',
'You can upload a big SQL file via FTP and import it from server.' => 'Podes subir un ficheiro SQL de gran tamaño vía FTP e importalo dende o servidor',
'Size' => 'Tamaño',

293
adminer/lang/he.inc.php Normal file
View File

@@ -0,0 +1,293 @@
<?php
$translations = array(
'Login' => 'התחברות',
'Logout successful.' => 'ההתחברות הצליחה',
'Invalid credentials.' => 'פרטי התחברות שגויים',
'Server' => 'שרת',
'Username' => 'שם משתמש',
'Password' => 'סיסמה',
'Select database' => 'בחר מסד נתונים',
'Invalid database.' => 'מסד נתונים שגוי',
'Table has been dropped.' => 'הטבלה הושלכה',
'Table has been altered.' => 'הטבלה שונתה',
'Table has been created.' => 'הטבלה נוצרה',
'Alter table' => 'שנה טבלה',
'Create table' => 'צור טבלה',
'Table name' => 'שם הטבלה',
'engine' => 'מנוע',
'collation' => 'קולקציה',
'Column name' => 'שם עמודה',
'Type' => 'סוג',
'Length' => 'אורך',
'Auto Increment' => 'הגדלה אוטומטית',
'Options' => 'אפשרויות',
'Save' => 'שמור',
'Drop' => 'השלך',
'Database has been created.' => 'מסד הנתונים נוצר',
'Database has been renamed.' => 'שם מסד הנתונים שונה',
'Database has been altered.' => 'מסד הנתונים שונה',
'Alter database' => 'שנה מסד נתונים',
'Create database' => 'צור מסד נתונים',
'SQL command' => 'שאילתת SQL',
'Logout' => 'התנתק',
'database' => 'מסד נתונים',
'Use' => 'השתמש',
'No tables.' => 'אין טבלאות',
'select' => 'בחר',
'Item has been deleted.' => 'הפריט נמחק',
'Item has been updated.' => 'הפריט עודכן',
'Edit' => 'ערוך',
'Insert' => 'הכנס',
'Save and insert next' => 'שמור והמשך להכניס',
'Delete' => 'מחק',
'Database' => 'מסד נתונים',
'Routines' => 'רוטינות',
'Indexes have been altered.' => 'האינדקסים שונו',
'Indexes' => 'אינדקסים',
'Alter indexes' => 'שנה אינדקסים',
'Add next' => 'הוסף הבא',
'Language' => 'שפה',
'Select' => 'בחר',
'New item' => 'פריט חדש',
'Search' => 'חפש',
'Sort' => 'מיין',
'descending' => 'סדר הפוך',
'Limit' => 'הגבל',
'No rows.' => 'אין שורות',
'Action' => 'פעולות',
'edit' => 'ערוך',
'Page' => 'עמוד',
'Query executed OK, %d row(s) affected.' => 'השאילתה בוצעה כהלכה, %d שורות הושפעו',
'Error in query' => 'שגיאה בשאילתה',
'Execute' => 'הרץ',
'Table' => 'טבלה',
'Foreign keys' => 'מפתחות זרים',
'Triggers' => 'מפעילים',
'View' => 'הצג',
'Unable to select the table' => 'בחירת הטבלה נכשלה',
'Invalid CSRF token. Send the form again.' => 'כשל באבטחת נתונים, שלח טופס שוב',
'Comment' => 'הערה',
'Default values' => 'ערכי ברירת מחדל',
'%d byte(s)' => '%d בתים',
'No commands to execute.' => 'לא נמצאו פקודות להרצה',
'Unable to upload a file.' => 'העלאת הקובץ נכשלה',
'File upload' => 'העלה קובץ',
'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.' => 'תם זמן ההפעלה, אנא התחבר שוב',
'Text length' => 'אורך הטקסט',
'Foreign key has been dropped.' => 'המפתח הזר הושלך',
'Foreign key has been altered.' => 'המפתח הזר שונה',
'Foreign key has been created.' => 'המפתח הזר נוצר',
'Foreign key' => 'מפתח זר',
'Target table' => 'טבלת יעד',
'Change' => 'שנה',
'Source' => 'מקור',
'Target' => 'יעד',
'Add column' => 'הוסף עמודה',
'Alter' => 'שנה',
'Add foreign key' => 'הוסף מפתח זר',
'ON DELETE' => 'בעת מחיקה',
'ON UPDATE' => 'בעת עידכון',
'Index Type' => 'סוג אינדקס',
'Column (length)' => 'עמודה (אורך)',
'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 תהליכים חוסלו',
'Kill' => 'חסל',
'Parameter name' => 'שם הפרמטר',
'Database schema' => 'סכמת מסד נתונים',
'Create procedure' => 'צור פרוצדורה',
'Create function' => 'צור פונקציה',
'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.' => 'הטריגר נוצר',
'Alter trigger' => 'שנה טריגר',
'Create trigger' => 'צור טריגר',
'Time' => 'זמן',
'Event' => 'אירוע',
'%d row(s)' => '%d שורות',
'Remove' => 'הסר',
'Are you sure?' => 'האם אתה בטוח?',
'Privileges' => 'פריווילגיות',
'Create user' => 'צור משתמש',
'User has been dropped.' => 'המשתמש הושלך',
'User has been altered.' => 'המשתמש שונה',
'User has been created.' => 'המשתמש נוצר',
'Hashed' => 'הצפנה',
'Column' => 'עמודה',
'Routine' => 'רוטינה',
'Grant' => 'הענק',
'Revoke' => 'שלול',
'%s version: %s through PHP extension %s' => '%s גרסה: %s דרך תוסף PHP %s',
'Logged as: %s' => 'מחובר כ: %s',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'מידע גדול מידי נשלח ב-POST. הקטן את את המידע הוא הגדלת את הגדרות ה-%s',
'Move up' => 'הזז למעלה',
'Move down' => 'הזז למטה',
'Export' => 'יצא',
'Tables' => 'טבלאות',
'Data' => 'נתונים',
'Output' => 'פלט',
'open' => 'פתח',
'save' => 'שמור',
'Format' => 'פורמט',
'Functions' => 'פונקציות',
'Aggregation' => 'צבירה',
'Event has been dropped.' => 'האירוע הושלך',
'Event has been altered.' => 'האירוע שונה',
'Event has been created.' => 'האירוע נוצר',
'Alter event' => 'שנה אירוע',
'Create event' => 'צור אירוע',
'Start' => 'התחלה',
'End' => 'סיום',
'Every' => 'כל',
'Status' => 'סטטוס',
'On completion preserve' => 'בעת סיום שמור',
'Events' => 'אירועים',
'Schedule' => 'תזמן',
'At given time' => 'לפי זמן נתון',
'Save and continue edit' => 'שמור והמשך לערוך',
'original' => 'מקורי',
'Tables have been truncated.' => 'הטבלה קוצרה',
'Tables have been moved.' => 'הטבלה הועברה',
'Tables have been dropped.' => 'הטבלה הושלכה',
'Tables and views' => 'טבלאות ותצוגות',
'Engine' => 'מנוע',
'Collation' => 'קולקציה',
'Data Length' => 'אורך נתונים',
'Index Length' => 'אורך אינדקס',
'Data Free' => 'נתונים משוחררים',
'Rows' => 'שורות',
',' => ',',
'0123456789' => '0123456789',
'Analyze' => 'נתח',
'Optimize' => 'יעל',
'Check' => 'בדוק',
'Repair' => 'תקן',
'Truncate' => 'קצר',
'Move to other database' => 'העבר למסד נתונים אחר',
'Move' => 'העבר',
'%d item(s) have been affected.' => '%d פריטים הושפעו',
'Whole result' => 'כל התוצאות',
'Clone' => 'שכפל',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'הגעת למספר השדות המרבי. בבקשה הגדל את %s',
'Partition by' => 'מחיצות ע"י',
'Partitions' => 'מחיצות',
'Partition name' => 'שם מחיצה',
'Values' => 'ערכים',
'%d row(s) have been imported.' => '%d שורות יובאו',
'anywhere' => 'בכל מקום',
'Import' => 'יבא',
'Stop on error' => 'עצור בעת שגיאה',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$1-$3-$5',
'[yyyy]-mm-dd' => '[yyyy]-mm-dd',
'History' => 'היסטוריה',
'Variables' => 'משתנים',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => 'על עמודות המקור והיעד להיות מאותו טיפוס נתונים, חובה שיהיה אינדקס בעמודת היעד ושהמידע המתאים יהיה קיים',
'Relations' => 'הקשרים',
'Run file' => 'הרץ קובץ',
'Clear' => 'נקה',
'Maximum allowed file size is %sB.' => 'גודל מקסימלאי להעלאה: %sB',
'Numbers' => 'מספרים',
'Date and time' => 'תאריך ושעה',
'Strings' => 'מחרוזות',
'Binary' => 'בינארי',
'Lists' => 'רשימות',
'Editor' => 'עורך',
'E-mail' => 'דוא"ל',
'From' => 'מ:',
'Subject' => 'נושא',
'Send' => 'שלח',
'%d e-mail(s) have been sent.' => '%d הודעות דוא"ל נשלחו',
'Webserver file %s' => 'קובץ השרת %s',
'File does not exist.' => 'הקובץ אינו קיים',
'%d in total' => '%d בסך הכל',
'Permanent login' => 'התחבר לצמיתות',
'Databases have been dropped.' => 'מסד הנתונים הושלך',
'Database has been dropped.' => 'מסד הנתונים הושלך',
'Search data in tables' => 'חפש מידע בטבלאות',
'Schema' => 'סכמה',
'Alter schema' => 'שנה סכמה',
'Create schema' => 'צור סכמה',
'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.' => 'הסדרה שונתה',
'User types' => 'סוגי משתמשים',
'Create type' => 'צור סוג',
'Alter type' => 'שנה סוג',
'Type has been dropped.' => 'הסוג הושלך',
'Type has been created.' => 'הסוג נוצר',
'Use edit link to modify this value.' => 'השתמש בקישור העריכה בשביל לשנות את הערך',
'last' => 'אחרון',
'From server' => 'משרת',
'System' => 'מערכת',
'Select data' => 'בחר נתונים',
'Show structure' => 'הראה מבנה',
'empty' => 'ריק',
'Network' => 'רשת',
'Geometry' => 'גיאומטריה',
'File exists.' => 'קובץ קיים',
'Attachments' => 'קבצים מצורפים',
'Item%s has been inserted.' => 'הפריט %s הוזן בהצלחה',
'now' => 'כעת',
'%d query(s) executed OK.' => '%d שאילתות בוצעו בהצלחה',
'Show only errors' => 'הראה שגיאות בלבד',
'Refresh' => 'רענן',
'Invalid schema.' => 'סכמה שגויה',
'Please use one of the extensions %s.' => 'בבקשה השתמש באחד מהתוספים %s',
'ltr' => 'rtl',
'Tables have been copied.' => 'הטבלה הועתקה',
'Copy' => 'העתק',
'Permanent link' => 'קישור סופי',
'Edit all' => 'ערוך הכל',
'HH:MM:SS' => 'HH:MM:SS',
'Tables have been optimized.' => 'הטבלאות עברו אופטימיזציה',
'Materialized view' => 'תצוגת מימוש ',
'Vacuum' => 'וואקום',
'Selected' => 'נבחרים',
'Ctrl+click on a value to modify it.' => 'לחץ ctrl + לחיצת עכבר לערוך ערך זה',
'File must be in UTF-8 encoding.' => 'על הקובץ להיות בקידוד utf-8',
'Modify' => 'ערוך',
'Loading' => 'טוען',
'Load more data' => 'טען נתונים נוספים',
'ATTACH queries are not supported.' => 'שאילתת ATTACH אינה נתמכת',
'%d / ' => '%d / ',
'Limit rows' => 'הגבל שורות',
'Default value' => 'ערך ברירת מחדל',
'Full table scan' => 'סריקה טבלה מלאה',
'Too many unsuccessful logins, try again in %d minute(s).' => 'יותר מידי נסיונות כניסה נכשלו, אנא נסה עוד %d דקות',
'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>.',
'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> על מנת להפוך את זה לתמידי',
'If you did not send this request from Adminer then close this page.' => 'אם לא אתה שלחת בקשה ל-Adminer הינך יכול לסגור חלון זה',
'You can upload a big SQL file via FTP and import it from server.' => 'ניתן לעלות קבצים ב-FTP ואז למשוך אותם מהשרת',
'Size' => 'גודל',
'Compute' => 'חישוב',
'You are offline.' => 'הינך לא מקוון',
'You have no privileges to update this table.' => 'אין לך ההרשאות המתאימות לעדכן טבלה זו',
'Saving' => 'שומר',
'yes' => 'כן',
'no' => 'לא',
);

View File

@@ -185,7 +185,7 @@ $translations = array(
'Save and continue edit' => 'Mentés és szerkesztés folytatása',
'original' => 'eredeti',
'%d item(s) have been affected.' => array('%d tétel érintett.', '%d tétel érintett.', '%d tétel érintett.'),
'whole result' => 'összes eredményt mutatása',
'Whole result' => 'Összes eredményt mutatása',
'Tables have been dropped.' => 'Táblák eldobva.',
'Clone' => 'Klónoz',
'Partition by' => 'Particionálás ezzel',

View File

@@ -231,7 +231,7 @@ $translations = array(
'%d row(s)' => '%d baris',
'Page' => 'Halaman',
'last' => 'terakhir',
'whole result' => 'Seluruh hasil',
'Whole result' => 'Seluruh hasil',
'%d byte(s)' => '%d bita',
'Import' => 'Impor',

View File

@@ -186,7 +186,7 @@ $translations = array(
'Move to other database' => 'Sposta in altro database',
'Move' => 'Sposta',
'%d item(s) have been affected.' => array('Il risultato consiste in %d elemento.', 'Il risultato consiste in %d elementi.'),
'whole result' => 'intero risultato',
'Whole result' => 'Intero risultato',
'Clone' => 'Clona',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Troppi campi. Per favore aumentare %s.',
'Partition by' => 'Partiziona per',

View File

@@ -178,13 +178,13 @@ $translations = array(
'Optimize' => '最適化',
'Check' => 'チェック',
'Repair' => '修復',
'Truncate' => 'Truncate',
'Truncate' => '空にする',
'Move to other database' => '別のデータベースへ移動',
'Move' => '移動',
'Save and continue edit' => '保存して継続',
'original' => '元',
'%d item(s) have been affected.' => '%d を更新しました',
'whole result' => '全結果',
'Whole result' => '全結果',
'Tables have been dropped.' => 'テーブルを削除しました',
'Clone' => 'クローン',
'Maximum number of allowed fields exceeded. Please increase %s.' => '定義可能な最大フィールド数を越えました。%s を増やしてください。',
@@ -264,4 +264,14 @@ $translations = array(
'Permanent link' => 'パーマネントリンク',
'Edit all' => 'すべて編集',
'HH:MM:SS' => '時:分:秒',
'Selected' => '選択済',
'Modify' => '修正',
'Load more data' => '続きを読み込み',
'Loading' => '読み込み中',
'Size' => 'サイズ',
'Compute' => '算出',
'Saving' => '保存中',
'yes' => 'はい',
'no' => 'いいえ',
'Default value' => '既定値',
);

303
adminer/lang/ka.inc.php Normal file
View File

@@ -0,0 +1,303 @@
<?php
$translations = array(
'Login' => 'შესვლა',
'Logout successful.' => 'გამოხვედით სისტემიდან.',
'Invalid credentials.' => 'არასწორი მომხმარებელი ან პაროლი.',
'Server' => 'სერვერი',
'Username' => 'მომხმარებელი',
'Password' => 'პაროლი',
'Select database' => 'ბაზა',
'Invalid database.' => 'არასწორი ბაზა.',
'Table has been dropped.' => 'ცხრილი წაიშალა.',
'Table has been altered.' => 'ცხრილი შეიცვალა.',
'Table has been created.' => 'ცხრილი შეიქმნა.',
'Alter table' => 'ცხრილის შეცვლა',
'Create table' => 'ცხრილის შექმნა',
'Table name' => 'სახელი',
'engine' => 'სახეობა',
'collation' => 'კოდირება',
'Column name' => 'ველი',
'Type' => 'სახეობა',
'Length' => 'სიგრძე',
'Auto Increment' => 'ავტომატურად გაზრდა',
'Options' => 'მოქმედება',
'Save' => 'შენახვა',
'Drop' => 'წაშლა',
'Database has been dropped.' => 'ბაზა წაიშალა.',
'Database has been created.' => 'ბაზა შეიქმნა.',
'Database has been renamed.' => 'ბაზას გადაერქვა.',
'Database has been altered.' => 'ბაზა შეიცვალა.',
'Alter database' => 'ბაზის შეცვლა',
'Create database' => 'ბაზის შექმნა',
'SQL command' => 'SQL-ბრძანება',
'Logout' => 'გასვლა',
'database' => 'ბაზა',
'Use' => 'არჩევა',
'No tables.' => 'ბაზაში ცხრილი არაა.',
'select' => 'არჩევა',
'Item has been deleted.' => 'ჩანაწერი წაიშალა.',
'Item has been updated.' => 'ჩანაწერი განახლდა.',
'Item%s has been inserted.' => 'ჩანაწერი%s ჩაჯდა.',
'Edit' => 'შეცვლა',
'Insert' => 'ჩასმა',
'Save and insert next' => 'შენახვა და სხვის ჩასმა',
'Delete' => 'წაშლა',
'Database' => 'ბაზა',
'Indexes have been altered.' => 'შეიცვალა ინდექსები.',
'Indexes' => 'ინდექსები',
'Alter indexes' => 'ინდექსის შეცვლა',
'Add next' => 'კიდევ დამატება',
'Language' => 'ენა',
'Select' => 'არჩევა',
'New item' => 'ახალი ჩანაწერი',
'Search' => 'ძებნა',
'Sort' => 'დალაგება',
'descending' => 'კლებადობით',
'Limit' => 'ზღვარი',
'No rows.' => 'ჩანაწერი არაა.',
'Action' => 'მოქმედება',
'edit' => 'რედაქტირება',
'Page' => 'გვერდი',
'Query executed OK, %d row(s) affected.' => 'მოთხოვდა შესრულდა, შეიცვალა %d ჩანაწერი.',
'Error in query' => 'შეცდომა მოთხოვნაში',
'Execute' => 'შესრულება',
'Table' => 'ცხრილი',
'Foreign keys' => 'გარე გასაღები',
'Triggers' => 'ტრიგერები',
'View' => 'ნახვა',
'Unable to select the table' => 'ცხრილიდან ინფორმაცია ვერ მოვიპოვე',
'Invalid CSRF token. Send the form again.' => 'უმოქმედო CSRF-ტოკენი. ფორმის კიდევ ერთხელ გაგზავნა.',
'Comment' => 'კომენტარები',
'Default values' => 'სტანდარტული მნიშვნელობა',
'%d byte(s)' => '%d ბაიტი',
'No commands to execute.' => 'შესასრულებელი ბრძანება არაა.',
'Unable to upload a file.' => 'ფაილი არ აიტვირთა სერვერზე.',
'File upload' => 'ფაილის ატვირთვა სერვერზე',
'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.' => 'არც ერთი მხარდაჭერილი გაფართოება არ მოიძებნა (%s).',
'Session support must be enabled.' => 'ჩართული უნდა იყოს სესია.',
'Session expired, please login again.' => 'სესიის მოქმედების დრო ამოიწურა, გაიარეთ ხელახალი ავტორიზაცია.',
'Text length' => 'ტექსტის სიგრძე',
'Foreign key has been dropped.' => 'გარე გასაღები წაიშალა.',
'Foreign key has been altered.' => 'გარე გასაღები შეიცვალა.',
'Foreign key has been created.' => 'გარე გასაღები შეიქმნა.',
'Foreign key' => 'გარე გასაღები',
'Change' => 'შეცვლა',
'Source' => 'წყარო',
'Target' => 'სამიზნე',
'Add column' => 'ველის დამატება',
'Alter' => 'შეცვლა',
'Add foreign key' => 'გარე გასაღები დამატება',
'ON DELETE' => 'წაშლისას',
'ON UPDATE' => 'განახლებისას',
'Index Type' => 'ინდექსის სახეობა',
'Column (length)' => 'ველი (სიგრძე)',
'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 პროცესი.',
'Kill' => 'დასრულება',
'Parameter name' => 'პარამეტრი',
'Database schema' => 'ბაზის სქემა',
'Create procedure' => 'პროცედურის შექმნა',
'Create function' => 'ფუნქციის შექმნა',
'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.' => 'ტრიგერი შეიქმნა.',
'Alter trigger' => 'ტრიგერის შეცვლა',
'Create trigger' => 'ტრიგერის შექმნა',
'Time' => 'დრო',
'Event' => 'ღონისძიება',
'%s version: %s through PHP extension %s' => 'ვერსია %s: %s PHP-გაფართოება %s',
'%d row(s)' => '%d რიგი',
'Remove' => 'წაშლა',
'Are you sure?' => 'ნამდვილად?',
'Privileges' => 'უფლებამოსილება',
'Create user' => 'მომხმარებლის შექმან',
'User has been dropped.' => 'მომხმარებელი წაიშალა.',
'User has been altered.' => 'მომხმარებელი შეიცვალა.',
'User has been created.' => 'მომხმარებელი შეიქმნა.',
'Hashed' => 'ჰეშირებული',
'Column' => 'ველი',
'Routine' => 'პროცედურა',
'Grant' => 'დაშვება',
'Revoke' => 'შეზღუდვა',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'POST ინფორმაცია ძალიან დიდია. შეამცირეთ ზომა ან გაზარდეს POST ინფორმაციის ზომა პარამეტრებიდან %s.',
'Logged as: %s' => 'შესული ხართ როგორც: %s',
'Move up' => 'ზემოთ ატანა',
'Move down' => 'ქვემოთ ჩატანა',
'Functions' => 'ფუნქციები',
'Aggregation' => 'აგრეგაცია',
'Export' => 'ექსპორტი',
'Output' => 'გამომავალი ინფორმაცია',
'open' => 'გახსნა',
'save' => 'შენახვა',
'Format' => 'ფორმატი',
'Tables' => 'ცხრილები',
'Data' => 'ინფორმაცია',
'Event has been dropped.' => 'ღონისძიება წაიშალა.',
'Event has been altered.' => 'ღონისძიება შეიცვალა.',
'Event has been created.' => 'ღონისძიება შეიქმნა.',
'Alter event' => 'ღონისძიების შეცვლა',
'Create event' => 'ღონისძიების შექმნა',
'At given time' => 'მოცემულ დროში',
'Every' => 'ყოველ',
'Events' => 'ღონისძიება',
'Schedule' => 'განრიგი',
'Start' => 'დასაწყისი',
'End' => 'დასასრული',
'Status' => 'მდგომარეობა',
'On completion preserve' => 'შენახვა დასრულებისას',
'Tables and views' => 'ცხრილები და წარმოდგენები',
'Data Length' => 'ინფორმაციის მოცულობა',
'Index Length' => 'ინდექსების მოცულობა',
'Data Free' => 'თავისუფალი სივრცე',
'Collation' => 'კოდირება',
'Analyze' => 'ანალიზი',
'Optimize' => 'ოპტიმიზაცია',
'Check' => 'შემოწმება',
'Repair' => 'გასწორება',
'Truncate' => 'გასუფთავება',
'Tables have been truncated.' => 'ცხრილი გასუფთავდა.',
'Rows' => 'რიგი',
',' => ' ',
'0123456789' => '0123456789',
'Tables have been moved.' => 'ცხრილი გადაადგილდა.',
'Move to other database' => 'გადატანა სხვა ბაზაში',
'Move' => 'გადატანა',
'Engine' => 'ძრავი',
'Save and continue edit' => 'შენახვა და ცვლილების გაგრძელება',
'original' => 'საწყისი',
'%d item(s) have been affected.' => 'შეიცვალა %d ჩანაწერი.',
'Whole result' => 'სრული შედეგი',
'Tables have been dropped.' => 'ცხრილები წაიშალა.',
'Clone' => 'კლონირება',
'Partition by' => 'დაყოფა',
'Partitions' => 'დანაყოფები',
'Partition name' => 'დანაყოფის სახელი',
'Values' => 'პარამეტრები',
'%d row(s) have been imported.' => 'დაიმპორტდა %d რიგი.',
'Import' => 'იმპორტი',
'Stop on error' => 'გაჩერება შეცდომისას',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'მიღწეულია დაშვებული ველების მაქსიმალური რაოდენობა, გაზარდეთ %s.',
'anywhere' => 'ნებისმიერ ადგილას',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5.$3.$1',
'[yyyy]-mm-dd' => 'დდ.თთ.[წწწწ]',
'History' => 'ისტორია',
'Variables' => 'ცვლადები',
'Relations' => 'ურთიერთობა',
'Run file' => 'ფაილის გაშვება',
'Clear' => 'გასუფთავება',
'Maximum allowed file size is %sB.' => 'ფაილის მაქსიმალური ზომა - %sB.',
'Numbers' => 'ციფრები',
'Date and time' => 'დრო და თარიღი',
'Binary' => 'ორობითი',
'Lists' => 'სია',
'Editor' => 'რედაქტორი',
'E-mail' => 'ელ. ფოსტა',
'From' => 'ავტორი:',
'Subject' => 'თემა',
'Send' => 'გაგზავნა',
'%d e-mail(s) have been sent.' => 'გაიგზავნა %d წერილი.',
'Webserver file %s' => 'ფაილი %s ვებსერვერზე',
'File does not exist.' => 'ასეთი ფაილი არ არსებობს.',
'%d in total' => 'სულ %d',
'Permanent login' => 'სისტემაში დარჩენა',
'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.' => 'სქემა შეიცვალა.',
'Sequences' => 'მიმდევრობა',
'Create sequence' => 'მიმდევრობის შექმნა',
'Alter sequence' => 'მიმდევრობის შეცვლა',
'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.' => 'სახეობა შეიქმნა.',
'Ctrl+click on a value to modify it.' => 'შესაცვლელად გამოიყენეთ Ctrl+თაგვის ღილაკი.',
'Use edit link to modify this value.' => 'ამ მნიშვნელობის შესაცვლელად გამოიყენეთ ბმული «შეცვლა».',
'last' => 'ბოლო',
'From server' => 'სერვერიდან',
'System' => 'სისტემა',
'Select data' => 'არჩევა',
'Show structure' => 'სტრუქტურის ჩვენება',
'empty' => 'ცარიელი',
'Network' => 'ქსელი',
'Geometry' => 'გეომეტრია',
'File exists.' => 'ფაილი უკვე არსებობს.',
'Attachments' => 'მიმაგრებული ფაილები',
'%d query(s) executed OK.' => '%d მოთხოვნა შესრულდა.',
'Show only errors' => 'მხოლოდ შეცდომები',
'Refresh' => 'განახლება',
'Invalid schema.' => 'არასწორი სქემა.',
'Please use one of the extensions %s.' => 'გამოიყენეთ ერთ-ერთი გაფართოება %s.',
'now' => 'ახლა',
'ltr' => 'ltr',
'Tables have been copied.' => 'ცხრილი დაკოპირდა.',
'Copy' => 'კოპირება',
'Permanent link' => 'მუდმივი ბმული',
'Edit all' => 'ყველას შეცვლა',
'HH:MM:SS' => 'სთ:წთ:წმ',
'Tables have been optimized.' => 'ცხრილებს გაუკეთდა ოპტიმიზაცია.',
'Materialized view' => 'მატერიალური ხედი',
'Vacuum' => 'ვაკუუმი',
'Selected' => 'არჩეული',
'File must be in UTF-8 encoding.' => 'ფაილი უნდა იყოს კოდირებაში UTF-8.',
'Modify' => 'შეცვლა',
'Loading' => 'ჩატვირთვა',
'Load more data' => 'მეტი ინფორმაციის ჩატვირთვა',
'ATTACH queries are not supported.' => 'ATTACH-მოთხოვნები არაა მხარდაჭერილი.',
'%d / ' => '%d / ',
'Limit rows' => 'რიგების შეზღუდვა',
'Default value' => 'სტანდარტული მნიშვნელობა',
'Full table scan' => 'სრული ცხრილის ანალიზი',
'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, რათა ის მუდმივი გახადოთ.',
'If you did not send this request from Adminer then close this page.' => 'ეს მოთხოვნა თქვენ თუ არ გაგიგზავნაით Adminer-იდან, დახურეთ ეს ფანჯარა..',
'You can upload a big SQL file via FTP and import it from server.' => 'დიდი ფაილი უნდა ატვირტოთ FTP-თი და შემდეგ გაუკეთოთ იმპორტი სერვერიდან.',
'Size' => 'ზომა',
'Compute' => 'გამოთვლა',
'You are offline.' => 'არ გაგივლიათ ავტორიზაცია.',
'You have no privileges to update this table.' => 'ამ ცხრილის განახლების უფლება არ გაქვთ.',
'Saving' => 'შენახვა',
'yes' => 'კი',
'no' => 'არა',
'Routines' => 'რუტინები',
'Target table' => 'მიზნობრივი ცხრილი',
'Strings' => 'ველები',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => 'საწყისი და მიზნობრივი ველები უნდა იყოს ერთიდაიგივე სახეობის, მიზნობრივ ველზე უნდა იყოს ინდექსი და უნდა არსებობდეს შესაბამისი ინფორმაცია.',
'Drop %s?' => 'წაიშალოს %s?',
'Warnings' => 'გაფრთხილება',
'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>.',
'DB' => 'ბაზა',
'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>.',
'The action will be performed after successful login with the same credentials.' => 'მოქმედება შესრულდება იგივე მომხმარებლით წარმატებული ავტორიზაციის შემდეგ.',
'Connecting to privileged ports is not allowed.' => 'პრივილეგირებულ პორტთან წვდომა დაუშვებელია.',
'There is a space in the input password which might be the cause.' => 'პაროლში არის გამოტოვება, შეიძლება ეს ქმნის პრობლემას.',
'Unknown error.' => 'უცნობი შეცდომა.',
'Database does not support password.' => 'ბაზაში არაა მხარდაჭერილი პაროლი.',
'Disable %s or enable %s or %s extensions.' => 'გათიშეთ %s ან ჩართეთ %s ან %s გაფართოება.',
);

View File

@@ -184,7 +184,7 @@ $translations = array(
'Save and continue edit' => '저장하고 계속',
'original' => '원래',
'%d item(s) have been affected.' => '%d를 갱신했습니다.',
'whole result' => '모든 결과',
'Whole result' => '모든 결과',
'Tables have been dropped.' => '테이블을 삭제했습니다.',
'Clone' => '복제',
'Maximum number of allowed fields exceeded. Please increase %s.' => '정의 가능한 최대 필드 수를 초과했습니다. %s를 늘리십시오.',

View File

@@ -229,7 +229,7 @@ $translations = array(
'%d row(s)' => array('%d įrašas', '%d įrašai', '%d įrašų'),
'Page' => 'Puslapis',
'last' => 'paskutinis',
'whole result' => 'visas rezultatas',
'Whole result' => 'Visas rezultatas',
'%d byte(s)' => array('%d baitas', '%d baigai', '%d baitų'),
'Import' => 'Importas',

340
adminer/lang/ms.inc.php Normal file
View File

@@ -0,0 +1,340 @@
<?php
$translations = array(
// label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem',
'Server' => 'Pelayan',
'Username' => 'Nama pengguna',
'Password' => 'Kata laluan',
'Permanent login' => 'Log masuk kekal',
'Login' => 'Log masuk',
'Logout' => 'Log keluar',
'Logged as: %s' => 'Log masuk sebagai: %s',
'Logout successful.' => 'Log keluar berjaya.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Terima kasih kerana menggunakan Adminer, pertimbangkan untuk <a href="https://www.adminer.org/en/donation/">menderma</a>.',
'Invalid credentials.' => 'Akses tidak sah.',
'Too many unsuccessful logins, try again in %d minute(s).' => 'Terlalu banyak percubaan log masuk yang gagal, sila cuba lagi dalam masa %d minit.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Kata laluan utama telah luput. <a href="https://www.adminer.org/en/extension/"%s>Gunakan</a> cara %s untuk mengekalkannya.',
'Language' => 'Bahasa',
'Invalid CSRF token. Send the form again.' => 'Token CSRF tidak sah. Sila hantar borang sekali lagi.',
'If you did not send this request from Adminer then close this page.' => 'Jika anda tidak menghantar permintaan ini dari Adminer sila tutup halaman ini.',
'No extension' => 'Tiada sambungan',
'None of the supported PHP extensions (%s) are available.' => 'Sambungan PHP yang (%s) disokong tidak wujud.',
'Connecting to privileged ports is not allowed.' => 'Penyambungan ke port yang istimewa tidak dibenarkan.',
'Session support must be enabled.' => 'Sokongan sesi perlu diaktifkan.',
'Session expired, please login again.' => 'Sesi telah luput, sila log masuk kembali.',
'%s version: %s through PHP extension %s' => 'Versi %s: %s melalui sambungan PHP %s',
'Refresh' => 'Segar kembali',
// text direction - 'ltr' or 'rtl'
'ltr' => 'ltr',
'Privileges' => 'Keistimewaan',
'Create user' => 'Bina pengguna',
'User has been dropped.' => 'Pengguna telah dijatuhkan.',
'User has been altered.' => 'Pengguna telah diubah.',
'User has been created.' => 'Pengguna telah dibuat.',
'Hashed' => 'Hashed',
'Column' => 'Kolum',
'Routine' => 'Rutin',
'Grant' => 'Beri',
'Revoke' => 'Batal',
'Process list' => 'Senarai proses',
'%d process(es) have been killed.' => '%d proses telah dihentikan.',
'Kill' => 'Henti',
'Variables' => 'Pembolehubah',
'Status' => 'Status',
'SQL command' => 'Arahan SQL',
'%d query(s) executed OK.' => '%d query berjaya dilaksanakan.',
'Query executed OK, %d row(s) affected.' => 'Query berjaya dilaksanakan, %d baris terjejas.',
'No commands to execute.' => 'Tiada arahan untuk dilaksanakan.',
'Error in query' => 'Ralat pada query',
'ATTACH queries are not supported.' => 'Query berikut tidak disokong.',
'Execute' => 'Laksana',
'Stop on error' => 'Berhenti jika ralat',
'Show only errors' => 'Paparkan jika ralat',
// sprintf() format for time of the command
'%.3f s' => '%.3f s',
'History' => 'Sejarah',
'Clear' => 'Bersih',
'Edit all' => 'Ubah semua',
'File upload' => 'Muat naik fail',
'From server' => 'Dari pelayan',
'Webserver file %s' => 'Fail pelayan sesawang %s',
'Run file' => 'Jalankan fail',
'File does not exist.' => 'Fail tidak wujud.',
'File uploads are disabled.' => 'Muat naik fail dihalang.',
'Unable to upload a file.' => 'Muat naik fail gagal.',
'Maximum allowed file size is %sB.' => 'Saiz fail maksimum yang dibenarkan adalah %sB.',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Data POST terlalu besar. Kecilkan data atau tingkatkan tetapan %s.',
'You can upload a big SQL file via FTP and import it from server.' => 'Anda boleh muat naik fail SQL yang besar melalui FTP dan import melalui pelayan.',
'You are offline.' => 'Anda sedang offline.',
'Export' => 'Eksport',
'Output' => 'Pengeluaran',
'open' => 'buka',
'save' => 'simpan',
'Saving' => 'Menyimpan',
'Format' => 'Format',
'Data' => 'Data',
'Database' => 'Pangkalan data',
'database' => 'pangkalan data',
'Use' => 'Guna',
'Select database' => 'Pilih pangkalan data',
'Invalid database.' => 'Pangkalan data tidak sah.',
'Database has been dropped.' => 'Pangkalan data telah dijatuhkan.',
'Databases have been dropped.' => 'Pangkalan data telah dijatuhkan.',
'Database has been created.' => 'Pangkalan data telah dibuat.',
'Database has been renamed.' => 'Pangkalan data telah ditukar nama.',
'Database has been altered.' => 'Pangkalan data telah diubah.',
'Alter database' => 'Ubah pangkalan data',
'Create database' => 'Bina pangkalan data',
'Database schema' => 'Skema pangkalan data',
// link to current database schema layout
'Permanent link' => 'Pautan kekal',
// thousands separator - must contain single byte
',' => ',',
'0123456789' => '0123456789',
'Engine' => 'Enjin',
'Collation' => 'Collation',
'Data Length' => 'Panjang Data',
'Index Length' => 'Panjang Indeks',
'Data Free' => 'Data Free',
'Rows' => 'Baris',
'%d in total' => '%d secara keseluruhan',
'Analyze' => 'Menganalisis',
'Optimize' => 'Mengoptimum',
'Vacuum' => 'Vacuum',
'Check' => 'Periksa',
'Repair' => 'Baiki',
'Truncate' => 'Memangkas',
'Tables have been truncated.' => 'Jadual telah dimangkaskan.',
'Move to other database' => 'Pindahkan ke pangkalan data yang lain',
'Move' => 'Pindah',
'Tables have been moved.' => 'Jadual telah dipindahkan.',
'Copy' => 'Salin',
'Tables have been copied.' => 'Jadual telah disalin.',
'Routines' => 'Rutin',
'Routine has been called, %d row(s) affected.' => 'Rutin telah dipanggil, %d baris terjejas.',
'Call' => 'Panggil',
'Parameter name' => 'Nama pembolehubah',
'Create procedure' => 'Bina prosedur',
'Create function' => 'Bina fungsi',
'Routine has been dropped.' => 'Rutin telah dijatuhkan.',
'Routine has been altered.' => 'Rutin telah diubah.',
'Routine has been created.' => 'Rutin telah dibuat.',
'Alter function' => 'Ubah fungsi',
'Alter procedure' => 'Ubah prosedur',
'Return type' => 'Jenis Return',
'Events' => 'Peristiwa',
'Event has been dropped.' => 'Peristiwa telah dijatuhkan.',
'Event has been altered.' => 'Peristiwa telah diubah.',
'Event has been created.' => 'Peristiwa telah dibuat.',
'Alter event' => 'Ubah peristiwa',
'Create event' => 'Bina peristiwa',
'At given time' => 'Pada masa tersebut',
'Every' => 'Setiap',
'Schedule' => 'Jadual',
'Start' => 'Mula',
'End' => 'Habis',
'On completion preserve' => 'Dalam melestarikan penyelesaian',
'Tables' => 'Jadual',
'Tables and views' => 'Jadual dan pandangan',
'Table' => 'Jadual',
'No tables.' => 'Tiada jadual.',
'Alter table' => 'Ubah jadual',
'Create table' => 'Bina jadual',
'Table has been dropped.' => 'Jadual telah dijatuhkan.',
'Tables have been dropped.' => 'Jadual telah dijatuhkan.',
'Tables have been optimized.' => 'Jadual telah dioptimumkan.',
'Table has been altered.' => 'Jadual telah diubah.',
'Table has been created.' => 'Jadual telah dibuat.',
'Table name' => 'Nama jadual',
'Show structure' => 'Paparkan struktur',
'engine' => 'enjin',
'collation' => 'collation',
'Column name' => 'Nama kolum',
'Type' => 'Jenis',
'Length' => 'Kepanjangan',
'Auto Increment' => 'Kenaikan Auto',
'Options' => 'Pilihan',
'Comment' => 'Komen',
'Default value' => 'Nilai lalai',
'Default values' => 'Nilai lalai',
'Drop' => 'Jatuh',
'Drop %s?' => 'Jatuhkan %s?',
'Are you sure?' => 'Anda pasti?',
'Size' => 'Saiz',
'Compute' => 'Kira',
'Move up' => 'Gerak ke atas',
'Move down' => 'Gerak ke bawah',
'Remove' => 'Buang',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Bilangan medan telah melebihi had yang dibenarkan. Sila tingkatkan %s.',
'Partition by' => 'Partition mengikut',
'Partitions' => 'Partition',
'Partition name' => 'Nama partition',
'Values' => 'Nilai',
'View' => 'Papar',
'Materialized view' => 'Paparan yang menjadi kenyataan',
'View has been dropped.' => 'Paparan telah dijatuhkan.',
'View has been altered.' => 'Paparan telah diubah.',
'View has been created.' => 'Paparan telah dibuat.',
'Alter view' => 'Ubah paparan',
'Create view' => 'Bina paparan',
'Indexes' => 'Indeks',
'Indexes have been altered.' => 'Indeks telah diubah.',
'Alter indexes' => 'Ubah indeks',
'Add next' => 'Tambah yang seterusnya',
'Index Type' => 'Jenis Indeks',
'Column (length)' => 'Kolum (kepanjangan)',
'Foreign keys' => 'Kunci asing',
'Foreign key' => 'Kunci asing',
'Foreign key has been dropped.' => 'Kunci asing telah dijatuhkan.',
'Foreign key has been altered.' => 'Kunci asing telah diubah.',
'Foreign key has been created.' => 'Kunci asing telah dibuat.',
'Target table' => 'Jadual sasaran',
'Change' => 'Tukar',
'Source' => 'Sumber',
'Target' => 'Sasaran',
'Add column' => 'Tambah kolum',
'Alter' => 'Ubah',
'Add foreign key' => 'Tambah kunci asing',
'ON DELETE' => 'ON DELETE',
'ON UPDATE' => 'ON UPDATE',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => 'Kolum sumber dan sasaran perlu mempunyai jenis data yang sama, indeks diperlukan pada kolum sasaran dan data yang dirujuk wujud.',
'Triggers' => ' Pencetus',
'Add trigger' => 'Tambah pencetus',
'Trigger has been dropped.' => 'Pencetus telah dijatuhkan.',
'Trigger has been altered.' => 'Pencetus telah diubah.',
'Trigger has been created.' => 'Pencetus telah dibuat.',
'Alter trigger' => 'Ubah pencetus',
'Create trigger' => 'Buat pencetus',
'Time' => 'Masa',
'Event' => 'Peristiwa',
'Name' => 'Nama',
'select' => 'pilih',
'Select' => 'Pilih',
'Select data' => 'Pilih data',
'Functions' => 'Fungsi',
'Aggregation' => 'Pengagregatan',
'Search' => 'Cari',
'anywhere' => 'di mana-mana',
'Search data in tables' => 'Cari data dalam jadual',
'Sort' => 'Susun',
'descending' => 'menurun',
'Limit' => 'Had',
'Limit rows' => 'Had baris',
'Text length' => 'Kepanjangan teks',
'Action' => 'Aksi',
'Full table scan' => 'Imbasan penuh jadual',
'Unable to select the table' => 'Pemilihan jadual tidak berjaya',
'No rows.' => 'Tiada baris.',
'%d / ' => '%d / ',
'%d row(s)' => '%d baris',
'Page' => 'Halaman',
'last' => 'akhir',
'Load more data' => 'Load lebih data',
'Loading' => 'Loading',
'Whole result' => 'Keputusan keseluruhan',
'%d byte(s)' => array('%d byte', '%d bytes'),
'Import' => 'Import',
'%d row(s) have been imported.' => '%d baris telah diimport.',
'File must be in UTF-8 encoding.' => 'Fail mesti dalam pengekodan UTF-8.',
// in-place editing in select
'Modify' => 'Pinda',
'Ctrl+click on a value to modify it.' => 'Ctrl+click pada nilai untuk meminda.',
'Use edit link to modify this value.' => 'Guna pautan ubah untuk meminda nilai ini.',
// %s can contain auto-increment value
'Item%s has been inserted.' => 'Item%s telah dimasukkan.',
'Item has been deleted.' => 'Item telah dipadamkan.',
'Item has been updated.' => 'Item telah dikemaskini.',
'%d item(s) have been affected.' => '%d item telah terjejas.',
'New item' => 'Item baru',
'original' => 'asli',
// label for value '' in enum data type
'empty' => 'kosong',
'edit' => 'ubah',
'Edit' => 'Ubah',
'Insert' => 'Masukkan',
'Save' => 'Simpan',
'Save and continue edit' => 'Simpan dan sambung ubah',
'Save and insert next' => 'Simpan dan masukkan seterusnya',
'Selected' => 'Terpilih',
'Clone' => 'Klon',
'Delete' => 'Padam',
'You have no privileges to update this table.' => 'Anda tidak mempunyai keistimewaan untuk mengemaskini jadual ini.',
'E-mail' => 'Emel',
'From' => 'Dari',
'Subject' => 'Subjek',
'Attachments' => 'Lampiran',
'Send' => 'Hantar',
'%d e-mail(s) have been sent.' => '%d emel telah dihantar.',
// data type descriptions
'Numbers' => 'Nombor',
'Date and time' => 'Tarikh dan masa',
'Strings' => 'String',
'Binary' => 'Binari',
'Lists' => 'Senarai',
'Network' => 'Rangkaian',
'Geometry' => 'Geometri',
'Relations' => 'Hubungan',
'Editor' => 'Editor',
// date format in Editor: $1 yyyy, $2 yy, $3 mm, $4 m, $5 dd, $6 d
'$1-$3-$5' => '$1-$3-$5',
// hint for date format - use language equivalents for day, month and year shortcuts
'[yyyy]-mm-dd' => '[yyyy]-mm-dd',
// hint for time format - use language equivalents for hour, minute and second shortcuts
'HH:MM:SS' => 'HH:MM:SS',
'now' => 'sekarang',
'yes' => 'ya',
'no' => 'tidak',
// general SQLite error in create, drop or rename database
'File exists.' => 'Fail wujud.',
'Please use one of the extensions %s.' => 'Sila guna salah satu sambungan %s.',
// PostgreSQL and MS SQL schema support
'Alter schema' => 'Ubah skema',
'Create schema' => 'Buat skema',
'Schema has been dropped.' => 'Skema telah dijatuhkan.',
'Schema has been created.' => 'Skema telah dibuat.',
'Schema has been altered.' => 'Skema telah diubah.',
'Schema' => 'Skema',
'Invalid schema.' => 'Skema tidak sah.',
// PostgreSQL sequences support
'Sequences' => 'Turutan',
'Create sequence' => 'Buat turutan',
'Sequence has been dropped.' => 'Turutan telah dijatuhkan.',
'Sequence has been created.' => 'Turutan telah dibuat.',
'Sequence has been altered.' => 'Turutan telah diubah.',
'Alter sequence' => 'Ubah turutan',
// PostgreSQL user types support
'User types' => 'Jenis pengguna',
'Create type' => 'Buat jenis',
'Type has been dropped.' => 'Jenis telah dijatuhkan.',
'Type has been created.' => 'Jenis telah dibuat.',
'Alter type' => 'Ubah jenis',
);

View File

@@ -187,7 +187,7 @@ $translations = array(
'Move to other database' => 'Verplaats naar andere database',
'Move' => 'Verplaats',
'%d item(s) have been affected.' => array('%d item aangepast.', '%d items aangepast.'),
'whole result' => 'volledig resultaat',
'Whole result' => 'Volledig resultaat',
'Clone' => 'Dupliceer',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Maximum aantal velden bereikt. Verhoog %s.',
'Partition by' => 'Partitioneren op',

View File

@@ -10,7 +10,7 @@ $translations = array(
'Logged as: %s' => 'Logget inn som: %s',
'Logout successful.' => 'Utlogging vellykket.',
'Invalid credentials.' => 'Ugylding innloggingsinformasjon.',
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Master-passord er utløpt. <a href="https://www.adminer.org/en/extension/" target="_blank">Implementer</a> en metode for %s for å gjøre det permanent.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Master-passord er utløpt. <a href="https://www.adminer.org/en/extension/"%s>Implementer</a> en metode for %s for å gjøre det permanent.',
'Language' => 'Språk',
'Invalid CSRF token. Send the form again.' => 'Ugylding CSRF-token - Send inn skjemaet igjen.',
'No extension' => 'Ingen utvidelse',
@@ -212,7 +212,7 @@ $translations = array(
'last' => 'siste',
'Load more data' => 'Last mer data',
'Loading' => 'Laster',
'whole result' => 'hele resultatet',
'Whole result' => 'Hele resultatet',
'%d byte(s)' => array('%d byte', '%d bytes'),
'Import' => 'Importer',
'%d row(s) have been imported.' => array('%d rad er importert.', '%d rader er importert.'),

View File

@@ -10,14 +10,16 @@ $translations = array(
'Logout' => 'Wyloguj',
'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ż proszę <a href="https://www.adminer.org/pl/donation/">dotację</a>.',
'Invalid credentials.' => 'Nieprawidłowe dane logowania.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Za dużo nieudanych prób logowania, spróbuj ponownie za %d minutę.', 'Za dużo nieudanych prób logowania, spróbuj ponownie za %d minuty.', 'Za dużo nieudanych prób logowania, spróbuj ponownie za %d minut.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Ważność hasła głównego wygasła. <a href="https://www.adminer.org/pl/extension/" target="_blank">Zaimplementuj</a> własną metodę %s, aby ustawić je na stałe.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Ważność hasła głównego wygasła. <a href="https://www.adminer.org/pl/extension/"%s>Zaimplementuj</a> własną metodę %s, aby ustawić je na stałe.',
'Language' => 'Język',
'Invalid CSRF token. Send the form again.' => 'Nieprawidłowy token CSRF. Spróbuj wysłać formularz ponownie.',
'If you did not send this request from Adminer then close this page.' => 'Jeżeli nie wywołałeś tej strony z Adminera, zamknij to okno.',
'No extension' => 'Brak rozszerzenia',
'None of the supported PHP extensions (%s) are available.' => 'Żadne z rozszerzeń PHP umożliwiających połączenie się z bazą danych (%s) nie jest dostępne.',
'Connecting to privileged ports is not allowed.' => 'Łączenie do portów uprzywilejowanych jest niedozwolone.',
'Session support must be enabled.' => 'Wymagana jest obsługa sesji w PHP.',
'Session expired, please login again.' => 'Sesja wygasła, zaloguj się ponownie.',
'%s version: %s through PHP extension %s' => 'Wersja %s: %s za pomocą %s',
@@ -49,6 +51,7 @@ $translations = array(
'Query executed OK, %d row(s) affected.' => array('Zapytanie wykonane pomyślnie, zmieniono %d rekord.', 'Zapytanie wykonane pomyślnie, zmieniono %d rekordy.', 'Zapytanie wykonane pomyślnie, zmieniono %d rekordów.'),
'No commands to execute.' => 'Nic do wykonania.',
'Error in query' => 'Błąd w zapytaniu',
'ATTACH queries are not supported.' => 'Zapytania ATTACH są niewspierane.',
'Execute' => 'Wykonaj',
'Stop on error' => 'Zatrzymaj w przypadku błędu',
'Show only errors' => 'Pokaż tylko błędy',
@@ -167,6 +170,7 @@ $translations = array(
'Default value' => 'Wartość domyślna',
'Default values' => 'Wartości domyślne',
'Drop' => 'Usuń',
'Drop %s?' => 'Usunąć %s?',
'Are you sure?' => 'Czy jesteś pewien?',
'Size' => 'Wielkość',
'Compute' => 'Oblicz',
@@ -233,17 +237,19 @@ $translations = array(
'Sort' => 'Sortuj',
'descending' => 'malejąco',
'Limit' => 'Limit',
'Limit rows' => 'Limit rekordów',
'Text length' => 'Długość tekstu',
'Action' => 'Czynność',
'Full table scan' => 'Wymaga pełnego przeskanowania tabeli',
'Unable to select the table' => 'Nie udało się pobrać danych z tabeli',
'No rows.' => 'Brak rekordów.',
'%d / ' => '%d / ',
'%d row(s)' => array('%d rekord', '%d rekordy', '%d rekordów'),
'Page' => 'Strona',
'last' => 'ostatni',
'Load more data' => 'Wczytaj więcej danych',
'Loading' => 'Wczytywanie',
'whole result' => 'wybierz wszystkie',
'Whole result' => 'Wybierz wszystkie',
'%d byte(s)' => array('%d bajt', '%d bajty', '%d bajtów'),
'Import' => 'Import',

View File

@@ -186,7 +186,7 @@ $translations = array(
'original' => 'original',
'Tables have been dropped.' => 'As Tabelas foram eliminadas.',
'%d item(s) have been affected.' => array('%d item foi afetado.', '%d itens foram afetados.'),
'whole result' => 'resultado completo',
'Whole result' => 'Resultado completo',
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Quantidade máxima de campos permitidos excedidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',

View File

@@ -186,7 +186,7 @@ $translations = array(
'original' => 'original',
'Tables have been dropped.' => 'As tabelas foram eliminadas.',
'%d item(s) have been affected.' => array('%d item afetado.', '%d itens afetados.'),
'whole result' => 'resultado completo',
'Whole result' => 'Resultado completo',
'Clone' => 'Clonar',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Quantidade máxima de campos permitidos excedidos. Por favor aumente %s.',
'Partition by' => 'Particionar por',

View File

@@ -185,7 +185,7 @@ $translations = array(
'Save and continue edit' => 'Salvează și continuă editarea',
'original' => 'original',
'%d item(s) have been affected.' => array('A fost modificată %d înscriere.', 'Au fost modificate %d înscrieri.'),
'whole result' => 'tot rezultatul',
'Whole result' => 'Tot rezultatul',
'Tables have been dropped.' => 'Tabelele au fost șterse.',
'Clone' => 'Clonează',
'Partition by' => 'Împarte',

View File

@@ -185,7 +185,7 @@ $translations = array(
'Save and continue edit' => 'Сохранить и продолжить редактирование',
'original' => 'исходный',
'%d item(s) have been affected.' => array('Была изменена %d запись.', 'Были изменены %d записи.', 'Было изменено %d записей.'),
'whole result' => 'весь результат',
'Whole result' => 'Весь результат',
'Tables have been dropped.' => 'Таблицы были удалены.',
'Clone' => 'Клонировать',
'Partition by' => 'Разделить по',
@@ -269,9 +269,6 @@ $translations = array(
'Materialized view' => 'Материализованное представление',
'Vacuum' => 'Вакуум',
'Selected' => 'Выбранные',
'Replication' => 'Репликация',
'Master status' => 'состояние мастер-сервера',
'Slave status' => 'состояние ведомого сервера',
'File must be in UTF-8 encoding.' => 'Файл должен быть в кодировке UTF-8.',
'Modify' => 'Изменить',
'Loading' => 'Загрузка',
@@ -279,11 +276,10 @@ $translations = array(
'ATTACH queries are not supported.' => 'ATTACH-запросы не поддерживаются.',
'%d / ' => '%d / ',
'Limit rows' => 'Лимит строк',
'<a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to use SQLite.' => '<a href="https://www.adminer.org/en/extension/" target="_blank">Реализуйте</a> метод %s, чтобы использовать SQLite.',
'Default value' => 'Значение по умолчанию',
'Full table scan' => 'Анализ полной таблицы',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Слишком много неудачных попыток входа. Попробуйте снова через %d минуту.', 'Слишком много неудачных попыток входа. Попробуйте снова через %d минуты.', 'Слишком много неудачных попыток входа. Попробуйте снова через %d минут.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Мастер-пароль истёк. <a href="https://www.adminer.org/en/extension/" target="_blank">Реализуйте</a> метод %s, чтобы сделать его постоянным.',
'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, чтобы сделать его постоянным.',
'If you did not send this request from Adminer then close this page.' => 'Если вы не посылали этот запрос из Adminer, закройте эту страницу.',
'You can upload a big SQL file via FTP and import it from server.' => 'Вы можете закачать большой SQL-файл по FTP и затем импортировать его с сервера.',
'Size' => 'Размер',

View File

@@ -187,7 +187,7 @@ $translations = array(
'Move to other database' => 'Presunúť do inej databázy',
'Move' => 'Presunúť',
'%d item(s) have been affected.' => '%d položiek bolo ovplyvnených.',
'whole result' => 'celý výsledok',
'Whole result' => 'Celý výsledok',
'Clone' => 'Klonovať',
'Partition by' => 'Rozdeliť podľa',
'Partitions' => 'Oddiely',

View File

@@ -225,7 +225,7 @@ $translations = array(
'%d row(s)' => array('%d vrstica', '%d vrstici', '%d vrstice', '%d vrstic'),
'Page' => 'Stran',
'last' => 'Zadnja',
'whole result' => 'cel razultat',
'Whole result' => 'Cel razultat',
'%d byte(s)' => array('%d bajt', '%d bajta', '%d bajti', '%d bajtov'),
'Import' => 'Uvozi',

View File

@@ -231,9 +231,9 @@ $translations = array(
'%d row(s)' => array('%d ред', '%d реда', '%d редова'),
'Page' => 'Страна',
'last' => 'последња',
'Loading' => 'Учитавам',
'Load more data' => 'Учитавам још података',
'whole result' => 'цео резултат',
'Loading' => 'Учитавам',
'Load more data' => 'Учитавам још података',
'Whole result' => 'Цео резултат',
'%d byte(s)' => array('%d бајт', '%d бајта', '%d бајтова'),
'Import' => 'Увоз',

View File

@@ -183,7 +183,7 @@ $translations = array(
'original' => 'அச‌ல்',
'Tables have been dropped.' => 'அட்ட‌வ‌ணை நீக்க‌ப்ப‌ட்ட‌து.',
'%d item(s) have been affected.' => array('%d உருப்ப‌டி மாற்ற‌ம‌டைந்தது.', '%d உருப்ப‌டிக‌ள் மாற்ற‌ம‌டைந்த‌ன‌.'),
'whole result' => 'முழுமையான‌ முடிவு',
'Whole result' => 'முழுமையான‌ முடிவு',
'Clone' => 'ந‌க‌லி (Clone)',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'அனும‌திக்க‌ப்ப‌ட்ட‌ அதிக‌ப‌ட்ச‌ கோப்புக‌ளின் எண்ணிக்கை மீற‌ப்ப‌ட்ட‌து. த‌ய‌வு செய்து %s ம‌ற்றும் %s யை அதிக‌ரிக்க‌வும்.',
'Partition by' => 'பிரித்த‌து',

View File

@@ -186,7 +186,7 @@ $translations = array(
'original' => 'ต้นฉบับ',
'Tables have been dropped.' => 'ตารางถูกลบแล้ว.',
'%d item(s) have been affected.' => 'มี %d รายการถูกดำเนินการแล้ว.',
'whole result' => 'รวมผล',
'Whole result' => 'รวมผล',
'Clone' => 'ทำซ้ำ',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'จำนวนสูงสุดของฟิลด์อนุญาตให้เกิน กรุณาเพิ่มอีก %s.',
'Partition by' => 'พาร์ทิชันโดย',

View File

@@ -9,14 +9,20 @@ $translations = array(
'Login' => 'Giriş',
'Logout' => ıkış',
'Logged as: %s' => '%s olarak giriş yapıldı.',
'Logout successful.' => 'Başarıyla çıkış yapıldı.',
'Invalid credentials.' => 'Geçersiz kimlik.',
'Logout successful.' => 'Oturum başarıyla sonlandı.',
'Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.' => 'Adminer kullandığınız için teşekkür ederiz <a href="https://www.adminer.org/en/donation/">bağış yapmayı düşünün</a>.',
'Invalid credentials.' => 'Geçersiz kimlik bilgileri.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Çok fazla oturum açma denemesi yapıldı.', '%d Dakika sonra tekrar deneyiniz.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Ana şifrenin süresi doldu. Kalıcı olması için <a href="https://www.adminer.org/en/extension/"%s>%s medodunu</a> kullanın.',
'Language' => 'Dil',
'Invalid CSRF token. Send the form again.' => 'Geçersiz (CSRF) jetonu. Formu tekrar yolla.',
'If you did not send this request from Adminer then close this page.' => 'Bu isteği Adminer\'den göndermediyseniz bu sayfayı kapatın.',
'No extension' => 'Uzantı yok',
'None of the supported PHP extensions (%s) are available.' => 'Desteklenen PHP eklentilerinden (%s) hiçbiri mevcut değil.',
'Connecting to privileged ports is not allowed.' => 'Ayrıcalıklı bağlantı noktalarına bağlanmaya izin verilmiyor.',
'Session support must be enabled.' => 'Oturum desteği etkin olmalıdır.',
'Session expired, please login again.' => 'Oturum süresi doldu, lütfen tekrar giriş yapın.',
'The action will be performed after successful login with the same credentials.' => 'İşlem, aynı kimlik bilgileriyle başarıyla oturum açıldıktan sonra gerçekleştirilecektir.',
'%s version: %s through PHP extension %s' => '%s sürüm: %s, %s PHP eklentisi ile',
'Refresh' => 'Tazele',
@@ -46,6 +52,8 @@ $translations = array(
'Query executed OK, %d row(s) affected.' => array('Sorgu başarıyla çalıştırıldı, %d adet kayıt etkilendi.', 'Sorgu başarıyla çalıştırıldı, %d adet kayıt etkilendi.'),
'No commands to execute.' => 'Çalıştırılacak komut yok.',
'Error in query' => 'Sorguda hata',
'Warnings' => 'Uyarılar',
'ATTACH queries are not supported.' => 'ATTACH sorguları desteklenmiyor.',
'Execute' => 'Çalıştır',
'Stop on error' => 'Hata oluşursa dur',
'Show only errors' => 'Sadece hataları göster.',
@@ -64,16 +72,20 @@ $translations = array(
'Unable to upload a file.' => 'Dosya gönderilemiyor.',
'Maximum allowed file size is %sB.' => 'İzin verilen dosya boyutu sınırı %sB.',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Çok büyük POST verisi, veriyi azaltın ya da %s ayar yönergesini uygun olarak yapılandırın.',
'You can upload a big SQL file via FTP and import it from server.' => 'FTP yoluyla büyük bir SQL dosyası yükleyebilir ve sunucudan içe aktarabilirsiniz.',
'You are offline.' => 'Çevrimdışısınız.',
'Export' => 'Dışarı Aktar',
'Output' => ıktı',
'open' => 'aç',
'save' => 'kaydet',
'Saving' => 'Saydediliyor',
'Format' => 'Biçim',
'Data' => 'Veri',
'Database' => 'Veri Tabanı',
'database' => 'veri tabanı',
'DB' => 'DB',
'Use' => 'Kullan',
'Select database' => 'Veri tabanı seç',
'Invalid database.' => 'Geçersiz veri tabanı.',
@@ -95,12 +107,13 @@ $translations = array(
'Engine' => 'Motor',
'Collation' => 'Karşılaştırma',
'Data Length' => 'Veri Uzunluğu',
'Index Length' => 'Dizin Uzunluğu',
'Index Length' => 'İndex Uzunluğu',
'Data Free' => 'Boş Veri',
'Rows' => 'Kayıtlar',
'%d in total' => 'toplam %d',
'Analyze' => 'Çözümle',
'Optimize' => 'En uygun hale getir',
'Optimize' => 'Optimize Et',
'Vacuum' => 'Vakumla',
'Check' => 'Denetle',
'Repair' => 'Tamir Et',
'Truncate' => 'Boşalt',
@@ -158,9 +171,13 @@ $translations = array(
'Auto Increment' => 'Otomatik Artır',
'Options' => 'Seçenekler',
'Comment' => 'Yorum',
'Default value' => 'Varsayılan değer',
'Default values' => 'Varsayılan değerler',
'Drop' => 'Sil',
'Drop %s?' => 'Sil %s?',
'Are you sure?' => 'Emin misiniz?',
'Size' => 'Boyut',
'Compute' => 'Hesapla',
'Move up' => 'Yukarı taşı',
'Move down' => 'Aşağı taşı',
'Remove' => 'Sil',
@@ -172,17 +189,18 @@ $translations = array(
'Values' => 'Değerler',
'View' => 'Görünüm',
'Materialized view' => 'Materialized Görünüm',
'View has been dropped.' => 'Görünüm silindi.',
'View has been altered.' => 'Görünüm değiştirildi.',
'View has been created.' => 'Görünüm oluşturuldu.',
'Alter view' => 'Görünümü değiştir',
'Create view' => 'Görünüm oluştur',
'Indexes' => 'Dizinler',
'Indexes have been altered.' => 'Dizinler değiştirildi.',
'Alter indexes' => 'Dizinleri değiştir',
'Indexes' => 'İndeksler',
'Indexes have been altered.' => 'İndeksler değiştirildi.',
'Alter indexes' => 'İndeksleri değiştir',
'Add next' => 'Bundan sonra ekle',
'Index Type' => 'Dizin Türü',
'Index Type' => 'İndex Türü',
'Column (length)' => 'Kolon (uzunluğu)',
'Foreign keys' => 'Dış anahtarlar',
@@ -221,25 +239,29 @@ $translations = array(
'anywhere' => 'hiçbir yerde',
'Search data in tables' => 'Tablolarda veri ara',
'Sort' => 'Sırala',
'descending' => 'azalan',
'Limit' => 'sınır',
'Text length' => 'Yazı uzunluğu',
'Action' => 'Eylem',
'Full table scan' => 'Tam tablo tarama',
'descending' => 'Azalan',
'Limit' => 'Limit',
'Limit rows' => 'Satır Limiti',
'Text length' => 'Metin Boyutu',
'Action' => 'İşlem',
'Full table scan' => 'Tam tablo taraması',
'Unable to select the table' => 'Tablo seçilemedi',
'No rows.' => 'Kayıt yok.',
'%d / ' => '%d / ',
'%d row(s)' => array('%d kayıt', '%d adet kayıt'),
'Page' => 'Sayfa',
'last' => 'son',
'Load more data' => 'Daha fazla veri yükle',
'Loading' => 'Yükleniyor',
'whole result' => 'tüm sonuç',
'Whole result' => 'Tüm sonuç',
'%d byte(s)' => array('%d bayt', '%d bayt'),
'Import' => 'İçeri Aktar',
'%d row(s) have been imported.' => array('%d kayıt içeri aktarıldı.', '%d adet kayıt içeri aktarıldı.'),
'File must be in UTF-8 encoding.' => 'Dosya UTF-8 kodlamasında olmalıdır.',
// in-place editing in select
'Modify' => 'Düzenle',
'Ctrl+click on a value to modify it.' => 'Bir değeri değiştirmek için üzerine Ctrl+tıklayın.',
'Use edit link to modify this value.' => 'Değeri değiştirmek için düzenleme bağlantısını kullanın.',
@@ -258,8 +280,10 @@ $translations = array(
'Save' => 'Kaydet',
'Save and continue edit' => 'Kaydet ve düzenlemeye devam et',
'Save and insert next' => 'Kaydet ve sonrakini ekle',
'Selected' => 'Seçildi',
'Clone' => 'Kopyala',
'Delete' => 'Sil',
'You have no privileges to update this table.' => 'Bu tabloyu güncellemek için yetkiniz yok.',
'E-mail' => 'E-posta',
'From' => 'Gönderen',

View File

@@ -230,7 +230,7 @@ $translations = array(
'%d row(s)' => array('%d рядок', '%d рядки', '%d рядків'),
'Page' => 'Сторінка',
'last' => 'остання',
'whole result' => 'весь результат',
'Whole result' => 'Весь результат',
'%d byte(s)' => array('%d байт', '%d байта', '%d байтів'),
'Import' => 'Імпортувати',
@@ -268,7 +268,7 @@ $translations = array(
// data type descriptions
'Numbers' => 'Числа',
'Date and time' => 'Дата і час',
'Strings' => 'Радки',
'Strings' => 'Рядки',
'Binary' => 'Двійкові',
'Lists' => 'Списки',
'Network' => 'Мережа',

View File

@@ -12,7 +12,7 @@ $translations = array(
'Logout successful.' => 'Đã thoát xong.',
'Invalid credentials.' => 'Tài khoản sai.',
'Too many unsuccessful logins, try again in %d minute(s).' => 'Bạn gõ sai tài khoản quá nhiều lần, hãy thử lại sau %d phút nữa.',
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => 'Mật khẩu đã hết hạn. <a href="https://www.adminer.org/en/extension/" target="_blank">Thử cách làm</a> để giữ cố định.',
'Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.' => 'Mật khẩu đã hết hạn. <a href="https://www.adminer.org/en/extension/"%s>Thử cách làm</a> để giữ cố định.',
'Language' => 'Ngôn ngữ',
'Invalid CSRF token. Send the form again.' => 'Mã kiểm tra CSRF sai, hãy nhập lại biểu mẫu.',
'No extension' => 'Không có phần mở rộng',
@@ -206,8 +206,8 @@ $translations = array(
'ON UPDATE' => 'Khi cập nhật',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => 'Cột gốc và cột đích phải cùng kiểu, phải đặt chỉ mục trong cột đích và dữ liệu tham chiếu phải tồn tại.',
'Triggers' => 'xx',
'Add trigger' => 'xx',
'Triggers' => 'Phản xạ',
'Add trigger' => 'Thêm phản xạ',
'Trigger has been dropped.' => 'Đã xoá phản xạ.',
'Trigger has been altered.' => 'Đã sửa phản xạ.',
'Trigger has been created.' => 'Đã tạo phản xạ.',
@@ -238,7 +238,7 @@ $translations = array(
'last' => 'cuối',
'Load more data' => 'Xem thêm dữ liệu',
'Loading' => 'Đang nạp',
'whole result' => 'toàn bộ kết quả',
'Whole result' => 'Toàn bộ kết quả',
'%d byte(s)' => '%d byte(s)',
'Import' => 'Nhập khẩu',
@@ -308,12 +308,12 @@ $translations = array(
'Schema has been dropped.' => 'Đã xoá schema.',
'Schema has been created.' => 'Đã tạo schema.',
'Schema has been altered.' => 'Đã thay đổi schema.',
'Schema' => 'schema',
'Invalid schema.' => 'Schema khong hợp lệ.',
'Schema' => 'Schema',
'Invalid schema.' => 'Schema không hợp lệ.',
// PostgreSQL sequences support
'Sequences' => 'Dãy số',
'Create sequence' => 'Tạo đãy số',
'Create sequence' => 'Tạo dãy số',
'Sequence has been dropped.' => 'Dãy số đã bị xoá.',
'Sequence has been created.' => 'Đã tạo dãy số.',
'Sequence has been altered.' => 'Đã sửa dãy số.',

View File

@@ -8,20 +8,26 @@ $translations = array(
'Permanent login' => 'Xx',
'Login' => 'Xx',
'Logout' => 'Xx',
'Logged as: %s' => 'Xx',
'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>.',
'Invalid credentials.' => 'Xx.',
'<a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to use SQLite.' => 'Xx.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Xx.', 'Xx.'),
'Master password expired. <a href="https://www.adminer.org/en/extension/" target="_blank">Implement</a> %s method to make it permanent.' => '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>.',
'Database does not support password.' => 'Xx.',
'Too many unsuccessful logins, try again in %d minute(s).' => array('Xx %d.', 'Xx %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>Xx</a> %s xx.',
'Language' => 'Xx',
'Invalid CSRF token. Send the form again.' => 'Xx.',
'If you did not send this request from Adminer then close this page.' => 'Xx.',
'No extension' => 'Xx',
'None of the supported PHP extensions (%s) are available.' => 'Xx.',
'None of the supported PHP extensions (%s) are available.' => 'Xx (%s).',
'Connecting to privileged ports is not allowed.' => 'Xx.',
'Disable %s or enable %s or %s extensions.' => 'Xx %s xx %s xx %s xx.',
'Session support must be enabled.' => 'Xx.',
'Session expired, please login again.' => 'Xx.',
'%s version: %s through PHP extension %s' => 'Xx',
'The action will be performed after successful login with the same credentials.' => 'Xx.',
'%s version: %s through PHP extension %s' => '%s xx: %s xx %s',
'Refresh' => 'Xx',
// text direction - 'ltr' or 'rtl'
@@ -39,40 +45,38 @@ $translations = array(
'Revoke' => 'Xx',
'Process list' => 'Xx',
'%d process(es) have been killed.' => array('Xx.', 'Xx.'),
'%d process(es) have been killed.' => array('%d xx.', '%d xx.'),
'Kill' => 'Xx',
'Variables' => 'Xx',
'Status' => 'Xx',
'Replication' => 'Xx',
'Master status' => 'Xx',
'Slave status' => 'Xx',
'SQL command' => 'Xx',
'%d query(s) executed OK.' => array('Xx.', 'Xx.'),
'Query executed OK, %d row(s) affected.' => array('Xx.', 'Xx.'),
'%d query(s) executed OK.' => array('%d xx.', '%d xx.'),
'Query executed OK, %d row(s) affected.' => array('Xx, %d.', 'Xx, %d.'),
'No commands to execute.' => 'Xx.',
'Error in query' => 'Xx',
'Unknown error.' => 'Xx.',
'Warnings' => 'Xx',
'ATTACH queries are not supported.' => 'Xx.',
'Execute' => 'Xx',
'Stop on error' => 'Xx',
'Show only errors' => 'Xx',
// sprintf() format for time of the command
'%.3f s' => 'xx',
'%.3f s' => '%.3f xx',
'History' => 'Xx',
'Clear' => 'Xx',
'Edit all' => 'Xx',
'File upload' => 'Xx',
'From server' => 'Xx',
'Webserver file %s' => 'Xx',
'Webserver file %s' => 'Xx %s',
'Run file' => 'Xx',
'File does not exist.' => 'Xx.',
'File uploads are disabled.' => 'Xx.',
'Unable to upload a file.' => 'Xx.',
'Maximum allowed file size is %sB.' => 'Xx.',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Xx.',
'Maximum allowed file size is %sB.' => 'Xx %sB.',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Xx %s.',
'You can upload a big SQL file via FTP and import it from server.' => 'Xx.',
'You are offline.' => 'Xx.',
@@ -86,6 +90,7 @@ $translations = array(
'Database' => 'Xx',
'database' => 'xx',
'DB' => 'XX',
'Use' => 'Xx',
'Select database' => 'Xx',
'Invalid database.' => 'Xx.',
@@ -110,7 +115,7 @@ $translations = array(
'Index Length' => 'Xx',
'Data Free' => 'Xx',
'Rows' => 'Xx',
'%d in total' => 'xx',
'%d in total' => '%d xx',
'Analyze' => 'Xx',
'Optimize' => 'Xx',
'Vacuum' => 'Xx',
@@ -123,9 +128,10 @@ $translations = array(
'Tables have been moved.' => 'Xx.',
'Copy' => 'Xx',
'Tables have been copied.' => 'Xx.',
'overwrite' => 'xx',
'Routines' => 'Xx',
'Routine has been called, %d row(s) affected.' => array('Xx.', 'Xx.'),
'Routine has been called, %d row(s) affected.' => array('Xx, %d.', 'Xx, %d.'),
'Call' => 'Xx',
'Parameter name' => 'Xx',
'Create procedure' => 'Xx',
@@ -174,13 +180,14 @@ $translations = array(
'Default value' => 'Xx',
'Default values' => 'Xx',
'Drop' => 'Xx',
'Are you sure?' => 'Xx',
'Drop %s?' => 'Xx %s?',
'Are you sure?' => 'Xx?',
'Size' => 'Xx',
'Compute' => 'Xx',
'Move up' => 'Xx',
'Move down' => 'Xx',
'Remove' => 'Xx',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Xx.',
'Maximum number of allowed fields exceeded. Please increase %s.' => 'Xx %s.',
'Partition by' => 'Xx',
'Partitions' => 'Xx',
@@ -246,17 +253,17 @@ $translations = array(
'Full table scan' => 'Xx',
'Unable to select the table' => 'Xx',
'No rows.' => 'Xx.',
'%d / ' => 'xx',
'%d row(s)' => array('xx', 'xx'),
'%d / ' => '%d / ',
'%d row(s)' => array('%d xx', '%d xx'),
'Page' => 'Xx',
'last' => 'xx',
'Load more data' => 'Xx',
'Loading' => 'Xx',
'whole result' => 'xx',
'%d byte(s)' => array('xx', 'xx'),
'Whole result' => 'Xx',
'%d byte(s)' => array('%d xx', '%d xx'),
'Import' => 'Xx',
'%d row(s) have been imported.' => array('Xx.', 'Xx.'),
'%d row(s) have been imported.' => array('%d xx.', '%d xx.'),
'File must be in UTF-8 encoding.' => 'Xx.',
// in-place editing in select
@@ -265,10 +272,10 @@ $translations = array(
'Use edit link to modify this value.' => 'Xx.',
// %s can contain auto-increment value
'Item%s has been inserted.' => 'Xx.',
'Item%s has been inserted.' => 'Xx%s.',
'Item has been deleted.' => 'Xx.',
'Item has been updated.' => 'Xx.',
'%d item(s) have been affected.' => array('Xx.', 'Xx.'),
'%d item(s) have been affected.' => array('%d xx.', '%d xx.'),
'New item' => 'Xx',
'original' => 'xx',
// label for value '' in enum data type
@@ -289,7 +296,7 @@ $translations = array(
'Subject' => 'Xx',
'Attachments' => 'Xx',
'Send' => 'Xx',
'%d e-mail(s) have been sent.' => array('Xx.', 'Xx.'),
'%d e-mail(s) have been sent.' => array('%d xx.', '%d xx.'),
// data type descriptions
'Numbers' => 'Xx',
@@ -314,7 +321,7 @@ $translations = array(
// general SQLite error in create, drop or rename database
'File exists.' => 'Xx.',
'Please use one of the extensions %s.' => 'Xx.',
'Please use one of the extensions %s.' => 'Xx %s.',
// PostgreSQL and MS SQL schema support
'Alter schema' => 'Xx',

View File

@@ -1,119 +1,230 @@
<?php
$translations = array(
'Login' => '登入',
'Logout successful.' => '成功登出。',
'Invalid credentials.' => '無效的憑證。',
// label for database system selection (MySQL, SQLite, ...)
'System' => '資料庫系統',
'Server' => '伺服器',
'Username' => '帳號',
'Password' => '密碼',
'Permanent login' => '永久登入',
'Login' => '登入',
'Logout' => '登出',
'Logged as: %s' => '登錄為: %s',
'Logout successful.' => '成功登出。',
'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>.',
'Invalid credentials.' => '無效的憑證。',
'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 方法讓它永久化。',
'Language' => '語言',
'Invalid CSRF token. Send the form again.' => '無效的 CSRF token。請重新發送表單。',
'If you did not send this request from Adminer then close this page.' => '如果您並沒有從Adminer發送請求請關閉此頁面。',
'No extension' => '無擴充模組',
'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 必須被啟用。',
'Session expired, please login again.' => 'Session 已過期,請重新登入。',
'The action will be performed after successful login with the same credentials.' => '此操作將在成功使用相同的憑據登錄後執行。',
'%s version: %s through PHP extension %s' => '%s 版本:%s 透過 PHP 擴充模組 %s',
'Refresh' => '重新載入',
// text direction - 'ltr' or 'rtl'
'ltr' => 'ltr',
'Privileges' => '權限',
'Create user' => '建立使用者',
'User has been dropped.' => '已刪除使用者。',
'User has been altered.' => '已修改使用者。',
'User has been created.' => '已建立使用者。',
'Hashed' => 'Hashed',
'Column' => '欄位',
'Routine' => '程序',
'Grant' => '授權',
'Revoke' => '廢除',
'Process list' => '處理程序列表',
'%d process(es) have been killed.' => '%d 個 Process(es) 被終止',
'Kill' => '終止',
'Variables' => '變數',
'Status' => '狀態',
'SQL command' => 'SQL 命令',
'%d query(s) executed OK.' => '已順利執行 %d 個查詢。',
'Query executed OK, %d row(s) affected.' => '執行查詢 OK%d 行受影響。',
'No commands to execute.' => '沒有命令可執行。',
'Error in query' => '查詢發生錯誤',
'Unknown error.' => '未知錯誤。',
'Warnings' => '警告',
'ATTACH queries are not supported.' => '不支援ATTACH查詢。',
'Execute' => '執行',
'Stop on error' => '出錯時停止',
'Show only errors' => '僅顯示錯誤訊息',
// sprintf() format for time of the command
'%.3f s' => '%.3f 秒',
'History' => '紀錄',
'Clear' => '清除',
'Edit all' => '編輯全部',
'File upload' => '檔案上傳',
'From server' => '從伺服器',
'Webserver file %s' => '網頁伺服器檔案 %s',
'Run file' => '執行檔案',
'File does not exist.' => '檔案不存在',
'File uploads are disabled.' => '檔案上傳已經被停用。',
'Unable to upload a file.' => '無法上傳檔案。',
'Maximum allowed file size is %sB.' => '允許的檔案上限大小為 %sB',
'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.' => '您可以通過FTP上傳大型SQL檔並從伺服器導入。',
'You are offline.' => '您離線了。',
'Export' => '匯出',
'Output' => '輸出',
'open' => '打開',
'save' => '儲存',
'Saving' => '保存中',
'Format' => '格式',
'Data' => '資料',
'Database' => '資料庫',
'database' => '資料庫',
'DB' => '資料庫',
'Use' => '使用',
'Select database' => '選擇資料庫',
'Invalid database.' => '無效的資料庫。',
'Table has been altered.' => '資料表已修改。',
'Table has been created.' => '資料表已修改。',
'Alter table' => '修改資料表',
'Create table' => '建立資料表',
'Table name' => '資料表名稱',
'engine' => '引擎',
'collation' => '校對',
'Column name' => '列名',
'Type' => '類型',
'Length' => '長度',
'Auto Increment' => '自動遞增',
'Options' => '選項',
'Save' => '儲存',
'Drop' => '刪除',
'Database has been dropped.' => '資料庫已刪除。',
'Databases have been dropped.' => '資料庫已刪除。',
'Database has been created.' => '已建立資料庫。',
'Database has been renamed.' => '已重新命名資料庫。',
'Database has been altered.' => '已修改資料庫。',
'Alter database' => '修改資料庫',
'Create database' => '建立資料庫',
'SQL command' => 'SQL命令',
'Logout' => '登出',
'database' => '資料庫',
'Use' => '使用',
'No tables.' => '沒有資料表。',
'select' => '選擇',
'Item has been updated.' => '已更新項目。',
'Item%s has been inserted.' => '已新增項目%s。',
'Edit' => '編輯',
'Insert' => '新增',
'Save and insert next' => '儲存並新增下一筆',
'Delete' => '刪除',
'Database' => '資料',
'Database schema' => '資料庫結構',
// link to current database schema layout
'Permanent link' => '永久連結',
// thousands separator - must contain single byte
',' => ',',
'0123456789' => '0123456789',
'Engine' => '引擎',
'Collation' => '校對',
'Data Length' => '資料長度',
'Index Length' => '索引長度',
'Data Free' => '資料空閒',
'Rows' => '行數',
'%d in total' => '總共 %d 個',
'Analyze' => '分析',
'Optimize' => '最佳化',
'Vacuum' => '整理Vacuum',
'Check' => '檢查',
'Repair' => '修復',
'Truncate' => '清空',
'Tables have been truncated.' => '已清空資料表。',
'Move to other database' => '轉移到其它資料庫',
'Move' => '轉移',
'Tables have been moved.' => '已轉移資料表。',
'Copy' => '複製',
'Tables have been copied.' => '資料表已經複製',
'Routines' => '程序',
'Indexes have been altered.' => '已修改索引。',
'Indexes' => '索引',
'Alter indexes' => '修改索引',
'Add next' => '新增下一筆',
'Language' => '語言',
'Select' => '選擇',
'New item' => '新增項目',
'Search' => '搜尋',
'Sort' => '排序',
'descending' => '降冪(遞減)',
'Limit' => '限定',
'No rows.' => '沒有行。',
'Action' => '動作',
'edit' => '編輯',
'Page' => '頁',
'Query executed OK, %d row(s) affected.' => '執行查詢OK%d行受影響',
'Error in query' => '查詢發生錯誤',
'Execute' => '執行',
'Table' => '資料表',
'Foreign keys' => '外來鍵',
'Triggers' => '觸發器',
'View' => '檢視表',
'Unable to select the table' => '無法選擇該資料表',
'Invalid CSRF token. Send the form again.' => '無效的 CSRF token。請重新發送表單。',
'Comment' => '註解',
'Default values' => '預設值',
'%d byte(s)' => '%d byte(s)',
'No commands to execute.' => '沒有命令可執行。',
'Unable to upload a file.' => '無法上傳檔案。',
'File upload' => '檔案上傳',
'File uploads are disabled.' => '檔案上傳已經被停用。',
'Routine has been called, %d row(s) affected.' => '程序已被執行,%d行被影響',
'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 必須被啟用。',
'Session expired, please login again.' => 'Session 已過期,請重新登入。',
'Text length' => 'Text 長度',
'Foreign key has been dropped.' => '已刪除外來鍵。',
'Foreign key has been altered.' => '修改外來鍵。',
'Foreign key has been created.' => '已建立外來鍵。',
'Foreign key' => '外來鍵',
'Target table' => '目標資料表',
'Change' => '修改',
'Source' => '來源',
'Target' => '目標',
'Add column' => '新增資料列',
'Alter' => '修改',
'Add foreign key' => '新增外來鍵',
'ON DELETE' => 'ON DELETE',
'ON UPDATE' => 'ON UPDATE',
'Index Type' => '索引類型',
'Column (length)' => '列(長度)',
'Parameter name' => '參數名稱',
'Create procedure' => '建立預存程序',
'Create function' => '建立函式',
'Routine has been dropped.' => '已刪除程序。',
'Routine has been altered.' => '已修改子程序。',
'Routine has been created.' => '已建立子程序。',
'Alter function' => '修改函式',
'Alter procedure' => '修改預存程序',
'Return type' => '回傳類型',
'Events' => '事件',
'Event has been dropped.' => '已刪除事件。',
'Event has been altered.' => '已修改事件。',
'Event has been created.' => '已建立事件。',
'Alter event' => '修改事件',
'Create event' => '建立事件',
'At given time' => '在指定時間',
'Every' => '',
'Schedule' => '排程',
'Start' => '開始',
'End' => '結束',
'On completion preserve' => '在完成後儲存',
'Tables' => '資料表',
'Tables and views' => '資料表和檢視表',
'Table' => '資料表',
'No tables.' => '沒有資料表。',
'Alter table' => '修改資料表',
'Create table' => '建立資料表',
'Table has been dropped.' => '已經刪除資料表。',
'Tables have been dropped.' => '已經將資料表刪除。',
'Tables have been optimized.' => '已優化資料表。',
'Table has been altered.' => '資料表已修改。',
'Table has been created.' => '資料表已建立。',
'Table name' => '資料表名稱',
'Show structure' => '顯示結構',
'engine' => '引擎',
'collation' => '校對',
'Column name' => '欄位名稱',
'Type' => '類型',
'Length' => '長度',
'Auto Increment' => '自動遞增',
'Options' => '選項',
'Comment' => '註解',
'Default value' => '預設值',
'Default values' => '預設值',
'Drop' => '刪除',
'Drop %s?' => '刪除 %s?',
'Are you sure?' => '你確定嗎?',
'Size' => '大小',
'Compute' => '計算',
'Move up' => '上移',
'Move down' => '下移',
'Remove' => '移除',
'Maximum number of allowed fields exceeded. Please increase %s.' => '超過允許的字段數量的最大值。請增加 %s。',
'Partition by' => '分區類型',
'Partitions' => '分區',
'Partition name' => '分區名稱',
'Values' => '值',
'View' => '檢視表',
'Materialized view' => '物化視圖',
'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 個 Process(es) 被終止',
'Kill' => '終止',
'Parameter name' => '參數名稱',
'Database schema' => '資料庫架構',
'Create procedure' => '建立預存程序',
'Create function' => '建立函數',
'Routine has been dropped.' => '已刪除程序。',
'Routine has been altered.' => '已修改子程序。',
'Routine has been created.' => '已建立子程序。',
'Alter function' => '修改函數',
'Alter procedure' => '修改過程',
'Return type' => '回傳類型',
'Indexes' => '索引',
'Indexes have been altered.' => '已修改索引。',
'Alter indexes' => '修改索引',
'Add next' => '新增下一筆',
'Index Type' => '索引類型',
'Column (length)' => '欄位(長度)',
'Foreign keys' => '外來鍵',
'Foreign key' => '外來鍵',
'Foreign key has been dropped.' => '已刪除外來鍵。',
'Foreign key has been altered.' => '修改外來鍵。',
'Foreign key has been created.' => '已建立外來鍵。',
'Target table' => '目標資料表',
'Change' => '變更',
'Source' => '來源',
'Target' => '目標',
'Add column' => '新增欄位',
'Alter' => '修改',
'Add foreign key' => '新增外來鍵',
'ON DELETE' => 'ON DELETE',
'ON UPDATE' => 'ON UPDATE',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => '來源列和目標列必須具有相同的資料類型,在目標列上必須有一個索引並且引用的資料必須存在。',
'Triggers' => '觸發器',
'Add trigger' => '建立觸發器',
'Trigger has been dropped.' => '已刪除觸發器。',
'Trigger has been altered.' => '已修改觸發器。',
@@ -122,146 +233,116 @@ $translations = array(
'Create trigger' => '建立觸發器',
'Time' => '時間',
'Event' => '事件',
'%s version: %s through PHP extension %s' => '%s版本%s 透過PHP擴充模組 %s',
'%d row(s)' => '%d行',
'Remove' => '移除',
'Are you sure?' => '你確定嗎?',
'Privileges' => '權限',
'Create user' => '建立使用者',
'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 的設定值。',
'Move up' => '上移',
'Move down' => '下移',
'Export' => '匯出',
'Tables' => '資料表',
'Data' => '資料',
'Output' => '輸出',
'open' => '打開',
'save' => '儲存',
'Format' => '格式',
'Functions' => '函數',
'Name' => '名稱',
'select' => '選擇',
'Select' => '選擇',
'Select data' => '選擇資料',
'Functions' => '函式',
'Aggregation' => '集合',
'Event has been dropped.' => '已刪除事件。',
'Event has been altered.' => '已修改事件。',
'Event has been created.' => '已建立事件。',
'Alter event' => '修改事件',
'Create event' => '建立事件',
'Start' => '開始',
'End' => '結束',
'Every' => '每',
'Status' => '狀態',
'On completion preserve' => '在完成後儲存',
'Events' => '事件',
'Schedule' => '排程',
'At given time' => '在指定時間',
'Tables have been truncated.' => '已清空資料表。',
'Tables have been moved.' => '已轉移資料表。',
'Tables and views' => '資料表和檢視表',
'Engine' => '引擎',
'Collation' => '校對',
'Data Length' => '資料長度',
'Index Length' => '索引長度',
'Data Free' => '資料空閒',
'Rows' => '行數',
',' => ',',
'0123456789' => '0123456789',
'Analyze' => '分析',
'Optimize' => '最佳化',
'Check' => '檢查',
'Repair' => '修復',
'Truncate' => '清空',
'Move to other database' => '轉移到其它資料庫',
'Move' => '轉移',
'Save and continue edit' => '儲存並繼續編輯',
'original' => '原始',
'%d item(s) have been affected.' => '%d個項目受到影響。',
'whole result' => '所有結果',
'Tables have been dropped.' => '已經將資料表刪除。',
'Clone' => '複製',
'Maximum number of allowed fields exceeded. Please increase %s.' => '超過允許的字段數量的最大值。請增加%s。',
'Partition by' => '分區類型',
'Partitions' => '分區',
'Partition name' => '分區名稱',
'Values' => '值',
'%d row(s) have been imported.' => '已匯入%d行。',
'Search' => '搜尋',
'anywhere' => '任意位置',
'Search data in tables' => '在資料庫搜尋',
'Sort' => '排序',
'descending' => '降冪 (遞減)',
'Limit' => '限定',
'Limit rows' => '限制行數',
'Text length' => 'Text 長度',
'Action' => '動作',
'Full table scan' => '全資料表掃描',
'Unable to select the table' => '無法選擇該資料表',
'No rows.' => '沒有資料行。',
'%d / ' => '%d / ',
'%d row(s)' => '%d 行',
'Page' => '頁',
'last' => '最後一頁',
'Load more data' => '載入更多資料',
'Loading' => '載入中',
'Whole result' => '所有結果',
'%d byte(s)' => '%d byte(s)',
'Import' => '匯入',
'Stop on error' => '出錯時停止',
'%.3f s' => '%.3f秒',
'$1-$3-$5' => '$1.$3.$5',
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
'History' => '紀錄',
'Variables' => '變數',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => '來源列和目標列必須具有相同的資料類型,在目標列上必須有一個索引並且引用的資料必須存在。',
'Relations' => '關聯',
'Run file' => '執行檔案',
'Clear' => '清除',
'Maximum allowed file size is %sB.' => '允許的檔案上限大小為%sB',
'%d row(s) have been imported.' => '已匯入 %d 行。',
'File must be in UTF-8 encoding.' => '檔必須使用UTF-8編碼。',
// in-place editing in select
'Modify' => '修改',
'Ctrl+click on a value to modify it.' => '按住Ctrl並按一下某個值進行修改。',
'Use edit link to modify this value.' => '使用編輯連結來修改。',
// %s can contain auto-increment value
'Item%s has been inserted.' => '已新增項目 %s。',
'Item has been deleted.' => '該項目已被刪除',
'Item has been updated.' => '已更新項目。',
'%d item(s) have been affected.' => '%d 個項目受到影響。',
'New item' => '新增項目',
'original' => '原始',
// label for value '' in enum data type
'empty' => '空值',
'edit' => '編輯',
'Edit' => '編輯',
'Insert' => '新增',
'Save' => '儲存',
'Save and continue edit' => '儲存並繼續編輯',
'Save and insert next' => '儲存並新增下一筆',
'Selected' => '已選中',
'Clone' => '複製',
'Delete' => '刪除',
'You have no privileges to update this table.' => '您沒有許可權更新這個資料表。',
'E-mail' => '電子郵件',
'From' => '來自',
'Subject' => '主旨',
'Attachments' => '附件',
'Send' => '寄出',
'%d e-mail(s) have been sent.' => '已寄出 %d 封郵件。',
// data type descriptions
'Numbers' => '數字',
'Date and time' => '日期時間',
'Strings' => '字串',
'Binary' => '二進位',
'Lists' => '列表',
'Network' => '網路',
'Geometry' => '幾何',
'Relations' => '關聯',
'Editor' => '編輯器',
'E-mail' => '電子郵件',
'From' => '來自',
'Subject' => '主旨',
'Send' => '寄出',
'%d e-mail(s) have been sent.' => '已寄出 %d 封郵件。',
'Webserver file %s' => '網頁伺服器檔案 %s',
'File does not exist.' => '檔案不存在',
'Item has been deleted.' => '該項目已被刪除',
'%d in total' => '總共 %d 個',
'Permanent login' => '永久登入',
'Table has been dropped.' => '已經刪除資料表。',
'Databases have been dropped.' => '資料庫已刪除。',
'Search data in tables' => '在資料庫搜尋',
'Schema' => '資料表結構',
// date format in Editor: $1 yyyy, $2 yy, $3 mm, $4 m, $5 dd, $6 d
'$1-$3-$5' => '$1.$3.$5',
// hint for date format - use language equivalents for day, month and year shortcuts
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
// hint for time format - use language equivalents for hour, minute and second shortcuts
'HH:MM:SS' => 'HH:MM:SS',
'now' => '在',
'yes' => '',
'no' => '',
// general SQLite error in create, drop or rename database
'File exists.' => '檔案已存在。',
'Please use one of the extensions %s.' => '請使用下列其中一個擴充模組 %s。',
// PostgreSQL and MS SQL schema support
'Alter schema' => '修改資料表結構',
'Create schema' => '建立資料表結構',
'Schema has been dropped.' => '已刪除資料表結構。',
'Schema has been created.' => '已建立資料表結構。',
'Schema has been altered.' => '已修改資料表結構。',
'Schema' => '資料表結構',
'Invalid schema.' => '無效的資料表結構。',
// PostgreSQL sequences support
'Sequences' => '序列',
'Create sequence' => '建立序列',
'Alter sequence' => '修改序列',
'Sequence has been dropped.' => '已刪除序列。',
'Sequence has been created.' => '已建立序列。',
'Sequence has been altered.' => '已修改序列。',
'Alter sequence' => '修改序列',
// PostgreSQL user types support
'User types' => '使用者類型',
'Create type' => '建立類型',
'Alter type' => '修改類型',
'Type has been dropped.' => '已刪除類型。',
'Type has been created.' => '已建立類型。',
'Use edit link to modify this value.' => '使用編輯連結來修改。',
'last' => '最後一頁',
'From server' => '從伺服器',
'System' => '資料庫系統',
'Select data' => '選擇資料',
'Show structure' => '顯示結構',
'empty' => '空值',
'Network' => '網路',
'Geometry' => '幾何',
'File exists.' => '檔案已存在。',
'Attachments' => '附件',
'%d query(s) executed OK.' => '已順利執行 %d 個查詢。',
'Show only errors' => '僅顯示錯誤訊息',
'Refresh' => '重新載入',
'Invalid schema.' => '無效的資料表結構。',
'Please use one of the extensions %s.' => '請使用下列其中一個擴充模組 %s。',
'now' => '現在',
'ltr' => 'ltr',
'Tables have been copied.' => '資料表已經複製',
'Copy' => '複製',
'Permanent link' => '永久連結',
'Edit all' => '編輯全部',
'HH:MM:SS' => 'HH:MM:SS',
'Alter type' => '修改類型',
);

View File

@@ -1,133 +1,38 @@
<?php
$translations = array(
'Login' => '登录',
'Logout successful.' => '注销成功。',
'Invalid credentials.' => '无效凭据。',
// label for database system selection (MySQL, SQLite, ...)
'System' => '系统',
'Server' => '服务器',
'Username' => '用户名',
'Password' => '密码',
'Select database' => '选择数据库',
'Invalid database.' => '无效数据库。',
'Table has been dropped.' => '已删除表。',
'Table has been altered.' => '已修改表。',
'Table has been created.' => '已创建表。',
'Alter table' => '修改表',
'Create table' => '创建表',
'Table name' => '表名',
'engine' => '引擎',
'collation' => '校对',
'Column name' => '字段名',
'Type' => '类型',
'Length' => '长度',
'Auto Increment' => '自动增量',
'Options' => '选项',
'Save' => '保存',
'Drop' => '删除',
'Database has been dropped.' => '已删除数据库。',
'Database has been created.' => '已创建数据库。',
'Database has been renamed.' => '已重命名数据库。',
'Database has been altered.' => '已修改数据库。',
'Alter database' => '修改数据库',
'Create database' => '创建数据库',
'SQL command' => 'SQL命令',
'Logout' => '注销',
'database' => '数据库',
'Use' => '使用',
'No tables.' => '没有表。',
'select' => '选择',
'Item has been deleted.' => '已删除项目。',
'Item has been updated.' => '已更新项目。',
'Item%s has been inserted.' => '已插入项目%s。',
'Edit' => '编辑',
'Insert' => '插入',
'Save and insert next' => '保存并插入下一个',
'Delete' => '删除',
'Database' => '数据库',
'Routines' => '子程序',
'Indexes have been altered.' => '已修改索引。',
'Indexes' => '索引',
'Alter indexes' => '修改索引',
'Add next' => '下一行插入',
'Permanent login' => '保持登录',
'Login' => '登录',
'Logout' => '登出',
'Logged as: %s' => '登录用户:%s',
'Logout successful.' => '成功登出。',
'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>.',
'Invalid credentials.' => '无效凭据。',
'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 方法让它永久化。',
'Language' => '语言',
'Select' => '选择',
'New item' => '新建数据',
'Search' => '搜索',
'Sort' => '排序',
'descending' => '降序',
'Limit' => '范围',
'No rows.' => '无数据。',
'Action' => '动作',
'edit' => '编辑',
'Page' => '页面',
'Query executed OK, %d row(s) affected.' => '查询执行完毕,%d 行受影响。',
'Error in query' => '查询出错',
'Execute' => '执行',
'Table' => '表',
'Foreign keys' => '外键',
'Triggers' => '触发器',
'View' => '视图',
'Unable to select the table' => '不能选择该表',
'Invalid CSRF token. Send the form again.' => '无效 CSRF 令牌。重新发送表单。',
'Comment' => '注释',
'Default values' => '默认值',
'%d byte(s)' => '%d 字节',
'No commands to execute.' => '没有命令被执行。',
'Unable to upload a file.' => '不能上传文件。',
'File upload' => '文件上传',
'File uploads are disabled.' => '文件上传被禁用。',
'Routine has been called, %d row(s) affected.' => '子程序被调用,%d 行被影响。',
'Call' => '调用',
'Invalid CSRF token. Send the form again.' => '无效 CSRF 令牌。请重新发送表单。',
'If you did not send this request from Adminer then close this page.' => '如果您并没有从Adminer发送请求请关闭此页面。',
'No extension' => '没有扩展',
'None of the supported PHP extensions (%s) are available.' => '没有支持的 PHP 扩展可用(%s。',
'Session support must be enabled.' => 'Session 必须被启用。',
'Session expired, please login again.' => 'Session 已过期,请重新登录。',
'Text length' => '文本显示限制',
'Foreign key has been dropped.' => '已删除外键。',
'Foreign key has been altered.' => '已修改外键。',
'Foreign key has been created.' => '已创建外键。',
'Foreign key' => '外键',
'Target table' => '目标表',
'Change' => '修改',
'Source' => '源',
'Target' => '目标',
'Add column' => '增加列',
'Alter' => '修改',
'Add foreign key' => '添加外键',
'ON DELETE' => 'ON DELETE',
'ON UPDATE' => 'ON UPDATE',
'Index Type' => '索引类型',
'Column (length)' => '列(长度)',
'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 个进程被终止',
'Kill' => '终止',
'Parameter name' => '参数名',
'Database schema' => '数据库概要',
'Create procedure' => '创建过程',
'Create function' => '创建函数',
'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.' => '已创建触发器。',
'Alter trigger' => '修改触发器',
'Create trigger' => '创建触发器',
'Time' => '时间',
'Event' => '事件',
'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.' => '此操作将在成功使用相同的凭据登录后执行。',
'%s version: %s through PHP extension %s' => '%s 版本:%s 使用PHP扩展 %s',
'%d row(s)' => '%d 行',
'Remove' => '移除',
'Are you sure?' => '你确定吗?',
'Refresh' => '刷新',
// text direction - 'ltr' or 'rtl'
'ltr' => 'ltr',
'Privileges' => '权限',
'Create user' => '创建用户',
'User has been dropped.' => '已删除用户。',
@@ -138,130 +43,306 @@ $translations = array(
'Routine' => '子程序',
'Grant' => '授权',
'Revoke' => '废除',
'Logged as: %s' => '登录用户:%s',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => '太大的 POST 数据。减少数据或者增加 %s 配置命令。',
'Move up' => '上移',
'Move down' => '下移',
'Process list' => '进程列表',
'%d process(es) have been killed.' => '%d 个进程被终止',
'Kill' => '终止',
'Variables' => '变量',
'Status' => '状态',
'SQL command' => 'SQL命令',
'%d query(s) executed OK.' => '%d 条查询已成功执行。',
'Query executed OK, %d row(s) affected.' => '查询执行完毕,%d 行受影响。',
'No commands to execute.' => '没有命令被执行。',
'Error in query' => '查询出错',
'Unknown error.' => '未知错误。',
'Warnings' => '警告',
'ATTACH queries are not supported.' => '不支持ATTACH查询。',
'Execute' => '执行',
'Stop on error' => '出错时停止',
'Show only errors' => '仅显示错误',
// sprintf() format for time of the command
'%.3f s' => '%.3f 秒',
'History' => '历史',
'Clear' => '清除',
'Edit all' => '编辑全部',
'File upload' => '文件上传',
'From server' => '来自服务器',
'Webserver file %s' => 'Web服务器文件 %s',
'Run file' => '运行文件',
'File does not exist.' => '文件不存在。',
'File uploads are disabled.' => '文件上传被禁用。',
'Unable to upload a file.' => '不能上传文件。',
'Maximum allowed file size is %sB.' => '最多允许的文件大小为 %sB。',
'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.' => '您可以通过FTP上传大型SQL文件并从服务器导入。',
'You are offline.' => '您离线了。',
'Export' => '导出',
'Tables' => '表',
'Data' => '数据',
'Output' => '输出',
'open' => '打开',
'save' => '保存',
'Saving' => '保存中',
'Format' => '格式',
'Functions' => '数',
'Aggregation' => '集合',
'Event has been dropped.' => '已删除事件。',
'Event has been altered.' => '已修改事件。',
'Event has been created.' => '已创建事件。',
'Alter event' => '修改事件',
'Create event' => '创建事件',
'Start' => '开始',
'End' => '结束',
'Every' => '',
'Status' => '状态',
'On completion preserve' => '完成后保存',
'Events' => '事件',
'Schedule' => '调度',
'At given time' => '在指定时间',
'Tables have been truncated.' => '已清空表。',
'Tables have been moved.' => '已转移表。',
'Tables and views' => '表和视图',
'Data' => '数',
'Database' => '数据库',
'database' => '数据库',
'DB' => '数据库',
'Use' => '使用',
'Select database' => '选择数据库',
'Invalid database.' => '无效数据库。',
'Database has been dropped.' => '已删除数据库。',
'Databases have been dropped.' => '已删除数据库。',
'Database has been created.' => '已创建数据库。',
'Database has been renamed.' => '已重命名数据库。',
'Database has been altered.' => '已修改数据库。',
'Alter database' => '修改数据库',
'Create database' => '创建数据库',
'Database schema' => '数据库概要',
// link to current database schema layout
'Permanent link' => '固定链接',
// thousands separator - must contain single byte
',' => ',',
'0123456789' => '0123456789',
'Engine' => '引擎',
'Collation' => '校对',
'Data Length' => '数据长度',
'Index Length' => '索引长度',
'Data Free' => '数据空闲',
'Rows' => '行数',
',' => ',',
'0123456789' => '0123456789',
'%d in total' => '共计 %d',
'Analyze' => '分析',
'Optimize' => '优化',
'Vacuum' => '整理Vacuum',
'Check' => '检查',
'Repair' => '修复',
'Truncate' => '清空',
'Tables have been truncated.' => '已清空表。',
'Move to other database' => '转移到其它数据库',
'Move' => '转移',
'Save and continue edit' => '保存并继续编辑',
'original' => '原始',
'%d item(s) have been affected.' => '%d 个项目受到影响。',
'whole result' => '所有结果',
'Tables have been moved.' => '已转移表。',
'Copy' => '复制',
'Tables have been copied.' => '已复制表。',
'Routines' => '子程序',
'Routine has been called, %d row(s) affected.' => '子程序被调用,%d 行被影响。',
'Call' => '调用',
'Parameter name' => '参数名',
'Create procedure' => '创建过程',
'Create function' => '创建函数',
'Routine has been dropped.' => '已删除子程序。',
'Routine has been altered.' => '已修改子程序。',
'Routine has been created.' => '已创建子程序。',
'Alter function' => '修改函数',
'Alter procedure' => '修改过程',
'Return type' => '返回类型',
'Events' => '事件',
'Event has been dropped.' => '已删除事件。',
'Event has been altered.' => '已修改事件。',
'Event has been created.' => '已创建事件。',
'Alter event' => '修改事件',
'Create event' => '创建事件',
'At given time' => '在指定时间',
'Every' => '每',
'Schedule' => '调度',
'Start' => '开始',
'End' => '结束',
'On completion preserve' => '完成后仍保留',
'Tables' => '表',
'Tables and views' => '表和视图',
'Table' => '表',
'No tables.' => '没有表。',
'Alter table' => '修改表',
'Create table' => '创建表',
'Table has been dropped.' => '已删除表。',
'Tables have been dropped.' => '已删除表。',
'Clone' => '复制',
'Tables have been optimized.' => '已优化表。',
'Table has been altered.' => '已修改表。',
'Table has been created.' => '已创建表。',
'Table name' => '表名',
'Show structure' => '显示结构',
'engine' => '引擎',
'collation' => '校对',
'Column name' => '字段名',
'Type' => '类型',
'Length' => '长度',
'Auto Increment' => '自动增量',
'Options' => '选项',
'Comment' => '注释',
'Default value' => '默认值',
'Default values' => '默认值',
'Drop' => '删除',
'Drop %s?' => '删除 %s?',
'Are you sure?' => '您确定吗?',
'Size' => '大小',
'Compute' => '计算',
'Move up' => '上移',
'Move down' => '下移',
'Remove' => '移除',
'Maximum number of allowed fields exceeded. Please increase %s.' => '超过最多允许的字段数量。请增加 %s。',
'Partition by' => '分区类型',
'Partitions' => '分区',
'Partition name' => '分区名',
'Values' => '值',
'%d row(s) have been imported.' => '%d 行已导入。',
'anywhere' => '任意位置',
'Import' => '导入',
'Stop on error' => '出错时停止',
'%.3f s' => '%.3f 秒',
'$1-$3-$5' => '$1.$3.$5',
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
'History' => '历史',
'Variables' => '变量',
'View' => '视图',
'Materialized view' => '物化视图',
'View has been dropped.' => '已删除视图。',
'View has been altered.' => '已修改视图。',
'View has been created.' => '已创建视图。',
'Alter view' => '修改视图',
'Create view' => '创建视图',
'Indexes' => '索引',
'Indexes have been altered.' => '已修改索引。',
'Alter indexes' => '修改索引',
'Add next' => '下一行插入',
'Index Type' => '索引类型',
'Column (length)' => '列(长度)',
'Foreign keys' => '外键',
'Foreign key' => '外键',
'Foreign key has been dropped.' => '已删除外键。',
'Foreign key has been altered.' => '已修改外键。',
'Foreign key has been created.' => '已创建外键。',
'Target table' => '目标表',
'Change' => '修改',
'Source' => '源',
'Target' => '目标',
'Add column' => '增加列',
'Alter' => '修改',
'Add foreign key' => '添加外键',
'ON DELETE' => 'ON DELETE',
'ON UPDATE' => 'ON UPDATE',
'Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.' => '源列和目标列必须具有相同的数据类型,在目标列上必须有一个索引并且引用的数据必须存在。',
'Relations' => '关联信息',
'Run file' => '运行文件',
'Clear' => '清除',
'Maximum allowed file size is %sB.' => '最多允许的文件大小为 %sB',
'Triggers' => '触发器',
'Add trigger' => '创建触发器',
'Trigger has been dropped.' => '已删除触发器。',
'Trigger has been altered.' => '已修改触发器。',
'Trigger has been created.' => '已创建触发器。',
'Alter trigger' => '修改触发器',
'Create trigger' => '创建触发器',
'Time' => '时间',
'Event' => '事件',
'Name' => '名称',
'select' => '选择',
'Select' => '选择',
'Select data' => '选择数据',
'Functions' => '函数',
'Aggregation' => '集合',
'Search' => '搜索',
'anywhere' => '任意位置',
'Search data in tables' => '在表中搜索数据',
'Sort' => '排序',
'descending' => '降序',
'Limit' => '范围',
'Limit rows' => '限制行数',
'Text length' => '文本显示限制',
'Action' => '动作',
'Full table scan' => '全表扫描',
'Unable to select the table' => '不能选择该表',
'No rows.' => '无数据。',
'%d / ' => '%d / ',
'%d row(s)' => '%d 行',
'Page' => '页面',
'last' => '最后',
'Load more data' => '加载更多数据',
'Loading' => '加载中',
'Whole result' => '所有结果',
'%d byte(s)' => '%d 字节',
'Import' => '导入',
'%d row(s) have been imported.' => '%d 行已导入。',
'File must be in UTF-8 encoding.' => '文件必须使用UTF-8编码。',
// in-place editing in select
'Modify' => '修改',
'Ctrl+click on a value to modify it.' => '按住Ctrl并单击某个值进行修改。',
'Use edit link to modify this value.' => '使用编辑链接修改该值。',
// %s can contain auto-increment value
'Item%s has been inserted.' => '已插入项目%s。',
'Item has been deleted.' => '已删除项目。',
'Item has been updated.' => '已更新项目。',
'%d item(s) have been affected.' => '%d 个项目受到影响。',
'New item' => '新建数据',
'original' => '原始',
// label for value '' in enum data type
'empty' => '空',
'edit' => '编辑',
'Edit' => '编辑',
'Insert' => '插入',
'Save' => '保存',
'Save and continue edit' => '保存并继续编辑',
'Save and insert next' => '保存并插入下一个',
'Selected' => '已选中',
'Clone' => '复制',
'Delete' => '删除',
'You have no privileges to update this table.' => '您没有权限更新这个表。',
'E-mail' => '电子邮件',
'From' => '来自',
'Subject' => '主题',
'Attachments' => '附件',
'Send' => '发送',
'%d e-mail(s) have been sent.' => '%d 封邮件已发送。',
// data type descriptions
'Numbers' => '数字',
'Date and time' => '日期时间',
'Strings' => '字符串',
'Binary' => '二进制',
'Lists' => '列表',
'Network' => '网络',
'Geometry' => '几何图形',
'Relations' => '关联信息',
'Editor' => '编辑器',
'E-mail' => '电子邮件',
'From' => '来自',
'Subject' => '主题',
'Send' => '发送',
'%d e-mail(s) have been sent.' => '%d 封邮件已发送。',
'Webserver file %s' => 'Web服务器文件 %s',
'File does not exist.' => '文件不存在。',
'%d in total' => '共计 %d',
'Permanent login' => '保持登录',
'Databases have been dropped.' => '已删除数据库。',
'Search data in tables' => '在表中搜索数据',
'Schema' => '模式',
// date format in Editor: $1 yyyy, $2 yy, $3 mm, $4 m, $5 dd, $6 d
'$1-$3-$5' => '$1.$3.$5',
// hint for date format - use language equivalents for day, month and year shortcuts
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
// hint for time format - use language equivalents for hour, minute and second shortcuts
'HH:MM:SS' => 'HH:MM:SS',
'now' => '现在',
'yes' => '',
'no' => '',
// general SQLite error in create, drop or rename database
'File exists.' => '文件已存在。',
'Please use one of the extensions %s.' => '请使用其中一个扩展:%s。',
// PostgreSQL and MS SQL schema support
'Alter schema' => '修改模式',
'Create schema' => '创建模式',
'Schema has been dropped.' => '已删除模式。',
'Schema has been created.' => '已创建模式。',
'Schema has been altered.' => '已修改模式。',
'Schema' => '模式',
'Invalid schema.' => '非法模式。',
// PostgreSQL sequences support
'Sequences' => '序列',
'Create sequence' => '创建序列',
'Alter sequence' => '修改序列',
'Sequence has been dropped.' => '已删除序列。',
'Sequence has been created.' => '已创建序列。',
'Sequence has been altered.' => '已修改序列。',
'Alter sequence' => '修改序列',
// PostgreSQL user types support
'User types' => '用户类型',
'Create type' => '创建类型',
'Alter type' => '修改类型',
'Type has been dropped.' => '已删除类型。',
'Type has been created.' => '已创建类型。',
'Use edit link to modify this value.' => '使用编辑链接来修改该值。',
'last' => '最后',
'From server' => '来自服务器',
'System' => '系统',
'Select data' => '选择数据',
'Show structure' => '显示结构',
'empty' => '空',
'Network' => '网络',
'Geometry' => '几何图形',
'File exists.' => '文件已存在。',
'Attachments' => '附件',
'%d query(s) executed OK.' => '%d 条查询已成功执行。',
'Show only errors' => '仅显示错误',
'Refresh' => '刷新',
'Invalid schema.' => '非法模式。',
'Please use one of the extensions %s.' => '请使用这些扩展中的一个:%s。',
'now' => '现在',
'ltr' => 'ltr',
'Tables have been copied.' => '表已复制。',
'Copy' => '复制',
'Permanent link' => '固定链接',
'Edit all' => '编辑全部',
'HH:MM:SS' => 'HH:MM:SS',
'Alter type' => '修改类型',
);

View File

@@ -17,7 +17,7 @@ function adminer_object() {
new AdminerDumpXml,
new AdminerDumpAlter,
//~ new AdminerSqlLog("past-" . rtrim(`git describe --tags --abbrev=0`) . ".sql"),
//~ new AdminerEditCalendar("<script type='text/javascript' src='../externals/jquery-ui/jquery-1.4.4.js'></script>\n<script type='text/javascript' src='../externals/jquery-ui/ui/jquery.ui.core.js'></script>\n<script type='text/javascript' src='../externals/jquery-ui/ui/jquery.ui.widget.js'></script>\n<script type='text/javascript' src='../externals/jquery-ui/ui/jquery.ui.datepicker.js'></script>\n<script type='text/javascript' src='../externals/jquery-ui/ui/jquery.ui.mouse.js'></script>\n<script type='text/javascript' src='../externals/jquery-ui/ui/jquery.ui.slider.js'></script>\n<script type='text/javascript' src='../externals/jquery-timepicker/jquery-ui-timepicker-addon.js'></script>\n<link rel='stylesheet' href='../externals/jquery-ui/themes/base/jquery.ui.all.css'>\n<style type='text/css'>\n.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }\n.ui-timepicker-div dl { text-align: left; }\n.ui-timepicker-div dl dt { height: 25px; }\n.ui-timepicker-div dl dd { margin: -25px 0 10px 65px; }\n.ui-timepicker-div td { font-size: 90%; }\n</style>\n", "../externals/jquery-ui/ui/i18n/jquery.ui.datepicker-%s.js"),
//~ new AdminerEditCalendar(script_src("../externals/jquery-ui/jquery-1.4.4.js") . script_src("../externals/jquery-ui/ui/jquery.ui.core.js") . script_src("../externals/jquery-ui/ui/jquery.ui.widget.js") . script_src("../externals/jquery-ui/ui/jquery.ui.datepicker.js") . script_src("../externals/jquery-ui/ui/jquery.ui.mouse.js") . script_src("../externals/jquery-ui/ui/jquery.ui.slider.js") . script_src("../externals/jquery-timepicker/jquery-ui-timepicker-addon.js") . "<link rel='stylesheet' href='../externals/jquery-ui/themes/base/jquery.ui.all.css'>\n<style>\n.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }\n.ui-timepicker-div dl { text-align: left; }\n.ui-timepicker-div dl dt { height: 25px; }\n.ui-timepicker-div dl dd { margin: -25px 0 10px 65px; }\n.ui-timepicker-div td { font-size: 90%; }\n</style>\n", "../externals/jquery-ui/ui/i18n/jquery.ui.datepicker-%s.js"),
//~ new AdminerTinymce("../externals/tinymce/jscripts/tiny_mce/tiny_mce_dev.js"),
//~ new AdminerWymeditor(array("../externals/wymeditor/src/jquery/jquery.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.explorer.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.mozilla.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.opera.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.safari.js")),
new AdminerFileUpload(""),

View File

@@ -15,7 +15,7 @@ hidden_fields_get();
echo "<input type='hidden' name='db' value='" . h(DB) . "'>\n";
echo ($grant ? "" : "<input type='hidden' name='grant' value=''>\n");
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th>" . lang('Username') . "<th>" . lang('Server') . "<th>&nbsp;</thead>\n";
echo "<thead><tr><th>" . lang('Username') . "<th>" . lang('Server') . "<th></thead>\n";
while ($row = $result->fetch_assoc()) {
echo '<tr' . odd() . '><td>' . h($row["User"]) . "<td>" . h($row["Host"]) . '<td><a href="' . h(ME . 'user=' . urlencode($row["User"]) . '&host=' . urlencode($row["Host"])) . '">' . lang('Edit') . "</a>\n";

View File

@@ -1,17 +1,18 @@
<?php
$PROCEDURE = $_GET["procedure"];
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["procedure"]);
$routine = (isset($_GET["function"]) ? "FUNCTION" : "PROCEDURE");
$row = $_POST;
$row["fields"] = (array) $row["fields"];
if ($_POST && !process_fields($row["fields"]) && !$error) {
$orig = routine($_GET["procedure"], $routine);
$temp_name = "$row[name]_adminer_" . uniqid();
drop_create(
"DROP $routine " . idf_escape($PROCEDURE),
"DROP $routine " . routine_id($PROCEDURE, $orig),
create_routine($routine, $row),
"DROP $routine " . idf_escape($row["name"]),
"DROP $routine " . routine_id($row["name"], $row),
create_routine($routine, array("name" => $temp_name) + $row),
"DROP $routine " . idf_escape($temp_name),
"DROP $routine " . routine_id($temp_name, $row),
substr(ME, 0, -1),
lang('Routine has been dropped.'),
lang('Routine has been altered.'),
@@ -24,7 +25,7 @@ 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($PROCEDURE, $routine);
$row = routine($_GET["procedure"], $routine);
$row["name"] = $PROCEDURE;
}
@@ -34,21 +35,23 @@ $routine_languages = routine_languages();
?>
<form action="" method="post" id="form">
<p><?php echo lang('Name'); ?>: <input name="name" value="<?php echo h($row["name"]); ?>" maxlength="64" autocapitalize="off">
<?php echo ($routine_languages ? lang('Language') . ": " . html_select("language", $routine_languages, $row["language"]) : ""); ?>
<p><?php echo lang('Name'); ?>: <input name="name" value="<?php echo h($row["name"]); ?>" data-maxlength="64" autocapitalize="off">
<?php echo ($routine_languages ? lang('Language') . ": " . html_select("language", $routine_languages, $row["language"]) . "\n" : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<div class="scrollable">
<table cellspacing="0" class="nowrap">
<?php
edit_fields($row["fields"], $collations, $routine);
if (isset($_GET["function"])) {
echo "<tr><td>" . lang('Return type');
edit_type("returns", $row["returns"], $collations);
edit_type("returns", $row["returns"], $collations, array(), ($jush == "pgsql" ? array("void", "trigger") : array()));
}
?>
</table>
</div>
<p><?php textarea("definition", $row["definition"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($PROCEDURE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?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; ?>">
</form>

View File

@@ -13,14 +13,16 @@ page_header(lang('Process list'), $error);
?>
<form action="" method="post">
<table cellspacing="0" onclick="tableClick(event);" ondblclick="tableClick(event, true);" class="nowrap checkable">
<div class="scrollable">
<table cellspacing="0" class="nowrap checkable">
<?php
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
// HTML valid because there is always at least one process
$i = -1;
foreach (process_list() as $i => $row) {
if (!$i) {
echo "<thead><tr lang='en'>" . (support("kill") ? "<th>&nbsp;" : "");
echo "<thead><tr lang='en'>" . (support("kill") ? "<th>" : "");
foreach ($row as $key => $val) {
echo "<th>$key" . doc_link(array(
'sql' => "show-processlist.html#processlist_" . strtolower($key),
@@ -37,14 +39,14 @@ foreach (process_list() as $i => $row) {
($jush == "pgsql" && $key == "current_query" && $val != "<IDLE>") ||
($jush == "oracle" && $key == "sql_text" && $val != "")
? "<code class='jush-$jush'>" . shorten_utf8($val, 100, "</code>") . ' <a href="' . h(ME . ($row["db"] != "" ? "db=" . urlencode($row["db"]) . "&" : "") . "sql=" . urlencode($val)) . '">' . lang('Clone') . '</a>'
: nbsp($val)
: h($val)
);
}
echo "\n";
}
?>
</table>
<script type='text/javascript'>tableCheck();</script>
</div>
<p>
<?php
if (support("kill")) {
@@ -54,3 +56,4 @@ if (support("kill")) {
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php echo script("tableCheck();"); ?>

View File

@@ -1,30 +0,0 @@
<?php
page_header(lang('Replication'));
echo "<h3>" . lang('Master status') . doc_link(array("sql" => "show-master-status.html")) . "</h3>\n";
$master_replication_status = replication_status("MASTER");
if (!$master_replication_status) {
echo "<p class='message'>" . lang('No rows.') . "\n";
} else {
echo "<table cellspacing='0'>\n";
foreach ($master_replication_status[0] as $key => $val) {
echo "<tr>";
echo "<th>" . h($key);
echo "<td>" . nbsp($val);
}
echo "</table>\n";
}
$slave_replication_status = replication_status("SLAVE");
if ($slave_replication_status) {
echo "<h3>" . lang('Slave status') . doc_link(array("sql" => "show-slave-status.html")) . "</h3>\n";
foreach ($slave_replication_status[0] as $slave) {
echo "<table cellspacing='0'>\n";
foreach ($slave as $key => $val) {
echo "<tr>";
echo "<th>" . h($key);
echo "<td>" . nbsp($val);
}
echo "</table>\n";
}
}

View File

@@ -48,19 +48,19 @@ foreach (table_status('', true) as $table => $table_status) {
}
?>
<div id="schema" style="height: <?php echo $top; ?>em;" onselectstart="return false;">
<script type="text/javascript">
<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 = document.getElementById('schema').offsetHeight / <?php echo $top; ?>;
var em = qs('#schema').offsetHeight / <?php echo $top; ?>;
document.onmousemove = schemaMousemove;
document.onmouseup = function (ev) {
schemaMouseup(ev, '<?php echo js_escape(DB); ?>');
};
document.onmouseup = partialArg(schemaMouseup, '<?php echo js_escape(DB); ?>');
</script>
<?php
foreach ($schema as $name => $table) {
echo "<div class='table' style='top: " . $table["pos"][0] . "em; left: " . $table["pos"][1] . "em;' onmousedown='schemaMousedown(this, event);'>";
echo "<div class='table' style='top: " . $table["pos"][0] . "em; left: " . $table["pos"][1] . "em;'>";
echo '<a href="' . h(ME) . 'table=' . urlencode($name) . '"><b>' . h($name) . "</b></a>";
echo script("qsl('div').onmousedown = schemaMousedown;");
foreach ($table["fields"] as $field) {
$val = '<span' . type_class($field["type"]) . ' title="' . h($field["full_type"] . ($field["null"] ? " NULL" : '')) . '">' . h($field["field"]) . '</span>';

View File

@@ -27,11 +27,11 @@ if (!$row) {
<form action="" method="post">
<p><input name="name" id="name" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<script type='text/javascript'>focus(document.getElementById('name'));</script>
<?php echo script("focus(qs('#name'));"); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php
if ($_GET["ns"] != "") {
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'" . confirm() . ">\n";
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $_GET["ns"])) . "\n";
}
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">

View File

@@ -4,10 +4,10 @@ header("Content-Type: text/javascript; charset=utf-8");
if ($_GET["script"] == "db") {
$sums = array("Data_length" => 0, "Index_length" => 0, "Data_free" => 0);
foreach (table_status() as $name => $table_status) {
json_row("Comment-$name", nbsp($table_status["Comment"]));
json_row("Comment-$name", h($table_status["Comment"]));
if (!is_view($table_status)) {
foreach (array("Engine", "Collation") as $key) {
json_row("$key-$name", nbsp($table_status[$key]));
json_row("$key-$name", h($table_status[$key]));
}
foreach ($sums + array("Auto_increment" => 0, "Rows" => 0) as $key => $val) {
if ($table_status[$key] != "") {

View File

@@ -4,11 +4,7 @@ $table_status = table_status1($TABLE);
$indexes = indexes($TABLE);
$fields = fields($TABLE);
$foreign_keys = column_foreign_keys($TABLE);
$oid = "";
if ($table_status["Oid"]) {
$oid = ($jush == "sqlite" ? "rowid" : "oid");
$indexes[] = array("type" => "PRIMARY", "columns" => array($oid));
}
$oid = $table_status["Oid"];
parse_str($_COOKIE["adminer_import"], $adminer_import);
$rights = array(); // privilege => 0
@@ -30,10 +26,6 @@ $is_group = count($group) < count($select);
$where = $adminer->selectSearchProcess($fields, $indexes);
$order = $adminer->selectOrderProcess($fields, $indexes);
$limit = $adminer->selectLimitProcess();
$from = ($select ? implode(", ", $select) : "*" . ($oid ? ", $oid" : ""))
. convert_fields($columns, $fields, $select)
. "\nFROM " . table($TABLE);
$group_by = ($group && $is_group ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : "");
if ($_GET["val"] && is_ajax()) {
header("Content-Type: text/plain; charset=utf-8");
@@ -49,6 +41,24 @@ if ($_GET["val"] && is_ajax()) {
exit;
}
$primary = $unselected = null;
foreach ($indexes as $index) {
if ($index["type"] == "PRIMARY") {
$primary = array_flip($index["columns"]);
$unselected = ($select ? $primary : array());
foreach ($unselected as $key => $val) {
if (in_array(idf_escape($key), $select)) {
unset($unselected[$key]);
}
}
break;
}
}
if ($oid && !$primary) {
$primary = $unselected = array($oid => 0);
$indexes[] = array("type" => "PRIMARY", "columns" => array($oid));
}
if ($_POST && !$error) {
$where_check = $where;
if (!$_POST["all"] && is_array($_POST["check"])) {
@@ -59,25 +69,15 @@ if ($_POST && !$error) {
$where_check[] = "((" . implode(") OR (", $checks) . "))";
}
$where_check = ($where_check ? "\nWHERE " . implode(" AND ", $where_check) : "");
$primary = $unselected = null;
foreach ($indexes as $index) {
if ($index["type"] == "PRIMARY") {
$primary = array_flip($index["columns"]);
$unselected = ($select ? $primary : array());
break;
}
}
foreach ((array) $unselected as $key => $val) {
if (in_array(idf_escape($key), $select)) {
unset($unselected[$key]);
}
}
if ($_POST["export"]) {
cookie("adminer_import", "output=" . urlencode($_POST["output"]) . "&format=" . urlencode($_POST["format"]));
dump_headers($TABLE);
$adminer->dumpTable($TABLE, "");
if (!is_array($_POST["check"]) || $unselected === array()) {
$from = ($select ? implode(", ", $select) : "*")
. convert_fields($columns, $fields, $select)
. "\nFROM " . table($TABLE);
$group_by = ($group && $is_group ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : "");
if (!is_array($_POST["check"]) || $primary) {
$query = "SELECT $from$where_check$group_by";
} else {
$union = array();
@@ -108,7 +108,7 @@ if ($_POST && !$error) {
if ($_POST["clone"]) {
$query = "INTO " . table($TABLE) . " (" . implode(", ", array_keys($set)) . ")\nSELECT " . implode(", ", $set) . "\nFROM " . table($TABLE);
}
if ($_POST["all"] || ($unselected === array() && is_array($_POST["check"])) || $is_group) {
if ($_POST["all"] || ($primary && is_array($_POST["check"])) || $is_group) {
$result = ($_POST["delete"]
? $driver->delete($TABLE, $where_check)
: ($_POST["clone"]
@@ -124,8 +124,8 @@ if ($_POST && !$error) {
$result = ($_POST["delete"]
? $driver->delete($TABLE, $where2, 1)
: ($_POST["clone"]
? queries("INSERT" . limit1($query, $where2))
: $driver->update($TABLE, $set, $where2)
? queries("INSERT" . limit1($TABLE, $query, $where2))
: $driver->update($TABLE, $set, $where2, 1)
)
);
if (!$result) {
@@ -165,7 +165,7 @@ if ($_POST && !$error) {
$TABLE,
$set,
" WHERE " . ($where ? implode(" AND ", $where) . " AND " : "") . where_check($unique_idf, $fields),
!($is_group || $unselected === array()),
!$is_group && !$primary,
" "
);
if (!$result) {
@@ -184,7 +184,7 @@ if ($_POST && !$error) {
cookie("adminer_import", "output=" . urlencode($adminer_import["output"]) . "&format=" . urlencode($_POST["separator"]));
$result = true;
$cols = array_keys($fields);
preg_match_all('~(?>"[^"]*"|[^"\\r\\n]+)+~', $file, $matches);
preg_match_all('~(?>"[^"]*"|[^"\r\n]+)+~', $file, $matches);
$affected = count($matches[0]);
$driver->begin();
$separator = ($_POST["separator"] == "csv" ? "," : ($_POST["separator"] == "tsv" ? "\t" : ";"));
@@ -226,7 +226,7 @@ $set = null;
if (isset($rights["insert"]) || !support("table")) {
$set = "";
foreach ((array) $_GET["where"] as $val) {
if (count($foreign_keys[$val["col"]]) == 1 && ($val["op"] == "="
if ($foreign_keys[$val["col"]] && count($foreign_keys[$val["col"]]) == 1 && ($val["op"] == "="
|| (!$val["op"] && !preg_match('~[_%]~', $val["val"])) // LIKE in Editor
)) {
$set .= "&set" . urlencode("[" . bracket_escape($val["col"]) . "]") . "=" . urlencode($val["val"]);
@@ -259,17 +259,29 @@ if (!$columns && support("table")) {
}
$select2 = $select;
$group2 = $group;
if (!$select2) {
$select2[] = "*";
if ($oid) {
$select2[] = $oid;
$convert_fields = convert_fields($columns, $fields, $select);
if ($convert_fields) {
$select2[] = substr($convert_fields, 2);
}
}
$convert_fields = convert_fields($columns, $fields, $select);
if ($convert_fields) {
$select2[] = substr($convert_fields, 2);
foreach ($select as $key => $val) {
$field = $fields[idf_unescape($val)];
if ($field && ($as = convert_field($field))) {
$select2[$key] = "$as AS $val";
}
}
$result = $driver->select($TABLE, $select2, $where, $group, $order, $limit, $page, true);
if (!$is_group && $unselected) {
foreach ($unselected as $key => $val) {
$select2[] = idf_escape($key);
if ($group2) {
$group2[] = idf_escape($key);
}
}
}
$result = $driver->select($TABLE, $select2, $where, $group2, $order, $limit, $page, true);
if (!$result) {
echo "<p class='error'>" . error() . "\n";
@@ -288,7 +300,7 @@ if (!$columns && support("table")) {
}
// use count($rows) without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest)
if ($_GET["page"] != "last" && +$limit && $group && $is_group && $jush == "sql") {
if ($_GET["page"] != "last" && $limit != "" && $group && $is_group && $jush == "sql") {
$found_rows = $connection->result(" SELECT FOUND_ROWS()"); // space to allow mysql.trace_mode
}
@@ -297,14 +309,19 @@ if (!$columns && support("table")) {
} else {
$backward_keys = $adminer->backwardKeys($TABLE, $table_name);
echo "<table id='table' cellspacing='0' class='nowrap checkable' onclick='tableClick(event);' ondblclick='tableClick(event, true);' onkeydown='return editingKeydown(event);'>\n";
echo "<thead><tr>" . (!$group && $select ? "" : "<td><input type='checkbox' id='all-page' onclick='formCheck(this, /check/);' class='jsonly'> <a href='" . h($_GET["modify"] ? remove_from_uri("modify") : $_SERVER["REQUEST_URI"] . "&modify=1") . "'>" . lang('Modify') . "</a>");
echo "<div class='scrollable'>";
echo "<table id='table' cellspacing='0' class='nowrap checkable'>";
echo script("mixin(qs('#table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true), onkeydown: editingKeydown});");
echo "<thead><tr>" . (!$group && $select
? ""
: "<td><input type='checkbox' id='all-page' class='jsonly'>" . script("qs('#all-page').onclick = partial(formCheck, /check/);", "")
. " <a href='" . h($_GET["modify"] ? remove_from_uri("modify") : $_SERVER["REQUEST_URI"] . "&modify=1") . "'>" . lang('Modify') . "</a>");
$names = array();
$functions = array();
reset($select);
$rank = 1;
foreach ($rows[0] as $key => $val) {
if ($key != $oid) {
if (!isset($unselected[$key])) {
$val = $_GET["columns"][key($select)];
$field = $fields[$select ? ($val ? $val["col"] : current($select)) : $key];
$name = ($field ? $adminer->fieldName($field, $rank) : ($val["fun"] ? "*" : $key));
@@ -314,13 +331,14 @@ if (!$columns && support("table")) {
$column = idf_escape($key);
$href = remove_from_uri('(order|desc)[^=]*|page') . '&order%5B0%5D=' . urlencode($key);
$desc = "&desc%5B0%5D=1";
echo '<th onmouseover="columnMouse(this);" onmouseout="columnMouse(this, \' hidden\');">';
echo "<th>" . script("mixin(qsl('th'), {onmouseover: partial(columnMouse), onmouseout: partial(columnMouse, ' hidden')});", "");
echo '<a href="' . h($href . ($order[0] == $column || $order[0] == $key || (!$order && $is_group && $group[0] == $column) ? $desc : '')) . '">'; // $order[0] == $key - COUNT(*)
echo apply_sql_function($val["fun"], $name) . "</a>"; //! columns looking like functions
echo "<span class='column hidden'>";
echo "<a href='" . h($href . $desc) . "' title='" . lang('descending') . "' class='text'> ↓</a>";
if (!$val["fun"]) {
echo '<a href="#fieldset-search" onclick="selectSearch(\'' . h(js_escape($key)) . '\'); return false;" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo '<a href="#fieldset-search" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo script("qsl('a').onclick = partial(selectSearch, '" . js_escape($key) . "');");
}
echo "</span>";
}
@@ -352,25 +370,29 @@ if (!$columns && support("table")) {
if (!$unique_array) {
$unique_array = array();
foreach ($rows[$n] as $key => $val) {
if (!preg_match('~^(COUNT\\((\\*|(DISTINCT )?`(?:[^`]|``)+`)\\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\\(`(?:[^`]|``)+`\\))$~', $key)) { //! columns looking like functions
if (!preg_match('~^(COUNT\((\*|(DISTINCT )?`(?:[^`]|``)+`)\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\(`(?:[^`]|``)+`\))$~', $key)) { //! columns looking like functions
$unique_array[$key] = $val;
}
}
}
$unique_idf = "";
foreach ($unique_array as $key => $val) {
if (($jush == "sql" || $jush == "pgsql") && strlen($val) > 64) {
if (($jush == "sql" || $jush == "pgsql") && preg_match('~char|text|enum|set~', $fields[$key]["type"]) && strlen($val) > 64) {
$key = (strpos($key, '(') ? $key : idf_escape($key)); //! columns looking like functions
$key = "MD5(" . ($jush == 'sql' && preg_match("~^utf8_~", $fields[$key]["collation"]) ? $key : "CONVERT($key USING " . charset($connection) . ")") . ")";
$key = "MD5(" . ($jush != 'sql' || preg_match("~^utf8~", $fields[$key]["collation"]) ? $key : "CONVERT($key USING " . charset($connection) . ")") . ")";
$val = md5($val);
}
$unique_idf .= "&" . ($val !== null ? urlencode("where[" . bracket_escape($key) . "]") . "=" . urlencode($val) : "null%5B%5D=" . urlencode($key));
}
echo "<tr" . odd() . ">" . (!$group && $select ? "" : "<td>" . checkbox("check[]", substr($unique_idf, 1), in_array(substr($unique_idf, 1), (array) $_POST["check"]), "", "this.form['all'].checked = false; formUncheck('all-page');") . ($is_group || information_schema(DB) ? "" : " <a href='" . h(ME . "edit=" . urlencode($TABLE) . $unique_idf) . "'>" . lang('edit') . "</a>"));
echo "<tr" . odd() . ">" . (!$group && $select ? "" : "<td>"
. checkbox("check[]", substr($unique_idf, 1), in_array(substr($unique_idf, 1), (array) $_POST["check"]))
. ($is_group || information_schema(DB) ? "" : " <a href='" . h(ME . "edit=" . urlencode($TABLE) . $unique_idf) . "' class='edit'>" . lang('edit') . "</a>")
);
foreach ($row as $key => $val) {
if (isset($names[$key])) {
$field = $fields[$key];
$val = $driver->value($val, $field);
if ($val != "" && (!isset($email_fields[$key]) || $email_fields[$key] != "")) {
$email_fields[$key] = (is_mail($val) ? $names[$key] : ""); //! filled e-mails can be contained on other pages
}
@@ -386,9 +408,9 @@ if (!$columns && support("table")) {
foreach ($foreign_key["source"] as $i => $source) {
$link .= where_link($i, $foreign_key["target"][$i], $rows[$n][$source]);
}
$link = ($foreign_key["db"] != "" ? preg_replace('~([?&]db=)[^&]+~', '\\1' . urlencode($foreign_key["db"]), ME) : ME) . 'select=' . urlencode($foreign_key["table"]) . $link; // InnoDB supports non-UNIQUE keys
$link = ($foreign_key["db"] != "" ? preg_replace('~([?&]db=)[^&]+~', '\1' . urlencode($foreign_key["db"]), ME) : ME) . 'select=' . urlencode($foreign_key["table"]) . $link; // InnoDB supports non-UNIQUE keys
if ($foreign_key["ns"]) {
$link = preg_replace('~([?&]ns=)[^&]+~', '\\1' . urlencode($foreign_key["ns"]), $link);
$link = preg_replace('~([?&]ns=)[^&]+~', '\1' . urlencode($foreign_key["ns"]), $link);
}
if (count($foreign_key["source"]) == 1) {
break;
@@ -418,8 +440,11 @@ if (!$columns && support("table")) {
$h_value = h($value !== null ? $value : $row[$key]);
echo "<td>" . ($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]'>");
} else {
$long = strpos($val, "<i>...</i>");
echo "<td id='$id' onclick=\"selectClick(this, event, " . ($long ? 2 : ($text ? 1 : 0)) . ($editable ? "" : ", '" . h(lang('Use edit link to modify this value.')) . "'") . ");\">$val";
$long = strpos($val, "<i></i>");
echo "<td id='$id' data-text='" . ($long ? 2 : ($text ? 1 : 0)) . "'"
. ($editable ? "" : " data-warning='" . h(lang('Use edit link to modify this value.')) . "'")
. ">$val</td>"
;
}
}
}
@@ -435,105 +460,125 @@ if (!$columns && support("table")) {
exit;
}
echo "</table>\n";
echo "</div>\n";
}
if (($rows || $page) && !is_ajax()) {
$exact_count = true;
if ($_GET["page"] != "last") {
if (!+$limit) {
$found_rows = count($rows);
} elseif ($jush != "sql" || !$is_group) {
$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)));
} else {
$exact_count = false;
if (!is_ajax()) {
if ($rows || $page) {
$exact_count = true;
if ($_GET["page"] != "last") {
if ($limit == "" || (count($rows) < $limit && ($rows || !$page))) {
$found_rows = ($page ? $page * $limit : 0) + count($rows);
} elseif ($jush != "sql" || !$is_group) {
$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)));
} else {
$exact_count = false;
}
}
}
}
if (+$limit && ($found_rows === false || $found_rows > $limit || $page)) {
echo "<p class='pages'>";
// display first, previous 4, next 4 and last page
$max_page = ($found_rows === false
? $page + (count($rows) >= $limit ? 2 : 1)
: floor(($found_rows - 1) / $limit)
);
if ($jush != "simpledb") {
echo '<a href="' . h(remove_from_uri("page")) . "\" onclick=\"pageClick(this.href, +prompt('" . lang('Page') . "', '" . ($page + 1) . "'), event); return false;\">" . lang('Page') . "</a>:";
echo pagination(0, $page) . ($page > 5 ? " ..." : "");
for ($i = max(1, $page - 4); $i < min($max_page, $page + 5); $i++) {
echo pagination($i, $page);
}
if ($max_page > 0) {
echo ($page + 5 < $max_page ? " ..." : "");
echo ($exact_count && $found_rows !== false
? pagination($max_page, $page)
: " <a href='" . h(remove_from_uri("page") . "&page=last") . "' title='~$max_page'>" . lang('last') . "</a>"
);
}
$pagination = ($limit != "" && ($found_rows === false || $found_rows > $limit || $page));
if ($pagination) {
echo (($found_rows === false ? count($rows) + 1 : $found_rows - $page * $limit) > $limit
? ' <a href="' . h(remove_from_uri("page") . "&page=" . ($page + 1)) . '" onclick="return !selectLoadMore(this, ' . (+$limit) . ', \'' . lang('Loading') . '...\');" class="loadmore">' . lang('Load more data') . '</a>'
? '<p><a href="' . h(remove_from_uri("page") . "&page=" . ($page + 1)) . '" class="loadmore">' . lang('Load more data') . '</a>'
. script("qsl('a').onclick = partial(selectLoadMore, " . (+$limit) . ", '" . lang('Loading') . "…');", "")
: ''
);
} else {
echo lang('Page') . ":";
echo pagination(0, $page) . ($page > 1 ? " ..." : "");
echo ($page ? pagination($page, $page) : "");
echo ($max_page > $page ? pagination($page + 1, $page) . ($max_page > $page + 1 ? " ..." : "") : "");
echo "\n";
}
}
echo "<div class='footer'><div>\n";
if ($rows || $page) {
if ($pagination) {
// display first, previous 4, next 4 and last page
$max_page = ($found_rows === false
? $page + (count($rows) >= $limit ? 2 : 1)
: floor(($found_rows - 1) / $limit)
);
echo "<fieldset>";
if ($jush != "simpledb") {
echo "<legend><a href='" . h(remove_from_uri("page")) . "'>" . lang('Page') . "</a></legend>";
echo script("qsl('a').onclick = function () { pageClick(this.href, +prompt('" . lang('Page') . "', '" . ($page + 1) . "')); return false; };");
echo pagination(0, $page) . ($page > 5 ? "" : "");
for ($i = max(1, $page - 4); $i < min($max_page, $page + 5); $i++) {
echo pagination($i, $page);
}
if ($max_page > 0) {
echo ($page + 5 < $max_page ? "" : "");
echo ($exact_count && $found_rows !== false
? pagination($max_page, $page)
: " <a href='" . h(remove_from_uri("page") . "&page=last") . "' title='~$max_page'>" . lang('last') . "</a>"
);
}
} else {
echo "<legend>" . lang('Page') . "</legend>";
echo pagination(0, $page) . ($page > 1 ? "" : "");
echo ($page ? pagination($page, $page) : "");
echo ($max_page > $page ? pagination($page + 1, $page) . ($max_page > $page + 1 ? "" : "") : "");
}
echo "</fieldset>\n";
}
echo "<fieldset>";
echo "<legend>" . lang('Whole result') . "</legend>";
$display_rows = ($exact_count ? "" : "~ ") . $found_rows;
echo checkbox("all", 1, 0, ($found_rows !== false ? ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) : ""), "var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);") . "\n";
echo "</fieldset>\n";
echo "<p class='count'>\n";
echo ($found_rows !== false ? "(" . ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) . ") " : "");
$display_rows = ($exact_count ? "" : "~ ") . $found_rows;
echo checkbox("all", 1, 0, lang('whole result'), "var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);") . "\n";
if ($adminer->selectCommandPrint()) {
?>
if ($adminer->selectCommandPrint()) {
?>
<fieldset<?php echo ($_GET["modify"] ? '' : ' class="jsonly"'); ?>><legend><?php echo lang('Modify'); ?></legend><div>
<input type="submit" value="<?php echo lang('Save'); ?>"<?php echo ($_GET["modify"] ? '' : ' title="' . lang('Ctrl+click on a value to modify it.') . '"'); ?>>
</div></fieldset>
<fieldset><legend><?php echo lang('Selected'); ?> <span id="selected"></span></legend><div>
<input type="submit" name="edit" value="<?php echo lang('Edit'); ?>">
<input type="submit" name="clone" value="<?php echo lang('Clone'); ?>">
<input type="submit" name="delete" value="<?php echo lang('Delete'); ?>"<?php echo confirm(); ?>>
<input type="submit" name="delete" value="<?php echo lang('Delete'); ?>"><?php echo confirm(); ?>
</div></fieldset>
<?php
}
$format = $adminer->dumpFormat();
foreach ((array) $_GET["columns"] as $column) {
if ($column["fun"]) {
unset($format['sql']);
break;
}
}
if ($format) {
print_fieldset("export", lang('Export') . " <span id='selected2'></span>");
$output = $adminer->dumpOutput();
echo ($output ? html_select("output", $output, $adminer_import["output"]) . " " : "");
echo html_select("format", $format, $adminer_import["format"]);
echo " <input type='submit' name='export' value='" . lang('Export') . "'>\n";
echo "</div></fieldset>\n";
$format = $adminer->dumpFormat();
foreach ((array) $_GET["columns"] as $column) {
if ($column["fun"]) {
unset($format['sql']);
break;
}
}
if ($format) {
print_fieldset("export", lang('Export') . " <span id='selected2'></span>");
$output = $adminer->dumpOutput();
echo ($output ? html_select("output", $output, $adminer_import["output"]) . " " : "");
echo html_select("format", $format, $adminer_import["format"]);
echo " <input type='submit' name='export' value='" . lang('Export') . "'>\n";
echo "</div></fieldset>\n";
}
$adminer->selectEmailPrint(array_filter($email_fields, 'strlen'), $columns);
}
echo (!$group && $select ? "" : "<script type='text/javascript'>tableCheck();</script>\n");
echo "</div></div>\n";
if ($adminer->selectImportPrint()) {
echo "<div>";
echo "<a href='#import'>" . lang('Import') . "</a>";
echo script("qsl('a').onclick = partial(toggle, 'import');", "");
echo "<span id='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 " <input type='submit' name='import' value='" . lang('Import') . "'>";
echo "</span>";
echo "</div>";
}
echo "<input type='hidden' name='token' value='$token'>\n";
echo "</form>\n";
echo (!$group && $select ? "" : script("tableCheck();"));
}
if ($adminer->selectImportPrint()) {
print_fieldset("import", lang('Import'), !$rows);
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 " <input type='submit' name='import' value='" . lang('Import') . "'>";
echo "</div></fieldset>\n";
}
$adminer->selectEmailPrint(array_filter($email_fields, 'strlen'), $columns);
echo "<p><input type='hidden' name='token' value='$token'></p>\n";
echo "</form>\n";
}
}

View File

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

View File

@@ -21,9 +21,10 @@ if (!$error && $_POST) {
if (!isset($_GET["import"])) {
$query = $_POST["query"];
} elseif ($_POST["webfile"]) {
$fp = @fopen((file_exists("adminer.sql")
? "adminer.sql"
: "compress.zlib://adminer.sql.gz"
$sql_file_path = $adminer->importServerPath();
$fp = @fopen((file_exists($sql_file_path)
? $sql_file_path
: "compress.zlib://$sql_file_path.gz"
), "rb");
$query = ($fp ? fread($fp, 1e6) : false);
} else {
@@ -55,7 +56,7 @@ if (!$error && $_POST) {
}
$commands = 0;
$errors = array();
$parse = '[\'"' . ($jush == "sql" ? '`#' : ($jush == "sqlite" ? '`[' : ($jush == "mssql" ? '[' : ''))) . ']|/\\*|-- |$' . ($jush == "pgsql" ? '|\\$[^$]*\\$' : '');
$parse = '[\'"' . ($jush == "sql" ? '`#' : ($jush == "sqlite" ? '`[' : ($jush == "mssql" ? '[' : ''))) . ']|/\*|-- |$' . ($jush == "pgsql" ? '|\$[^$]*\$' : '');
$total_start = microtime(true);
parse_str($_COOKIE["adminer_export"], $adminer_export);
$dump_format = $adminer->dumpFormat();
@@ -77,7 +78,7 @@ if (!$error && $_POST) {
$offset = $pos + strlen($found);
if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end
while (preg_match('(' . ($found == '/*' ? '\\*/' : ($found == '[' ? ']' : (preg_match('~^-- |^#~', $found) ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { //! respect sql_mode NO_BACKSLASH_ESCAPES
while (preg_match('(' . ($found == '/*' ? '\*/' : ($found == '[' ? ']' : (preg_match('~^-- |^#~', $found) ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { //! respect sql_mode NO_BACKSLASH_ESCAPES
$s = $match[0][0];
if (!$s && $fp && !feof($fp)) {
$query .= fread($fp, 1e5);
@@ -116,9 +117,6 @@ if (!$error && $_POST) {
do {
$result = $connection->store_result();
$time = " <span class='time'>(" . format_time($start) . ")</span>"
. (strlen($q) < 1000 ? " <a href='" . h(ME) . "sql=" . urlencode(trim($q)) . "'>" . lang('Edit') . "</a>" : "") // 1000 - maximum length of encoded URL in IE is 2083 characters
;
if ($connection->error) {
echo ($_POST["only_errors"] ? $print : "");
@@ -128,41 +126,54 @@ if (!$error && $_POST) {
break 2;
}
} elseif (is_object($result)) {
$limit = $_POST["limit"];
$orgtables = select($result, $connection2, array(), $limit);
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 $time;
$id = "export-$commands";
$export = ", <a href='#$id' onclick=\"return !toggle('$id');\">" . lang('Export') . "</a><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"
;
if ($connection2 && preg_match("~^($space|\\()*+SELECT\\b~i", $q) && ($explain = explain($connection2, $q))) {
$id = "explain-$commands";
echo ", <a href='#$id' onclick=\"return !toggle('$id');\">EXPLAIN</a>$export";
echo "<div id='$id' class='hidden'>\n";
select($explain, $connection2, $orgtables);
echo "</div>\n";
} else {
echo $export;
}
echo "</form>\n";
}
} else {
if (preg_match("~^$space*+(CREATE|DROP|ALTER)$space++(DATABASE|SCHEMA)\\b~i", $q)) {
restart_session();
set_session("dbs", null); // clear cache
stop_session();
$time = " <span class='time'>(" . format_time($start) . ")</span>"
. (strlen($q) < 1000 ? " <a href='" . h(ME) . "sql=" . urlencode(trim($q)) . "'>" . lang('Edit') . "</a>" : "") // 1000 - maximum length of encoded URL in IE is 2083 characters
;
$affected = $connection->affected_rows; // getting warnigns overwrites this
$warnings = ($_POST["only_errors"] ? "" : $driver->warnings());
$warnings_id = "warnings-$commands";
if ($warnings) {
$time .= ", <a href='#$warnings_id'>" . lang('Warnings') . "</a>" . script("qsl('a').onclick = partial(toggle, '$warnings_id');", "");
}
if (!$_POST["only_errors"]) {
echo "<p class='message' title='" . h($connection->info) . "'>" . lang('Query executed OK, %d row(s) affected.', $connection->affected_rows) . "$time\n";
$explain = null;
$explain_id = "explain-$commands";
if (is_object($result)) {
$limit = $_POST["limit"];
$orgtables = select($result, $connection2, array(), $limit);
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 $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');", "");
}
$id = "export-$commands";
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"
. "</form>\n"
;
}
} else {
if (preg_match("~^$space*+(CREATE|DROP|ALTER)$space++(DATABASE|SCHEMA)\\b~i", $q)) {
restart_session();
set_session("dbs", null); // clear cache
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 ($warnings ? "<div id='$warnings_id' class='hidden'>\n$warnings</div>\n" : "");
if ($explain) {
echo "<div id='$explain_id' class='hidden'>\n";
select($explain, $connection2, $orgtables);
echo "</div>\n";
}
}
@@ -208,21 +219,25 @@ if (!isset($_GET["import"])) {
}
echo "<p>";
textarea("query", $q, 20);
echo ($_POST ? "" : "<script type='text/javascript'>document.getElementsByTagName('textarea')[0].focus();</script>\n");
echo script(($_POST ? "" : "qs('textarea').focus();\n") . "qs('#form').onsubmit = partial(sqlSubmit, qs('#form'), '" . remove_from_uri("sql|limit|error_stops|only_errors") . "');");
echo "<p>$execute\n";
echo lang('Limit rows') . ": <input type='number' name='limit' class='size' value='" . h($_POST ? $_POST["limit"] : $_GET["limit"]) . "'>\n";
} else {
echo "<fieldset><legend>" . lang('File upload') . "</legend><div>";
$gz = (extension_loaded("zlib") ? "[.gz]" : "");
echo (ini_bool("file_uploads")
? "SQL (&lt; " . ini_get("upload_max_filesize") . "B): <input type='file' name='sql_file[]' multiple>\n$execute" // ignore post_max_size because it is for all form fields together and bytes computing would be necessary
? "SQL$gz (&lt; " . ini_get("upload_max_filesize") . "B): <input type='file' name='sql_file[]' multiple>\n$execute" // ignore post_max_size because it is for all form fields together and bytes computing would be necessary
: lang('File uploads are disabled.')
);
echo "</div></fieldset>\n";
echo "<fieldset><legend>" . lang('From server') . "</legend><div>";
echo lang('Webserver file %s', "<code>adminer.sql" . (extension_loaded("zlib") ? "[.gz]" : "") . "</code>");
echo ' <input type="submit" name="webfile" value="' . lang('Run file') . '">';
echo "</div></fieldset>\n";
$importServerPath = $adminer->importServerPath();
if ($importServerPath) {
echo "<fieldset><legend>" . lang('From server') . "</legend><div>";
echo lang('Webserver file %s', "<code>" . h($importServerPath) . "$gz</code>");
echo ' <input type="submit" name="webfile" value="' . lang('Run file') . '">';
echo "</div></fieldset>\n";
}
echo "<p>";
}

View File

@@ -1,8 +1,11 @@
<?php
function adminer_object() {
include_once "../plugins/plugin.php";
include_once "../plugins/login-sqlite.php";
return new AdminerPlugin(array(new AdminerLoginSqlite));
include_once "../plugins/login-password-less.php";
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

@@ -1,5 +1,5 @@
/** @author Ondrej Valka, http://valka.info */
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; }
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; width: -moz-fit-content; width: fit-content; }
a { color: blue; text-decoration: none; }
a:visited { color: navy; }
a:link:hover, a:visited:hover { color: red; text-decoration: underline; }
@@ -10,11 +10,11 @@ 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: 0; border-top: 1px solid #999; border-left: 1px solid #999; font-size: 90%; }
td, th { border: 0; border-right: 1px solid #999; border-bottom: 1px solid #999; padding: .2em .3em; }
table { margin: 1em 20px 0 0; border-collapse: collapse; font-size: 90%; }
td, th { border: 1px solid #999; padding: .2em .3em; }
th { background: #eee; text-align: left; }
thead th { text-align: center; padding: .2em .5em; }
thead td, thead th { background: #ddf; }
thead td, thead th { background: #ddf; } /* position: sticky; causes Firefox to lose borders */
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; }
@@ -23,7 +23,7 @@ code { background: #eee; }
tbody tr:hover td, tbody tr:hover th { background: #eee; }
pre { margin: 1em 0 0; }
pre, textarea { font: 100%/1.25 monospace; }
input[type=image] { vertical-align: middle; }
input { vertical-align: middle; }
input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; }
input.maxlength { box-shadow: 1px 1px 1px red; }
@@ -32,11 +32,12 @@ input.wayoff { left: -1000px; position: absolute; }
.version { color: #777; font-size: 67%; }
.js .hidden, .nojs .jsonly { display: none; }
.js .column { position: absolute; background: #ddf; padding: .27em 1ex .3em 0; margin-top: -.27em; }
.nowrap td, .nowrap th, td.nowrap { white-space: pre; }
.nowrap td, .nowrap th, td.nowrap, p.nowrap { white-space: pre; }
.wrap td { white-space: normal; }
.error { color: red; background: #fee; }
.error b { background: #fff; font-weight: normal; }
.message { color: green; background: #efe; }
.message table { color: #000; background: #fff; }
.error, .message { padding: .5em .8em; margin: 1em 20px 0 0; }
.char { color: #007F00; }
.date { color: #7F007F; }
@@ -57,13 +58,16 @@ input.wayoff { left: -1000px; position: absolute; }
.icon:hover { background-color: red; }
.size { width: 6ex; }
.help { cursor: help; }
.pages { position: fixed; bottom: 0; left: 21em; padding: 5px; background: #ddf; border: 1px solid #999; }
.footer { position: sticky; bottom: 0; margin-right: -20px; border-top: 20px solid rgba(255, 255, 255, .7); border-image: linear-gradient(rgba(255, 255, 255, .2), #fff) 100% 0; }
.footer > div { background: #fff; padding: 0 0 .5em; }
.footer fieldset { margin-top: 0; }
.links a { white-space: nowrap; margin-right: 20px; }
.logout { margin-top: .5em; position: absolute; top: 0; right: 0; }
.loadmore { margin-left: 1ex; }
/* .edit used in designs */
#menu { position: absolute; margin: 10px 0 0; padding: 0 0 30px 0; top: 2em; left: 0; width: 19em; }
#menu p, #tables { padding: .8em 1em; margin: 0; border-bottom: 1px solid #ccc; }
#tables li{ list-style: none; }
#menu p, #logins, #tables { padding: .8em 1em; margin: 0; border-bottom: 1px solid #ccc; }
#logins li, #tables li { list-style: none; }
#dbs { overflow: hidden; }
#logins, #tables { white-space: nowrap; overflow: auto; }
#logins a, #tables a, #tables span { background: #fff; }

View File

@@ -2,18 +2,29 @@
/** Load syntax highlighting
* @param string first three characters of database system version
* @param [boolean]
*/
function bodyLoad(version) {
function bodyLoad(version, maria) {
if (window.jush) {
jush.create_links = ' target="_blank" rel="noreferrer"';
jush.create_links = ' target="_blank" rel="noreferrer noopener"';
if (version) {
for (var key in jush.urls) {
var obj = jush.urls;
if (typeof obj[key] != 'string') {
obj = obj[key];
key = 0;
if (maria) {
for (var i = 1; i < obj.length; i++) {
obj[i] = obj[i]
.replace(/\.html/, '/')
.replace(/(numeric)(-type-overview)/, '$1-data$2')
.replace(/#statvar_.*/, '#$$1')
;
}
}
}
obj[key] = obj[key]
.replace(/dev\.mysql\.com\/doc\/mysql\/en\//, (maria ? 'mariadb.com/kb/en/library/' : '$&')) // MariaDB
.replace(/\/doc\/mysql/, '/doc/refman/' + version) // MySQL
.replace(/\/docs\/current/, '/docs/' + version) // PostgreSQL
;
@@ -23,7 +34,7 @@ function bodyLoad(version) {
jush.custom_links = jushLinks;
}
jush.highlight_tag('code', 0);
var tags = document.getElementsByTagName('textarea');
var tags = qsa('textarea', document);
for (var i = 0; i < tags.length; i++) {
if (/(^|\s)jush-/.test(tags[i].className)) {
var pre = jush.textarea(tags[i]);
@@ -60,6 +71,28 @@ function typePassword(el, disable) {
}
}
/** Install toggle handler
* @param [HTMLElement]
*/
function messagesPrint(el) {
var els = qsa('.toggle', el || document);
for (var i = 0; i < els.length; i++) {
els[i].onclick = partial(toggle, els[i].getAttribute('href').substr(1));
}
}
/** Hide or show some login rows for selected driver
* @param HTMLSelectElement
*/
function loginDriver(driver) {
var trs = parentTag(driver, 'table').rows;
var disabled = /sqlite/.test(selectValue(driver));
alterClass(trs[1], 'hidden', disabled); // 1 - row with server
trs[1].getElementsByTagName('input')[0].disabled = disabled;
}
var dbCtrl;
@@ -67,45 +100,46 @@ var dbPrevious = {};
/** Check if database should be opened to a new window
* @param MouseEvent
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function dbMouseDown(event, el) {
function dbMouseDown(event) {
dbCtrl = isCtrl(event);
if (dbPrevious[el.name] == undefined) {
dbPrevious[el.name] = el.value;
if (dbPrevious[this.name] == undefined) {
dbPrevious[this.name] = this.value;
}
}
/** Load database after selecting it
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function dbChange(el) {
function dbChange() {
if (dbCtrl) {
el.form.target = '_blank';
this.form.target = '_blank';
}
el.form.submit();
el.form.target = '';
if (dbCtrl && dbPrevious[el.name] != undefined) {
el.value = dbPrevious[el.name];
dbPrevious[el.name] = undefined;
this.form.submit();
this.form.target = '';
if (dbCtrl && dbPrevious[this.name] != undefined) {
this.value = dbPrevious[this.name];
dbPrevious[this.name] = undefined;
}
}
/** Check whether the query will be executed with index
* @param HTMLFormElement
* @this HTMLElement
*/
function selectFieldChange(form) {
function selectFieldChange() {
var form = this.form;
var ok = (function () {
var inputs = form.getElementsByTagName('input');
var inputs = qsa('input', form);
for (var i=0; i < inputs.length; i++) {
if (inputs[i].value && /^fulltext/.test(inputs[i].name)) {
return true;
}
}
var ok = form.limit.value;
var selects = form.getElementsByTagName('select');
var selects = qsa('select', form);
var group = false;
var columns = {};
for (var i=0; i < selects.length; i++) {
@@ -171,15 +205,61 @@ function idfEscape(s) {
return s.replace(/`/, '``');
}
/** Detect foreign key
* @param HTMLInputElement
/** Handle clicks on fields editing
* @param MouseEvent
* @return boolean false to cancel action
*/
function editingNameChange(field) {
var name = field.name.substr(0, field.name.length - 7);
var type = formField(field.form, name + '[type]');
function editingClick(event) {
var el = getTarget(event);
if (!isTag(el, 'input')) {
el = parentTag(target, 'label');
el = el && qs('input', el);
}
if (el) {
var name = el.name;
if (/^add\[/.test(name)) {
editingAddRow.call(el, 1);
} else if (/^up\[/.test(name)) {
editingMoveRow.call(el, 1);
} else if (/^down\[/.test(name)) {
editingMoveRow.call(el);
} else if (/^drop_col\[/.test(name)) {
editingRemoveRow.call(el, 'fields\$1[field]');
} else {
if (name == 'auto_increment_col') {
var field = el.form['fields[' + el.value + '][field]'];
if (!field.value) {
field.value = 'id';
field.oninput();
}
}
return;
}
return false;
}
}
/** Handle input on fields editing
* @param InputEvent
*/
function editingInput(event) {
var el = getTarget(event);
if (/\[default\]$/.test(el.name)) {
el.previousSibling.checked = true;
}
}
/** Detect foreign key
* @this HTMLInputElement
*/
function editingNameChange() {
var name = this.name.substr(0, this.name.length - 7);
var type = formField(this.form, name + '[type]');
var opts = type.options;
var candidate; // don't select anything with ambiguous match (like column `id`)
var val = field.value;
var val = this.value;
for (var i = opts.length; i--; ) {
var match = /(.+)`(.+)/.exec(opts[i].value);
if (!match) { // common type
@@ -209,23 +289,23 @@ function editingNameChange(field) {
}
/** Add table row for next field
* @param HTMLInputElement
* @param boolean
* @return boolean
* @return boolean false
* @this HTMLInputElement
*/
function editingAddRow(button, focus) {
var match = /(\d+)(\.\d+)?/.exec(button.name);
function editingAddRow(focus) {
var match = /(\d+)(\.\d+)?/.exec(this.name);
var x = match[0] + (match[2] ? added.substr(match[2].length) : added) + '1';
var row = parentTag(button, 'tr');
var row = parentTag(this, 'tr');
var row2 = cloneNode(row);
var tags = row.getElementsByTagName('select');
var tags2 = row2.getElementsByTagName('select');
var tags = qsa('select', row);
var tags2 = qsa('select', row2);
for (var i=0; i < tags.length; i++) {
tags2[i].name = tags[i].name.replace(/[0-9.]+/, x);
tags2[i].selectedIndex = tags[i].selectedIndex;
}
tags = row.getElementsByTagName('input');
tags2 = row2.getElementsByTagName('input');
tags = qsa('input', row);
tags2 = qsa('input', row2);
var input = tags2[0]; // IE loose tags2 after insertBefore()
for (var i=0; i < tags.length; i++) {
if (tags[i].name == 'auto_increment_col') {
@@ -240,59 +320,52 @@ function editingAddRow(button, focus) {
tags2[i].checked = false;
}
}
tags[0].onchange = function () {
editingNameChange(tags[0]);
};
tags[0].onkeyup = function () {
};
tags[0].oninput = editingNameChange;
row.parentNode.insertBefore(row2, row.nextSibling);
if (focus) {
input.onchange = function () {
editingNameChange(input);
};
input.onkeyup = function () {
};
input.oninput = editingNameChange;
input.focus();
}
added += '0';
rowCount++;
return true;
return false;
}
/** Remove table row for field
* @param HTMLInputElement
* @param string
* @return boolean
* @param string regular expression replacement
* @return boolean false
* @this HTMLInputElement
*/
function editingRemoveRow(button, name) {
var field = formField(button.form, button.name.replace(/[^\[]+(.+)/, name));
function editingRemoveRow(name) {
var field = formField(this.form, this.name.replace(/[^\[]+(.+)/, name));
field.parentNode.removeChild(field);
parentTag(button, 'tr').style.display = 'none';
return true;
parentTag(this, 'tr').style.display = 'none';
return false;
}
/** Move table row for field
* @param HTMLInputElement
* @param boolean direction to move row, true for up or false for down
* @return boolean
* @param [boolean]
* @return boolean false for success
* @this HTMLInputElement
*/
function editingMoveRow(button, dir){
var row = parentTag(button, 'tr');
function editingMoveRow(up){
var row = parentTag(this, 'tr');
if (!('nextElementSibling' in row)) {
return false;
return true;
}
row.parentNode.insertBefore(row, dir
row.parentNode.insertBefore(row, up
? row.previousElementSibling
: row.nextElementSibling ? row.nextElementSibling.nextElementSibling : row.parentNode.firstChild);
return true;
return false;
}
var lastType = '';
/** Clear length and hide collation or unsigned
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function editingTypeChange(type) {
function editingTypeChange() {
var type = this;
var name = type.name.substr(0, type.name.length - 6);
var text = selectValue(type);
for (var i=0; i < type.form.elements.length; i++) {
@@ -304,7 +377,7 @@ function editingTypeChange(type) {
)) {
el.value = '';
}
el.onchange.apply(el);
el.oninput.apply(el);
}
if (lastType == 'timestamp' && el.name == name + '[has_default]' && /timestamp/i.test(formField(type.form, name + '[default]').value)) {
el.checked = false;
@@ -313,7 +386,7 @@ function editingTypeChange(type) {
alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text));
}
if (el.name == name + '[unsigned]') {
alterClass(el, 'hidden', !/((^|[^o])int|float|double|decimal)$/.test(text));
alterClass(el, 'hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
}
if (el.name == name + '[on_update]') {
alterClass(el, 'hidden', !/timestamp|datetime/.test(text)); // MySQL supports datetime since 5.6.5
@@ -326,37 +399,55 @@ function editingTypeChange(type) {
}
/** Mark length as required
* @param HTMLInputElement
* @this HTMLInputElement
*/
function editingLengthChange(el) {
alterClass(el, 'required', !el.value.length && /var(char|binary)$/.test(selectValue(el.parentNode.previousSibling.firstChild)));
function editingLengthChange() {
alterClass(this, 'required', !this.value.length && /var(char|binary)$/.test(selectValue(this.parentNode.previousSibling.firstChild)));
}
/** Edit enum or set
* @param HTMLInputElement
* @this HTMLInputElement
*/
function editingLengthFocus(field) {
var td = field.parentNode;
function editingLengthFocus() {
var td = this.parentNode;
if (/(enum|set)$/.test(selectValue(td.previousSibling.firstChild))) {
var edit = document.getElementById('enum-edit');
var val = field.value;
edit.value = (/^'.+'$/.test(val) ? val.substr(1, val.length - 2).replace(/','/g, "\n").replace(/''/g, "'") : val); //! doesn't handle 'a'',''b' correctly
var edit = qs('#enum-edit');
edit.value = enumValues(this.value);
td.appendChild(edit);
field.style.display = 'none';
this.style.display = 'none';
edit.style.display = 'inline';
edit.focus();
}
}
/** Finish editing of enum or set
* @param HTMLTextAreaElement
/** Get enum values
* @param string
* @return string values separated by newlines
*/
function editingLengthBlur(edit) {
var field = edit.parentNode.firstChild;
var val = edit.value;
field.value = (/^'[^\n]+'$/.test(val) ? val : "'" + val.replace(/\n+$/, '').replace(/'/g, "''").replace(/\n/g, "','") + "'");
function enumValues(s) {
var re = /(^|,)\s*'(([^\\']|\\.|'')*)'\s*/g;
var result = [];
var offset = 0;
var match;
while (match = re.exec(s)) {
if (offset != match.index) {
break;
}
result.push(match[2].replace(/'(')|\\(.)/g, '$1$2'));
offset += match[0].length;
}
return (offset == s.length ? result.join('\n') : s);
}
/** Finish editing of enum or set
* @this HTMLTextAreaElement
*/
function editingLengthBlur() {
var field = this.parentNode.firstChild;
var val = this.value;
field.value = (/^'[^\n]+'$/.test(val) ? val : val && "'" + val.replace(/\n+$/, '').replace(/'/g, "''").replace(/\\/g, '\\\\').replace(/\n/g, "','") + "'");
field.style.display = 'inline';
edit.style.display = 'none';
this.style.display = 'none';
}
/** Show or hide selected table column
@@ -364,86 +455,108 @@ function editingLengthBlur(edit) {
* @param number
*/
function columnShow(checked, column) {
var trs = document.getElementById('edit-fields').getElementsByTagName('tr');
var trs = qsa('tr', qs('#edit-fields'));
for (var i=0; i < trs.length; i++) {
alterClass(trs[i].getElementsByTagName('td')[column], 'hidden', !checked);
}
}
/** Hide column with default values in narrow window
*/
function editingHideDefaults() {
if (innerWidth < document.documentElement.scrollWidth) {
document.getElementById('form')['defaults'].checked = false;
columnShow(false, 5);
alterClass(qsa('td', trs[i])[column], 'hidden', !checked);
}
}
/** Display partition options
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function partitionByChange(el) {
var partitionTable = /RANGE|LIST/.test(selectValue(el));
alterClass(el.form['partitions'], 'hidden', partitionTable || !el.selectedIndex);
alterClass(document.getElementById('partition-table'), 'hidden', !partitionTable);
function partitionByChange() {
var partitionTable = /RANGE|LIST/.test(selectValue(this));
alterClass(this.form['partitions'], 'hidden', partitionTable || !this.selectedIndex);
alterClass(qs('#partition-table'), 'hidden', !partitionTable);
helpClose();
}
/** Add next partition row
* @param HTMLInputElement
* @this HTMLInputElement
*/
function partitionNameChange(el) {
var row = cloneNode(parentTag(el, 'tr'));
function partitionNameChange() {
var row = cloneNode(parentTag(this, 'tr'));
row.firstChild.firstChild.value = '';
parentTag(el, 'table').appendChild(row);
el.onchange = function () {};
parentTag(this, 'table').appendChild(row);
this.oninput = function () {};
}
/** Show or hide comment fields
* @param HTMLInputElement
* @param [boolean] whether to focus Comment if checked
*/
function editingCommentsClick(el, focus) {
var comment = el.form['Comment'];
columnShow(el.checked, 6);
alterClass(comment, 'hidden', !el.checked);
if (focus && el.checked) {
comment.focus();
}
}
/** Uncheck 'all' checkbox
* @param MouseEvent
* @this HTMLTableElement
*/
function dumpClick(event) {
var el = parentTag(getTarget(event), 'label');
if (el) {
el = qs('input', el);
var match = /(.+)\[\]$/.exec(el.name);
if (match) {
checkboxClick.call(el, event);
formUncheck('check-' + match[1]);
}
}
}
/** Add row for foreign key
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function foreignAddRow(field) {
field.onchange = function () { };
var row = cloneNode(parentTag(field, 'tr'));
var selects = row.getElementsByTagName('select');
function foreignAddRow() {
var row = cloneNode(parentTag(this, 'tr'));
this.onchange = function () { };
var selects = qsa('select', row);
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/\]/, '1$&');
selects[i].selectedIndex = 0;
}
parentTag(field, 'table').appendChild(row);
parentTag(this, 'table').appendChild(row);
}
/** Add row for indexes
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function indexesAddRow(field) {
field.onchange = function () { };
var row = cloneNode(parentTag(field, 'tr'));
var selects = row.getElementsByTagName('select');
function indexesAddRow() {
var row = cloneNode(parentTag(this, 'tr'));
this.onchange = function () { };
var selects = qsa('select', row);
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/indexes\[\d+/, '$&1');
selects[i].selectedIndex = 0;
}
var inputs = row.getElementsByTagName('input');
var inputs = qsa('input', row);
for (var i=0; i < inputs.length; i++) {
inputs[i].name = inputs[i].name.replace(/indexes\[\d+/, '$&1');
inputs[i].value = '';
}
parentTag(field, 'table').appendChild(row);
parentTag(this, 'table').appendChild(row);
}
/** Change column in index
* @param HTMLSelectElement
* @param string name prefix
* @this HTMLSelectElement
*/
function indexesChangeColumn(field, prefix) {
function indexesChangeColumn(prefix) {
var names = [];
for (var tag in { 'select': 1, 'input': 1 }) {
var columns = parentTag(field, 'td').getElementsByTagName(tag);
var columns = qsa(tag, parentTag(this, 'td'));
for (var i=0; i < columns.length; i++) {
if (/\[columns\]/.test(columns[i].name)) {
var value = selectValue(columns[i]);
@@ -453,17 +566,15 @@ function indexesChangeColumn(field, prefix) {
}
}
}
field.form[field.name.replace(/\].*/, '][name]')].value = prefix + names.join('_');
this.form[this.name.replace(/\].*/, '][name]')].value = prefix + names.join('_');
}
/** Add column for index
* @param HTMLSelectElement
* @param string name prefix
* @this HTMLSelectElement
*/
function indexesAddColumn(field, prefix) {
field.onchange = function () {
indexesChangeColumn(field, prefix);
};
function indexesAddColumn(prefix) {
var field = this;
var select = field.form[field.name.replace(/\].*/, '][type]')];
if (!select.selectedIndex) {
while (selectValue(select) != "INDEX" && select.selectedIndex < select.options.length) {
@@ -472,13 +583,14 @@ function indexesAddColumn(field, prefix) {
select.onchange();
}
var column = cloneNode(field.parentNode);
var selects = column.getElementsByTagName('select');
var selects = qsa('select', column);
for (var i = 0; i < selects.length; i++) {
select = selects[i];
select.name = select.name.replace(/\]\[\d+/, '$&1');
select.selectedIndex = 0;
}
var inputs = column.getElementsByTagName('input');
field.onchange = partial(indexesChangeColumn, prefix);
var inputs = qsa('input', column);
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
input.name = input.name.replace(/\]\[\d+/, '$&1');
@@ -492,6 +604,23 @@ function indexesAddColumn(field, prefix) {
/** Updates the form action
* @param HTMLFormElement
* @param string
*/
function sqlSubmit(form, root) {
if (encodeURIComponent(form['query'].value).length < 2e3) {
form.action = root
+ '&sql=' + encodeURIComponent(form['query'].value)
+ (form['limit'].value ? '&limit=' + +form['limit'].value : '')
+ (form['error_stops'].checked ? '&error_stops=1' : '')
+ (form['only_errors'].checked ? '&only_errors=1' : '')
;
}
}
/** Handle changing trigger time or event
* @param RegExp
* @param string
@@ -510,48 +639,47 @@ function triggerChange(tableRe, table, form) {
var that, x, y; // em and tablePos defined in schema.inc.php
/** Get mouse position
* @param HTMLElement
* @param MouseEvent
* @this HTMLElement
*/
function schemaMousedown(el, event) {
function schemaMousedown(event) {
if ((event.which ? event.which : event.button) == 1) {
that = el;
x = event.clientX - el.offsetLeft;
y = event.clientY - el.offsetTop;
that = this;
x = event.clientX - this.offsetLeft;
y = event.clientY - this.offsetTop;
}
}
/** Move object
* @param MouseEvent
*/
function schemaMousemove(ev) {
function schemaMousemove(event) {
if (that !== undefined) {
ev = ev || event;
var left = (ev.clientX - x) / em;
var top = (ev.clientY - y) / em;
var divs = that.getElementsByTagName('div');
var left = (event.clientX - x) / em;
var top = (event.clientY - y) / em;
var divs = qsa('div', that);
var lineSet = { };
for (var i=0; i < divs.length; i++) {
if (divs[i].className == 'references') {
var div2 = document.getElementById((/^refs/.test(divs[i].id) ? 'refd' : 'refs') + divs[i].id.substr(4));
var div2 = qs('[id="' + (/^refs/.test(divs[i].id) ? 'refd' : 'refs') + divs[i].id.substr(4) + '"]');
var ref = (tablePos[divs[i].title] ? tablePos[divs[i].title] : [ div2.parentNode.offsetTop / em, 0 ]);
var left1 = -1;
var id = divs[i].id.replace(/^ref.(.+)-.+/, '$1');
if (divs[i].parentNode != div2.parentNode) {
left1 = Math.min(0, ref[1] - left) - 1;
divs[i].style.left = left1 + 'em';
divs[i].getElementsByTagName('div')[0].style.width = -left1 + 'em';
divs[i].querySelector('div').style.width = -left1 + 'em';
var left2 = Math.min(0, left - ref[1]) - 1;
div2.style.left = left2 + 'em';
div2.getElementsByTagName('div')[0].style.width = -left2 + 'em';
div2.querySelector('div').style.width = -left2 + 'em';
}
if (!lineSet[id]) {
var line = document.getElementById(divs[i].id.replace(/^....(.+)-.+$/, 'refl$1'));
var line = qs('[id="' + divs[i].id.replace(/^....(.+)-.+$/, 'refl$1') + '"]');
var top1 = top + divs[i].offsetTop / em;
var top2 = top + div2.offsetTop / em;
if (divs[i].parentNode != div2.parentNode) {
top2 += ref[0] - top;
line.getElementsByTagName('div')[0].style.height = Math.abs(top1 - top2) + 'em';
line.querySelector('div').style.height = Math.abs(top1 - top2) + 'em';
}
line.style.left = (left + left1) + 'em';
line.style.top = Math.min(top1, top2) + 'em';
@@ -568,17 +696,16 @@ function schemaMousemove(ev) {
* @param MouseEvent
* @param string
*/
function schemaMouseup(ev, db) {
function schemaMouseup(event, db) {
if (that !== undefined) {
ev = ev || event;
tablePos[that.firstChild.firstChild.firstChild.data] = [ (ev.clientY - y) / em, (ev.clientX - x) / em ];
tablePos[that.firstChild.firstChild.firstChild.data] = [ (event.clientY - y) / em, (event.clientX - x) / em ];
that = undefined;
var s = '';
for (var key in tablePos) {
s += '_' + key + ':' + Math.round(tablePos[key][0] * 10000) / 10000 + 'x' + Math.round(tablePos[key][1] * 10000) / 10000;
}
s = encodeURIComponent(s.substr(1));
var link = document.getElementById('schema-link');
var link = qs('#schema-link');
link.href = link.href.replace(/[^=]+$/, '') + s;
cookie('adminer_schema-' + db + '=' + s, 30); //! special chars in db
}
@@ -589,18 +716,18 @@ function schemaMouseup(ev, db) {
var helpOpen, helpIgnore; // when mouse outs <option> then it mouse overs border of <select> - ignore it
/** Display help
* @param HTMLElement
* @param MouseEvent
* @param string
* @param bool display on left side (otherwise on top)
* @this HTMLElement
*/
function helpMouseover(el, event, text, side) {
function helpMouseover(event, text, side) {
var target = getTarget(event);
if (!text) {
helpClose();
} else if (window.jush && (!helpIgnore || el != target)) {
} else if (window.jush && (!helpIgnore || this != target)) {
helpOpen = 1;
var help = document.getElementById('help');
var help = qs('#help');
help.innerHTML = text;
jush.highlight_tag([ help ]);
alterClass(help, 'hidden');
@@ -612,12 +739,12 @@ function helpMouseover(el, event, text, side) {
}
/** Close help after timeout
* @param HTMLElement
* @param MouseEvent
* @this HTMLElement
*/
function helpMouseout(el, event) {
function helpMouseout(event) {
helpOpen = 0;
helpIgnore = (el != getTarget(event));
helpIgnore = (this != getTarget(event));
setTimeout(function () {
if (!helpOpen) {
helpClose();
@@ -628,5 +755,5 @@ function helpMouseout(el, event) {
/** Close help
*/
function helpClose() {
alterClass(document.getElementById('help'), 'hidden', true);
alterClass(qs('#help'), 'hidden', true);
}

View File

@@ -1,4 +1,67 @@
/** Get first element by selector
* @param string
* @param [HTMLElement] defaults to document
* @return HTMLElement
*/
function qs(selector, context) {
return (context || document).querySelector(selector);
}
/** Get last element by selector
* @param string
* @param [HTMLElement] defaults to document
* @return HTMLElement
*/
function qsl(selector, context) {
var els = qsa(selector, context || document);
return els[els.length - 1];
}
/** Get all elements by selector
* @param string
* @param HTMLElement
* @return NodeList
*/
function qsa(selector, context) {
return context.querySelectorAll(selector);
}
/** Return a function calling fn with the next arguments
* @param function
* @param ...
* @return function with preserved this
*/
function partial(fn) {
var args = Array.apply(null, arguments).slice(1);
return function () {
return fn.apply(this, args);
};
}
/** Return a function calling fn with the first parameter and then the next arguments
* @param function
* @param ...
* @return function with preserved this
*/
function partialArg(fn) {
var args = Array.apply(null, arguments);
return function (arg) {
args[0] = arg;
return fn.apply(this, args);
};
}
/** Assign values from source to target
* @param Object
* @param Object
*/
function mixin(target, source) {
for (var key in source) {
target[key] = source[key];
}
}
/** Add or remove CSS class
* @param HTMLElement
* @param string
@@ -12,12 +75,12 @@ function alterClass(el, className, enable) {
/** Toggle visibility
* @param string
* @return boolean
* @return boolean false
*/
function toggle(id) {
var el = document.getElementById(id);
var el = qs('#' + id);
el.className = (el.className == 'hidden' ? '' : 'hidden');
return true;
return false;
}
/** Set permanent cookie
@@ -33,8 +96,10 @@ function cookie(assign, days) {
/** Verify current Adminer version
* @param string
* @param string own URL base
* @param string
*/
function verifyVersion(current) {
function verifyVersion(current, url, token) {
cookie('adminer_version=0', 1);
var iframe = document.createElement('iframe');
iframe.src = 'https://www.adminer.org/version/?current=' + current;
@@ -50,11 +115,13 @@ function verifyVersion(current) {
var match = /version=(.+)/.exec(event.data);
if (match) {
cookie('adminer_version=' + match[1], 1);
ajax(url + 'script=version', function () {
}, event.data + '&token=' + token);
}
}
}, false);
}
document.getElementById('version').appendChild(iframe);
qs('#version').appendChild(iframe);
}
/** Get value of select
@@ -70,20 +137,20 @@ function selectValue(select) {
}
/** Verify if element has a specified tag name
* @param HTMLElement
* @param string regular expression
* @return bool
*/
* @param HTMLElement
* @param string regular expression
* @return bool
*/
function isTag(el, tag) {
var re = new RegExp('^(' + tag + ')$', 'i');
return re.test(el.tagName);
return el && re.test(el.tagName);
}
/** Get parent node with specified tag name
* @param HTMLElement
* @param string regular expression
* @return HTMLElement
*/
* @param HTMLElement
* @param string regular expression
* @return HTMLElement
*/
function parentTag(el, tag) {
while (el && !isTag(el, tag)) {
el = el.parentNode;
@@ -105,27 +172,31 @@ function trCheck(el) {
/** Fill number of selected items
* @param string
* @param string
* @uses thousandsSeparator
*/
function selectCount(id, count) {
setHtml(id, (count === '' ? '' : '(' + (count + '').replace(/\B(?=(\d{3})+$)/g, ' ') + ')'));
var inputs = document.getElementById(id).parentNode.parentNode.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if (input.type == 'submit') {
input.disabled = (count == '0');
setHtml(id, (count === '' ? '' : '(' + (count + '').replace(/\B(?=(\d{3})+$)/g, thousandsSeparator) + ')'));
var el = qs('#' + id);
if (el) {
var inputs = qsa('input', el.parentNode.parentNode);
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if (input.type == 'submit') {
input.disabled = (count == '0');
}
}
}
}
/** Check all elements matching given name
* @param HTMLInputElement
* @param RegExp
* @this HTMLInputElement
*/
function formCheck(el, name) {
var elems = el.form.elements;
function formCheck(name) {
var elems = this.form.elements;
for (var i=0; i < elems.length; i++) {
if (name.test(elems[i].name)) {
elems[i].checked = el.checked;
elems[i].checked = this.checked;
trCheck(elems[i]);
}
}
@@ -134,14 +205,9 @@ function formCheck(el, name) {
/** Check all rows in <table class="checkable">
*/
function tableCheck() {
var tables = document.getElementsByTagName('table');
for (var i=0; i < tables.length; i++) {
if (/(^|\s)checkable(\s|$)/.test(tables[i].className)) {
var trs = tables[i].getElementsByTagName('tr');
for (var j=0; j < trs.length; j++) {
trCheck(trs[j].firstChild.firstChild);
}
}
var inputs = qsa('table.checkable td:first-child input', document);
for (var i=0; i < inputs.length; i++) {
trCheck(inputs[i]);
}
}
@@ -149,7 +215,7 @@ function tableCheck() {
* @param string
*/
function formUncheck(id) {
var el = document.getElementById(id);
var el = qs('#' + id);
el.checked = false;
trCheck(el);
}
@@ -175,6 +241,13 @@ function formChecked(el, name) {
* @param [boolean] force click
*/
function tableClick(event, click) {
var td = parentTag(getTarget(event), 'td');
var text;
if (td && (text = td.getAttribute('data-text'))) {
if (selectClick.call(td, event, +text, td.getAttribute('data-warning'))) {
return;
}
}
click = (click || !window.getSelection || getSelection().isCollapsed);
var el = getTarget(event);
while (!isTag(el, 'tr')) {
@@ -182,7 +255,7 @@ function tableClick(event, click) {
if (el.type != 'checkbox') {
return;
}
checkboxClick(event, el);
checkboxClick.call(el, event);
click = false;
}
el = el.parentNode;
@@ -195,31 +268,38 @@ function tableClick(event, click) {
el.checked = !el.checked;
el.onclick && el.onclick();
}
if (el.name == 'check[]') {
el.form['all'].checked = false;
formUncheck('all-page');
}
if (/^(tables|views)\[\]$/.test(el.name)) {
formUncheck('check-all');
}
trCheck(el);
}
var lastChecked;
/** Shift-click on checkbox for multiple selection.
* @param MouseEvent
* @param HTMLInputElement
*/
function checkboxClick(event, el) {
if (!el.name) {
* @param MouseEvent
* @this HTMLInputElement
*/
function checkboxClick(event) {
if (!this.name) {
return;
}
if (event.shiftKey && (!lastChecked || lastChecked.name == el.name)) {
if (event.shiftKey && (!lastChecked || lastChecked.name == this.name)) {
var checked = (lastChecked ? lastChecked.checked : true);
var inputs = parentTag(el, 'table').getElementsByTagName('input');
var inputs = qsa('input', parentTag(this, 'table'));
var checking = !lastChecked;
for (var i=0; i < inputs.length; i++) {
var input = inputs[i];
if (input.name === el.name) {
if (input.name === this.name) {
if (checking) {
input.checked = checked;
trCheck(input);
}
if (input === el || input === lastChecked) {
if (input === this || input === lastChecked) {
if (checking) {
break;
}
@@ -228,19 +308,19 @@ function checkboxClick(event, el) {
}
}
} else {
lastChecked = el;
lastChecked = this;
}
}
/** Set HTML code of an element
* @param string
* @param string undefined to set parentNode to &nbsp;
* @param string undefined to set parentNode to empty string
*/
function setHtml(id, html) {
var el = document.getElementById(id);
var el = qs('[id="' + id.replace(/[\\"]/g, '\\$&') + '"]'); // database name is used as ID
if (el) {
if (html == null) {
el.parentNode.innerHTML = '&nbsp;';
el.parentNode.innerHTML = '';
} else {
el.innerHTML = html;
}
@@ -262,52 +342,49 @@ function nodePosition(el) {
/** Go to the specified page
* @param string
* @param string
* @param [MouseEvent]
*/
function pageClick(href, page, event) {
function pageClick(href, page) {
if (!isNaN(page) && page) {
href += (page != 1 ? '&page=' + (page - 1) : '');
location.href = href;
location.href = href + (page != 1 ? '&page=' + (page - 1) : '');
}
}
/** Display items in menu
* @param HTMLElement
* @param MouseEvent
* @this HTMLElement
*/
function menuOver(el, event) {
function menuOver(event) {
var a = getTarget(event);
if (isTag(a, 'a|span') && a.offsetLeft + a.offsetWidth > a.parentNode.offsetWidth - 15) { // 15 - ellipsis
el.style.overflow = 'visible';
this.style.overflow = 'visible';
}
}
/** Hide items in menu
* @param HTMLElement
* @this HTMLElement
*/
function menuOut(el) {
el.style.overflow = 'auto';
function menuOut() {
this.style.overflow = 'auto';
}
/** Add row in select fieldset
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function selectAddRow(field) {
field.onchange = function () {
selectFieldChange(field.form);
};
field.onchange();
function selectAddRow() {
var field = this;
var row = cloneNode(field.parentNode);
var selects = row.getElementsByTagName('select');
field.onchange = selectFieldChange;
field.onchange();
var selects = qsa('select', row);
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/[a-z]\[\d+/, '$&1');
selects[i].selectedIndex = 0;
}
var inputs = row.getElementsByTagName('input');
var inputs = qsa('input', row);
for (var i=0; i < inputs.length; i++) {
inputs[i].name = inputs[i].name.replace(/[a-z]\[\d+/, '$&1');
inputs[i].className = '';
@@ -321,33 +398,33 @@ function selectAddRow(field) {
}
/** Prevent onsearch handler on Enter
* @param HTMLInputElement
* @param KeyboardEvent
* @this HTMLInputElement
*/
function selectSearchKeydown(el, event) {
function selectSearchKeydown(event) {
if (event.keyCode == 13 || event.keyCode == 10) {
el.onsearch = function () {
this.onsearch = function () {
};
}
}
/** Clear column name after resetting search
* @param HTMLInputElement
* @this HTMLInputElement
*/
function selectSearchSearch(el) {
if (!el.value) {
el.parentNode.firstChild.selectedIndex = 0;
function selectSearchSearch() {
if (!this.value) {
this.parentNode.firstChild.selectedIndex = 0;
}
}
/** Toggles column context menu
* @param HTMLElement
* @param [string] extra class name
*/
function columnMouse(el, className) {
var spans = el.getElementsByTagName('span');
* @param [string] extra class name
* @this HTMLElement
*/
function columnMouse(className) {
var spans = qsa('span', this);
for (var i=0; i < spans.length; i++) {
if (/column/.test(spans[i].className)) {
spans[i].className = 'column' + (className || '');
@@ -358,12 +435,13 @@ function columnMouse(el, className) {
/** Fill column in search field
* @param string
*/
* @param string
* @return boolean false
*/
function selectSearch(name) {
var el = document.getElementById('fieldset-search');
var el = qs('#fieldset-search');
el.className = '';
var divs = el.getElementsByTagName('div');
var divs = qsa('div', el);
for (var i=0; i < divs.length; i++) {
var div = divs[i];
if (isTag(div.firstChild, 'select') && selectValue(div.firstChild) == name) {
@@ -374,7 +452,8 @@ function selectSearch(name) {
div.firstChild.value = name;
div.firstChild.onchange();
}
div.lastChild.focus();
qs('[name$="[val]"]', div).focus();
return false;
}
@@ -402,6 +481,7 @@ function getTarget(event) {
* @return boolean
*/
function bodyKeydown(event, button) {
eventStop(event);
var target = getTarget(event);
if (target.jushTextarea) {
target = target.jushTextarea;
@@ -411,6 +491,9 @@ function bodyKeydown(event, button) {
if (button) {
target.form[button].click();
} else {
if (target.form.onsubmit) {
target.form.onsubmit();
}
target.form.submit();
}
target.focus();
@@ -450,56 +533,58 @@ function editingKeydown(event) {
return false;
}
if (event.shiftKey && !bodyKeydown(event, 'insert')) {
eventStop(event);
return false;
}
return true;
}
/** Disable maxlength for functions
* @param HTMLSelectElement
* @this HTMLSelectElement
*/
function functionChange(select) {
var input = select.form[select.name.replace(/^function/, 'fields')];
if (selectValue(select)) {
if (input.origType === undefined) {
input.origType = input.type;
input.origMaxLength = input.getAttribute('data-maxlength');
}
input.removeAttribute('data-maxlength');
input.type = 'text';
} else if (input.origType) {
input.type = input.origType;
if (input.origMaxLength >= 0) {
input.setAttribute('data-maxlength', input.origMaxLength);
function functionChange() {
var input = this.form[this.name.replace(/^function/, 'fields')];
if (input) { // undefined with the set data type
if (selectValue(this)) {
if (input.origType === undefined) {
input.origType = input.type;
input.origMaxLength = input.getAttribute('data-maxlength');
}
input.removeAttribute('data-maxlength');
input.type = 'text';
} else if (input.origType) {
input.type = input.origType;
if (input.origMaxLength >= 0) {
input.setAttribute('data-maxlength', input.origMaxLength);
}
}
oninput({target: input});
}
oninput({target: input});
helpClose();
}
/** Call this.onchange() if value changes
* @this HTMLInputElement
/** Skip 'original' when typing
* @param number
* @this HTMLTableCellElement
*/
function keyupChange() {
if (this.value != this.getAttribute('value')) {
this.onchange();
this.setAttribute('value', this.value);
function skipOriginal(first) {
var fnSelect = this.previousSibling.firstChild;
if (fnSelect.selectedIndex < first) {
fnSelect.selectedIndex = first;
}
}
/** Add new field in schema-less edit
* @param HTMLInputElement
* @this HTMLInputElement
*/
function fieldChange(field) {
var row = cloneNode(parentTag(field, 'tr'));
var inputs = row.getElementsByTagName('input');
function fieldChange() {
var row = cloneNode(parentTag(this, 'tr'));
var inputs = qsa('input', row);
for (var i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
// keep value in <select> (function)
parentTag(field, 'table').appendChild(row);
field.onchange = function () { };
parentTag(this, 'table').appendChild(row);
this.oninput = function () { };
}
@@ -510,11 +595,12 @@ function fieldChange(field) {
* @param [string]
* @param [string]
* @return XMLHttpRequest or false in case of an error
* @uses offlineMessage
*/
function ajax(url, callback, data, message) {
var request = (window.XMLHttpRequest ? new XMLHttpRequest() : (window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : false));
if (request) {
var ajaxStatus = document.getElementById('ajaxstatus');
var ajaxStatus = qs('#ajaxstatus');
if (message) {
ajaxStatus.innerHTML = '<div class="message">' + message + '</div>';
ajaxStatus.className = ajaxStatus.className.replace(/ hidden/g, '');
@@ -543,11 +629,11 @@ function ajax(url, callback, data, message) {
/** Use setHtml(key, value) for JSON response
* @param string
* @return XMLHttpRequest or false in case of an error
* @return boolean false for success
*/
function ajaxSetHtml(url) {
return ajax(url, function (request) {
var data = eval('(' + request.responseText + ')');
return !ajax(url, function (request) {
var data = window.JSON ? JSON.parse(request.responseText) : eval('(' + request.responseText + ')');
for (var key in data) {
setHtml(key, data[key]);
}
@@ -584,26 +670,30 @@ function ajaxForm(form, message, button) {
return ajax(url, function (request) {
setHtml('ajaxstatus', request.responseText);
if (window.jush) {
jush.highlight_tag(document.getElementById('ajaxstatus').getElementsByTagName('code'), 0);
jush.highlight_tag(qsa('code', qs('#ajaxstatus')), 0);
}
messagesPrint(qs('#ajaxstatus'));
}, data, message);
}
/** Display edit field
* @param HTMLElement
* @param MouseEvent
* @param number display textarea instead of input, 2 - load long text
* @param string warning to display
* @param [string] warning to display
* @return boolean
* @this HTMLElement
*/
function selectClick(td, event, text, warning) {
function selectClick(event, text, warning) {
var td = this;
var target = getTarget(event);
if (!isCtrl(event) || isTag(td.firstChild, 'input|textarea') || isTag(target, 'a')) {
return;
}
if (warning) {
return alert(warning);
alert(warning);
return true;
}
var original = td.innerHTML;
text = text || /\n/.test(original);
@@ -618,7 +708,7 @@ function selectClick(td, event, text, warning) {
}
};
var pos = event.rangeOffset;
var value = td.firstChild.alt || td.textContent || td.innerText;
var value = (td.firstChild && td.firstChild.alt) || td.textContent || td.innerText;
input.style.width = Math.max(td.clientWidth - 14, 20) + 'px'; // 14 = 2 * (td.border + td.padding + input.border)
if (text) {
var rows = 1;
@@ -627,7 +717,7 @@ function selectClick(td, event, text, warning) {
});
input.rows = rows;
}
if (value == '\u00A0' || td.getElementsByTagName('i').length) { // &nbsp; or i - NULL
if (qsa('i', td).length) { // <i> - NULL
value = '';
}
if (document.selection) {
@@ -659,26 +749,28 @@ function selectClick(td, event, text, warning) {
range.moveEnd('character', -input.value.length + pos);
range.select();
}
return true;
}
/** Load and display next page in select
* @param HTMLLinkElement
* @param number
* @param string
* @return boolean
* @return boolean false for success
* @this HTMLLinkElement
*/
function selectLoadMore(a, limit, loading) {
function selectLoadMore(limit, loading) {
var a = this;
var title = a.innerHTML;
var href = a.href;
a.innerHTML = loading;
if (href) {
a.removeAttribute('href');
return ajax(href, function (request) {
return !ajax(href, function (request) {
var tbody = document.createElement('tbody');
tbody.innerHTML = request.responseText;
document.getElementById('table').appendChild(tbody);
qs('#table').appendChild(tbody);
if (tbody.children.length < limit) {
a.parentNode.removeChild(a);
} else {
@@ -711,7 +803,7 @@ function eventStop(event) {
*/
function setupSubmitHighlight(parent) {
for (var key in { input: 1, select: 1, textarea: 1 }) {
var inputs = parent.getElementsByTagName(key);
var inputs = qsa(key, parent);
for (var i = 0; i < inputs.length; i++) {
setupSubmitHighlightInput(inputs[i])
}
@@ -756,7 +848,10 @@ function findDefaultSubmit(el) {
if (el.jushTextarea) {
el = el.jushTextarea;
}
var inputs = el.form.getElementsByTagName('input');
if (!el.form) {
return null;
}
var inputs = qsa('input', el.form);
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if (input.type == 'submit' && !input.style.zIndex) {
@@ -795,6 +890,17 @@ function focus(el) {
*/
function cloneNode(el) {
var el2 = el.cloneNode(true);
var selector = 'input, select';
var origEls = qsa(selector, el);
var cloneEls = qsa(selector, el2);
for (var i=0; i < origEls.length; i++) {
var origEl = origEls[i];
for (var key in origEl) {
if (/^on/.test(key) && origEl[key]) {
cloneEls[i][key] = origEl[key];
}
}
}
setupSubmitHighlight(el2);
return el2;
}

View File

@@ -5,13 +5,14 @@ if (!$fields) {
$error = error();
}
$table_status = table_status1($TABLE, true);
$name = $adminer->tableName($table_status);
page_header(($fields && is_view($table_status) ? $table_status['Engine'] == 'materialized view' ? lang('Materialized view') : lang('View') : lang('Table')) . ": " . h($TABLE), $error);
page_header(($fields && is_view($table_status) ? $table_status['Engine'] == 'materialized view' ? lang('Materialized view') : lang('View') : lang('Table')) . ": " . ($name != "" ? $name : h($TABLE)), $error);
$adminer->selectLinks($table_status);
$comment = $table_status["Comment"];
if ($comment != "") {
echo "<p>" . lang('Comment') . ": " . h($comment) . "\n";
echo "<p class='nowrap'>" . lang('Comment') . ": " . h($comment) . "\n";
}
if ($fields) {
@@ -33,7 +34,7 @@ if (!is_view($table_status)) {
$foreign_keys = foreign_keys($TABLE);
if ($foreign_keys) {
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th>" . lang('Source') . "<td>" . lang('Target') . "<td>" . lang('ON DELETE') . "<td>" . lang('ON UPDATE') . "<td>&nbsp;</thead>\n";
echo "<thead><tr><th>" . lang('Source') . "<td>" . lang('Target') . "<td>" . lang('ON DELETE') . "<td>" . lang('ON UPDATE') . "<td></thead>\n";
foreach ($foreign_keys as $name => $foreign_key) {
echo "<tr title='" . h($name) . "'>";
echo "<th><i>" . implode("</i>, <i>", array_map('h', $foreign_key["source"])) . "</i>";
@@ -42,8 +43,8 @@ if (!is_view($table_status)) {
. "</a>"
;
echo "(<i>" . implode("</i>, <i>", array_map('h', $foreign_key["target"])) . "</i>)";
echo "<td>" . nbsp($foreign_key["on_delete"]) . "\n";
echo "<td>" . nbsp($foreign_key["on_update"]) . "\n";
echo "<td>" . h($foreign_key["on_delete"]) . "\n";
echo "<td>" . h($foreign_key["on_update"]) . "\n";
echo '<td><a href="' . h(ME . 'foreign=' . urlencode($TABLE) . '&name=' . urlencode($name)) . '">' . lang('Alter') . '</a>';
}
echo "</table>\n";

View File

@@ -33,17 +33,17 @@ page_header(($name != "" ? lang('Alter trigger') . ": " . h($name) : lang('Creat
?>
<form action="" method="post" id="form">
<table cellspacing="0">
<table cellspacing="0" class="layout">
<tr><th><?php echo lang('Time'); ?><td><?php echo html_select("Timing", $trigger_options["Timing"], $row["Timing"], "triggerChange(/^" . preg_quote($TABLE, "/") . "_[ba][iud]$/, '" . js_escape($TABLE) . "', this.form);"); ?>
<tr><th><?php echo lang('Event'); ?><td><?php echo html_select("Event", $trigger_options["Event"], $row["Event"], "this.form['Timing'].onchange();"); ?>
<?php echo (in_array("UPDATE OF", $trigger_options["Event"]) ? " <input name='Of' value='" . h($row["Of"]) . "' class='hidden'>": ""); ?>
<tr><th><?php echo lang('Type'); ?><td><?php echo html_select("Type", $trigger_options["Type"], $row["Type"]); ?>
</table>
<p><?php echo lang('Name'); ?>: <input name="Trigger" value="<?php echo h($row["Trigger"]); ?>" maxlength="64" autocapitalize="off">
<script type="text/javascript">document.getElementById('form')['Timing'].onchange();</script>
<p><?php echo lang('Name'); ?>: <input name="Trigger" value="<?php echo h($row["Trigger"]); ?>" data-maxlength="64" autocapitalize="off">
<?php echo script("qs('#form')['Timing'].onchange();"); ?>
<p><?php textarea("Statement", $row["Statement"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($name != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?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; ?>">
</form>

View File

@@ -22,7 +22,7 @@ if (!$row) {
<p>
<?php
if ($TYPE != "") {
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'" . confirm() . ">\n";
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $TYPE)) . "\n";
} else {
echo "<input name='name' value='" . h($row['name']) . "' autocapitalize='off'>\n";
textarea("as", $row["as"]);

View File

@@ -29,7 +29,7 @@ $old_pass = "";
if (isset($_GET["host"]) && ($result = $connection->query("SHOW GRANTS FOR " . q($USER) . "@" . q($_GET["host"])))) { //! use information_schema for MySQL 5 - column names in column privileges are not escaped
while ($row = $result->fetch_row()) {
if (preg_match('~GRANT (.*) ON (.*) TO ~', $row[0], $match) && preg_match_all('~ *([^(,]*[^ ,(])( *\\([^)]+\\))?~', $match[1], $matches, PREG_SET_ORDER)) { //! escape the part between ON and TO
if (preg_match('~GRANT (.*) ON (.*) TO ~', $row[0], $match) && preg_match_all('~ *([^(,]*[^ ,(])( *\([^)]+\))?~', $match[1], $matches, PREG_SET_ORDER)) { //! escape the part between ON and TO
foreach ($matches as $val) {
if ($val[1] != "USAGE") {
$grants["$match[2]$val[2]"][$val[1]] = true;
@@ -52,7 +52,7 @@ if ($_POST && !$error) {
} else {
$new_user = q($_POST["user"]) . "@" . q($_POST["host"]); // if $_GET["host"] is not set then $new_user is always different
$pass = $_POST["pass"];
if ($pass != '' && !$_POST["hashed"]) {
if ($pass != '' && !$_POST["hashed"] && !min_version(8)) {
// compute hash in a separate query so that plain text password is not saved to history
$pass = $connection->result("SELECT PASSWORD(" . q($pass) . ")");
$error = !$pass;
@@ -61,7 +61,7 @@ if ($_POST && !$error) {
$created = false;
if (!$error) {
if ($old_user != $new_user) {
$created = queries(($connection->server_info < 5 ? "GRANT USAGE ON *.* TO" : "CREATE USER") . " $new_user IDENTIFIED BY PASSWORD " . q($pass));
$created = queries((min_version(5) ? "CREATE USER" : "GRANT USAGE ON *.* TO") . " $new_user IDENTIFIED BY " . (min_version(8) ? "" : "PASSWORD ") . q($pass));
$error = !$created;
} elseif ($pass != $old_pass) {
queries("SET PASSWORD FOR $new_user = " . q($pass));
@@ -84,7 +84,7 @@ if ($_POST && !$error) {
$grant = array_diff($grant, $old_grant);
unset($grants[$object]);
}
if (preg_match('~^(.+)\\s*(\\(.*\\))?$~U', $object, $match) && (
if (preg_match('~^(.+)\s*(\(.*\))?$~U', $object, $match) && (
!grant("REVOKE", $revoke, $match[2], " ON $match[1] FROM $new_user") //! SQL injection
|| !grant("GRANT", $grant, $match[2], " ON $match[1] TO $new_user")
)) {
@@ -99,7 +99,7 @@ if ($_POST && !$error) {
queries("DROP USER $old_user");
} elseif (!isset($_GET["grant"])) {
foreach ($grants as $object => $revoke) {
if (preg_match('~^(.+)(\\(.*\\))?$~U', $object, $match)) {
if (preg_match('~^(.+)(\(.*\))?$~U', $object, $match)) {
grant("REVOKE", array_keys($revoke), $match[2], " ON $match[1] FROM $new_user");
}
}
@@ -131,12 +131,12 @@ if ($_POST) {
?>
<form action="" method="post">
<table cellspacing="0">
<tr><th><?php echo lang('Server'); ?><td><input name="host" maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="user" maxlength="16" value="<?php echo h($row["user"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>">
<?php if (!$row["hashed"]) { ?><script type="text/javascript">typePassword(document.getElementById('pass'));</script><?php } ?>
<?php echo checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);"); ?>
<table cellspacing="0" class="layout">
<tr><th><?php echo lang('Server'); ?><td><input name="host" data-maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="user" data-maxlength="80" value="<?php echo h($row["user"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>" autocomplete="new-password">
<?php if (!$row["hashed"]) { echo script("typePassword(qs('#pass'));"); } ?>
<?php echo (min_version(8) ? "" : checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);")); ?>
</table>
<?php
@@ -165,11 +165,15 @@ foreach (array(
$name = "'grants[$i][" . h(strtoupper($privilege)) . "]'";
$value = $grant[strtoupper($privilege)];
if ($context == "Server Admin" && $object != (isset($grants["*.*"]) ? "*.*" : ".*")) {
echo "<td>&nbsp;";
echo "<td>";
} elseif (isset($_GET["grant"])) {
echo "<td><select name=$name><option><option value='1'" . ($value ? " selected" : "") . ">" . lang('Grant') . "<option value='0'" . ($value == "0" ? " selected" : "") . ">" . lang('Revoke') . "</select>";
} else {
echo "<td align='center'><label class='block'><input type='checkbox' name=$name value='1'" . ($value ? " checked" : "") . ($privilege == "All privileges" ? " id='grants-$i-all'" : ($privilege == "Grant option" ? "" : " onclick=\"if (this.checked) formUncheck('grants-$i-all');\"")) . "></label>"; //! uncheck all except grant if all is checked
echo "<td align='center'><label class='block'>";
echo "<input type='checkbox' name=$name value='1'" . ($value ? " checked" : "") . ($privilege == "All privileges"
? " id='grants-$i-all'>" //! uncheck all except grant if all is checked
: ">" . ($privilege == "Grant option" ? "" : script("qsl('input').onclick = function () { if (this.checked) formUncheck('grants-$i-all'); };")));
echo "</label>";
}
$i++;
}
@@ -180,6 +184,6 @@ echo "</table>\n";
?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if (isset($_GET["host"])) { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?php if (isset($_GET["host"])) { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', "$USER@$_GET[host]")); ?><?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -10,7 +10,7 @@ if (!$variables) {
foreach ($variables as $key => $val) {
echo "<tr>";
echo "<th><code class='jush-" . $jush . ($status ? "status" : "set") . "'>" . h($key) . "</code>";
echo "<td>" . nbsp($val);
echo "<td>" . h($val);
}
echo "</table>\n";
}

View File

@@ -48,11 +48,11 @@ page_header(($TABLE != "" ? lang('Alter view') : lang('Create view')), $error, a
?>
<form action="" method="post">
<p><?php echo lang('Name'); ?>: <input name="name" value="<?php echo h($row["name"]); ?>" maxlength="64" autocapitalize="off">
<p><?php echo lang('Name'); ?>: <input name="name" value="<?php echo h($row["name"]); ?>" data-maxlength="64" autocapitalize="off">
<?php echo (support("materializedview") ? " " . checkbox("materialized", 1, $row["materialized"], lang('Materialized view')) : ""); ?>
<p><?php textarea("select", $row["select"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($_GET["view"] != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo confirm(); ?>><?php } ?>
<?php if ($TABLE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $TABLE)); ?><?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>

View File

@@ -1,3 +1,166 @@
Adminer 4.7.3 (released 2019-08-27):
Allow editing foreign keys pointing to tables in other database/schema (bug #694)
Fix blocking of concurrent instances in PHP >7.2 (bug #703)
MySQL: Speed up displaying tables in large databases (bug #700, regression from 4.7.2)
MySQL: Allow editing rows identified by negative floats (bug #695)
MySQL: Skip editing generated columns
SQLite: Quote strings stored in integer columns in export (bug #696)
SQLite: Handle error in altering table (bug #697)
SQLite: Allow setting auto increment for empty tables
SQLite: Preserve auto increment when recreating table
MS SQL: Support foreign keys to other DB
MongoDB: Allow setting authSource from environment variable
Adminer 4.7.2 (released 2019-07-18):
Do not attempt logging in without password (bug #676)
Stretch footer over the whole table width (bug #624)
Allow overwriting tables when copying them
Fix displaying SQL command after Save and continue edit
Cache busting for adminer.css
MySQL: Fix displaying multi-columns foreign keys (bug #675, regression from 4.7.0)
MySQL: Fix creating users and changing password in MySQL 8 (bug #663)
MySQL: Pass SRID to GeomFromText
PostgreSQL: Fix setting column comments on new table
PostgreSQL: Display definitions of materialized views (bug #682)
PostgreSQL: Fix table status in PostgreSQL 12 (bug #683)
MS SQL: Support comments
Elasticsearch: Fix setting number of rows
Adminer 4.7.1 (released 2019-01-24):
Display the tables scrollbar (bug #647)
Remember visible columns in Create Table form (bug #493)
Add autocomplete attributes to login form
PHP <5.4 compatibility even with ClickHouse enabled (regression from 4.7.0)
SQLite: Hide server field in login form
Editor: Allow disabling boolean fields in PostgreSQL (bug #640)
Adminer 4.7.0 (released 2018-11-24):
Simplify storing executed SQL queries to bookmarks
Warn when using password with leading or trailing spaces
Hide import from server if importServerPath() returns an empty string
Fix inline editing of empty cells (regression from 4.6.3)
Allow adding more than two indexes and forign key columns at a time (regression from 4.4.0)
Avoid overwriting existing tables when copying tables (bug #642)
Fix function change with set data type
Increase username maxlength to 80 (bug #623)
Make maxlength in all fields a soft limit
Make tables horizontally scrollable
MySQL: Support foreign keys created with ANSI quotes (bug #620)
MySQL: Recognize ON UPDATE current_timestamp() (bug #632, bug #638)
MySQL: Descending indexes in MySQL 8 (bug #643)
PostgreSQL: Quote array values in export (bug #621)
PostgreSQL: Export DESC indexes (bug #639)
PostgreSQL: Support GENERATED BY DEFAULT AS IDENTITY in PostgreSQL 10
MS SQL: Pass database when connecting
ClickHouse: Connect, databases list, tables list, select, SQL command
Georgian translation
Adminer 4.6.3 (released 2018-06-28):
Disallow using password-less databases
Copy triggers when copying table
Stop session before connecting
Simplify running slow queries
Decrease timeout for running slow queries from 5 seconds to 2 seconds
Fix displaying info about non-alphabetical objects (bug #599)
Use secure cookies on HTTP if session.cookie_secure is set
PDO: Support binary fields download
MySQL: Disallow LOAD DATA LOCAL INFILE
MySQL: Use CONVERT() only when searching for non-ASCII (bug #603)
MySQL: Order database names in MySQL 8 (bug #613)
PostgreSQL: Fix editing data in views (bug #605, regression from 4.6.0)
PostgreSQL: Do not cast date/time/number/uuid searches to text (bug #608)
PostgreSQL: Export false as 0 in PDO (bug #619)
MS SQL: Support port with sqlsrv
Editor: Do not check boolean checkboxes with false in PostgreSQL (bug #607)
Adminer 4.6.2 (released 2018-02-20):
Semi-transparent border on table actions
Shorten JSON values in select (bug #594)
Speed up alter table form (regression from 4.4.0)
Store current version without authentication and in Editor
PostgreSQL: Fix exporting string default values
PostgreSQL: Fix exporting sequences in PostgreSQL 10
PostgreSQL: Add IF EXISTS to DROP SEQUENCE in export (bug #595)
Editor: Fix displaying of true boolean values (regression from 4.5.0)
Adminer 4.6.1 (released 2018-02-09):
Sticky position of table actions
Speed up rendering of long tables (regression from 4.4.0)
Display notification about performing action after relogin
Add system tables help links
MySQL: Support non-utf8 charset in search in column
MySQL: Support geometry in MySQL 8 (bug #574)
MariaDB: Links to documentation
SQLite: Allow deleting PRIMARY KEY from tables with auto increment
PostgreSQL: Support binary files in bytea fields
PostgreSQL: Don't treat interval type as number (bug #474)
PostgreSQL: Cast to string when searching using LIKE (bug #325)
PostgreSQL: Fix condition for selecting no rows
PostgreSQL: Support TRUNCATE+INSERT export
Customization: Support connecting to MySQL via SSL
Customization: Allow specifying server name displayed in breadcrumbs
Adminer 4.6.0 (released 2018-02-05):
Fix counting selected rows after going back to select page
PHP <5.3 compatibility even with Elasticsearch enabled
Fully support functions in default values
Stop redirecting links via adminer.org
Support X-Forwarded-Prefix
Display options for timestamp columns when creating a new table
Disable autocompleting password on create user page
Use primary key to edit rows even if not selected
MySQL, PostgreSQL: Display warnings
MySQL: Add floor and ceil select functions
MySQL: Add FIND_IN_SET search operator
MariaDB: Support JSON since MariaDB 10.2
SQLite, PostgreSQL: Limit rows in data manipulation without unique key
PostgreSQL: Support routines
PostgreSQL: Allow editing views with uppercase letters (bug #467)
PostgreSQL: Allow now() as default value (bug #525)
SimpleDB: Document that allow_url_fopen is required
Malay translation
Adminer 4.5.0 (released 2018-01-24):
Display name of the object in confirmation when dropping it
Display newlines in column comments (bug #573)
Support current_timestamp() as default of time fields (bug #572)
Hide window.opener from pages opened in a new window (bug #561)
Display error when getting row to edit
Store current Adminer version server-side to avoid excessive requests
Adminer: Fix Search data in tables (regression from 4.4.0)
CSP: Allow any styles, images, media and fonts, disallow base-uri
MySQL: Support geometry in MySQL 8 (bug #574)
MySQL: Support routines with comments in parameters (bug #460)
MariaDB: Support fulltext and spatial indexes in InnoDB (bug #583)
SQLite: Enable foreign key checks
PostgreSQL: Respect NULL default value
PostgreSQL: Display foreign tables (bug #576)
PostgreSQL: Do not export triggers if not requested
PostgreSQL: Export DROP SEQUENCE if dropping table
PostgreSQL: Display boolean values as code (bug #562)
MS SQL: Support freetds
non-MySQL: Avoid CONVERT() (bug #509)
Elasticsearch: Insert, update, delete
MongoDB: Support mongodb PHP extension
Editor: Fix displaying of false values in PostgreSQL (bug #568)
Adminer 4.4.0 (released 2018-01-17):
Add Content Security Policy
Disallow scripts without nonce
Rate limit password-less login attempts from the same IP address
Disallow connecting to privileged ports
Add nosniff header
PHP 7.1: Prevent warning when using empty limit
PHP 7.2: Prevent warning when searching in select
MySQL: Remove dedicated view for replication status (added in 4.3.0)
PostgreSQL: Sort table names (regression from 4.3.1)
Editor: Don't set time zone from PHP, fixes DST
Editor: Display field comment's text inside [] only in edit form
Editor: Fix doubleclick on database page
Editor: Fix Search data in tables
Customization: Always send security headers
Hebrew translation
Adminer 4.3.1 (released 2017-04-14):
Fix permanent login after logout (bug #539)
Fix SQL command autofocus (regression from 4.0.0)

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