diff options
Diffstat (limited to 'libraries')
395 files changed, 11680 insertions, 10696 deletions
diff --git a/libraries/advisory_rules_generic.php b/libraries/advisory_rules_generic.php deleted file mode 100644 index e3970c9402..0000000000 --- a/libraries/advisory_rules_generic.php +++ /dev/null @@ -1,718 +0,0 @@ -<?php - -declare(strict_types=1); - -return [ - // Queries - [ - 'id' => 'Uptime below one day', - 'name' => __('Uptime below one day'), - 'formula' => 'Uptime', - 'test' => 'value < 86400', - 'issue' => __('Uptime is less than 1 day, performance tuning may not be accurate.'), - 'recommendation' => __( - 'To have more accurate averages it is recommended to let the server run for' - . ' longer than a day before running this analyzer' - ), - 'justification' => __('The uptime is only %s'), - 'justification_formula' => 'ADVISOR_timespanFormat(Uptime)', - ], - [ - 'id' => 'Questions below 1,000', - 'name' => __('Questions below 1,000'), - 'formula' => 'Questions', - 'test' => 'value < 1000', - 'issue' => __( - 'Fewer than 1,000 questions have been run against this server.' - . ' The recommendations may not be accurate.' - ), - 'recommendation' => __( - 'Let the server run for a longer time until it has executed a greater amount of queries.' - ), - 'justification' => __('Current amount of Questions: %s'), - 'justification_formula' => 'Questions', - ], - [ - 'id' => 'Percentage of slow queries', - 'name' => __('Percentage of slow queries'), - 'precondition' => 'Questions > 0', - 'formula' => 'Slow_queries / Questions * 100', - 'test' => 'value >= 5', - 'issue' => __('There is a lot of slow queries compared to the overall amount of Queries.'), - 'recommendation' => __( - 'You might want to increase {long_query_time} or optimize the queries listed in the slow query log' - ), - 'justification' => __('The slow query rate should be below 5%%, your value is %s%%.'), - 'justification_formula' => 'round(value,2)', - ], - [ - 'id' => 'Slow query rate', - 'name' => __('Slow query rate'), - 'precondition' => 'Questions > 0', - 'formula' => '(Slow_queries / Questions * 100) / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('There is a high percentage of slow queries compared to the server uptime.'), - 'recommendation' => __( - 'You might want to increase {long_query_time} or optimize the queries listed in the slow query log' - ), - 'justification' => __('You have a slow query rate of %s per hour, you should have less than 1%% per hour.'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Long query time', - 'name' => __('Long query time'), - 'formula' => 'long_query_time', - 'test' => 'value >= 10', - 'issue' => __( - '{long_query_time} is set to 10 seconds or more,' - . ' thus only slow queries that take above 10 seconds are logged.' - ), - 'recommendation' => __( - 'It is suggested to set {long_query_time} to a lower value, depending on your environment.' - . ' Usually a value of 1-5 seconds is suggested.' - ), - 'justification' => __('long_query_time is currently set to %ds.'), - 'justification_formula' => 'value', - ], - [ - 'id' => 'Slow query logging', - 'name' => __('Slow query logging'), - 'precondition' => 'PMA_MYSQL_INT_VERSION < 50600', - 'formula' => 'log_slow_queries', - 'test' => 'value == \'OFF\'', - 'issue' => __('The slow query log is disabled.'), - 'recommendation' => __( - 'Enable slow query logging by setting {log_slow_queries} to \'ON\'.' - . ' This will help troubleshooting badly performing queries.' - ), - 'justification' => __('log_slow_queries is set to \'OFF\''), - ], - [ - 'id' => 'Slow query logging', - 'name' => __('Slow query logging'), - 'precondition' => 'PMA_MYSQL_INT_VERSION >= 50600', - 'formula' => 'slow_query_log', - 'test' => 'value == \'OFF\'', - 'issue' => __('The slow query log is disabled.'), - 'recommendation' => __( - 'Enable slow query logging by setting {slow_query_log} to \'ON\'.' - . ' This will help troubleshooting badly performing queries.' - ), - 'justification' => __('slow_query_log is set to \'OFF\''), - ], - // Versions - [ - 'id' => 'Release Series', - 'name' => __('Release Series'), - 'formula' => 'version', - 'test' => 'substr(value,0,2) <= \'5.\' && substr(value,2,1) < 1', - 'issue' => __('The MySQL server version less than 5.1.'), - 'recommendation' => __( - 'You should upgrade, as MySQL 5.1 has improved performance, and MySQL 5.5 even more so.' - ), - 'justification' => __('Current version: %s'), - 'justification_formula' => 'value', - ], - [ - 'id' => 'Minor Version', - 'name' => __('Minor Version'), - 'precondition' => '! fired(\'Release Series\')', - 'formula' => 'version', - 'test' => 'substr(value,0,2) <= \'5.\' && substr(value,2,1) <= 1 && substr(value,4,2) < 30', - 'issue' => __('Version less than 5.1.30 (the first GA release of 5.1).'), - 'recommendation' => __( - 'You should upgrade, as recent versions of MySQL 5.1 have improved performance' - . ' and MySQL 5.5 even more so.' - ), - 'justification' => __('Current version: %s'), - 'justification_formula' => 'value', - ], - [ - 'id' => 'Minor Version', - 'name' => __('Minor Version'), - 'precondition' => '! fired(\'Release Series\')', - 'formula' => 'version', - 'test' => 'substr(value,0,1) == 5 && substr(value,2,1) == 5 && substr(value,4,2) < 8', - 'issue' => __('Version less than 5.5.8 (the first GA release of 5.5).'), - 'recommendation' => __('You should upgrade, to a stable version of MySQL 5.5.'), - 'justification' => __('Current version: %s'), - 'justification_formula' => 'value', - ], - [ - 'id' => 'Distribution', - 'name' => __('Distribution'), - 'formula' => 'version_comment', - 'test' => 'preg_match(\'/source/i\',value)', - 'issue' => __('Version is compiled from source, not a MySQL official binary.'), - 'recommendation' => __( - 'If you did not compile from source, you may be using a package modified by a distribution.' - . ' The MySQL manual only is accurate for official MySQL binaries,' - . ' not any package distributions (such as RedHat, Debian/Ubuntu etc).' - ), - 'justification' => __('\'source\' found in version_comment'), - ], - [ - 'id' => 'Distribution', - 'name' => __('Distribution'), - 'formula' => 'version_comment', - 'test' => 'preg_match(\'/percona/i\',value)', - 'issue' => __('The MySQL manual only is accurate for official MySQL binaries.'), - 'recommendation' => __( - 'Percona documentation is at <a href="https://www.percona.com/software/documentation/">' - . 'https://www.percona.com/software/documentation/</a>' - ), - 'justification' => __('\'percona\' found in version_comment'), - ], - [ - 'id' => 'MySQL Architecture', - 'name' => __('MySQL Architecture'), - 'formula' => 'system_memory', - 'test' => 'value > 3072*1024 && !preg_match(\'/64/\',version_compile_machine)' - . ' && !preg_match(\'/64/\',version_compile_os)', - 'issue' => __('MySQL is not compiled as a 64-bit package.'), - 'recommendation' => __( - 'Your memory capacity is above 3 GiB (assuming the Server is on localhost),' - . ' so MySQL might not be able to access all of your memory.' - . ' You might want to consider installing the 64-bit version of MySQL.' - ), - 'justification' => __('Available memory on this host: %s'), - 'justification_formula' => 'ADVISOR_formatByteDown(value*1024, 2, 2)', - ], - // Query cache - [ - 'id' => 'Query caching method', - 'name' => __('Query caching method'), - 'precondition' => '!fired(\'Query cache disabled\')', - 'formula' => 'Questions / Uptime', - 'test' => 'value > 100', - 'issue' => __('Suboptimal caching method.'), - 'recommendation' => __( - 'You are using the MySQL Query cache with a fairly high traffic database.' - . ' It might be worth considering to use ' - . '<a href="https://dev.mysql.com/doc/refman/5.6/en/ha-memcached.html">memcached</a>' - . ' instead of the MySQL Query cache, especially if you have multiple replicas.' - ), - 'justification' => __( - 'The query cache is enabled and the server receives %d queries per second.' - . ' This rule fires if there is more than 100 queries per second.' - ), - 'justification_formula' => 'round(value,1)', - ], - // Sorts - [ - 'id' => 'Percentage of sorts that cause temporary tables', - 'name' => __('Percentage of sorts that cause temporary tables'), - 'precondition' => 'Sort_scan + Sort_range > 0', - 'formula' => 'Sort_merge_passes / (Sort_scan + Sort_range) * 100', - 'test' => 'value > 10', - 'issue' => __('Too many sorts are causing temporary tables.'), - 'recommendation' => __( - 'Consider increasing {sort_buffer_size} and/or {read_rnd_buffer_size},' - . ' depending on your system memory limits.' - ), - 'justification' => __('%s%% of all sorts cause temporary tables, this value should be lower than 10%%.'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Rate of sorts that cause temporary tables', - 'name' => __('Rate of sorts that cause temporary tables'), - 'formula' => 'Sort_merge_passes / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('Too many sorts are causing temporary tables.'), - 'recommendation' => __( - 'Consider increasing {sort_buffer_size} and/or {read_rnd_buffer_size},' - . ' depending on your system memory limits.' - ), - 'justification' => __('Temporary tables average: %s, this value should be less than 1 per hour.'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Sort rows', - 'name' => __('Sort rows'), - 'formula' => 'Sort_rows / Uptime', - 'test' => 'value * 60 >= 1', - 'issue' => __('There are lots of rows being sorted.'), - 'recommendation' => __( - 'While there is nothing wrong with a high amount of row sorting, you might want to' - . ' make sure that the queries which require a lot of sorting use indexed columns in' - . ' the ORDER BY clause, as this will result in much faster sorting.' - ), - 'justification' => __('Sorted rows average: %s'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - // Joins, scans - [ - 'id' => 'Rate of joins without indexes', - 'name' => __('Rate of joins without indexes'), - 'formula' => '(Select_range_check + Select_scan + Select_full_join) / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('There are too many joins without indexes.'), - 'recommendation' => __( - 'This means that joins are doing full table scans. Adding indexes for the columns being' - . ' used in the join conditions will greatly speed up table joins.' - ), - 'justification' => __('Table joins average: %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Rate of reading first index entry', - 'name' => __('Rate of reading first index entry'), - 'formula' => 'Handler_read_first / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('The rate of reading the first index entry is high.'), - 'recommendation' => __( - 'This usually indicates frequent full index scans. Full index scans are faster than' - . ' table scans but require lots of CPU cycles in big tables, if those tables that have or' - . ' had high volumes of UPDATEs and DELETEs, running \'OPTIMIZE TABLE\' might reduce the' - . ' amount of and/or speed up full index scans. Other than that full index scans can' - . ' only be reduced by rewriting queries.' - ), - 'justification' => __('Index scans average: %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Rate of reading fixed position', - 'name' => __('Rate of reading fixed position'), - 'formula' => 'Handler_read_rnd / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('The rate of reading data from a fixed position is high.'), - 'recommendation' => __( - 'This indicates that many queries need to sort results and/or do a full table scan,' - . ' including join queries that do not use indexes. Add indexes where applicable.' - ), - 'justification' => __('Rate of reading fixed position average: %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Rate of reading next table row', - 'name' => __('Rate of reading next table row'), - 'formula' => 'Handler_read_rnd_next / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('The rate of reading the next table row is high.'), - 'recommendation' => __( - 'This indicates that many queries are doing full table scans. Add indexes where applicable.' - ), - 'justification' => __('Rate of reading next table row: %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - // Temp tables - [ - 'id' => 'Different tmp_table_size and max_heap_table_size', - 'name' => __('Different tmp_table_size and max_heap_table_size'), - 'formula' => 'tmp_table_size - max_heap_table_size', - 'test' => 'value !=0', - 'issue' => __('{tmp_table_size} and {max_heap_table_size} are not the same.'), - 'recommendation' => __( - 'If you have deliberately changed one of either: The server uses the lower value of either' - . ' to determine the maximum size of in-memory tables. So if you wish to increase the' - . ' in-memory table limit you will have to increase the other value as well.' - ), - 'justification' => __('Current values are tmp_table_size: %s, max_heap_table_size: %s'), - 'justification_formula' => 'ADVISOR_formatByteDown(tmp_table_size, 2, 2),' - . ' ADVISOR_formatByteDown(max_heap_table_size, 2, 2)', - ], - [ - 'id' => 'Percentage of temp tables on disk', - 'name' => __('Percentage of temp tables on disk'), - 'precondition' => 'Created_tmp_tables + Created_tmp_disk_tables > 0', - 'formula' => 'Created_tmp_disk_tables / (Created_tmp_tables + Created_tmp_disk_tables) * 100', - 'test' => 'value > 25', - 'issue' => __('Many temporary tables are being written to disk instead of being kept in memory.'), - 'recommendation' => __( - 'Increasing {max_heap_table_size} and {tmp_table_size} might help. However some' - . ' temporary tables are always being written to disk, independent of the value of these variables.' - . ' To eliminate these you will have to rewrite your queries to avoid those conditions' - . ' (Within a temporary table: Presence of a BLOB or TEXT column or presence of a column' - . ' bigger than 512 bytes) as mentioned in the beginning of an <a href="' - . 'https://www.facebook.com/note.php?note_id=10150111255065841&comments' - . '">Article by the Pythian Group</a>' - ), - 'justification' => __( - '%s%% of all temporary tables are being written to disk, this value should be below 25%%' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Temp disk rate', - 'name' => __('Temp disk rate'), - 'precondition' => '!fired(\'Percentage of temp tables on disk\')', - 'formula' => 'Created_tmp_disk_tables / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('Many temporary tables are being written to disk instead of being kept in memory.'), - 'recommendation' => __( - 'Increasing {max_heap_table_size} and {tmp_table_size} might help. However some' - . ' temporary tables are always being written to disk, independent of the value of these variables.' - . ' To eliminate these you will have to rewrite your queries to avoid those conditions' - . ' (Within a temporary table: Presence of a BLOB or TEXT column or presence of a column' - . ' bigger than 512 bytes) as mentioned in the <a href="' - . 'https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html' - . '">MySQL Documentation</a>' - ), - 'justification' => __( - 'Rate of temporary tables being written to disk: %s, this value should be less than 1 per hour' - ), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - // MyISAM index cache - [ - 'id' => 'MyISAM key buffer size', - 'name' => __('MyISAM key buffer size'), - 'formula' => 'key_buffer_size', - 'test' => 'value == 0', - 'issue' => __('Key buffer is not initialized. No MyISAM indexes will be cached.'), - 'recommendation' => __( - 'Set {key_buffer_size} depending on the size of your MyISAM indexes. 64M is a good start.' - ), - 'justification' => __('key_buffer_size is 0'), - ], - [ - 'id' => 'Max % MyISAM key buffer ever used', - /* xgettext:no-php-format */ - 'name' => __('Max % MyISAM key buffer ever used'), - 'precondition' => 'key_buffer_size > 0', - 'formula' => 'Key_blocks_used * key_cache_block_size / key_buffer_size * 100', - 'test' => 'value < 95', - /* xgettext:no-php-format */ - 'issue' => __('MyISAM key buffer (index cache) % used is low.'), - 'recommendation' => __( - 'You may need to decrease the size of {key_buffer_size}, re-examine your tables to see' - . ' if indexes have been removed, or examine queries and expectations' - . ' about what indexes are being used.' - ), - 'justification' => __('max %% MyISAM key buffer ever used: %s%%, this value should be above 95%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Percentage of MyISAM key buffer used', - 'name' => __('Percentage of MyISAM key buffer used'), - // Don't fire if above rule fired - we don't need the same advice twice - 'precondition' => 'key_buffer_size > 0 && !fired(\'Max % MyISAM key buffer ever used\')', - 'formula' => '( 1 - Key_blocks_unused * key_cache_block_size / key_buffer_size) * 100', - 'test' => 'value < 95', - /* xgettext:no-php-format */ - 'issue' => __('MyISAM key buffer (index cache) % used is low.'), - 'recommendation' => __( - 'You may need to decrease the size of {key_buffer_size}, re-examine your tables to see' - . ' if indexes have been removed, or examine queries and expectations' - . ' about what indexes are being used.' - ), - 'justification' => __('%% MyISAM key buffer used: %s%%, this value should be above 95%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Percentage of index reads from memory', - 'name' => __('Percentage of index reads from memory'), - 'precondition' => 'Key_read_requests > 0', - 'formula' => '100 - (Key_reads / Key_read_requests * 100)', - 'test' => 'value < 95', - /* xgettext:no-php-format */ - 'issue' => __('The % of indexes that use the MyISAM key buffer is low.'), - 'recommendation' => __('You may need to increase {key_buffer_size}.'), - 'justification' => __('Index reads from memory: %s%%, this value should be above 95%%'), - 'justification_formula' => 'round(value,1)', - ], - // Other caches - [ - 'id' => 'Rate of table open', - 'name' => __('Rate of table open'), - 'formula' => 'Opened_tables / Uptime', - 'test' => 'value*60*60 > 10', - 'issue' => __('The rate of opening tables is high.'), - 'recommendation' => __( - 'Opening tables requires disk I/O which is costly. Increasing {table_open_cache} might avoid this.' - ), - 'justification' => __('Opened table rate: %s, this value should be less than 10 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Percentage of used open files limit', - 'name' => __('Percentage of used open files limit'), - 'formula' => 'Open_files / open_files_limit * 100', - 'test' => 'value > 85', - 'issue' => __( - 'The number of open files is approaching the max number of open files.' - . ' You may get a "Too many open files" error.' - ), - 'recommendation' => __( - 'Consider increasing {open_files_limit}, and check the error log when' - . ' restarting after changing {open_files_limit}.' - ), - 'justification' => __('The number of opened files is at %s%% of the limit. It should be below 85%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Rate of open files', - 'name' => __('Rate of open files'), - 'formula' => 'Open_files / Uptime', - 'test' => 'value * 60 * 60 > 5', - 'issue' => __('The rate of opening files is high.'), - 'recommendation' => __( - 'Consider increasing {open_files_limit}, and check the error log when' - . ' restarting after changing {open_files_limit}.' - ), - 'justification' => __('Opened files rate: %s, this value should be less than 5 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Immediate table locks %', - /* xgettext:no-php-format */ - 'name' => __('Immediate table locks %'), - 'precondition' => 'Table_locks_waited + Table_locks_immediate > 0', - 'formula' => 'Table_locks_immediate / (Table_locks_waited + Table_locks_immediate) * 100', - 'test' => 'value < 95', - 'issue' => __('Too many table locks were not granted immediately.'), - 'recommendation' => __('Optimize queries and/or use InnoDB to reduce lock wait.'), - 'justification' => __('Immediate table locks: %s%%, this value should be above 95%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Table lock wait rate', - 'name' => __('Table lock wait rate'), - 'formula' => 'Table_locks_waited / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('Too many table locks were not granted immediately.'), - 'recommendation' => __('Optimize queries and/or use InnoDB to reduce lock wait.'), - 'justification' => __('Table lock wait rate: %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Thread cache', - 'name' => __('Thread cache'), - 'formula' => 'thread_cache_size', - 'test' => 'value < 1', - 'issue' => __('Thread cache is disabled, resulting in more overhead from new connections to MySQL.'), - 'recommendation' => __('Enable the thread cache by setting {thread_cache_size} > 0.'), - 'justification' => __('The thread cache is set to 0'), - ], - [ - 'id' => 'Thread cache hit rate %', - /* xgettext:no-php-format */ - 'name' => __('Thread cache hit rate %'), - 'precondition' => 'thread_cache_size > 0', - 'formula' => '100 - Threads_created / Connections', - 'test' => 'value < 80', - 'issue' => __('Thread cache is not efficient.'), - 'recommendation' => __('Increase {thread_cache_size}.'), - 'justification' => __('Thread cache hitrate: %s%%, this value should be above 80%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Threads that are slow to launch', - 'name' => __('Threads that are slow to launch'), - 'precondition' => 'slow_launch_time > 0', - 'formula' => 'Slow_launch_threads', - 'test' => 'value > 0', - 'issue' => __('There are too many threads that are slow to launch.'), - 'recommendation' => __( - 'This generally happens in case of general system overload as it is pretty simple' - . ' operations. You might want to monitor your system load carefully.' - ), - 'justification' => __('%s thread(s) took longer than %s seconds to start, it should be 0'), - 'justification_formula' => 'value, slow_launch_time', - ], - [ - 'id' => 'Slow launch time', - 'name' => __('Slow launch time'), - 'formula' => 'slow_launch_time', - 'test' => 'value > 2', - 'issue' => __('Slow_launch_time is above 2s.'), - 'recommendation' => __( - 'Set {slow_launch_time} to 1s or 2s to correctly count threads that are slow to launch.' - ), - 'justification' => __('slow_launch_time is set to %s'), - 'justification_formula' => 'value', - ], - // Connections - [ - 'id' => 'Percentage of used connections', - 'name' => __('Percentage of used connections'), - 'formula' => 'Max_used_connections / max_connections * 100', - 'test' => 'value > 80', - 'issue' => __('The maximum amount of used connections is getting close to the value of {max_connections}.'), - 'recommendation' => __( - 'Increase {max_connections}, or decrease {wait_timeout} so that connections that do not' - . ' close database handlers properly get killed sooner.' - . ' Make sure the code closes database handlers properly.' - ), - 'justification' => __('Max_used_connections is at %s%% of max_connections, it should be below 80%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Percentage of aborted connections', - 'name' => __('Percentage of aborted connections'), - 'formula' => 'Aborted_connects / Connections * 100', - 'test' => 'value > 1', - 'issue' => __('Too many connections are aborted.'), - 'recommendation' => __( - 'Connections are usually aborted when they cannot be authorized. <a href="' - . 'https://www.percona.com/blog/2008/08/23/how-to-track-down-the-source-of-aborted_connects/' - . '">This article</a> might help you track down the source.' - ), - 'justification' => __('%s%% of all connections are aborted. This value should be below 1%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Rate of aborted connections', - 'name' => __('Rate of aborted connections'), - 'formula' => 'Aborted_connects / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('Too many connections are aborted.'), - 'recommendation' => __( - 'Connections are usually aborted when they cannot be authorized. <a href="' - . 'https://www.percona.com/blog/2008/08/23/how-to-track-down-the-source-of-aborted_connects/' - . '">This article</a> might help you track down the source.' - ), - 'justification' => __('Aborted connections rate is at %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - [ - 'id' => 'Percentage of aborted clients', - 'name' => __('Percentage of aborted clients'), - 'formula' => 'Aborted_clients / Connections * 100', - 'test' => 'value > 2', - 'issue' => __('Too many clients are aborted.'), - 'recommendation' => __( - 'Clients are usually aborted when they did not close their connection to MySQL properly.' - . ' This can be due to network issues or code not closing a database handler properly.' - . ' Check your network and code.' - ), - 'justification' => __('%s%% of all clients are aborted. This value should be below 2%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Rate of aborted clients', - 'name' => __('Rate of aborted clients'), - 'formula' => 'Aborted_clients / Uptime', - 'test' => 'value * 60 * 60 > 1', - 'issue' => __('Too many clients are aborted.'), - 'recommendation' => __( - 'Clients are usually aborted when they did not close their connection to MySQL properly.' - . ' This can be due to network issues or code not closing a database handler properly.' - . ' Check your network and code.' - ), - 'justification' => __('Aborted client rate is at %s, this value should be less than 1 per hour'), - 'justification_formula' => 'ADVISOR_bytime(value,2)', - ], - // InnoDB - [ - 'id' => 'Is InnoDB disabled?', - 'name' => __('Is InnoDB disabled?'), - 'precondition' => 'PMA_MYSQL_INT_VERSION < 50600', - 'formula' => 'have_innodb', - 'test' => 'value != "YES"', - 'issue' => __('You do not have InnoDB enabled.'), - 'recommendation' => __('InnoDB is usually the better choice for table engines.'), - 'justification' => __('have_innodb is set to \'value\''), - ], - [ - 'id' => 'InnoDB log size', - 'name' => __('InnoDB log size'), - 'precondition' => 'innodb_buffer_pool_size > 0 && ! (IS_MARIADB && PMA_MYSQL_INT_VERSION > 100500)', - 'formula' => '(innodb_log_file_size * innodb_log_files_in_group)/ innodb_buffer_pool_size * 100', - 'test' => 'value < 20 && innodb_log_file_size / (1024 * 1024) < 256', - 'issue' => __('The InnoDB log file size is not an appropriate size, in relation to the InnoDB buffer pool.'), - 'recommendation' => __(/* xgettext:no-php-format */ - 'Especially on a system with a lot of writes to InnoDB tables you should set' - . ' {innodb_log_file_size} to 25% of {innodb_buffer_pool_size}. However the bigger this value,' - . ' the longer the recovery time will be when database crashes, so this value should not be set' - . ' much higher than 256 MiB. Please note however that you cannot simply change the value of' - . ' this variable. You need to shutdown the server, remove the InnoDB log files, set the new' - . ' value in my.cnf, start the server, then check the error logs if everything went fine.' - . ' See also <a href="' - . 'https://mysqldatabaseadministration.blogspot.com/2007/01/increase-innodblogfilesize-proper-way.html' - . '">this blog entry</a>' - ), - 'justification' => __( - 'Your InnoDB log size is at %s%% in relation to the InnoDB buffer pool size,' - . ' it should not be below 20%%' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'InnoDB log size', - 'name' => __('InnoDB log size'), - 'precondition' => 'innodb_buffer_pool_size > 0 && IS_MARIADB && PMA_MYSQL_INT_VERSION > 100500', - // From MariaDB 10.5, there is 1 redo log. - // For MariaDB 10.4 and before, the number of redo log files is configured - // by the innodb_log_files_in_group system variable. - 'formula' => 'innodb_log_file_size / innodb_buffer_pool_size * 100', - 'test' => 'value < 20 && innodb_log_file_size / (1024 * 1024) < 256', - 'issue' => __('The InnoDB log file size is not an appropriate size, in relation to the InnoDB buffer pool.'), - 'recommendation' => __(/* xgettext:no-php-format */ - 'Especially on a system with a lot of writes to InnoDB tables you should set' - . ' {innodb_log_file_size} to 25% of {innodb_buffer_pool_size}. However the bigger this value,' - . ' the longer the recovery time will be when database crashes, so this value should not be set' - . ' much higher than 256 MiB. Please note however that you cannot simply change the value of' - . ' this variable. You need to shutdown the server, remove the InnoDB log files, set the new' - . ' value in my.cnf, start the server, then check the error logs if everything went fine.' - . ' See also <a href="' - . 'https://mysqldatabaseadministration.blogspot.com/2007/01/increase-innodblogfilesize-proper-way.html' - . '">this blog entry</a>' - ), - 'justification' => __( - 'Your InnoDB log size is at %s%% in relation to the InnoDB buffer pool size,' - . ' it should not be below 20%%' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Max InnoDB log size', - 'name' => __('Max InnoDB log size'), - 'precondition' => 'innodb_buffer_pool_size > 0 && innodb_log_file_size / innodb_buffer_pool_size * 100 < 30', - 'formula' => 'innodb_log_file_size / (1024 * 1024)', - 'test' => 'value > 256', - 'issue' => __('The InnoDB log file size is inadequately large.'), - 'recommendation' => __(/* xgettext:no-php-format */ - 'It is usually sufficient to set {innodb_log_file_size} to 25% of the size of' - . ' {innodb_buffer_pool_size}. A very big {innodb_log_file_size} slows down the recovery' - . ' time after a database crash considerably. See also ' - . '<a href="https://www.percona.com/blog/2006/07/03/choosing-proper-innodb_log_file_size/">' - . 'this Article</a>. You need to shutdown the server, remove the InnoDB log files, set the' - . ' new value in my.cnf, start the server, then check the error logs' - . ' if everything went fine. See also <a href="' - . 'https://mysqldatabaseadministration.blogspot.com/2007/01/increase-innodblogfilesize-proper-way.html' - . '">this blog entry</a>' - ), - 'justification' => __('Your absolute InnoDB log size is %s MiB'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'InnoDB buffer pool size', - 'name' => __('InnoDB buffer pool size'), - 'precondition' => 'system_memory > 0', - 'formula' => 'innodb_buffer_pool_size / system_memory * 100', - 'test' => 'value < 60', - 'issue' => __('Your InnoDB buffer pool is fairly small.'), - 'recommendation' => __(/* xgettext:no-php-format */ - 'The InnoDB buffer pool has a profound impact on performance for InnoDB tables.' - . ' Assign all your remaining memory to this buffer. For database servers that use solely InnoDB' - . ' as storage engine and have no other services (e.g. a web server) running, you may set this' - . ' as high as 80% of your available memory. If that is not the case, you need to carefully' - . ' assess the memory consumption of your other services and non-InnoDB-Tables and set this' - . ' variable accordingly. If it is set too high, your system will start swapping,' - . ' which decreases performance significantly. See also ' - . '<a href="https://www.percona.com/blog/2007/11/03/choosing-innodb_buffer_pool_size/">this article</a>' - ), - 'justification' => __( - 'You are currently using %s%% of your memory for the InnoDB buffer pool.' - . ' This rule fires if you are assigning less than 60%%, however this might be perfectly' - . ' adequate for your system if you don\'t have much InnoDB tables' - . ' or other services running on the same machine.' - ), - 'justification_formula' => 'value', - ], - // Other - [ - 'id' => 'MyISAM concurrent inserts', - 'name' => __('MyISAM concurrent inserts'), - 'formula' => 'concurrent_insert', - 'test' => 'value === 0 || value === \'NEVER\'', - 'issue' => __('Enable {concurrent_insert} by setting it to 1'), - 'recommendation' => __( - 'Setting {concurrent_insert} to 1 reduces contention between' - . ' readers and writers for a given table. See also ' - . '<a href="https://dev.mysql.com/doc/refman/5.5/en/concurrent-inserts.html">MySQL Documentation</a>' - ), - 'justification' => __('concurrent_insert is set to 0'), - ], -]; diff --git a/libraries/advisory_rules_mysql_before80003.php b/libraries/advisory_rules_mysql_before80003.php deleted file mode 100644 index 4493c16eea..0000000000 --- a/libraries/advisory_rules_mysql_before80003.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php - -declare(strict_types=1); - -return [ - // Query cache - [ - 'id' => 'Query cache disabled', - 'name' => __('Query cache disabled'), - 'formula' => 'query_cache_size', - 'test' => 'value == 0 || query_cache_type == \'OFF\' || query_cache_type == \'0\'', - 'issue' => __('The query cache is not enabled.'), - 'recommendation' => __( - 'The query cache is known to greatly improve performance if configured correctly. Enable it by' - . ' setting {query_cache_size} to a 2 digit MiB value and setting {query_cache_type} to \'ON\'.' - . ' <b>Note:</b> If you are using memcached, ignore this recommendation.' - ), - 'justification' => __('query_cache_size is set to 0 or query_cache_type is set to \'OFF\''), - ], - [ - 'id' => 'Query cache efficiency (%)', - /* xgettext:no-php-format */ - 'name' => __('Query cache efficiency (%)'), - 'precondition' => 'Com_select + Qcache_hits > 0 && !fired(\'Query cache disabled\')', - 'formula' => 'Qcache_hits / (Com_select + Qcache_hits) * 100', - 'test' => 'value < 20', - 'issue' => __('Query cache not running efficiently, it has a low hit rate.'), - 'recommendation' => __('Consider increasing {query_cache_limit}.'), - 'justification' => __('The current query cache hit rate of %s%% is below 20%%'), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Query Cache usage', - 'name' => __('Query Cache usage'), - 'precondition' => '!fired(\'Query cache disabled\')', - 'formula' => '100 - Qcache_free_memory / query_cache_size * 100', - 'test' => 'value < 80', - /* xgettext:no-php-format */ - 'issue' => __('Less than 80% of the query cache is being utilized.'), - 'recommendation' => __( - 'This might be caused by {query_cache_limit} being too low.' - . ' Flushing the query cache might help as well.' - ), - 'justification' => __( - 'The current ratio of free query cache memory to total query' - . ' cache size is %s%%. It should be above 80%%' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Query cache fragmentation', - 'name' => __('Query cache fragmentation'), - 'precondition' => '!fired(\'Query cache disabled\')', - 'formula' => 'Qcache_free_blocks / (Qcache_total_blocks / 2) * 100', - 'test' => 'value > 20', - 'issue' => __('The query cache is considerably fragmented.'), - 'recommendation' => __( - 'Severe fragmentation is likely to (further) increase Qcache_lowmem_prunes. This might be' - . ' caused by many Query cache low memory prunes due to {query_cache_size} being too small. For a' - . ' immediate but short lived fix you can flush the query cache (might lock the query cache for a' - . ' long time). Carefully adjusting {query_cache_min_res_unit} to a lower value might help too,' - . ' e.g. you can set it to the average size of your queries in the cache using this formula:' - . ' (query_cache_size - qcache_free_memory) / qcache_queries_in_cache' - ), - 'justification' => __( - 'The cache is currently fragmented by %s%% , with 100%% fragmentation meaning that the query' - . ' cache is an alternating pattern of free and used blocks. This value should be below 20%%.' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Query cache low memory prunes', - 'name' => __('Query cache low memory prunes'), - 'precondition' => 'Qcache_inserts > 0 && !fired(\'Query cache disabled\')', - 'formula' => 'Qcache_lowmem_prunes / Qcache_inserts * 100', - 'test' => 'value > 0.1', - 'issue' => __('Cached queries are removed due to low query cache memory from the query cache.'), - 'recommendation' => __( - 'You might want to increase {query_cache_size}, however keep in mind that the overhead of' - . ' maintaining the cache is likely to increase with its size, so do this in small increments' - . ' and monitor the results.' - ), - 'justification' => __( - 'The ratio of removed queries to inserted queries is %s%%. The lower this value is,' - . ' the better (This rules firing limit: 0.1%%)' - ), - 'justification_formula' => 'round(value,1)', - ], - [ - 'id' => 'Query cache max size', - 'name' => __('Query cache max size'), - 'precondition' => '!fired(\'Query cache disabled\')', - 'formula' => 'query_cache_size', - 'test' => 'value > 1024 * 1024 * 128', - 'issue' => __( - 'The query cache size is above 128 MiB. Big query caches may cause significant' - . ' overhead that is required to maintain the cache.' - ), - 'recommendation' => __( - 'Depending on your environment, it might be performance increasing to reduce this value.' - ), - 'justification' => __('Current query cache size: %s'), - 'justification_formula' => 'ADVISOR_formatByteDown(value, 2, 2)', - ], - [ - 'id' => 'Query cache min result size', - 'name' => __('Query cache min result size'), - 'precondition' => '!fired(\'Query cache disabled\')', - 'formula' => 'query_cache_limit', - 'test' => 'value == 1024*1024', - 'issue' => __('The max size of the result set in the query cache is the default of 1 MiB.'), - 'recommendation' => __( - 'Changing {query_cache_limit} (usually by increasing) may increase efficiency. This variable' - . ' determines the maximum size a query result may have to be inserted into the query cache.' - . ' If there are many query results above 1 MiB that are well cacheable (many reads, little writes)' - . ' then increasing {query_cache_limit} will increase efficiency. Whereas in the case of many query' - . ' results being above 1 MiB that are not very well cacheable (often invalidated due to table' - . ' updates) increasing {query_cache_limit} might reduce efficiency.' - ), - 'justification' => __('query_cache_limit is set to 1 MiB'), - ], -]; diff --git a/libraries/classes/Advisor.php b/libraries/classes/Advisory/Advisor.php index cb66f195c7..ca963b959b 100644 --- a/libraries/classes/Advisor.php +++ b/libraries/classes/Advisory/Advisor.php @@ -2,9 +2,13 @@ declare(strict_types=1); -namespace PhpMyAdmin; +namespace PhpMyAdmin\Advisory; +use PhpMyAdmin\Core; +use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Server\SysInfo\SysInfo; +use PhpMyAdmin\Url; +use PhpMyAdmin\Util; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Throwable; @@ -21,13 +25,12 @@ use function substr; use function vsprintf; /** - * A simple rules engine, that executes the rules in the advisory_rules files. + * A simple rules engine, that executes the rules in the {@see Rules} class. + * + * @psalm-import-type RuleType from Rules */ class Advisor { - private const GENERIC_RULES_FILE = 'libraries/advisory_rules_generic.php'; - private const BEFORE_MYSQL80003_RULES_FILE = 'libraries/advisory_rules_mysql_before80003.php'; - /** @var DatabaseInterface */ private $dbi; @@ -37,8 +40,11 @@ class Advisor /** @var array */ private $globals; - /** @var array */ - private $rules; + /** + * @var array<int, array<string, string>> + * @psalm-var list<RuleType> + */ + private $rules = []; /** @var array */ private $runResult; @@ -190,7 +196,7 @@ class Advisor private function setRules(): void { $isMariaDB = str_contains($this->variables['version'], 'MariaDB'); - $genericRules = include ROOT_PATH . self::GENERIC_RULES_FILE; + $genericRules = Rules::getGeneric(); if (! $isMariaDB && $this->globals['PMA_MYSQL_INT_VERSION'] >= 80003) { $this->rules = $genericRules; @@ -198,7 +204,7 @@ class Advisor return; } - $extraRules = include ROOT_PATH . self::BEFORE_MYSQL80003_RULES_FILE; + $extraRules = Rules::getBeforeMySql80003(); $this->rules = array_merge($genericRules, $extraRules); } diff --git a/libraries/classes/Advisory/Rules.php b/libraries/classes/Advisory/Rules.php new file mode 100644 index 0000000000..478ffb6b57 --- /dev/null +++ b/libraries/classes/Advisory/Rules.php @@ -0,0 +1,887 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Advisory; + +use function __; + +/** + * @psalm-type RuleType = array{ + * id: non-empty-string, + * name: string, + * precondition?: non-empty-string, + * formula: non-empty-string, + * test: non-empty-string, + * issue: string, + * recommendation: string, + * justification: string, + * justification_formula?: non-empty-string + * } + */ +final class Rules +{ + /** + * @return array<int, array<string, string>> + * @psalm-return list<RuleType> + */ + public static function getGeneric(): array + { + return [ + // Queries + [ + 'id' => 'Uptime below one day', + 'name' => __('Uptime below one day'), + 'formula' => 'Uptime', + 'test' => 'value < 86400', + 'issue' => __('Uptime is less than 1 day, performance tuning may not be accurate.'), + 'recommendation' => __( + 'To have more accurate averages it is recommended to let the server run for' + . ' longer than a day before running this analyzer' + ), + 'justification' => __('The uptime is only %s'), + 'justification_formula' => 'ADVISOR_timespanFormat(Uptime)', + ], + [ + 'id' => 'Questions below 1,000', + 'name' => __('Questions below 1,000'), + 'formula' => 'Questions', + 'test' => 'value < 1000', + 'issue' => __( + 'Fewer than 1,000 questions have been run against this server.' + . ' The recommendations may not be accurate.' + ), + 'recommendation' => __( + 'Let the server run for a longer time until it has executed a greater amount of queries.' + ), + 'justification' => __('Current amount of Questions: %s'), + 'justification_formula' => 'Questions', + ], + [ + 'id' => 'Percentage of slow queries', + 'name' => __('Percentage of slow queries'), + 'precondition' => 'Questions > 0', + 'formula' => 'Slow_queries / Questions * 100', + 'test' => 'value >= 5', + 'issue' => __('There is a lot of slow queries compared to the overall amount of Queries.'), + 'recommendation' => __( + 'You might want to increase {long_query_time} or optimize the queries listed in the slow query log' + ), + 'justification' => __('The slow query rate should be below 5%%, your value is %s%%.'), + 'justification_formula' => 'round(value,2)', + ], + [ + 'id' => 'Slow query rate', + 'name' => __('Slow query rate'), + 'precondition' => 'Questions > 0', + 'formula' => '(Slow_queries / Questions * 100) / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('There is a high percentage of slow queries compared to the server uptime.'), + 'recommendation' => __( + 'You might want to increase {long_query_time} or optimize the queries listed in the slow query log' + ), + 'justification' => __( + 'You have a slow query rate of %s per hour, you should have less than 1%% per hour.' + ), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Long query time', + 'name' => __('Long query time'), + 'formula' => 'long_query_time', + 'test' => 'value >= 10', + 'issue' => __( + '{long_query_time} is set to 10 seconds or more,' + . ' thus only slow queries that take above 10 seconds are logged.' + ), + 'recommendation' => __( + 'It is suggested to set {long_query_time} to a lower value, depending on your environment.' + . ' Usually a value of 1-5 seconds is suggested.' + ), + 'justification' => __('long_query_time is currently set to %ds.'), + 'justification_formula' => 'value', + ], + [ + 'id' => 'Slow query logging', + 'name' => __('Slow query logging'), + 'precondition' => 'PMA_MYSQL_INT_VERSION < 50600', + 'formula' => 'log_slow_queries', + 'test' => 'value == \'OFF\'', + 'issue' => __('The slow query log is disabled.'), + 'recommendation' => __( + 'Enable slow query logging by setting {log_slow_queries} to \'ON\'.' + . ' This will help troubleshooting badly performing queries.' + ), + 'justification' => __('log_slow_queries is set to \'OFF\''), + ], + [ + 'id' => 'Slow query logging', + 'name' => __('Slow query logging'), + 'precondition' => 'PMA_MYSQL_INT_VERSION >= 50600', + 'formula' => 'slow_query_log', + 'test' => 'value == \'OFF\'', + 'issue' => __('The slow query log is disabled.'), + 'recommendation' => __( + 'Enable slow query logging by setting {slow_query_log} to \'ON\'.' + . ' This will help troubleshooting badly performing queries.' + ), + 'justification' => __('slow_query_log is set to \'OFF\''), + ], + // Versions + [ + 'id' => 'Release Series', + 'name' => __('Release Series'), + 'formula' => 'version', + 'test' => 'substr(value,0,2) <= \'5.\' && substr(value,2,1) < 1', + 'issue' => __('The MySQL server version less than 5.1.'), + 'recommendation' => __( + 'You should upgrade, as MySQL 5.1 has improved performance, and MySQL 5.5 even more so.' + ), + 'justification' => __('Current version: %s'), + 'justification_formula' => 'value', + ], + [ + 'id' => 'Minor Version', + 'name' => __('Minor Version'), + 'precondition' => '! fired(\'Release Series\')', + 'formula' => 'version', + 'test' => 'substr(value,0,2) <= \'5.\' && substr(value,2,1) <= 1 && substr(value,4,2) < 30', + 'issue' => __('Version less than 5.1.30 (the first GA release of 5.1).'), + 'recommendation' => __( + 'You should upgrade, as recent versions of MySQL 5.1 have improved performance' + . ' and MySQL 5.5 even more so.' + ), + 'justification' => __('Current version: %s'), + 'justification_formula' => 'value', + ], + [ + 'id' => 'Minor Version', + 'name' => __('Minor Version'), + 'precondition' => '! fired(\'Release Series\')', + 'formula' => 'version', + 'test' => 'substr(value,0,1) == 5 && substr(value,2,1) == 5 && substr(value,4,2) < 8', + 'issue' => __('Version less than 5.5.8 (the first GA release of 5.5).'), + 'recommendation' => __('You should upgrade, to a stable version of MySQL 5.5.'), + 'justification' => __('Current version: %s'), + 'justification_formula' => 'value', + ], + [ + 'id' => 'Distribution', + 'name' => __('Distribution'), + 'formula' => 'version_comment', + 'test' => 'preg_match(\'/source/i\',value)', + 'issue' => __('Version is compiled from source, not a MySQL official binary.'), + 'recommendation' => __( + 'If you did not compile from source, you may be using a package modified by a distribution.' + . ' The MySQL manual only is accurate for official MySQL binaries,' + . ' not any package distributions (such as RedHat, Debian/Ubuntu etc).' + ), + 'justification' => __('\'source\' found in version_comment'), + ], + [ + 'id' => 'Distribution', + 'name' => __('Distribution'), + 'formula' => 'version_comment', + 'test' => 'preg_match(\'/percona/i\',value)', + 'issue' => __('The MySQL manual only is accurate for official MySQL binaries.'), + 'recommendation' => __( + 'Percona documentation is at <a href="https://www.percona.com/software/documentation/">' + . 'https://www.percona.com/software/documentation/</a>' + ), + 'justification' => __('\'percona\' found in version_comment'), + ], + [ + 'id' => 'MySQL Architecture', + 'name' => __('MySQL Architecture'), + 'formula' => 'system_memory', + 'test' => 'value > 3072*1024 && !preg_match(\'/64/\',version_compile_machine)' + . ' && !preg_match(\'/64/\',version_compile_os)', + 'issue' => __('MySQL is not compiled as a 64-bit package.'), + 'recommendation' => __( + 'Your memory capacity is above 3 GiB (assuming the Server is on localhost),' + . ' so MySQL might not be able to access all of your memory.' + . ' You might want to consider installing the 64-bit version of MySQL.' + ), + 'justification' => __('Available memory on this host: %s'), + 'justification_formula' => 'ADVISOR_formatByteDown(value*1024, 2, 2)', + ], + // Query cache + [ + 'id' => 'Query caching method', + 'name' => __('Query caching method'), + 'precondition' => '!fired(\'Query cache disabled\')', + 'formula' => 'Questions / Uptime', + 'test' => 'value > 100', + 'issue' => __('Suboptimal caching method.'), + 'recommendation' => __( + 'You are using the MySQL Query cache with a fairly high traffic database.' + . ' It might be worth considering to use ' + . '<a href="https://dev.mysql.com/doc/refman/5.6/en/ha-memcached.html">memcached</a>' + . ' instead of the MySQL Query cache, especially if you have multiple replicas.' + ), + 'justification' => __( + 'The query cache is enabled and the server receives %d queries per second.' + . ' This rule fires if there is more than 100 queries per second.' + ), + 'justification_formula' => 'round(value,1)', + ], + // Sorts + [ + 'id' => 'Percentage of sorts that cause temporary tables', + 'name' => __('Percentage of sorts that cause temporary tables'), + 'precondition' => 'Sort_scan + Sort_range > 0', + 'formula' => 'Sort_merge_passes / (Sort_scan + Sort_range) * 100', + 'test' => 'value > 10', + 'issue' => __('Too many sorts are causing temporary tables.'), + 'recommendation' => __( + 'Consider increasing {sort_buffer_size} and/or {read_rnd_buffer_size},' + . ' depending on your system memory limits.' + ), + 'justification' => __( + '%s%% of all sorts cause temporary tables, this value should be lower than 10%%.' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Rate of sorts that cause temporary tables', + 'name' => __('Rate of sorts that cause temporary tables'), + 'formula' => 'Sort_merge_passes / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('Too many sorts are causing temporary tables.'), + 'recommendation' => __( + 'Consider increasing {sort_buffer_size} and/or {read_rnd_buffer_size},' + . ' depending on your system memory limits.' + ), + 'justification' => __('Temporary tables average: %s, this value should be less than 1 per hour.'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Sort rows', + 'name' => __('Sort rows'), + 'formula' => 'Sort_rows / Uptime', + 'test' => 'value * 60 >= 1', + 'issue' => __('There are lots of rows being sorted.'), + 'recommendation' => __( + 'While there is nothing wrong with a high amount of row sorting, you might want to' + . ' make sure that the queries which require a lot of sorting use indexed columns in' + . ' the ORDER BY clause, as this will result in much faster sorting.' + ), + 'justification' => __('Sorted rows average: %s'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + // Joins, scans + [ + 'id' => 'Rate of joins without indexes', + 'name' => __('Rate of joins without indexes'), + 'formula' => '(Select_range_check + Select_scan + Select_full_join) / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('There are too many joins without indexes.'), + 'recommendation' => __( + 'This means that joins are doing full table scans. Adding indexes for the columns being' + . ' used in the join conditions will greatly speed up table joins.' + ), + 'justification' => __('Table joins average: %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Rate of reading first index entry', + 'name' => __('Rate of reading first index entry'), + 'formula' => 'Handler_read_first / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('The rate of reading the first index entry is high.'), + 'recommendation' => __( + 'This usually indicates frequent full index scans. Full index scans are faster than' + . ' table scans but require lots of CPU cycles in big tables, if those tables that have or' + . ' had high volumes of UPDATEs and DELETEs, running \'OPTIMIZE TABLE\' might reduce the' + . ' amount of and/or speed up full index scans. Other than that full index scans can' + . ' only be reduced by rewriting queries.' + ), + 'justification' => __('Index scans average: %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Rate of reading fixed position', + 'name' => __('Rate of reading fixed position'), + 'formula' => 'Handler_read_rnd / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('The rate of reading data from a fixed position is high.'), + 'recommendation' => __( + 'This indicates that many queries need to sort results and/or do a full table scan,' + . ' including join queries that do not use indexes. Add indexes where applicable.' + ), + 'justification' => __( + 'Rate of reading fixed position average: %s, this value should be less than 1 per hour' + ), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Rate of reading next table row', + 'name' => __('Rate of reading next table row'), + 'formula' => 'Handler_read_rnd_next / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('The rate of reading the next table row is high.'), + 'recommendation' => __( + 'This indicates that many queries are doing full table scans. Add indexes where applicable.' + ), + 'justification' => __('Rate of reading next table row: %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + // Temp tables + [ + 'id' => 'Different tmp_table_size and max_heap_table_size', + 'name' => __('Different tmp_table_size and max_heap_table_size'), + 'formula' => 'tmp_table_size - max_heap_table_size', + 'test' => 'value !=0', + 'issue' => __('{tmp_table_size} and {max_heap_table_size} are not the same.'), + 'recommendation' => __( + 'If you have deliberately changed one of either: The server uses the lower value of either' + . ' to determine the maximum size of in-memory tables. So if you wish to increase the' + . ' in-memory table limit you will have to increase the other value as well.' + ), + 'justification' => __('Current values are tmp_table_size: %s, max_heap_table_size: %s'), + 'justification_formula' => 'ADVISOR_formatByteDown(tmp_table_size, 2, 2),' + . ' ADVISOR_formatByteDown(max_heap_table_size, 2, 2)', + ], + [ + 'id' => 'Percentage of temp tables on disk', + 'name' => __('Percentage of temp tables on disk'), + 'precondition' => 'Created_tmp_tables + Created_tmp_disk_tables > 0', + 'formula' => 'Created_tmp_disk_tables / (Created_tmp_tables + Created_tmp_disk_tables) * 100', + 'test' => 'value > 25', + 'issue' => __('Many temporary tables are being written to disk instead of being kept in memory.'), + 'recommendation' => __( + 'Increasing {max_heap_table_size} and {tmp_table_size} might help. However some' + . ' temporary tables are always being written to disk, independent of the value of these variables.' + . ' To eliminate these you will have to rewrite your queries to avoid those conditions' + . ' (Within a temporary table: Presence of a BLOB or TEXT column or presence of a column' + . ' bigger than 512 bytes) as mentioned in the beginning of an <a href="' + . 'https://www.facebook.com/note.php?note_id=10150111255065841&comments' + . '">Article by the Pythian Group</a>' + ), + 'justification' => __( + '%s%% of all temporary tables are being written to disk, this value should be below 25%%' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Temp disk rate', + 'name' => __('Temp disk rate'), + 'precondition' => '!fired(\'Percentage of temp tables on disk\')', + 'formula' => 'Created_tmp_disk_tables / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('Many temporary tables are being written to disk instead of being kept in memory.'), + 'recommendation' => __( + 'Increasing {max_heap_table_size} and {tmp_table_size} might help. However some' + . ' temporary tables are always being written to disk, independent of the value of these variables.' + . ' To eliminate these you will have to rewrite your queries to avoid those conditions' + . ' (Within a temporary table: Presence of a BLOB or TEXT column or presence of a column' + . ' bigger than 512 bytes) as mentioned in the <a href="' + . 'https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html' + . '">MySQL Documentation</a>' + ), + 'justification' => __( + 'Rate of temporary tables being written to disk: %s, this value should be less than 1 per hour' + ), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + // MyISAM index cache + [ + 'id' => 'MyISAM key buffer size', + 'name' => __('MyISAM key buffer size'), + 'formula' => 'key_buffer_size', + 'test' => 'value == 0', + 'issue' => __('Key buffer is not initialized. No MyISAM indexes will be cached.'), + 'recommendation' => __( + 'Set {key_buffer_size} depending on the size of your MyISAM indexes. 64M is a good start.' + ), + 'justification' => __('key_buffer_size is 0'), + ], + [ + 'id' => 'Max % MyISAM key buffer ever used', + /* xgettext:no-php-format */ + 'name' => __('Max % MyISAM key buffer ever used'), + 'precondition' => 'key_buffer_size > 0', + 'formula' => 'Key_blocks_used * key_cache_block_size / key_buffer_size * 100', + 'test' => 'value < 95', + /* xgettext:no-php-format */ + 'issue' => __('MyISAM key buffer (index cache) % used is low.'), + 'recommendation' => __( + 'You may need to decrease the size of {key_buffer_size}, re-examine your tables to see' + . ' if indexes have been removed, or examine queries and expectations' + . ' about what indexes are being used.' + ), + 'justification' => __('max %% MyISAM key buffer ever used: %s%%, this value should be above 95%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Percentage of MyISAM key buffer used', + 'name' => __('Percentage of MyISAM key buffer used'), + // Don't fire if above rule fired - we don't need the same advice twice + 'precondition' => 'key_buffer_size > 0 && !fired(\'Max % MyISAM key buffer ever used\')', + 'formula' => '( 1 - Key_blocks_unused * key_cache_block_size / key_buffer_size) * 100', + 'test' => 'value < 95', + /* xgettext:no-php-format */ + 'issue' => __('MyISAM key buffer (index cache) % used is low.'), + 'recommendation' => __( + 'You may need to decrease the size of {key_buffer_size}, re-examine your tables to see' + . ' if indexes have been removed, or examine queries and expectations' + . ' about what indexes are being used.' + ), + 'justification' => __('%% MyISAM key buffer used: %s%%, this value should be above 95%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Percentage of index reads from memory', + 'name' => __('Percentage of index reads from memory'), + 'precondition' => 'Key_read_requests > 0', + 'formula' => '100 - (Key_reads / Key_read_requests * 100)', + 'test' => 'value < 95', + /* xgettext:no-php-format */ + 'issue' => __('The % of indexes that use the MyISAM key buffer is low.'), + 'recommendation' => __('You may need to increase {key_buffer_size}.'), + 'justification' => __('Index reads from memory: %s%%, this value should be above 95%%'), + 'justification_formula' => 'round(value,1)', + ], + // Other caches + [ + 'id' => 'Rate of table open', + 'name' => __('Rate of table open'), + 'formula' => 'Opened_tables / Uptime', + 'test' => 'value*60*60 > 10', + 'issue' => __('The rate of opening tables is high.'), + 'recommendation' => __( + 'Opening tables requires disk I/O which is costly. Increasing {table_open_cache} might avoid this.' + ), + 'justification' => __('Opened table rate: %s, this value should be less than 10 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Percentage of used open files limit', + 'name' => __('Percentage of used open files limit'), + 'formula' => 'Open_files / open_files_limit * 100', + 'test' => 'value > 85', + 'issue' => __( + 'The number of open files is approaching the max number of open files.' + . ' You may get a "Too many open files" error.' + ), + 'recommendation' => __( + 'Consider increasing {open_files_limit}, and check the error log when' + . ' restarting after changing {open_files_limit}.' + ), + 'justification' => __('The number of opened files is at %s%% of the limit. It should be below 85%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Rate of open files', + 'name' => __('Rate of open files'), + 'formula' => 'Open_files / Uptime', + 'test' => 'value * 60 * 60 > 5', + 'issue' => __('The rate of opening files is high.'), + 'recommendation' => __( + 'Consider increasing {open_files_limit}, and check the error log when' + . ' restarting after changing {open_files_limit}.' + ), + 'justification' => __('Opened files rate: %s, this value should be less than 5 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Immediate table locks %', + /* xgettext:no-php-format */ + 'name' => __('Immediate table locks %'), + 'precondition' => 'Table_locks_waited + Table_locks_immediate > 0', + 'formula' => 'Table_locks_immediate / (Table_locks_waited + Table_locks_immediate) * 100', + 'test' => 'value < 95', + 'issue' => __('Too many table locks were not granted immediately.'), + 'recommendation' => __('Optimize queries and/or use InnoDB to reduce lock wait.'), + 'justification' => __('Immediate table locks: %s%%, this value should be above 95%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Table lock wait rate', + 'name' => __('Table lock wait rate'), + 'formula' => 'Table_locks_waited / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('Too many table locks were not granted immediately.'), + 'recommendation' => __('Optimize queries and/or use InnoDB to reduce lock wait.'), + 'justification' => __('Table lock wait rate: %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Thread cache', + 'name' => __('Thread cache'), + 'formula' => 'thread_cache_size', + 'test' => 'value < 1', + 'issue' => __('Thread cache is disabled, resulting in more overhead from new connections to MySQL.'), + 'recommendation' => __('Enable the thread cache by setting {thread_cache_size} > 0.'), + 'justification' => __('The thread cache is set to 0'), + ], + [ + 'id' => 'Thread cache hit rate %', + /* xgettext:no-php-format */ + 'name' => __('Thread cache hit rate %'), + 'precondition' => 'thread_cache_size > 0', + 'formula' => '100 - Threads_created / Connections', + 'test' => 'value < 80', + 'issue' => __('Thread cache is not efficient.'), + 'recommendation' => __('Increase {thread_cache_size}.'), + 'justification' => __('Thread cache hitrate: %s%%, this value should be above 80%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Threads that are slow to launch', + 'name' => __('Threads that are slow to launch'), + 'precondition' => 'slow_launch_time > 0', + 'formula' => 'Slow_launch_threads', + 'test' => 'value > 0', + 'issue' => __('There are too many threads that are slow to launch.'), + 'recommendation' => __( + 'This generally happens in case of general system overload as it is pretty simple' + . ' operations. You might want to monitor your system load carefully.' + ), + 'justification' => __('%s thread(s) took longer than %s seconds to start, it should be 0'), + 'justification_formula' => 'value, slow_launch_time', + ], + [ + 'id' => 'Slow launch time', + 'name' => __('Slow launch time'), + 'formula' => 'slow_launch_time', + 'test' => 'value > 2', + 'issue' => __('Slow_launch_time is above 2s.'), + 'recommendation' => __( + 'Set {slow_launch_time} to 1s or 2s to correctly count threads that are slow to launch.' + ), + 'justification' => __('slow_launch_time is set to %s'), + 'justification_formula' => 'value', + ], + // Connections + [ + 'id' => 'Percentage of used connections', + 'name' => __('Percentage of used connections'), + 'formula' => 'Max_used_connections / max_connections * 100', + 'test' => 'value > 80', + 'issue' => __( + 'The maximum amount of used connections is getting close to the value of {max_connections}.' + ), + 'recommendation' => __( + 'Increase {max_connections}, or decrease {wait_timeout} so that connections that do not' + . ' close database handlers properly get killed sooner.' + . ' Make sure the code closes database handlers properly.' + ), + 'justification' => __('Max_used_connections is at %s%% of max_connections, it should be below 80%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Percentage of aborted connections', + 'name' => __('Percentage of aborted connections'), + 'formula' => 'Aborted_connects / Connections * 100', + 'test' => 'value > 1', + 'issue' => __('Too many connections are aborted.'), + 'recommendation' => __( + 'Connections are usually aborted when they cannot be authorized. <a href="' + . 'https://www.percona.com/blog/2008/08/23/how-to-track-down-the-source-of-aborted_connects/' + . '">This article</a> might help you track down the source.' + ), + 'justification' => __('%s%% of all connections are aborted. This value should be below 1%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Rate of aborted connections', + 'name' => __('Rate of aborted connections'), + 'formula' => 'Aborted_connects / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('Too many connections are aborted.'), + 'recommendation' => __( + 'Connections are usually aborted when they cannot be authorized. <a href="' + . 'https://www.percona.com/blog/2008/08/23/how-to-track-down-the-source-of-aborted_connects/' + . '">This article</a> might help you track down the source.' + ), + 'justification' => __('Aborted connections rate is at %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + [ + 'id' => 'Percentage of aborted clients', + 'name' => __('Percentage of aborted clients'), + 'formula' => 'Aborted_clients / Connections * 100', + 'test' => 'value > 2', + 'issue' => __('Too many clients are aborted.'), + 'recommendation' => __( + 'Clients are usually aborted when they did not close their connection to MySQL properly.' + . ' This can be due to network issues or code not closing a database handler properly.' + . ' Check your network and code.' + ), + 'justification' => __('%s%% of all clients are aborted. This value should be below 2%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Rate of aborted clients', + 'name' => __('Rate of aborted clients'), + 'formula' => 'Aborted_clients / Uptime', + 'test' => 'value * 60 * 60 > 1', + 'issue' => __('Too many clients are aborted.'), + 'recommendation' => __( + 'Clients are usually aborted when they did not close their connection to MySQL properly.' + . ' This can be due to network issues or code not closing a database handler properly.' + . ' Check your network and code.' + ), + 'justification' => __('Aborted client rate is at %s, this value should be less than 1 per hour'), + 'justification_formula' => 'ADVISOR_bytime(value,2)', + ], + // InnoDB + [ + 'id' => 'Is InnoDB disabled?', + 'name' => __('Is InnoDB disabled?'), + 'precondition' => 'PMA_MYSQL_INT_VERSION < 50600', + 'formula' => 'have_innodb', + 'test' => 'value != "YES"', + 'issue' => __('You do not have InnoDB enabled.'), + 'recommendation' => __('InnoDB is usually the better choice for table engines.'), + 'justification' => __('have_innodb is set to \'value\''), + ], + [ + 'id' => 'InnoDB log size', + 'name' => __('InnoDB log size'), + 'precondition' => 'innodb_buffer_pool_size > 0 && ! (IS_MARIADB && PMA_MYSQL_INT_VERSION > 100500)', + 'formula' => '(innodb_log_file_size * innodb_log_files_in_group)/ innodb_buffer_pool_size * 100', + 'test' => 'value < 20 && innodb_log_file_size / (1024 * 1024) < 256', + 'issue' => __( + 'The InnoDB log file size is not an appropriate size, in relation to the InnoDB buffer pool.' + ), + 'recommendation' => __(/* xgettext:no-php-format */ + 'Especially on a system with a lot of writes to InnoDB tables you should set' + . ' {innodb_log_file_size} to 25% of {innodb_buffer_pool_size}. However the bigger this value,' + . ' the longer the recovery time will be when database crashes, so this value should not be set' + . ' much higher than 256 MiB. Please note however that you cannot simply change the value of' + . ' this variable. You need to shutdown the server, remove the InnoDB log files, set the new' + . ' value in my.cnf, start the server, then check the error logs if everything went fine.' + . ' See also <a href="' + . 'https://mysqldatabaseadministration.blogspot.com' + . '/2007/01/increase-innodblogfilesize-proper-way.html' + . '">this blog entry</a>' + ), + 'justification' => __( + 'Your InnoDB log size is at %s%% in relation to the InnoDB buffer pool size,' + . ' it should not be below 20%%' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'InnoDB log size', + 'name' => __('InnoDB log size'), + 'precondition' => 'innodb_buffer_pool_size > 0 && IS_MARIADB && PMA_MYSQL_INT_VERSION > 100500', + // From MariaDB 10.5, there is 1 redo log. + // For MariaDB 10.4 and before, the number of redo log files is configured + // by the innodb_log_files_in_group system variable. + 'formula' => 'innodb_log_file_size / innodb_buffer_pool_size * 100', + 'test' => 'value < 20 && innodb_log_file_size / (1024 * 1024) < 256', + 'issue' => __( + 'The InnoDB log file size is not an appropriate size, in relation to the InnoDB buffer pool.' + ), + 'recommendation' => __(/* xgettext:no-php-format */ + 'Especially on a system with a lot of writes to InnoDB tables you should set' + . ' {innodb_log_file_size} to 25% of {innodb_buffer_pool_size}. However the bigger this value,' + . ' the longer the recovery time will be when database crashes, so this value should not be set' + . ' much higher than 256 MiB. Please note however that you cannot simply change the value of' + . ' this variable. You need to shutdown the server, remove the InnoDB log files, set the new' + . ' value in my.cnf, start the server, then check the error logs if everything went fine.' + . ' See also <a href="' + . 'https://mysqldatabaseadministration.blogspot.com' + . '/2007/01/increase-innodblogfilesize-proper-way.html' + . '">this blog entry</a>' + ), + 'justification' => __( + 'Your InnoDB log size is at %s%% in relation to the InnoDB buffer pool size,' + . ' it should not be below 20%%' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Max InnoDB log size', + 'name' => __('Max InnoDB log size'), + 'precondition' => 'innodb_buffer_pool_size > 0' + . ' && innodb_log_file_size / innodb_buffer_pool_size * 100 < 30', + 'formula' => 'innodb_log_file_size / (1024 * 1024)', + 'test' => 'value > 256', + 'issue' => __('The InnoDB log file size is inadequately large.'), + 'recommendation' => __(/* xgettext:no-php-format */ + 'It is usually sufficient to set {innodb_log_file_size} to 25% of the size of' + . ' {innodb_buffer_pool_size}. A very big {innodb_log_file_size} slows down the recovery' + . ' time after a database crash considerably. See also ' + . '<a href="https://www.percona.com/blog/2006/07/03/choosing-proper-innodb_log_file_size/">' + . 'this Article</a>. You need to shutdown the server, remove the InnoDB log files, set the' + . ' new value in my.cnf, start the server, then check the error logs' + . ' if everything went fine. See also <a href="' + . 'https://mysqldatabaseadministration.blogspot.com' + . '/2007/01/increase-innodblogfilesize-proper-way.html' + . '">this blog entry</a>' + ), + 'justification' => __('Your absolute InnoDB log size is %s MiB'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'InnoDB buffer pool size', + 'name' => __('InnoDB buffer pool size'), + 'precondition' => 'system_memory > 0', + 'formula' => 'innodb_buffer_pool_size / system_memory * 100', + 'test' => 'value < 60', + 'issue' => __('Your InnoDB buffer pool is fairly small.'), + 'recommendation' => __(/* xgettext:no-php-format */ + 'The InnoDB buffer pool has a profound impact on performance for InnoDB tables.' + . ' Assign all your remaining memory to this buffer. For database servers that use solely InnoDB' + . ' as storage engine and have no other services (e.g. a web server) running, you may set this' + . ' as high as 80% of your available memory. If that is not the case, you need to carefully' + . ' assess the memory consumption of your other services and non-InnoDB-Tables and set this' + . ' variable accordingly. If it is set too high, your system will start swapping,' + . ' which decreases performance significantly. See also <a href="' + . 'https://www.percona.com/blog/2007/11/03/choosing-innodb_buffer_pool_size/">this article</a>' + ), + 'justification' => __( + 'You are currently using %s%% of your memory for the InnoDB buffer pool.' + . ' This rule fires if you are assigning less than 60%%, however this might be perfectly' + . ' adequate for your system if you don\'t have much InnoDB tables' + . ' or other services running on the same machine.' + ), + 'justification_formula' => 'value', + ], + // Other + [ + 'id' => 'MyISAM concurrent inserts', + 'name' => __('MyISAM concurrent inserts'), + 'formula' => 'concurrent_insert', + 'test' => 'value === 0 || value === \'NEVER\'', + 'issue' => __('Enable {concurrent_insert} by setting it to 1'), + 'recommendation' => __( + 'Setting {concurrent_insert} to 1 reduces contention between' + . ' readers and writers for a given table. See also <a' + . ' href="https://dev.mysql.com/doc/refman/5.5/en/concurrent-inserts.html">MySQL Documentation</a>' + ), + 'justification' => __('concurrent_insert is set to 0'), + ], + ]; + } + + /** + * @return array<int, array<string, string>> + * @psalm-return list<RuleType> + */ + public static function getBeforeMySql80003(): array + { + return [ + // Query cache + [ + 'id' => 'Query cache disabled', + 'name' => __('Query cache disabled'), + 'formula' => 'query_cache_size', + 'test' => 'value == 0 || query_cache_type == \'OFF\' || query_cache_type == \'0\'', + 'issue' => __('The query cache is not enabled.'), + 'recommendation' => __( + 'The query cache is known to greatly improve performance if configured correctly. Enable it by' + . ' setting {query_cache_size} to a 2 digit MiB value and setting {query_cache_type} to \'ON\'.' + . ' <b>Note:</b> If you are using memcached, ignore this recommendation.' + ), + 'justification' => __('query_cache_size is set to 0 or query_cache_type is set to \'OFF\''), + ], + [ + 'id' => 'Query cache efficiency (%)', + /* xgettext:no-php-format */ + 'name' => __('Query cache efficiency (%)'), + 'precondition' => 'Com_select + Qcache_hits > 0 && !fired(\'Query cache disabled\')', + 'formula' => 'Qcache_hits / (Com_select + Qcache_hits) * 100', + 'test' => 'value < 20', + 'issue' => __('Query cache not running efficiently, it has a low hit rate.'), + 'recommendation' => __('Consider increasing {query_cache_limit}.'), + 'justification' => __('The current query cache hit rate of %s%% is below 20%%'), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Query Cache usage', + 'name' => __('Query Cache usage'), + 'precondition' => '!fired(\'Query cache disabled\')', + 'formula' => '100 - Qcache_free_memory / query_cache_size * 100', + 'test' => 'value < 80', + /* xgettext:no-php-format */ + 'issue' => __('Less than 80% of the query cache is being utilized.'), + 'recommendation' => __( + 'This might be caused by {query_cache_limit} being too low.' + . ' Flushing the query cache might help as well.' + ), + 'justification' => __( + 'The current ratio of free query cache memory to total query' + . ' cache size is %s%%. It should be above 80%%' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Query cache fragmentation', + 'name' => __('Query cache fragmentation'), + 'precondition' => '!fired(\'Query cache disabled\')', + 'formula' => 'Qcache_free_blocks / (Qcache_total_blocks / 2) * 100', + 'test' => 'value > 20', + 'issue' => __('The query cache is considerably fragmented.'), + 'recommendation' => __( + 'Severe fragmentation is likely to (further) increase Qcache_lowmem_prunes. This might be' + . ' caused by many Query cache low memory prunes due to {query_cache_size} being too small. For a' + . ' immediate but short lived fix you can flush the query cache (might lock the query cache for a' + . ' long time). Carefully adjusting {query_cache_min_res_unit} to a lower value might help too,' + . ' e.g. you can set it to the average size of your queries in the cache using this formula:' + . ' (query_cache_size - qcache_free_memory) / qcache_queries_in_cache' + ), + 'justification' => __( + 'The cache is currently fragmented by %s%% , with 100%% fragmentation meaning that the query' + . ' cache is an alternating pattern of free and used blocks. This value should be below 20%%.' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Query cache low memory prunes', + 'name' => __('Query cache low memory prunes'), + 'precondition' => 'Qcache_inserts > 0 && !fired(\'Query cache disabled\')', + 'formula' => 'Qcache_lowmem_prunes / Qcache_inserts * 100', + 'test' => 'value > 0.1', + 'issue' => __('Cached queries are removed due to low query cache memory from the query cache.'), + 'recommendation' => __( + 'You might want to increase {query_cache_size}, however keep in mind that the overhead of' + . ' maintaining the cache is likely to increase with its size, so do this in small increments' + . ' and monitor the results.' + ), + 'justification' => __( + 'The ratio of removed queries to inserted queries is %s%%. The lower this value is,' + . ' the better (This rules firing limit: 0.1%%)' + ), + 'justification_formula' => 'round(value,1)', + ], + [ + 'id' => 'Query cache max size', + 'name' => __('Query cache max size'), + 'precondition' => '!fired(\'Query cache disabled\')', + 'formula' => 'query_cache_size', + 'test' => 'value > 1024 * 1024 * 128', + 'issue' => __( + 'The query cache size is above 128 MiB. Big query caches may cause significant' + . ' overhead that is required to maintain the cache.' + ), + 'recommendation' => __( + 'Depending on your environment, it might be performance increasing to reduce this value.' + ), + 'justification' => __('Current query cache size: %s'), + 'justification_formula' => 'ADVISOR_formatByteDown(value, 2, 2)', + ], + [ + 'id' => 'Query cache min result size', + 'name' => __('Query cache min result size'), + 'precondition' => '!fired(\'Query cache disabled\')', + 'formula' => 'query_cache_limit', + 'test' => 'value == 1024*1024', + 'issue' => __('The max size of the result set in the query cache is the default of 1 MiB.'), + 'recommendation' => __( + 'Changing {query_cache_limit} (usually by increasing) may increase efficiency. This variable' + . ' determines the maximum size a query result may have to be inserted into the query cache.' + . ' If there are many query results above 1 MiB that are well cacheable (many reads, little writes)' + . ' then increasing {query_cache_limit} will increase efficiency. Whereas in the case of many query' + . ' results being above 1 MiB that are not very well cacheable (often invalidated due to table' + . ' updates) increasing {query_cache_limit} might reduce efficiency.' + ), + 'justification' => __('query_cache_limit is set to 1 MiB'), + ], + ]; + } +} diff --git a/libraries/classes/BrowseForeigners.php b/libraries/classes/BrowseForeigners.php index 3cc8138f73..ac93911dda 100644 --- a/libraries/classes/BrowseForeigners.php +++ b/libraries/classes/BrowseForeigners.php @@ -39,14 +39,12 @@ class BrowseForeigners */ public function __construct(Template $template) { - global $cfg; - $this->template = $template; - $this->limitChars = (int) $cfg['LimitChars']; - $this->maxRows = (int) $cfg['MaxRows']; - $this->repeatCells = (int) $cfg['RepeatCells']; - $this->showAll = (bool) $cfg['ShowAll']; + $this->limitChars = (int) $GLOBALS['cfg']['LimitChars']; + $this->maxRows = (int) $GLOBALS['cfg']['MaxRows']; + $this->repeatCells = (int) $GLOBALS['cfg']['RepeatCells']; + $this->showAll = (bool) $GLOBALS['cfg']['ShowAll']; } /** @@ -71,7 +69,7 @@ class BrowseForeigners int $indexByDescription, string $currentValue ): array { - global $theme; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; $horizontalCount++; $output = ''; @@ -126,7 +124,7 @@ class BrowseForeigners ]); $output .= '<td width="20%"><img src="' - . ($theme instanceof Theme ? $theme->getImgPath('spacer.png') : '') + . ($GLOBALS['theme'] instanceof Theme ? $GLOBALS['theme']->getImgPath('spacer.png') : '') . '" alt="" width="1" height="1"></td>'; $output .= $this->template->render('table/browse_foreigners/column_element', [ diff --git a/libraries/classes/Command/CacheWarmupCommand.php b/libraries/classes/Command/CacheWarmupCommand.php index 198196ae09..2d18f65343 100644 --- a/libraries/classes/Command/CacheWarmupCommand.php +++ b/libraries/classes/Command/CacheWarmupCommand.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Template; use PhpMyAdmin\Tests\Stubs\DbiDummy; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; +use SplFileInfo; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -117,13 +118,13 @@ final class CacheWarmupCommand extends Command string $environment, bool $writeReplacements ): int { - global $cfg, $config, $dbi; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; $output->writeln('Warming up the twig cache', OutputInterface::VERBOSITY_VERBOSE); - $config = new Config(CONFIG_FILE); - $cfg['environment'] = $environment; - $config->set('environment', $cfg['environment']); - $dbi = new DatabaseInterface(new DbiDummy()); + $GLOBALS['config'] = new Config(CONFIG_FILE); + $GLOBALS['cfg']['environment'] = $environment; + $GLOBALS['config']->set('environment', $GLOBALS['cfg']['environment']); + $GLOBALS['dbi'] = new DatabaseInterface(new DbiDummy()); $tmpDir = ROOT_PATH . 'twig-templates'; $twig = Template::getTwigEnvironment($tmpDir); @@ -143,6 +144,7 @@ final class CacheWarmupCommand extends Command ); $output->writeln('Warming templates', OutputInterface::VERBOSITY_VERY_VERBOSE); + /** @var SplFileInfo $file */ foreach ($templates as $file) { // Skip test files if (str_contains($file->getPathname(), '/test/')) { diff --git a/libraries/classes/Common.php b/libraries/classes/Common.php index 635dc69c33..0e5b1b58e1 100644 --- a/libraries/classes/Common.php +++ b/libraries/classes/Common.php @@ -12,8 +12,6 @@ use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\SqlParser\Lexer; use Symfony\Component\DependencyInjection\ContainerInterface; -use Webmozart\Assert\Assert; -use Webmozart\Assert\InvalidArgumentException; use function __; use function array_pop; @@ -25,13 +23,16 @@ use function defined; use function explode; use function extension_loaded; use function function_exists; +use function gmdate; use function hash_equals; +use function header; use function htmlspecialchars; use function implode; use function ini_get; use function ini_set; use function is_array; use function is_scalar; +use function is_string; use function mb_internal_encoding; use function mb_strlen; use function mb_strpos; @@ -39,8 +40,8 @@ use function mb_strrpos; use function mb_substr; use function register_shutdown_function; use function session_id; -use function str_replace; use function strlen; +use function time; use function trigger_error; use function urldecode; @@ -48,6 +49,9 @@ use const E_USER_ERROR; final class Common { + /** @var ServerRequest|null */ + private static $request = null; + /** * Misc stuff and REQUIRED by ALL the scripts. * MUST be included by every script @@ -78,22 +82,37 @@ final class Common */ public static function run(): void { - global $containerBuilder, $errorHandler, $config, $server, $dbi, $request; - global $lang, $cfg, $isConfigLoading, $auth_plugin, $route, $theme; - global $urlParams, $isMinimumCommon, $sql_query, $token_mismatch; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; + $GLOBALS['lang'] = $GLOBALS['lang'] ?? null; + $GLOBALS['isConfigLoading'] = $GLOBALS['isConfigLoading'] ?? null; + $GLOBALS['auth_plugin'] = $GLOBALS['auth_plugin'] ?? null; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['token_mismatch'] = $GLOBALS['token_mismatch'] ?? null; + + $request = self::getRequest(); + $route = $request->getRoute(); - $request = ServerRequestFactory::createFromGlobals(); + if ($route === '/import-status' || $route === '/url' || $route === '/messages') { + $GLOBALS['isMinimumCommon'] = true; + } - $route = Routing::getCurrentRoute(); + if ($route === '/messages') { + // Send correct type. + header('Content-Type: text/javascript; charset=UTF-8'); + // Cache output in client + // the nocache query parameter makes sure that this file is reloaded when config changes. + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT'); - if ($route === '/import-status') { - $isMinimumCommon = true; + define('PMA_NO_SESSION', true); } - $containerBuilder = Core::getContainerBuilder(); + $GLOBALS['containerBuilder'] = Core::getContainerBuilder(); /** @var ErrorHandler $errorHandler */ - $errorHandler = $containerBuilder->get('error_handler'); + $errorHandler = $GLOBALS['containerBuilder']->get('error_handler'); + $GLOBALS['errorHandler'] = $errorHandler; self::checkRequiredPhpExtensions(); self::configurePhpSettings(); @@ -101,18 +120,14 @@ final class Common /* parsing configuration file LABEL_parsing_config_file */ - /** @var bool $isConfigLoading Indication for the error handler */ - $isConfigLoading = false; + /** Indication for the error handler */ + $GLOBALS['isConfigLoading'] = false; register_shutdown_function([Config::class, 'fatalErrorHandler']); - /** - * Force reading of config file, because we removed sensitive values - * in the previous iteration. - * - * @var Config $config - */ - $config = $containerBuilder->get('config'); + /** @var Config $config */ + $config = $GLOBALS['containerBuilder']->get('config'); + $GLOBALS['config'] = $config; /** * include session handling after the globals, to prevent overwriting @@ -132,24 +147,27 @@ final class Common * * @global array $urlParams */ - $urlParams = []; - $containerBuilder->setParameter('url_params', $urlParams); + $GLOBALS['urlParams'] = []; + $GLOBALS['containerBuilder']->setParameter('url_params', $GLOBALS['urlParams']); - self::setGotoAndBackGlobals($containerBuilder, $config); + self::setGotoAndBackGlobals($GLOBALS['containerBuilder'], $config); self::checkTokenRequestParam(); - self::setDatabaseAndTableFromRequest($containerBuilder, $request); + self::setDatabaseAndTableFromRequest($GLOBALS['containerBuilder'], $request); /** * SQL query to be executed * * @global string $sql_query */ - $sql_query = ''; + $GLOBALS['sql_query'] = ''; if ($request->isPost()) { - $sql_query = $request->getParsedBodyParam('sql_query', ''); + $GLOBALS['sql_query'] = $request->getParsedBodyParam('sql_query'); + if (! is_string($GLOBALS['sql_query'])) { + $GLOBALS['sql_query'] = ''; + } } - $containerBuilder->setParameter('sql_query', $sql_query); + $GLOBALS['containerBuilder']->setParameter('sql_query', $GLOBALS['sql_query']); //$_REQUEST['set_theme'] // checked later in this file LABEL_theme_setup //$_REQUEST['server']; // checked later in this file @@ -182,46 +200,47 @@ final class Common * * @global integer $server */ - $server = $config->selectServer(); - $urlParams['server'] = $server; - $containerBuilder->setParameter('server', $server); - $containerBuilder->setParameter('url_params', $urlParams); + $GLOBALS['server'] = $config->selectServer(); + $GLOBALS['urlParams']['server'] = $GLOBALS['server']; + $GLOBALS['containerBuilder']->setParameter('server', $GLOBALS['server']); + $GLOBALS['containerBuilder']->setParameter('url_params', $GLOBALS['urlParams']); - $cfg = $config->settings; + $GLOBALS['cfg'] = $config->settings; /* setup themes LABEL_theme_setup */ - $theme = ThemeManager::initializeTheme(); + $GLOBALS['theme'] = ThemeManager::initializeTheme(); - /** @var DatabaseInterface $dbi */ - $dbi = null; + $GLOBALS['dbi'] = null; - if (isset($isMinimumCommon)) { + if (isset($GLOBALS['isMinimumCommon'])) { $config->loadUserPreferences(); - $containerBuilder->set('theme_manager', ThemeManager::getInstance()); + $GLOBALS['containerBuilder']->set('theme_manager', ThemeManager::getInstance()); Tracker::enable(); + if ($route === '/url') { + UrlRedirector::redirect(); + } + return; } /** * save some settings in cookies - * - * @todo should be done in PhpMyAdmin\Config */ - $config->setCookie('pma_lang', (string) $lang); + $config->setCookie('pma_lang', (string) $GLOBALS['lang']); ThemeManager::getInstance()->setThemeCookie(); - $dbi = DatabaseInterface::load(); - $containerBuilder->set(DatabaseInterface::class, $dbi); - $containerBuilder->setAlias('dbi', DatabaseInterface::class); + $GLOBALS['dbi'] = DatabaseInterface::load(); + $GLOBALS['containerBuilder']->set(DatabaseInterface::class, $GLOBALS['dbi']); + $GLOBALS['containerBuilder']->setAlias('dbi', DatabaseInterface::class); - if (! empty($cfg['Server'])) { - $config->getLoginCookieValidityFromCache($server); + if (! empty($GLOBALS['cfg']['Server'])) { + $config->getLoginCookieValidityFromCache($GLOBALS['server']); - $auth_plugin = Plugins::getAuthPlugin(); - $auth_plugin->authenticate(); + $GLOBALS['auth_plugin'] = Plugins::getAuthPlugin(); + $GLOBALS['auth_plugin']->authenticate(); /* Enable LOAD DATA LOCAL INFILE for LDI plugin */ if ($route === '/import' && ($_POST['format'] ?? '') === 'ldi') { @@ -231,21 +250,21 @@ final class Common // phpcs:enable } - self::connectToDatabaseServer($dbi, $auth_plugin); + self::connectToDatabaseServer($GLOBALS['dbi'], $GLOBALS['auth_plugin']); - $auth_plugin->rememberCredentials(); + $GLOBALS['auth_plugin']->rememberCredentials(); - $auth_plugin->checkTwoFactor(); + $GLOBALS['auth_plugin']->checkTwoFactor(); /* Log success */ - Logging::logUser($cfg['Server']['user']); + Logging::logUser($GLOBALS['cfg']['Server']['user']); - if ($dbi->getVersion() < $cfg['MysqlMinVersion']['internal']) { + if ($GLOBALS['dbi']->getVersion() < $GLOBALS['cfg']['MysqlMinVersion']['internal']) { Core::fatalError( __('You should upgrade to %s %s or later.'), [ 'MySQL', - $cfg['MysqlMinVersion']['human'], + $GLOBALS['cfg']['MysqlMinVersion']['human'], ] ); } @@ -261,7 +280,7 @@ final class Common } else { // end server connecting $response = ResponseRenderer::getInstance(); $response->getHeader()->disableMenuAndConsole(); - $response->getFooter()->setMinimal(); + $response->setMinimalFooter(); } $response = ResponseRenderer::getInstance(); @@ -270,7 +289,7 @@ final class Common * There is no point in even attempting to process * an ajax request if there is a token mismatch */ - if ($response->isAjax() && $request->isPost() && $token_mismatch) { + if ($response->isAjax() && $request->isPost() && $GLOBALS['token_mismatch']) { $response->setRequestStatus(false); $response->addJSON( 'message', @@ -279,25 +298,25 @@ final class Common exit; } - Profiling::check($dbi, $response); + Profiling::check($GLOBALS['dbi'], $response); - $containerBuilder->set('response', ResponseRenderer::getInstance()); + $GLOBALS['containerBuilder']->set('response', ResponseRenderer::getInstance()); // load user preferences $config->loadUserPreferences(); - $containerBuilder->set('theme_manager', ThemeManager::getInstance()); + $GLOBALS['containerBuilder']->set('theme_manager', ThemeManager::getInstance()); /* Tell tracker that it can actually work */ Tracker::enable(); - if (empty($server) || ! isset($cfg['ZeroConf']) || $cfg['ZeroConf'] !== true) { + if (empty($GLOBALS['server']) || ! isset($GLOBALS['cfg']['ZeroConf']) || $GLOBALS['cfg']['ZeroConf'] !== true) { return; } /** @var Relation $relation */ - $relation = $containerBuilder->get('relation'); - $dbi->postConnectControl($relation); + $relation = $GLOBALS['containerBuilder']->get('relation'); + $GLOBALS['dbi']->postConnectControl($relation); } /** @@ -375,31 +394,29 @@ final class Common */ public static function cleanupPathInfo(): void { - global $PMA_PHP_SELF; - - $PMA_PHP_SELF = Core::getenv('PHP_SELF'); - if (empty($PMA_PHP_SELF)) { - $PMA_PHP_SELF = urldecode(Core::getenv('REQUEST_URI')); + $GLOBALS['PMA_PHP_SELF'] = Core::getenv('PHP_SELF'); + if (empty($GLOBALS['PMA_PHP_SELF'])) { + $GLOBALS['PMA_PHP_SELF'] = urldecode(Core::getenv('REQUEST_URI')); } $_PATH_INFO = Core::getenv('PATH_INFO'); - if (! empty($_PATH_INFO) && ! empty($PMA_PHP_SELF)) { - $question_pos = mb_strpos($PMA_PHP_SELF, '?'); + if (! empty($_PATH_INFO) && ! empty($GLOBALS['PMA_PHP_SELF'])) { + $question_pos = mb_strpos($GLOBALS['PMA_PHP_SELF'], '?'); if ($question_pos != false) { - $PMA_PHP_SELF = mb_substr($PMA_PHP_SELF, 0, $question_pos); + $GLOBALS['PMA_PHP_SELF'] = mb_substr($GLOBALS['PMA_PHP_SELF'], 0, $question_pos); } - $path_info_pos = mb_strrpos($PMA_PHP_SELF, $_PATH_INFO); + $path_info_pos = mb_strrpos($GLOBALS['PMA_PHP_SELF'], $_PATH_INFO); if ($path_info_pos !== false) { - $path_info_part = mb_substr($PMA_PHP_SELF, $path_info_pos, mb_strlen($_PATH_INFO)); + $path_info_part = mb_substr($GLOBALS['PMA_PHP_SELF'], $path_info_pos, mb_strlen($_PATH_INFO)); if ($path_info_part == $_PATH_INFO) { - $PMA_PHP_SELF = mb_substr($PMA_PHP_SELF, 0, $path_info_pos); + $GLOBALS['PMA_PHP_SELF'] = mb_substr($GLOBALS['PMA_PHP_SELF'], 0, $path_info_pos); } } } $path = []; - foreach (explode('/', $PMA_PHP_SELF) as $part) { + foreach (explode('/', $GLOBALS['PMA_PHP_SELF']) as $part) { // ignore parts that have no value if (empty($part) || $part === '.') { continue; @@ -417,22 +434,23 @@ final class Common // as there is nothing sane to do } - $PMA_PHP_SELF = htmlspecialchars('/' . implode('/', $path)); + $GLOBALS['PMA_PHP_SELF'] = htmlspecialchars('/' . implode('/', $path)); } private static function setGotoAndBackGlobals(ContainerInterface $container, Config $config): void { - global $goto, $back, $urlParams; + $GLOBALS['back'] = $GLOBALS['back'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; // Holds page that should be displayed. - $goto = ''; - $container->setParameter('goto', $goto); + $GLOBALS['goto'] = ''; + $container->setParameter('goto', $GLOBALS['goto']); if (isset($_REQUEST['goto']) && Core::checkPageValidity($_REQUEST['goto'])) { - $goto = $_REQUEST['goto']; - $urlParams['goto'] = $goto; - $container->setParameter('goto', $goto); - $container->setParameter('url_params', $urlParams); + $GLOBALS['goto'] = $_REQUEST['goto']; + $GLOBALS['urlParams']['goto'] = $GLOBALS['goto']; + $container->setParameter('goto', $GLOBALS['goto']); + $container->setParameter('url_params', $GLOBALS['urlParams']); } else { if ($config->issetCookie('goto')) { $config->removeCookie('goto'); @@ -443,8 +461,8 @@ final class Common if (isset($_REQUEST['back']) && Core::checkPageValidity($_REQUEST['back'])) { // Returning page. - $back = $_REQUEST['back']; - $container->setParameter('back', $back); + $GLOBALS['back'] = $_REQUEST['back']; + $container->setParameter('back', $GLOBALS['back']); return; } @@ -466,21 +484,19 @@ final class Common */ public static function checkTokenRequestParam(): void { - global $token_mismatch, $token_provided; - - $token_mismatch = true; - $token_provided = false; + $GLOBALS['token_mismatch'] = true; + $GLOBALS['token_provided'] = false; if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { return; } if (isset($_POST['token']) && is_scalar($_POST['token']) && strlen((string) $_POST['token']) > 0) { - $token_provided = true; - $token_mismatch = ! @hash_equals($_SESSION[' PMA_token '], (string) $_POST['token']); + $GLOBALS['token_provided'] = true; + $GLOBALS['token_mismatch'] = ! @hash_equals($_SESSION[' PMA_token '], (string) $_POST['token']); } - if (! $token_mismatch) { + if (! $GLOBALS['token_mismatch']) { return; } @@ -506,32 +522,21 @@ final class Common ContainerInterface $containerBuilder, ServerRequest $request ): void { - global $db, $table, $urlParams; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; - try { - $db = DatabaseName::fromValue($request->getParam('db'))->getName(); - } catch (InvalidArgumentException $exception) { - $db = ''; - } + $db = DatabaseName::tryFromValue($request->getParam('db')); + $table = TableName::tryFromValue($request->getParam('table')); - try { - Assert::stringNotEmpty($db); - $table = TableName::fromValue($request->getParam('table'))->getName(); - } catch (InvalidArgumentException $exception) { - $table = ''; - } + $GLOBALS['db'] = $db !== null ? $db->getName() : ''; + $GLOBALS['table'] = $table !== null ? $table->getName() : ''; - if (! is_array($urlParams)) { - $urlParams = []; + if (! is_array($GLOBALS['urlParams'])) { + $GLOBALS['urlParams'] = []; } - $urlParams['db'] = $db; - $urlParams['table'] = $table; - // If some parameter value includes the % character, you need to escape it by adding - // another % so Symfony doesn't consider it a reference to a parameter name. - $containerBuilder->setParameter('db', str_replace('%', '%%', $db)); - $containerBuilder->setParameter('table', str_replace('%', '%%', $table)); - $containerBuilder->setParameter('url_params', $urlParams); + $GLOBALS['urlParams']['db'] = $GLOBALS['db']; + $GLOBALS['urlParams']['table'] = $GLOBALS['table']; + $containerBuilder->setParameter('url_params', $GLOBALS['urlParams']); } /** @@ -592,14 +597,12 @@ final class Common private static function connectToDatabaseServer(DatabaseInterface $dbi, AuthenticationPlugin $auth): void { - global $cfg; - /** * Try to connect MySQL with the control user profile (will be used to get the privileges list for the current * user but the true user link must be open after this one so it would be default one for all the scripts). */ $controlLink = false; - if ($cfg['Server']['controluser'] !== '') { + if ($GLOBALS['cfg']['Server']['controluser'] !== '') { $controlLink = $dbi->connect(DatabaseInterface::CONNECT_CONTROL); } @@ -620,4 +623,13 @@ final class Common */ $dbi->connect(DatabaseInterface::CONNECT_USER, null, DatabaseInterface::CONNECT_CONTROL); } + + public static function getRequest(): ServerRequest + { + if (self::$request === null) { + self::$request = ServerRequestFactory::createFromGlobals(); + } + + return self::$request; + } } diff --git a/libraries/classes/Config.php b/libraries/classes/Config.php index c7f3c4f734..c4075da5c2 100644 --- a/libraries/classes/Config.php +++ b/libraries/classes/Config.php @@ -344,7 +344,7 @@ class Config */ public function load(?string $source = null): bool { - global $isConfigLoading; + $GLOBALS['isConfigLoading'] = $GLOBALS['isConfigLoading'] ?? null; $this->loadDefaults(); @@ -369,10 +369,10 @@ class Config } ob_start(); - $isConfigLoading = true; + $GLOBALS['isConfigLoading'] = true; /** @psalm-suppress UnresolvableInclude */ $eval_result = include $this->getSource(); - $isConfigLoading = false; + $GLOBALS['isConfigLoading'] = false; ob_end_clean(); if ($canUseErrorReporting) { @@ -415,14 +415,12 @@ class Config */ private function setConnectionCollation(): void { - global $dbi; - $collation_connection = $this->get('DefaultConnectionCollation'); if (empty($collation_connection) || $collation_connection == $GLOBALS['collation_connection']) { return; } - $dbi->setCollation($collation_connection); + $GLOBALS['dbi']->setCollation($collation_connection); } /** @@ -431,15 +429,13 @@ class Config */ public function loadUserPreferences(): void { - global $isMinimumCommon; - // index.php should load these settings, so that phpmyadmin.css.php // will have everything available in session cache $server = $GLOBALS['server'] ?? (! empty($GLOBALS['cfg']['ServerDefault']) ? $GLOBALS['cfg']['ServerDefault'] : 0); $cache_key = 'server_' . $server; - if ($server > 0 && ! isset($isMinimumCommon)) { + if ($server > 0 && ! isset($GLOBALS['isMinimumCommon'])) { // cache user preferences, use database only when needed if ( ! isset($_SESSION['cache'][$cache_key]['userprefs']) @@ -467,7 +463,7 @@ class Config $this->settings = array_replace_recursive($this->settings, $config_data); $GLOBALS['cfg'] = array_replace_recursive($GLOBALS['cfg'], $config_data); - if (isset($isMinimumCommon)) { + if (isset($GLOBALS['isMinimumCommon'])) { return; } @@ -1036,9 +1032,7 @@ class Config */ public static function fatalErrorHandler(): void { - global $isConfigLoading; - - if (! isset($isConfigLoading) || ! $isConfigLoading) { + if (! isset($GLOBALS['isConfigLoading']) || ! $GLOBALS['isConfigLoading']) { return; } @@ -1258,31 +1252,29 @@ class Config */ public static function getConnectionParams(int $mode, ?array $server = null): array { - global $cfg; - $user = null; $password = null; if ($mode == DatabaseInterface::CONNECT_USER) { - $user = $cfg['Server']['user']; - $password = $cfg['Server']['password']; - $server = $cfg['Server']; + $user = $GLOBALS['cfg']['Server']['user']; + $password = $GLOBALS['cfg']['Server']['password']; + $server = $GLOBALS['cfg']['Server']; } elseif ($mode == DatabaseInterface::CONNECT_CONTROL) { - $user = $cfg['Server']['controluser']; - $password = $cfg['Server']['controlpass']; + $user = $GLOBALS['cfg']['Server']['controluser']; + $password = $GLOBALS['cfg']['Server']['controlpass']; $server = []; - $server['hide_connection_errors'] = $cfg['Server']['hide_connection_errors']; + $server['hide_connection_errors'] = $GLOBALS['cfg']['Server']['hide_connection_errors']; - if (! empty($cfg['Server']['controlhost'])) { - $server['host'] = $cfg['Server']['controlhost']; + if (! empty($GLOBALS['cfg']['Server']['controlhost'])) { + $server['host'] = $GLOBALS['cfg']['Server']['controlhost']; } else { - $server['host'] = $cfg['Server']['host']; + $server['host'] = $GLOBALS['cfg']['Server']['host']; } // Share the settings if the host is same - if ($server['host'] == $cfg['Server']['host']) { + if ($server['host'] == $GLOBALS['cfg']['Server']['host']) { $shared = [ 'port', 'socket', @@ -1296,21 +1288,21 @@ class Config 'ssl_verify', ]; foreach ($shared as $item) { - if (! isset($cfg['Server'][$item])) { + if (! isset($GLOBALS['cfg']['Server'][$item])) { continue; } - $server[$item] = $cfg['Server'][$item]; + $server[$item] = $GLOBALS['cfg']['Server'][$item]; } } // Set configured port - if (! empty($cfg['Server']['controlport'])) { - $server['port'] = $cfg['Server']['controlport']; + if (! empty($GLOBALS['cfg']['Server']['controlport'])) { + $server['port'] = $GLOBALS['cfg']['Server']['controlport']; } // Set any configuration with control_ prefix - foreach ($cfg['Server'] as $key => $val) { + foreach ($GLOBALS['cfg']['Server'] as $key => $val) { if (substr($key, 0, 8) !== 'control_') { continue; } @@ -1375,8 +1367,6 @@ class Config */ public function getLoginCookieValidityFromCache(int $server): void { - global $cfg; - $cacheKey = 'server_' . $server; if (! isset($_SESSION['cache'][$cacheKey]['userprefs']['LoginCookieValidity'])) { @@ -1385,6 +1375,6 @@ class Config $value = $_SESSION['cache'][$cacheKey]['userprefs']['LoginCookieValidity']; $this->set('LoginCookieValidity', $value); - $cfg['LoginCookieValidity'] = $value; + $GLOBALS['cfg']['LoginCookieValidity'] = $value; } } diff --git a/libraries/classes/Config/FormDisplayTemplate.php b/libraries/classes/Config/FormDisplayTemplate.php index a7ae0bbbcd..946a3a6634 100644 --- a/libraries/classes/Config/FormDisplayTemplate.php +++ b/libraries/classes/Config/FormDisplayTemplate.php @@ -150,7 +150,8 @@ class FormDisplayTemplate } $vArgs = $vArgs ? ", ['" . implode("', '", $vArgs) . "']" : ''; - $jsArray[] = "registerFieldValidator('" . $fieldId . "', '" . $vName . "', true" . $vArgs . ')'; + $jsArray[] = "window.Config.registerFieldValidator('" + . $fieldId . "', '" . $vName . "', true" . $vArgs . ')'; } } diff --git a/libraries/classes/Config/PageSettings.php b/libraries/classes/Config/PageSettings.php index b45f7ec417..dc03140ba7 100644 --- a/libraries/classes/Config/PageSettings.php +++ b/libraries/classes/Config/PageSettings.php @@ -107,9 +107,7 @@ class PageSettings if ($result === true) { // reload page $response = ResponseRenderer::getInstance(); - Core::sendHeaderLocation( - $response->getFooter()->getSelfUrl() - ); + Core::sendHeaderLocation($response->getSelfUrl()); exit; } @@ -158,13 +156,7 @@ class PageSettings $retval .= '<div id="' . $this->elemId . '">'; $retval .= '<div class="page_settings">'; - $retval .= $formDisplay->getDisplay( - false, - $response->getFooter()->getSelfUrl(), - [ - 'submit_save' => $this->groupName, - ] - ); + $retval .= $formDisplay->getDisplay(false, $response->getSelfUrl(), ['submit_save' => $this->groupName]); $retval .= '</div>'; $retval .= '</div>'; diff --git a/libraries/classes/Config/Settings/Server.php b/libraries/classes/Config/Settings/Server.php index a38ed58f56..e1c1cd3057 100644 --- a/libraries/classes/Config/Settings/Server.php +++ b/libraries/classes/Config/Settings/Server.php @@ -576,6 +576,17 @@ final class Server } /** + * @return static + */ + public function withSSL(bool $ssl): Server + { + $clone = clone $this; + $clone->ssl = $ssl; + + return $clone; + } + + /** * @param array<int|string, mixed> $server */ private function setHost(array $server): string diff --git a/libraries/classes/Config/SpecialSchemaLinks.php b/libraries/classes/Config/SpecialSchemaLinks.php index 1a3c93ba15..b273fbaf0c 100644 --- a/libraries/classes/Config/SpecialSchemaLinks.php +++ b/libraries/classes/Config/SpecialSchemaLinks.php @@ -64,9 +64,7 @@ class SpecialSchemaLinks */ public static function get(): array { - global $cfg; - - $defaultPage = './' . Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + $defaultPage = './' . Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); return [ 'mysql' => [ diff --git a/libraries/classes/ConfigStorage/Relation.php b/libraries/classes/ConfigStorage/Relation.php index e55d787ed0..b3c036d874 100644 --- a/libraries/classes/ConfigStorage/Relation.php +++ b/libraries/classes/ConfigStorage/Relation.php @@ -1779,9 +1779,7 @@ class Relation public function getConfigurationStorageDbName(): string { - global $cfg; - - $cfgStorageDbName = $cfg['Server']['pmadb'] ?? ''; + $cfgStorageDbName = $GLOBALS['cfg']['Server']['pmadb'] ?? ''; // Use "phpmyadmin" as a default database name to check to keep the behavior consistent return empty($cfgStorageDbName) ? 'phpmyadmin' : $cfgStorageDbName; diff --git a/libraries/classes/ConfigStorage/RelationParameters.php b/libraries/classes/ConfigStorage/RelationParameters.php index 4c4bb4c162..780cb65bd0 100644 --- a/libraries/classes/ConfigStorage/RelationParameters.php +++ b/libraries/classes/ConfigStorage/RelationParameters.php @@ -23,10 +23,10 @@ use PhpMyAdmin\ConfigStorage\Features\TrackingFeature; use PhpMyAdmin\ConfigStorage\Features\UiPreferencesFeature; use PhpMyAdmin\ConfigStorage\Features\UserPreferencesFeature; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidDatabaseName; +use PhpMyAdmin\Dbal\InvalidTableName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Version; -use Webmozart\Assert\Assert; -use Webmozart\Assert\InvalidArgumentException; use function is_string; @@ -138,9 +138,8 @@ final class RelationParameters } try { - Assert::keyExists($params, 'db'); - $db = DatabaseName::fromValue($params['db']); - } catch (InvalidArgumentException $exception) { + $db = DatabaseName::fromValue($params['db'] ?? null); + } catch (InvalidDatabaseName $exception) { return new self($user, null); } @@ -465,7 +464,7 @@ final class RelationParameters { try { return TableName::fromValue($tableName); - } catch (InvalidArgumentException $exception) { + } catch (InvalidTableName $exception) { return null; } } diff --git a/libraries/classes/ConfigStorage/UserGroups.php b/libraries/classes/ConfigStorage/UserGroups.php index 9763f57a1b..14c629f7fd 100644 --- a/libraries/classes/ConfigStorage/UserGroups.php +++ b/libraries/classes/ConfigStorage/UserGroups.php @@ -37,8 +37,6 @@ class UserGroups ConfigurableMenusFeature $configurableMenusFeature, string $userGroup ): string { - global $dbi; - $users = []; $numRows = 0; @@ -46,9 +44,9 @@ class UserGroups $usersTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->users); $sql_query = 'SELECT `username` FROM ' . $usersTable - . " WHERE `usergroup`='" . $dbi->escapeString($userGroup) + . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) . "'"; - $result = $dbi->tryQueryAsControlUser($sql_query); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sql_query); if ($result) { $i = 0; while ($row = $result->fetchRow()) { @@ -75,12 +73,10 @@ class UserGroups */ public static function getHtmlForUserGroupsTable(ConfigurableMenusFeature $configurableMenusFeature): string { - global $dbi; - $groupTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->userGroups); $sql_query = 'SELECT * FROM ' . $groupTable . ' ORDER BY `usergroup` ASC'; - $result = $dbi->tryQueryAsControlUser($sql_query); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sql_query); $userGroups = []; $userGroupsValues = []; $action = Url::getFromRoute('/server/privileges'); @@ -171,20 +167,18 @@ class UserGroups */ public static function delete(ConfigurableMenusFeature $configurableMenusFeature, string $userGroup): void { - global $dbi; - $userTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->users); $groupTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->userGroups); $sql_query = 'DELETE FROM ' . $userTable - . " WHERE `usergroup`='" . $dbi->escapeString($userGroup) + . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) . "'"; - $dbi->queryAsControlUser($sql_query); + $GLOBALS['dbi']->queryAsControlUser($sql_query); $sql_query = 'DELETE FROM ' . $groupTable - . " WHERE `usergroup`='" . $dbi->escapeString($userGroup) + . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) . "'"; - $dbi->queryAsControlUser($sql_query); + $GLOBALS['dbi']->queryAsControlUser($sql_query); } /** @@ -198,8 +192,6 @@ class UserGroups ConfigurableMenusFeature $configurableMenusFeature, ?string $userGroup = null ): string { - global $dbi; - $urlParams = []; $editUserGroupSpecialChars = ''; @@ -223,9 +215,9 @@ class UserGroups $groupTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->userGroups); $sql_query = 'SELECT * FROM ' . $groupTable - . " WHERE `usergroup`='" . $dbi->escapeString($userGroup) + . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) . "'"; - $result = $dbi->tryQueryAsControlUser($sql_query); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sql_query); if ($result) { foreach ($result as $row) { $key = $row['tab']; @@ -312,17 +304,15 @@ class UserGroups string $userGroup, bool $new = false ): void { - global $dbi; - $tabs = Util::getMenuTabList(); $groupTable = Util::backquote($configurableMenusFeature->database) . '.' . Util::backquote($configurableMenusFeature->userGroups); if (! $new) { $sql_query = 'DELETE FROM ' . $groupTable - . " WHERE `usergroup`='" . $dbi->escapeString($userGroup) + . " WHERE `usergroup`='" . $GLOBALS['dbi']->escapeString($userGroup) . "';"; - $dbi->queryAsControlUser($sql_query); + $GLOBALS['dbi']->queryAsControlUser($sql_query); } $sql_query = 'INSERT INTO ' . $groupTable @@ -338,13 +328,13 @@ class UserGroups $tabName = $tabGroupName . '_' . $tab; $allowed = isset($_POST[$tabName]) && $_POST[$tabName] === 'Y'; - $sql_query .= "('" . $dbi->escapeString($userGroup) . "', '" . $tabName . "', '" + $sql_query .= "('" . $GLOBALS['dbi']->escapeString($userGroup) . "', '" . $tabName . "', '" . ($allowed ? 'Y' : 'N') . "')"; $first = false; } } $sql_query .= ';'; - $dbi->queryAsControlUser($sql_query); + $GLOBALS['dbi']->queryAsControlUser($sql_query); } } diff --git a/libraries/classes/Console.php b/libraries/classes/Console.php index c416355939..c02a2b64b0 100644 --- a/libraries/classes/Console.php +++ b/libraries/classes/Console.php @@ -24,14 +24,14 @@ class Console * * @var bool */ - private $isEnabled; + private $isEnabled = true; /** * Whether we are servicing an ajax request. * * @var bool */ - private $isAjax; + private $isAjax = false; /** @var Relation */ private $relation; @@ -39,16 +39,10 @@ class Console /** @var Template */ public $template; - /** - * Creates a new class instance - */ - public function __construct() + public function __construct(Relation $relation, Template $template) { - global $dbi; - - $this->isEnabled = true; - $this->relation = new Relation($dbi); - $this->template = new Template(); + $this->relation = $relation; + $this->template = $template; } /** @@ -75,16 +69,14 @@ class Console */ public static function getBookmarkContent(): string { - global $dbi; - $template = new Template(); - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $bookmarkFeature = $relation->getRelationParameters()->bookmarkFeature; if ($bookmarkFeature === null) { return ''; } - $bookmarks = Bookmark::getList($bookmarkFeature, $dbi, $GLOBALS['cfg']['Server']['user']); + $bookmarks = Bookmark::getList($bookmarkFeature, $GLOBALS['dbi'], $GLOBALS['cfg']['Server']['user']); $count_bookmarks = count($bookmarks); if ($count_bookmarks > 0) { $welcomeMessage = sprintf( @@ -125,13 +117,11 @@ class Console } $bookmarkFeature = $this->relation->getRelationParameters()->bookmarkFeature; - $image = Html\Generator::getImage('console', __('SQL Query Console')); $_sql_history = $this->relation->getHistory($GLOBALS['cfg']['Server']['user']); $bookmarkContent = static::getBookmarkContent(); return $this->template->render('console/display', [ 'has_bookmark_feature' => $bookmarkFeature !== null, - 'image' => $image, 'sql_history' => $_sql_history, 'bookmark_content' => $bookmarkContent, ]); diff --git a/libraries/classes/Controllers/AbstractController.php b/libraries/classes/Controllers/AbstractController.php index ac808b23ae..50d8ed644a 100644 --- a/libraries/classes/Controllers/AbstractController.php +++ b/libraries/classes/Controllers/AbstractController.php @@ -5,12 +5,15 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; +use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use function __; +use function basename; +use function defined; use function strlen; abstract class AbstractController @@ -47,25 +50,26 @@ abstract class AbstractController protected function hasDatabase(): bool { - global $db, $is_db, $errno, $dbi, $message; + $GLOBALS['errno'] = $GLOBALS['errno'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; - if (isset($is_db) && $is_db) { + if (isset($GLOBALS['is_db']) && $GLOBALS['is_db']) { return true; } - $is_db = false; - if (strlen($db) > 0) { - $is_db = $dbi->selectDb($db); + $GLOBALS['is_db'] = false; + if (strlen($GLOBALS['db']) > 0) { + $GLOBALS['is_db'] = $GLOBALS['dbi']->selectDb($GLOBALS['db']); // This "Command out of sync" 2014 error may happen, for example // after calling a MySQL procedure; at this point we can't select // the db but it's not necessarily wrong - if ($dbi->getError() && $errno == 2014) { - $is_db = true; - unset($errno); + if ($GLOBALS['dbi']->getError() && $GLOBALS['errno'] == 2014) { + $GLOBALS['is_db'] = true; + unset($GLOBALS['errno']); } } - if (strlen($db) === 0 || ! $is_db) { + if (strlen($GLOBALS['db']) === 0 || ! $GLOBALS['is_db']) { if ($this->response->isAjax()) { $this->response->setRequestStatus(false); $this->response->addJSON( @@ -78,8 +82,8 @@ abstract class AbstractController // Not a valid db name -> back to the welcome page $params = ['reload' => '1']; - if (isset($message)) { - $params['message'] = $message; + if (isset($GLOBALS['message'])) { + $params['message'] = $GLOBALS['message']; } $this->redirect('/', $params); @@ -87,7 +91,7 @@ abstract class AbstractController return false; } - return $is_db; + return $GLOBALS['is_db']; } /** @@ -95,7 +99,69 @@ abstract class AbstractController */ protected function redirect(string $route, array $params = []): void { + if (defined('TESTSUITE')) { + return; + } + $uri = './index.php?route=' . $route . Url::getCommonRaw($params, '&'); Core::sendHeaderLocation($uri); } + + /** + * Function added to avoid path disclosures. + * Called by each script that needs parameters, it displays + * an error message and, by default, stops the execution. + * + * @param bool $request Check parameters in request + * @psalm-param non-empty-list<non-empty-string> $params The names of the parameters needed by the calling script + */ + protected function checkParameters(array $params, bool $request = false): void + { + $reportedScriptName = basename($GLOBALS['PMA_PHP_SELF']); + $foundError = false; + $errorMessage = ''; + if ($request) { + $array = $_REQUEST; + } else { + $array = $GLOBALS; + } + + foreach ($params as $param) { + if (isset($array[$param]) && $array[$param] !== '') { + continue; + } + + $errorMessage .= $reportedScriptName + . ': ' . __('Missing parameter:') . ' ' + . $param + . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) + . '[br]'; + $foundError = true; + } + + if (! $foundError) { + return; + } + + $this->response->setHttpResponseCode(400); + Core::fatalError($errorMessage); + } + + /** + * @psalm-param int<400,599> $statusCode + */ + protected function sendErrorResponse(string $message, int $statusCode = 400): void + { + $this->response->setHttpResponseCode($statusCode); + $this->response->setRequestStatus(false); + + if ($this->response->isAjax()) { + $this->response->addJSON('isErrorResponse', true); + $this->response->addJSON('message', $message); + + return; + } + + $this->response->addHTML(Message::error($message)->getDisplay()); + } } diff --git a/libraries/classes/Controllers/BrowseForeignersController.php b/libraries/classes/Controllers/BrowseForeignersController.php index 7f65e991ca..098632f46f 100644 --- a/libraries/classes/Controllers/BrowseForeignersController.php +++ b/libraries/classes/Controllers/BrowseForeignersController.php @@ -53,7 +53,7 @@ class BrowseForeignersController extends AbstractController return; } - $this->response->getFooter()->setMinimal(); + $this->response->setMinimalFooter(); $header = $this->response->getHeader(); $header->disableMenuAndConsole(); $header->setBodyId('body_browse_foreigners'); diff --git a/libraries/classes/Controllers/ChangeLogController.php b/libraries/classes/Controllers/ChangeLogController.php index c37ed3e334..d1f5b667c5 100644 --- a/libraries/classes/Controllers/ChangeLogController.php +++ b/libraries/classes/Controllers/ChangeLogController.php @@ -7,6 +7,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Url; + use function __; use function array_keys; use function file_get_contents; @@ -21,7 +24,7 @@ use function substr; class ChangeLogController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->response->disable(); $this->response->getHeader()->sendHttpHeaders(); @@ -62,30 +65,34 @@ class ChangeLogController extends AbstractController $faq_url = 'https://docs.phpmyadmin.net/en/latest/faq.html'; $replaces = [ - '@(https?://[./a-zA-Z0-9.-_-]*[/a-zA-Z0-9_])@' => '<a href="url.php?url=\\1">\\1</a>', + '@(https?://[./a-zA-Z0-9.-_-]*[/a-zA-Z0-9_])@' => '<a href="' + . Url::getFromRoute('/url') . '&url=\\1">\\1</a>', // mail address '/([0-9]{4}-[0-9]{2}-[0-9]{2}) (.+[^ ]) +<(.*@.*)>/i' => '\\1 <a href="mailto:\\3">\\2</a>', // FAQ entries - '/FAQ ([0-9]+)\.([0-9a-z]+)/i' => '<a href="url.php?url=' . $faq_url . '#faq\\1-\\2">FAQ \\1.\\2</a>', + '/FAQ ([0-9]+)\.([0-9a-z]+)/i' => '<a href="' + . Url::getFromRoute('/url') . '&url=' . $faq_url . '#faq\\1-\\2">FAQ \\1.\\2</a>', // GitHub issues - '/issue\s*#?([0-9]{4,5}) /i' => '<a href="url.php?url=' . $github_url . 'issues/\\1">issue #\\1</a> ', + '/issue\s*#?([0-9]{4,5}) /i' => '<a href="' + . Url::getFromRoute('/url') . '&url=' . $github_url . 'issues/\\1">issue #\\1</a> ', // CVE/CAN entries - '/((CAN|CVE)-[0-9]+-[0-9]+)/' => '<a href="url.php?url=' + '/((CAN|CVE)-[0-9]+-[0-9]+)/' => '<a href="' . Url::getFromRoute('/url') . '&url=' . 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=\\1">\\1</a>', // PMASAentries - '/(PMASA-[0-9]+-[0-9]+)/' => '<a href="url.php?url=https://www.phpmyadmin.net/security/\\1/">\\1</a>', + '/(PMASA-[0-9]+-[0-9]+)/' => '<a href="' + . Url::getFromRoute('/url') . '&url=https://www.phpmyadmin.net/security/\\1/">\\1</a>', // Highlight releases (with links) '/([0-9]+)\.([0-9]+)\.([0-9]+)\.0 (\([0-9-]+\))/' => '<a id="\\1_\\2_\\3"></a>' - . '<a href="url.php?url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3">' + . '<a href="' . Url::getFromRoute('/url') . '&url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3">' . '\\1.\\2.\\3.0 \\4</a>', '/([0-9]+)\.([0-9]+)\.([0-9]+)\.([1-9][0-9]*) (\([0-9-]+\))/' => '<a id="\\1_\\2_\\3_\\4"></a>' - . '<a href="url.php?url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3_\\4">' + . '<a href="' . Url::getFromRoute('/url') . '&url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3_\\4">' . '\\1.\\2.\\3.\\4 \\5</a>', // Highlight releases (not linkable) @@ -93,7 +100,6 @@ class ChangeLogController extends AbstractController // Links target and rel '/a href="/' => 'a target="_blank" rel="noopener noreferrer" href="', - ]; $this->response->header('Content-type: text/html; charset=utf-8'); diff --git a/libraries/classes/Controllers/CheckRelationsController.php b/libraries/classes/Controllers/CheckRelationsController.php index 7ffe56c8e2..968c07a8e7 100644 --- a/libraries/classes/Controllers/CheckRelationsController.php +++ b/libraries/classes/Controllers/CheckRelationsController.php @@ -27,8 +27,6 @@ class CheckRelationsController extends AbstractController public function __invoke(ServerRequest $request): void { - global $db, $cfg; - /** @var string|null $createPmaDb */ $createPmaDb = $request->getParsedBodyParam('create_pmadb'); /** @var string|null $fixAllPmaDb */ @@ -45,7 +43,7 @@ class CheckRelationsController extends AbstractController // If request for creating all PMA tables. if (isset($fixAllPmaDb)) { - $this->relation->fixPmaTables($db); + $this->relation->fixPmaTables($GLOBALS['db']); } // If request for creating missing PMA tables. @@ -58,8 +56,8 @@ class CheckRelationsController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('relation/check_relations', [ - 'db' => $db, - 'zero_conf' => $cfg['ZeroConf'], + 'db' => $GLOBALS['db'], + 'zero_conf' => $GLOBALS['cfg']['ZeroConf'], 'relation_parameters' => $relationParameters->toArray(), 'sql_dir' => SQL_DIR, 'config_storage_database_name' => $cfgStorageDbName, diff --git a/libraries/classes/Controllers/CollationConnectionController.php b/libraries/classes/Controllers/CollationConnectionController.php index e11fe462bd..a61c7b98f8 100644 --- a/libraries/classes/Controllers/CollationConnectionController.php +++ b/libraries/classes/Controllers/CollationConnectionController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Config; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -20,7 +21,7 @@ final class CollationConnectionController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->config->setUserValue( null, diff --git a/libraries/classes/Controllers/Console/Bookmark/AddController.php b/libraries/classes/Controllers/Console/Bookmark/AddController.php new file mode 100644 index 0000000000..42b7ee6c09 --- /dev/null +++ b/libraries/classes/Controllers/Console/Bookmark/AddController.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Console\Bookmark; + +use PhpMyAdmin\Bookmark; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function __; +use function is_string; + +final class AddController extends AbstractController +{ + /** @var DatabaseInterface */ + private $dbi; + + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) + { + parent::__construct($response, $template); + $this->dbi = $dbi; + } + + public function __invoke(ServerRequest $request): void + { + $db = $request->getParsedBodyParam('db'); + $label = $request->getParsedBodyParam('label'); + $bookmarkQuery = $request->getParsedBodyParam('bookmark_query'); + $shared = $request->getParsedBodyParam('shared'); + + if (! is_string($label) || ! is_string($db) || ! is_string($bookmarkQuery) || ! is_string($shared)) { + $this->response->addJSON('message', __('Incomplete params')); + + return; + } + + $bookmarkFields = [ + 'bkm_database' => $db, + 'bkm_user' => $GLOBALS['cfg']['Server']['user'], + 'bkm_sql_query' => $bookmarkQuery, + 'bkm_label' => $label, + ]; + $bookmark = Bookmark::createBookmark($this->dbi, $bookmarkFields, $shared === 'true'); + if ($bookmark === false || ! $bookmark->save()) { + $this->response->addJSON('message', __('Failed')); + + return; + } + + $this->response->addJSON('message', __('Succeeded')); + $this->response->addJSON('data', $bookmarkFields); + $this->response->addJSON('isShared', $shared === 'true'); + } +} diff --git a/libraries/classes/Controllers/Console/Bookmark/RefreshController.php b/libraries/classes/Controllers/Console/Bookmark/RefreshController.php new file mode 100644 index 0000000000..6b482a671b --- /dev/null +++ b/libraries/classes/Controllers/Console/Bookmark/RefreshController.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Console\Bookmark; + +use PhpMyAdmin\Console; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; + +final class RefreshController extends AbstractController +{ + public function __invoke(ServerRequest $request): void + { + $this->response->addJSON('console_message_bookmark', Console::getBookmarkContent()); + } +} diff --git a/libraries/classes/Controllers/Database/AbstractController.php b/libraries/classes/Controllers/Database/AbstractController.php deleted file mode 100644 index 296920e2ec..0000000000 --- a/libraries/classes/Controllers/Database/AbstractController.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace PhpMyAdmin\Controllers\Database; - -use PhpMyAdmin\Controllers\AbstractController as Controller; -use PhpMyAdmin\ResponseRenderer; -use PhpMyAdmin\Template; - -abstract class AbstractController extends Controller -{ - /** @var string */ - protected $db; - - public function __construct(ResponseRenderer $response, Template $template, string $db) - { - parent::__construct($response, $template); - $this->db = $db; - } -} diff --git a/libraries/classes/Controllers/Database/CentralColumns/PopulateColumnsController.php b/libraries/classes/Controllers/Database/CentralColumns/PopulateColumnsController.php index 259976236b..8bec9c24e5 100644 --- a/libraries/classes/Controllers/Database/CentralColumns/PopulateColumnsController.php +++ b/libraries/classes/Controllers/Database/CentralColumns/PopulateColumnsController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\CentralColumns; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\CentralColumns; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -17,16 +18,15 @@ final class PopulateColumnsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, CentralColumns $centralColumns ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->centralColumns = $centralColumns; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - $columns = $this->centralColumns->getColumnsNotInCentralList($this->db, $_POST['selectedTable']); + $columns = $this->centralColumns->getColumnsNotInCentralList($GLOBALS['db'], $_POST['selectedTable']); $this->render('database/central_columns/populate_columns', ['columns' => $columns]); } } diff --git a/libraries/classes/Controllers/Database/CentralColumnsController.php b/libraries/classes/Controllers/Database/CentralColumnsController.php index f8c019e5c1..189714be32 100644 --- a/libraries/classes/Controllers/Database/CentralColumnsController.php +++ b/libraries/classes/Controllers/Database/CentralColumnsController.php @@ -7,7 +7,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\CentralColumns; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,16 +28,17 @@ class CentralColumnsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, CentralColumns $centralColumns ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->centralColumns = $centralColumns; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $message, $pos, $num_cols; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['num_cols'] = $GLOBALS['num_cols'] ?? null; if (isset($_POST['edit_save'])) { echo $this->editSave([ @@ -99,7 +102,7 @@ class CentralColumnsController extends AbstractController } if (isset($_POST['multi_edit_central_column_save'])) { - $message = $this->updateMultipleColumn([ + $GLOBALS['message'] = $this->updateMultipleColumn([ 'db' => $_POST['db'] ?? null, 'orig_col_name' => $_POST['orig_col_name'] ?? null, 'field_name' => $_POST['field_name'] ?? null, @@ -112,9 +115,9 @@ class CentralColumnsController extends AbstractController 'field_null' => $_POST['field_null'] ?? null, 'col_extra' => $_POST['col_extra'] ?? null, ]); - if (! is_bool($message)) { + if (! is_bool($GLOBALS['message'])) { $this->response->setRequestStatus(false); - $this->response->addJSON('message', $message); + $this->response->addJSON('message', $GLOBALS['message']); } } @@ -130,20 +133,24 @@ class CentralColumnsController extends AbstractController 'total_rows' => $_POST['total_rows'] ?? null, ]); - $pos = 0; + $GLOBALS['pos'] = 0; if (isset($_POST['pos']) && is_numeric($_POST['pos'])) { - $pos = (int) $_POST['pos']; + $GLOBALS['pos'] = (int) $_POST['pos']; } - $num_cols = $this->centralColumns->getColumnsCount($db, $pos, (int) $cfg['MaxRows']); - $message = Message::success( - sprintf(__('Showing rows %1$s - %2$s.'), $pos + 1, $pos + $num_cols) + $GLOBALS['num_cols'] = $this->centralColumns->getColumnsCount( + $GLOBALS['db'], + $GLOBALS['pos'], + (int) $GLOBALS['cfg']['MaxRows'] + ); + $GLOBALS['message'] = Message::success( + sprintf(__('Showing rows %1$s - %2$s.'), $GLOBALS['pos'] + 1, $GLOBALS['pos'] + $GLOBALS['num_cols']) ); if (! isset($tmp_msg) || $tmp_msg === true) { return; } - $message = $tmp_msg; + $GLOBALS['message'] = $tmp_msg; } /** @@ -151,12 +158,12 @@ class CentralColumnsController extends AbstractController */ public function main(array $params): void { - global $text_dir; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; if (! empty($params['total_rows']) && is_numeric($params['total_rows'])) { $totalRows = (int) $params['total_rows']; } else { - $totalRows = $this->centralColumns->getCount($this->db); + $totalRows = $this->centralColumns->getCount($GLOBALS['db']); } $pos = 0; @@ -164,7 +171,12 @@ class CentralColumnsController extends AbstractController $pos = (int) $params['pos']; } - $variables = $this->centralColumns->getTemplateVariablesForMain($this->db, $totalRows, $pos, $text_dir); + $variables = $this->centralColumns->getTemplateVariablesForMain( + $GLOBALS['db'], + $totalRows, + $pos, + $GLOBALS['text_dir'] + ); $this->render('database/central_columns/main', $variables); } @@ -176,7 +188,7 @@ class CentralColumnsController extends AbstractController */ public function getColumnList(array $params): array { - return $this->centralColumns->getListRaw($this->db, $params['cur_table'] ?? ''); + return $this->centralColumns->getListRaw($GLOBALS['db'], $params['cur_table'] ?? ''); } /** @@ -192,7 +204,7 @@ class CentralColumnsController extends AbstractController } return $this->centralColumns->updateOneColumn( - $this->db, + $GLOBALS['db'], $params['orig_col_name'], $params['col_name'], $params['col_type'], @@ -218,7 +230,7 @@ class CentralColumnsController extends AbstractController } return $this->centralColumns->updateOneColumn( - $this->db, + $GLOBALS['db'], '', $params['col_name'], $params['col_type'], diff --git a/libraries/classes/Controllers/Database/DataDictionaryController.php b/libraries/classes/Controllers/Database/DataDictionaryController.php index f86ba991d8..8284d5e39a 100644 --- a/libraries/classes/Controllers/Database/DataDictionaryController.php +++ b/libraries/classes/Controllers/Database/DataDictionaryController.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -29,45 +31,44 @@ class DataDictionaryController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Relation $relation, Transformations $transformations, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->relation = $relation; $this->transformations = $transformations; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - Util::checkParameters(['db'], true); + $this->checkParameters(['db'], true); $relationParameters = $this->relation->getRelationParameters(); - $comment = $this->relation->getDbComment($this->db); + $comment = $this->relation->getDbComment($GLOBALS['db']); - $this->dbi->selectDb($this->db); - $tablesNames = $this->dbi->getTables($this->db); + $this->dbi->selectDb($GLOBALS['db']); + $tablesNames = $this->dbi->getTables($GLOBALS['db']); $tables = []; foreach ($tablesNames as $tableName) { - $showComment = (string) $this->dbi->getTable($this->db, $tableName)->getStatusInfo('TABLE_COMMENT'); + $showComment = (string) $this->dbi->getTable($GLOBALS['db'], $tableName)->getStatusInfo('TABLE_COMMENT'); [, $primaryKeys] = Util::processIndexData( - $this->dbi->getTableIndexes($this->db, $tableName) + $this->dbi->getTableIndexes($GLOBALS['db'], $tableName) ); [$foreigners, $hasRelation] = $this->relation->getRelationsAndStatus( $relationParameters->relationFeature !== null, - $this->db, + $GLOBALS['db'], $tableName ); - $columnsComments = $this->relation->getComments($this->db, $tableName); + $columnsComments = $this->relation->getComments($GLOBALS['db'], $tableName); - $columns = $this->dbi->getColumns($this->db, $tableName); + $columns = $this->dbi->getColumns($GLOBALS['db'], $tableName); $rows = []; foreach ($columns as $row) { $extractedColumnSpec = Util::extractColumnSpec($row['Type']); @@ -84,7 +85,7 @@ class DataDictionaryController extends AbstractController $mime = ''; if ($relationParameters->browserTransformationFeature !== null) { - $mimeMap = $this->transformations->getMime($this->db, $tableName, true); + $mimeMap = $this->transformations->getMime($GLOBALS['db'], $tableName, true); if (is_array($mimeMap) && isset($mimeMap[$row['Field']]['mimetype'])) { $mime = str_replace('_', '/', $mimeMap[$row['Field']]['mimetype']); } @@ -109,12 +110,12 @@ class DataDictionaryController extends AbstractController 'has_relation' => $hasRelation, 'has_mime' => $relationParameters->browserTransformationFeature !== null, 'columns' => $rows, - 'indexes' => Index::getFromTable($tableName, $this->db), + 'indexes' => Index::getFromTable($this->dbi, $tableName, $GLOBALS['db']), ]; } $this->render('database/data_dictionary/index', [ - 'database' => $this->db, + 'database' => $GLOBALS['db'], 'comment' => $comment, 'tables' => $tables, ]); diff --git a/libraries/classes/Controllers/Database/DesignerController.php b/libraries/classes/Controllers/Database/DesignerController.php index bd17b3feac..cd72be8c5d 100644 --- a/libraries/classes/Controllers/Database/DesignerController.php +++ b/libraries/classes/Controllers/Database/DesignerController.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Designer; use PhpMyAdmin\Database\Designer\Common as DesignerCommon; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -27,21 +29,39 @@ class DesignerController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Designer $databaseDesigner, DesignerCommon $designerCommon ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->databaseDesigner = $databaseDesigner; $this->designerCommon = $designerCommon; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $script_display_field, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys; - global $success, $page, $message, $display_page, $selected_page, $tab_pos, $fullTableNames, $script_tables; - global $script_contr, $params, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos, $classes_side_menu, $cfg, $errorUrl; + $GLOBALS['script_display_field'] = $GLOBALS['script_display_field'] ?? null; + $GLOBALS['tab_column'] = $GLOBALS['tab_column'] ?? null; + $GLOBALS['tables_all_keys'] = $GLOBALS['tables_all_keys'] ?? null; + $GLOBALS['tables_pk_or_unique_keys'] = $GLOBALS['tables_pk_or_unique_keys'] ?? null; + $GLOBALS['success'] = $GLOBALS['success'] ?? null; + $GLOBALS['page'] = $GLOBALS['page'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['display_page'] = $GLOBALS['display_page'] ?? null; + $GLOBALS['selected_page'] = $GLOBALS['selected_page'] ?? null; + $GLOBALS['tab_pos'] = $GLOBALS['tab_pos'] ?? null; + $GLOBALS['fullTableNames'] = $GLOBALS['fullTableNames'] ?? null; + $GLOBALS['script_tables'] = $GLOBALS['script_tables'] ?? null; + $GLOBALS['script_contr'] = $GLOBALS['script_contr'] ?? null; + $GLOBALS['params'] = $GLOBALS['params'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['classes_side_menu'] = $GLOBALS['classes_side_menu'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if (isset($_POST['dialog'])) { if ($_POST['dialog'] === 'edit') { @@ -54,19 +74,21 @@ class DesignerController extends AbstractController $html = $this->databaseDesigner->getHtmlForSchemaExport($_POST['db'], $_POST['selected_page']); } elseif ($_POST['dialog'] === 'add_table') { // Pass the db and table to the getTablesInfo so we only have the table we asked for - $script_display_field = $this->designerCommon->getTablesInfo($_POST['db'], $_POST['table']); - $tab_column = $this->designerCommon->getColumnsInfo($script_display_field); - $tables_all_keys = $this->designerCommon->getAllKeys($script_display_field); - $tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field); + $GLOBALS['script_display_field'] = $this->designerCommon->getTablesInfo($_POST['db'], $_POST['table']); + $GLOBALS['tab_column'] = $this->designerCommon->getColumnsInfo($GLOBALS['script_display_field']); + $GLOBALS['tables_all_keys'] = $this->designerCommon->getAllKeys($GLOBALS['script_display_field']); + $GLOBALS['tables_pk_or_unique_keys'] = $this->designerCommon->getPkOrUniqueKeys( + $GLOBALS['script_display_field'] + ); $html = $this->databaseDesigner->getDatabaseTables( $_POST['db'], - $script_display_field, + $GLOBALS['script_display_field'], [], -1, - $tab_column, - $tables_all_keys, - $tables_pk_or_unique_keys + $GLOBALS['tab_column'], + $GLOBALS['tables_all_keys'], + $GLOBALS['tables_pk_or_unique_keys'] ); } @@ -79,11 +101,11 @@ class DesignerController extends AbstractController if (isset($_POST['operation'])) { if ($_POST['operation'] === 'deletePage') { - $success = $this->designerCommon->deletePage($_POST['selected_page']); - $this->response->setRequestStatus($success); + $GLOBALS['success'] = $this->designerCommon->deletePage($_POST['selected_page']); + $this->response->setRequestStatus($GLOBALS['success']); } elseif ($_POST['operation'] === 'savePage') { if ($_POST['save_page'] === 'same') { - $page = $_POST['selected_page']; + $GLOBALS['page'] = $_POST['selected_page']; } elseif ($this->designerCommon->getPageExists($_POST['selected_value'])) { $this->response->addJSON( 'message', @@ -97,21 +119,21 @@ class DesignerController extends AbstractController return; } else { - $page = $this->designerCommon->createNewPage($_POST['selected_value'], $_POST['db']); - $this->response->addJSON('id', $page); + $GLOBALS['page'] = $this->designerCommon->createNewPage($_POST['selected_value'], $_POST['db']); + $this->response->addJSON('id', $GLOBALS['page']); } - $success = $this->designerCommon->saveTablePositions($page); - $this->response->setRequestStatus($success); + $GLOBALS['success'] = $this->designerCommon->saveTablePositions($GLOBALS['page']); + $this->response->setRequestStatus($GLOBALS['success']); } elseif ($_POST['operation'] === 'setDisplayField') { [ - $success, - $message, + $GLOBALS['success'], + $GLOBALS['message'], ] = $this->designerCommon->saveDisplayField($_POST['db'], $_POST['table'], $_POST['field']); - $this->response->setRequestStatus($success); - $this->response->addJSON('message', $message); + $this->response->setRequestStatus($GLOBALS['success']); + $this->response->addJSON('message', $GLOBALS['message']); } elseif ($_POST['operation'] === 'addNewRelation') { - [$success, $message] = $this->designerCommon->addNewRelation( + [$GLOBALS['success'], $GLOBALS['message']] = $this->designerCommon->addNewRelation( $_POST['db'], $_POST['T1'], $_POST['F1'], @@ -122,86 +144,88 @@ class DesignerController extends AbstractController $_POST['DB1'], $_POST['DB2'] ); - $this->response->setRequestStatus($success); - $this->response->addJSON('message', $message); + $this->response->setRequestStatus($GLOBALS['success']); + $this->response->addJSON('message', $GLOBALS['message']); } elseif ($_POST['operation'] === 'removeRelation') { - [$success, $message] = $this->designerCommon->removeRelation( + [$GLOBALS['success'], $GLOBALS['message']] = $this->designerCommon->removeRelation( $_POST['T1'], $_POST['F1'], $_POST['T2'], $_POST['F2'] ); - $this->response->setRequestStatus($success); - $this->response->addJSON('message', $message); + $this->response->setRequestStatus($GLOBALS['success']); + $this->response->addJSON('message', $GLOBALS['message']); } elseif ($_POST['operation'] === 'save_setting_value') { - $success = $this->designerCommon->saveSetting($_POST['index'], $_POST['value']); - $this->response->setRequestStatus($success); + $GLOBALS['success'] = $this->designerCommon->saveSetting($_POST['index'], $_POST['value']); + $this->response->setRequestStatus($GLOBALS['success']); } return; } - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $script_display_field = $this->designerCommon->getTablesInfo(); + $GLOBALS['script_display_field'] = $this->designerCommon->getTablesInfo(); - $display_page = -1; - $selected_page = null; + $GLOBALS['display_page'] = -1; + $GLOBALS['selected_page'] = null; $visualBuilderMode = isset($_GET['query']); if ($visualBuilderMode) { - $display_page = $this->designerCommon->getDefaultPage($_GET['db']); + $GLOBALS['display_page'] = $this->designerCommon->getDefaultPage($_GET['db']); } elseif (! empty($_GET['page'])) { - $display_page = $_GET['page']; + $GLOBALS['display_page'] = $_GET['page']; } else { - $display_page = $this->designerCommon->getLoadingPage($_GET['db']); + $GLOBALS['display_page'] = $this->designerCommon->getLoadingPage($_GET['db']); } - if ($display_page != -1) { - $selected_page = $this->designerCommon->getPageName($display_page); + if ($GLOBALS['display_page'] != -1) { + $GLOBALS['selected_page'] = $this->designerCommon->getPageName($GLOBALS['display_page']); } - $tab_pos = $this->designerCommon->getTablePositions($display_page); + $GLOBALS['tab_pos'] = $this->designerCommon->getTablePositions($GLOBALS['display_page']); - $fullTableNames = []; + $GLOBALS['fullTableNames'] = []; - foreach ($script_display_field as $designerTable) { - $fullTableNames[] = $designerTable->getDbTableString(); + foreach ($GLOBALS['script_display_field'] as $designerTable) { + $GLOBALS['fullTableNames'][] = $designerTable->getDbTableString(); } - foreach ($tab_pos as $position) { - if (in_array($position['dbName'] . '.' . $position['tableName'], $fullTableNames)) { + foreach ($GLOBALS['tab_pos'] as $position) { + if (in_array($position['dbName'] . '.' . $position['tableName'], $GLOBALS['fullTableNames'])) { continue; } $designerTables = $this->designerCommon->getTablesInfo($position['dbName'], $position['tableName']); foreach ($designerTables as $designerTable) { - $script_display_field[] = $designerTable; + $GLOBALS['script_display_field'][] = $designerTable; } } - $tab_column = $this->designerCommon->getColumnsInfo($script_display_field); - $script_tables = $this->designerCommon->getScriptTabs($script_display_field); - $tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field); - $tables_all_keys = $this->designerCommon->getAllKeys($script_display_field); - $classes_side_menu = $this->databaseDesigner->returnClassNamesFromMenuButtons(); + $GLOBALS['tab_column'] = $this->designerCommon->getColumnsInfo($GLOBALS['script_display_field']); + $GLOBALS['script_tables'] = $this->designerCommon->getScriptTabs($GLOBALS['script_display_field']); + $GLOBALS['tables_pk_or_unique_keys'] = $this->designerCommon->getPkOrUniqueKeys( + $GLOBALS['script_display_field'] + ); + $GLOBALS['tables_all_keys'] = $this->designerCommon->getAllKeys($GLOBALS['script_display_field']); + $GLOBALS['classes_side_menu'] = $this->databaseDesigner->returnClassNamesFromMenuButtons(); - $script_contr = $this->designerCommon->getScriptContr($script_display_field); + $GLOBALS['script_contr'] = $this->designerCommon->getScriptContr($GLOBALS['script_display_field']); - $params = ['lang' => $GLOBALS['lang']]; + $GLOBALS['params'] = ['lang' => $GLOBALS['lang']]; if (isset($_GET['db'])) { - $params['db'] = $_GET['db']; + $GLOBALS['params']['db'] = $_GET['db']; } - $this->response->getFooter()->setMinimal(); + $this->response->setMinimalFooter(); $header = $this->response->getHeader(); $header->setBodyId('designer_body'); @@ -215,33 +239,33 @@ class DesignerController extends AbstractController ]); [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); // Embed some data into HTML, later it will be read // by designer/init.js and converted to JS variables. $this->response->addHTML( $this->databaseDesigner->getHtmlForMain( - $db, + $GLOBALS['db'], $_GET['db'], - $script_display_field, - $script_tables, - $script_contr, - $script_display_field, - $display_page, + $GLOBALS['script_display_field'], + $GLOBALS['script_tables'], + $GLOBALS['script_contr'], + $GLOBALS['script_display_field'], + $GLOBALS['display_page'], $visualBuilderMode, - $selected_page, - $classes_side_menu, - $tab_pos, - $tab_column, - $tables_all_keys, - $tables_pk_or_unique_keys + $GLOBALS['selected_page'], + $GLOBALS['classes_side_menu'], + $GLOBALS['tab_pos'], + $GLOBALS['tab_column'], + $GLOBALS['tables_all_keys'], + $GLOBALS['tables_pk_or_unique_keys'] ) ); diff --git a/libraries/classes/Controllers/Database/EventsController.php b/libraries/classes/Controllers/Database/EventsController.php index 6868233b1d..b0d6c70632 100644 --- a/libraries/classes/Controllers/Database/EventsController.php +++ b/libraries/classes/Controllers/Database/EventsController.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Events; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -24,62 +26,69 @@ final class EventsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Events $events, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->events = $events; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $tables, $num_tables, $total_num_tables, $sub_part, $errors, $text_dir; - global $tooltip_truename, $tooltip_aliasname, $pos, $cfg, $errorUrl; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['database/events.js']); if (! $this->response->isAjax()) { - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); - } elseif (strlen($db) > 0) { - $this->dbi->selectDb($db); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); + } elseif (strlen($GLOBALS['db']) > 0) { + $this->dbi->selectDb($GLOBALS['db']); } /** * Keep a list of errors that occurred while * processing an 'Add' or 'Edit' operation. */ - $errors = []; + $GLOBALS['errors'] = []; $this->events->handleEditor(); $this->events->export(); - $items = $this->dbi->getEvents($db); + $items = $this->events->getDetails($GLOBALS['db']); $this->render('database/events/index', [ - 'db' => $db, + 'db' => $GLOBALS['db'], 'items' => $items, - 'has_privilege' => Util::currentUserHasPrivilege('EVENT', $db), + 'has_privilege' => Util::currentUserHasPrivilege('EVENT', $GLOBALS['db']), 'scheduler_state' => $this->events->getEventSchedulerStatus(), - 'text_dir' => $text_dir, + 'text_dir' => $GLOBALS['text_dir'], 'is_ajax' => $this->response->isAjax() && empty($_REQUEST['ajax_page_request']), ]); } diff --git a/libraries/classes/Controllers/Database/ExportController.php b/libraries/classes/Controllers/Database/ExportController.php index 39503bc719..76444c327a 100644 --- a/libraries/classes/Controllers/Database/ExportController.php +++ b/libraries/classes/Controllers/Database/ExportController.php @@ -5,8 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Export; use PhpMyAdmin\Export\Options; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\ResponseRenderer; @@ -29,20 +31,27 @@ final class ExportController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Export $export, Options $exportOptions ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->export = $export; $this->exportOptions = $exportOptions; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $sub_part, $urlParams, $sql_query; - global $tables, $num_tables, $total_num_tables, $tooltip_truename; - global $tooltip_aliasname, $pos, $table_select, $unlim_num_rows, $cfg, $errorUrl; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['table_select'] = $GLOBALS['table_select'] ?? null; + $GLOBALS['unlim_num_rows'] = $GLOBALS['unlim_num_rows'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $pageSettings = new PageSettings('Export'); $pageSettingsErrorHtml = $pageSettings->getErrorHTML(); @@ -52,31 +61,31 @@ final class ExportController extends AbstractController // $sub_part is used in Util::getDbInfo() to see if we are coming from // /database/export, in which case we don't obey $cfg['MaxTableList'] - $sub_part = '_export'; + $GLOBALS['sub_part'] = '_export'; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $urlParams['goto'] = Url::getFromRoute('/database/export'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/database/export'); [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part']); // exit if no tables in db found - if ($num_tables < 1) { + if ($GLOBALS['num_tables'] < 1) { $this->response->addHTML( Message::error(__('No tables found in database.'))->getDisplay() ); @@ -84,17 +93,17 @@ final class ExportController extends AbstractController return; } - if (! empty($_POST['selected_tbl']) && empty($table_select)) { - $table_select = $_POST['selected_tbl']; + if (! empty($_POST['selected_tbl']) && empty($GLOBALS['table_select'])) { + $GLOBALS['table_select'] = $_POST['selected_tbl']; } $tablesForMultiValues = []; - foreach ($tables as $each_table) { + foreach ($GLOBALS['tables'] as $each_table) { if (isset($_POST['table_select']) && is_array($_POST['table_select'])) { $is_checked = $this->export->getCheckedClause($each_table['Name'], $_POST['table_select']); - } elseif (isset($table_select)) { - $is_checked = $this->export->getCheckedClause($each_table['Name'], $table_select); + } elseif (isset($GLOBALS['table_select'])) { + $is_checked = $this->export->getCheckedClause($each_table['Name'], $GLOBALS['table_select']); } else { $is_checked = true; } @@ -119,12 +128,12 @@ final class ExportController extends AbstractController ]; } - if (! isset($sql_query)) { - $sql_query = ''; + if (! isset($GLOBALS['sql_query'])) { + $GLOBALS['sql_query'] = ''; } - if (! isset($unlim_num_rows)) { - $unlim_num_rows = 0; + if (! isset($GLOBALS['unlim_num_rows'])) { + $GLOBALS['unlim_num_rows'] = 0; } $isReturnBackFromRawExport = isset($_POST['export_type']) && $_POST['export_type'] === 'raw'; @@ -148,11 +157,11 @@ final class ExportController extends AbstractController $options = $this->exportOptions->getOptions( $export_type, - $db, - $table, - $sql_query, - $num_tables, - $unlim_num_rows, + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['sql_query'], + $GLOBALS['num_tables'], + $GLOBALS['unlim_num_rows'], $exportList ); diff --git a/libraries/classes/Controllers/Database/ImportController.php b/libraries/classes/Controllers/Database/ImportController.php index 651ed1a14e..2755939d3c 100644 --- a/libraries/classes/Controllers/Database/ImportController.php +++ b/libraries/classes/Controllers/Database/ImportController.php @@ -6,8 +6,10 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Charsets; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Encoding; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Message; @@ -27,16 +29,23 @@ final class ImportController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $tables, $num_tables, $total_num_tables, $cfg; - global $tooltip_truename, $tooltip_aliasname, $pos, $sub_part, $SESSION_KEY, $errorUrl; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $pageSettings = new PageSettings('Import'); $pageSettingsErrorHtml = $pageSettings->getErrorHTML(); @@ -44,26 +53,26 @@ final class ImportController extends AbstractController $this->addScriptFiles(['import.js']); - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); - [$SESSION_KEY, $uploadId] = Ajax::uploadProgressSetup(); + [$GLOBALS['SESSION_KEY'], $uploadId] = Ajax::uploadProgressSetup(); $importList = Plugins::getImport('database'); @@ -84,13 +93,13 @@ final class ImportController extends AbstractController $localImportFile = $_REQUEST['local_import_file'] ?? null; $compressions = Import::getCompressions(); - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $idKey = $_SESSION[$SESSION_KEY]['handler']::getIdKey(); + $idKey = $_SESSION[$GLOBALS['SESSION_KEY']]['handler']::getIdKey(); $hiddenInputs = [ $idKey => $uploadId, 'import_type' => 'database', - 'db' => $db, + 'db' => $GLOBALS['db'], ]; $default = isset($_GET['format']) ? (string) $_GET['format'] : Plugins::getDefault('Import', 'format'); @@ -104,10 +113,10 @@ final class ImportController extends AbstractController 'page_settings_error_html' => $pageSettingsErrorHtml, 'page_settings_html' => $pageSettingsHtml, 'upload_id' => $uploadId, - 'handler' => $_SESSION[$SESSION_KEY]['handler'], + 'handler' => $_SESSION[$GLOBALS['SESSION_KEY']]['handler'], 'hidden_inputs' => $hiddenInputs, - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'max_upload_size' => $maxUploadSize, 'formatted_maximum_upload_size' => Util::getFormattedMaximumUploadSize($maxUploadSize), 'plugins_choice' => $choice, @@ -116,18 +125,18 @@ final class ImportController extends AbstractController 'is_allow_interrupt_checked' => $isAllowInterruptChecked, 'local_import_file' => $localImportFile, 'is_upload' => $GLOBALS['config']->get('enable_upload'), - 'upload_dir' => $cfg['UploadDir'] ?? null, + 'upload_dir' => $GLOBALS['cfg']['UploadDir'] ?? null, 'timeout_passed_global' => $GLOBALS['timeout_passed'] ?? null, 'compressions' => $compressions, 'is_encoding_supported' => Encoding::isSupported(), 'encodings' => Encoding::listEncodings(), - 'import_charset' => $cfg['Import']['charset'] ?? null, + 'import_charset' => $GLOBALS['cfg']['Import']['charset'] ?? null, 'timeout_passed' => $timeoutPassed, 'offset' => $offset, 'can_convert_kanji' => Encoding::canConvertKanji(), 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), - 'user_upload_dir' => Util::userDir((string) ($cfg['UploadDir'] ?? '')), + 'user_upload_dir' => Util::userDir((string) ($GLOBALS['cfg']['UploadDir'] ?? '')), 'local_files' => Import::getLocalFiles($importList), ]); } diff --git a/libraries/classes/Controllers/Database/MultiTableQuery/QueryController.php b/libraries/classes/Controllers/Database/MultiTableQuery/QueryController.php index 45c311a33e..aa76eee435 100644 --- a/libraries/classes/Controllers/Database/MultiTableQuery/QueryController.php +++ b/libraries/classes/Controllers/Database/MultiTableQuery/QueryController.php @@ -6,10 +6,11 @@ namespace PhpMyAdmin\Controllers\Database\MultiTableQuery; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\MultiTableQuery; +use PhpMyAdmin\Http\ServerRequest; final class QueryController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $params = [ 'sql_query' => $_POST['sql_query'], diff --git a/libraries/classes/Controllers/Database/MultiTableQuery/TablesController.php b/libraries/classes/Controllers/Database/MultiTableQuery/TablesController.php index ff46491517..c4725b94bd 100644 --- a/libraries/classes/Controllers/Database/MultiTableQuery/TablesController.php +++ b/libraries/classes/Controllers/Database/MultiTableQuery/TablesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Database\MultiTableQuery; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Query\Generator as QueryGenerator; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -23,7 +24,7 @@ final class TablesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $params = [ 'tables' => $_GET['tables'] ?? [], diff --git a/libraries/classes/Controllers/Database/MultiTableQueryController.php b/libraries/classes/Controllers/Database/MultiTableQueryController.php index 69f798fadb..9e269cf944 100644 --- a/libraries/classes/Controllers/Database/MultiTableQueryController.php +++ b/libraries/classes/Controllers/Database/MultiTableQueryController.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\MultiTableQuery; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -17,20 +19,20 @@ class MultiTableQueryController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->addScriptFiles([ 'database/multi_table_query.js', 'database/query_generator.js', ]); - $queryInstance = new MultiTableQuery($this->dbi, $this->template, $this->db); + $queryInstance = new MultiTableQuery($this->dbi, $this->template, $GLOBALS['db']); $this->response->addHTML($queryInstance->getFormHtml()); } diff --git a/libraries/classes/Controllers/Database/Operations/CollationController.php b/libraries/classes/Controllers/Database/Operations/CollationController.php index 5f1b890e03..9e97ccb38f 100644 --- a/libraries/classes/Controllers/Database/Operations/CollationController.php +++ b/libraries/classes/Controllers/Database/Operations/CollationController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Operations; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -26,18 +27,17 @@ final class CollationController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Operations $operations, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->operations = $operations; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $cfg, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if (! $this->response->isAjax()) { return; @@ -50,16 +50,16 @@ final class CollationController extends AbstractController return; } - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $sql_query = 'ALTER DATABASE ' . Util::backquote($db) + $sql_query = 'ALTER DATABASE ' . Util::backquote($GLOBALS['db']) . ' DEFAULT' . Util::getCharsetQueryPart($_POST['db_collation'] ?? ''); $this->dbi->query($sql_query); $message = Message::success(); @@ -68,16 +68,16 @@ final class CollationController extends AbstractController * Changes tables charset if requested by the user */ if (isset($_POST['change_all_tables_collations']) && $_POST['change_all_tables_collations'] === 'on') { - [$tables] = Util::getDbInfo($db, ''); - foreach ($tables as $tableName => $data) { - if ($this->dbi->getTable($db, $tableName)->isView()) { + [$tables] = Util::getDbInfo($GLOBALS['db'], ''); + foreach ($tables as ['Name' => $tableName]) { + if ($this->dbi->getTable($GLOBALS['db'], $tableName)->isView()) { // Skip views, we can not change the collation of a view. // issue #15283 continue; } $sql_query = 'ALTER TABLE ' - . Util::backquote($db) + . Util::backquote($GLOBALS['db']) . '.' . Util::backquote($tableName) . ' DEFAULT ' @@ -94,7 +94,7 @@ final class CollationController extends AbstractController continue; } - $this->operations->changeAllColumnsCollation($db, $tableName, $_POST['db_collation']); + $this->operations->changeAllColumnsCollation($GLOBALS['db'], $tableName, $_POST['db_collation']); } } diff --git a/libraries/classes/Controllers/Database/OperationsController.php b/libraries/classes/Controllers/Database/OperationsController.php index 9c45420b23..031a8096f4 100644 --- a/libraries/classes/Controllers/Database/OperationsController.php +++ b/libraries/classes/Controllers/Database/OperationsController.php @@ -8,12 +8,15 @@ use PhpMyAdmin\Charsets; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidDatabaseName; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\Plugins; -use PhpMyAdmin\Plugins\Export\ExportSql; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -48,14 +51,13 @@ class OperationsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Operations $operations, CheckUserPrivileges $checkUserPrivileges, Relation $relation, RelationCleanup $relationCleanup, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->operations = $operations; $this->checkUserPrivileges = $checkUserPrivileges; $this->relation = $relation; @@ -63,45 +65,65 @@ class OperationsController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $server, $sql_query, $move, $message, $tables_full, $errorUrl; - global $export_sql_plugin, $views, $sqlConstratints, $local_query, $reload, $urlParams, $tables; - global $total_num_tables, $sub_part, $tooltip_truename; - global $db_collation, $tooltip_aliasname, $pos, $is_information_schema, $single_table, $num_tables; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; + $GLOBALS['move'] = $GLOBALS['move'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['tables_full'] = $GLOBALS['tables_full'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['export_sql_plugin'] = $GLOBALS['export_sql_plugin'] ?? null; + $GLOBALS['views'] = $GLOBALS['views'] ?? null; + $GLOBALS['sqlConstratints'] = $GLOBALS['sqlConstratints'] ?? null; + $GLOBALS['local_query'] = $GLOBALS['local_query'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['db_collation'] = $GLOBALS['db_collation'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['is_information_schema'] = $GLOBALS['is_information_schema'] ?? null; + $GLOBALS['single_table'] = $GLOBALS['single_table'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; $this->checkUserPrivileges->getPrivileges(); $this->addScriptFiles(['database/operations.js']); - $sql_query = ''; + $GLOBALS['sql_query'] = ''; /** * Rename/move or copy database */ - if (strlen($db) > 0 && (! empty($_POST['db_rename']) || ! empty($_POST['db_copy']))) { + if (strlen($GLOBALS['db']) > 0 && (! empty($_POST['db_rename']) || ! empty($_POST['db_copy']))) { if (! empty($_POST['db_rename'])) { - $move = true; + $GLOBALS['move'] = true; } else { - $move = false; + $GLOBALS['move'] = false; } - if (! isset($_POST['newname']) || strlen($_POST['newname']) === 0) { - $message = Message::error(__('The database name is empty!')); - } else { - // lower_case_table_names=1 `DB` becomes `db` + try { + $newDatabaseName = DatabaseName::fromValue($request->getParsedBodyParam('newname')); if ($this->dbi->getLowerCaseNames() === '1') { - $_POST['newname'] = mb_strtolower($_POST['newname']); + $newDatabaseName = DatabaseName::fromValue(mb_strtolower($newDatabaseName->getName())); } + } catch (InvalidDatabaseName $exception) { + $newDatabaseName = null; + $GLOBALS['message'] = Message::error($exception->getMessage()); + } - if ($_POST['newname'] === $_REQUEST['db']) { - $message = Message::error( + if ($newDatabaseName !== null) { + if ($newDatabaseName->getName() === $_REQUEST['db']) { + $GLOBALS['message'] = Message::error( __('Cannot copy database to the same name. Change the name and try again.') ); } else { $_error = false; - if ($move || ! empty($_POST['create_database_before_copying'])) { - $this->operations->createDbBeforeCopy(); + if ($GLOBALS['move'] || ! empty($_POST['create_database_before_copying'])) { + $this->operations->createDbBeforeCopy($newDatabaseName); } // here I don't use DELIMITER because it's not part of the @@ -110,97 +132,114 @@ class OperationsController extends AbstractController // to avoid selecting alternatively the current and new db // we would need to modify the CREATE definitions to qualify // the db name - $this->operations->runProcedureAndFunctionDefinitions($db); + $this->operations->runProcedureAndFunctionDefinitions($GLOBALS['db'], $newDatabaseName); // go back to current db, just in case - $this->dbi->selectDb($db); + $this->dbi->selectDb($GLOBALS['db']); - $tables_full = $this->dbi->getTablesFull($db); + $GLOBALS['tables_full'] = $this->dbi->getTablesFull($GLOBALS['db']); // remove all foreign key constraints, otherwise we can get errors - /** @var ExportSql $export_sql_plugin */ - $export_sql_plugin = Plugins::getPlugin('export', 'sql', [ + $GLOBALS['export_sql_plugin'] = Plugins::getPlugin('export', 'sql', [ 'export_type' => 'database', - 'single_table' => isset($single_table), + 'single_table' => isset($GLOBALS['single_table']), ]); // create stand-in tables for views - $views = $this->operations->getViewsAndCreateSqlViewStandIn($tables_full, $export_sql_plugin, $db); + $GLOBALS['views'] = $this->operations->getViewsAndCreateSqlViewStandIn( + $GLOBALS['tables_full'], + $GLOBALS['export_sql_plugin'], + $GLOBALS['db'], + $newDatabaseName + ); // copy tables - $sqlConstratints = $this->operations->copyTables($tables_full, $move, $db); + $GLOBALS['sqlConstratints'] = $this->operations->copyTables( + $GLOBALS['tables_full'], + $GLOBALS['move'], + $GLOBALS['db'], + $newDatabaseName + ); // handle the views if (! $_error) { - $this->operations->handleTheViews($views, $move, $db); + $this->operations->handleTheViews( + $GLOBALS['views'], + $GLOBALS['move'], + $GLOBALS['db'], + $newDatabaseName + ); } - unset($views); + unset($GLOBALS['views']); // now that all tables exist, create all the accumulated constraints - if (! $_error && count($sqlConstratints) > 0) { - $this->operations->createAllAccumulatedConstraints($sqlConstratints); + if (! $_error && count($GLOBALS['sqlConstratints']) > 0) { + $this->operations->createAllAccumulatedConstraints( + $GLOBALS['sqlConstratints'], + $newDatabaseName + ); } - unset($sqlConstratints); + unset($GLOBALS['sqlConstratints']); if ($this->dbi->getVersion() >= 50100) { // here DELIMITER is not used because it's not part of the // language; each statement is sent one by one - $this->operations->runEventDefinitionsForDb($db); + $this->operations->runEventDefinitionsForDb($GLOBALS['db'], $newDatabaseName); } // go back to current db, just in case - $this->dbi->selectDb($db); + $this->dbi->selectDb($GLOBALS['db']); // Duplicate the bookmarks for this db (done once for each db) - $this->operations->duplicateBookmarks($_error, $db); + $this->operations->duplicateBookmarks($_error, $GLOBALS['db'], $newDatabaseName); - if (! $_error && $move) { + if (! $_error && $GLOBALS['move']) { if (isset($_POST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])) { - $this->operations->adjustPrivilegesMoveDb($db, $_POST['newname']); + $this->operations->adjustPrivilegesMoveDb($GLOBALS['db'], $newDatabaseName); } /** * cleanup pmadb stuff for this db */ - $this->relationCleanup->database($db); + $this->relationCleanup->database($GLOBALS['db']); // if someday the RENAME DATABASE reappears, do not DROP - $local_query = 'DROP DATABASE ' - . Util::backquote($db) . ';'; - $sql_query .= "\n" . $local_query; - $this->dbi->query($local_query); + $GLOBALS['local_query'] = 'DROP DATABASE ' + . Util::backquote($GLOBALS['db']) . ';'; + $GLOBALS['sql_query'] .= "\n" . $GLOBALS['local_query']; + $this->dbi->query($GLOBALS['local_query']); - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Database %1$s has been renamed to %2$s.') ); - $message->addParam($db); - $message->addParam($_POST['newname']); + $GLOBALS['message']->addParam($GLOBALS['db']); + $GLOBALS['message']->addParam($newDatabaseName->getName()); } elseif (! $_error) { if (isset($_POST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])) { - $this->operations->adjustPrivilegesCopyDb($db, $_POST['newname']); + $this->operations->adjustPrivilegesCopyDb($GLOBALS['db'], $newDatabaseName); } - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Database %1$s has been copied to %2$s.') ); - $message->addParam($db); - $message->addParam($_POST['newname']); + $GLOBALS['message']->addParam($GLOBALS['db']); + $GLOBALS['message']->addParam($newDatabaseName->getName()); } else { - $message = Message::error(); + $GLOBALS['message'] = Message::error(); } - $reload = true; + $GLOBALS['reload'] = true; /* Change database to be used */ - if (! $_error && $move) { - $db = $_POST['newname']; + if (! $_error && $GLOBALS['move']) { + $GLOBALS['db'] = $newDatabaseName->getName(); } elseif (! $_error) { if (isset($_POST['switch_to_new']) && $_POST['switch_to_new'] === 'true') { $_SESSION['pma_switch_to_new'] = true; - $db = $_POST['newname']; + $GLOBALS['db'] = $newDatabaseName->getName(); } else { $_SESSION['pma_switch_to_new'] = false; } @@ -213,14 +252,14 @@ class OperationsController extends AbstractController * generate the output with {@link ResponseRenderer} and exit */ if ($this->response->isAjax()) { - $this->response->setRequestStatus($message->isSuccess()); - $this->response->addJSON('message', $message); - $this->response->addJSON('newname', $_POST['newname']); + $this->response->setRequestStatus($GLOBALS['message']->isSuccess()); + $this->response->addJSON('message', $GLOBALS['message']); + $this->response->addJSON('newname', $newDatabaseName !== null ? $newDatabaseName->getName() : ''); $this->response->addJSON( 'sql_query', - Generator::getMessage('', $sql_query) + Generator::getMessage('', $GLOBALS['sql_query']) ); - $this->response->addJSON('db', $db); + $this->response->addJSON('db', $GLOBALS['db']); return; } @@ -233,86 +272,86 @@ class OperationsController extends AbstractController * (must be done before displaying the menu tabs) */ if (isset($_POST['comment'])) { - $this->relation->setDbComment($db, $_POST['comment']); + $this->relation->setDbComment($GLOBALS['db'], $_POST['comment']); } - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $urlParams['goto'] = Url::getFromRoute('/database/operations'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/database/operations'); // Gets the database structure - $sub_part = '_structure'; + $GLOBALS['sub_part'] = '_structure'; [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,, + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],, $isSystemSchema, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part); + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part']); $oldMessage = ''; - if (isset($message)) { - $oldMessage = Generator::getMessage($message, $sql_query); - unset($message); + if (isset($GLOBALS['message'])) { + $oldMessage = Generator::getMessage($GLOBALS['message'], $GLOBALS['sql_query']); + unset($GLOBALS['message']); } - $db_collation = $this->dbi->getDbCollation($db); - $is_information_schema = Utilities::isSystemSchema($db); + $GLOBALS['db_collation'] = $this->dbi->getDbCollation($GLOBALS['db']); + $GLOBALS['is_information_schema'] = Utilities::isSystemSchema($GLOBALS['db']); - if ($is_information_schema) { + if ($GLOBALS['is_information_schema']) { return; } $databaseComment = ''; if ($relationParameters->columnCommentsFeature !== null) { - $databaseComment = $this->relation->getDbComment($db); + $databaseComment = $this->relation->getDbComment($GLOBALS['db']); } $hasAdjustPrivileges = $GLOBALS['db_priv'] && $GLOBALS['table_priv'] && $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] && $GLOBALS['is_reload_priv']; - $isDropDatabaseAllowed = ($this->dbi->isSuperUser() || $cfg['AllowUserDropDatabase']) - && ! $isSystemSchema && $db !== 'mysql'; + $isDropDatabaseAllowed = ($this->dbi->isSuperUser() || $GLOBALS['cfg']['AllowUserDropDatabase']) + && ! $isSystemSchema && $GLOBALS['db'] !== 'mysql'; $switchToNew = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new']; $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - if (! $relationParameters->hasAllFeatures() && $cfg['PmaNoRelation_DisableWarning'] == false) { - $message = Message::notice( + if (! $relationParameters->hasAllFeatures() && $GLOBALS['cfg']['PmaNoRelation_DisableWarning'] == false) { + $GLOBALS['message'] = Message::notice( __( 'The phpMyAdmin configuration storage has been deactivated. %sFind out why%s.' ) ); - $message->addParamHtml( + $GLOBALS['message']->addParamHtml( '<a href="' . Url::getFromRoute('/check-relations') - . '" data-post="' . Url::getCommon(['db' => $db]) . '">' + . '" data-post="' . Url::getCommon(['db' => $GLOBALS['db']]) . '">' ); - $message->addParamHtml('</a>'); + $GLOBALS['message']->addParamHtml('</a>'); /* Show error if user has configured something, notice elsewhere */ - if (! empty($cfg['Servers'][$server]['pmadb'])) { - $message->isError(true); + if (! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['pmadb'])) { + $GLOBALS['message']->isError(true); } } $this->render('database/operations/index', [ 'message' => $oldMessage, - 'db' => $db, + 'db' => $GLOBALS['db'], 'has_comment' => $relationParameters->columnCommentsFeature !== null, 'db_comment' => $databaseComment, - 'db_collation' => $db_collation, + 'db_collation' => $GLOBALS['db_collation'], 'has_adjust_privileges' => $hasAdjustPrivileges, 'is_drop_database_allowed' => $isDropDatabaseAllowed, 'switch_to_new' => $switchToNew, diff --git a/libraries/classes/Controllers/Database/PrivilegesController.php b/libraries/classes/Controllers/Database/PrivilegesController.php index 811dd43f52..ae0ff11d0a 100644 --- a/libraries/classes/Controllers/Database/PrivilegesController.php +++ b/libraries/classes/Controllers/Database/PrivilegesController.php @@ -7,13 +7,20 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\CheckUserPrivileges; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Privileges; use PhpMyAdmin\Template; use PhpMyAdmin\Util; +use function __; use function mb_strtolower; +use function ob_get_clean; +use function ob_start; /** * Controller for database privileges @@ -29,28 +36,70 @@ class PrivilegesController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Privileges $privileges, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->privileges = $privileges; $this->dbi = $dbi; } - /** - * @param string[] $params Request parameters - * @psalm-param array{checkprivsdb: string} $params - */ - public function __invoke(array $params): string + public function __invoke(ServerRequest $request): void { - global $cfg, $text_dir; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; - $scriptName = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); + $checkUserPrivileges = new CheckUserPrivileges($this->dbi); + $checkUserPrivileges->getPrivileges(); - $db = $params['checkprivsdb']; + $this->addScriptFiles(['server/privileges.js', 'vendor/zxcvbn-ts.js']); + + /** + * Checks if the user is allowed to do what they try to... + */ + $isGrantUser = $this->dbi->isGrantUser(); + $isCreateUser = $this->dbi->isCreateUser(); + + if (! $this->dbi->isSuperUser() && ! $isGrantUser && ! $isCreateUser) { + $this->render('server/sub_page_header', [ + 'type' => 'privileges', + 'is_image' => false, + ]); + $this->response->addHTML( + Message::error(__('No Privileges')) + ->getDisplay() + ); + + return; + } + + if (! $isGrantUser && ! $isCreateUser) { + $this->response->addHTML(Message::notice( + __('You do not have the privileges to administrate the users!') + )->getDisplay()); + } + + // Gets the database structure + $GLOBALS['sub_part'] = '_structure'; + ob_start(); + + [ + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part']); + + $content = ob_get_clean(); + $this->response->addHTML($content . "\n"); + + $scriptName = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + + $db = $GLOBALS['db']; if ($this->dbi->getLowerCaseNames() === '1') { - $db = mb_strtolower($params['checkprivsdb']); + $db = mb_strtolower($GLOBALS['db']); } $privileges = []; @@ -58,14 +107,15 @@ class PrivilegesController extends AbstractController $privileges = $this->privileges->getAllPrivileges($db); } - return $this->template->render('database/privileges/index', [ + $this->render('database/privileges/index', [ 'is_superuser' => $this->dbi->isSuperUser(), 'db' => $db, 'database_url' => $scriptName, - 'text_dir' => $text_dir, + 'text_dir' => $GLOBALS['text_dir'], 'is_createuser' => $this->dbi->isCreateUser(), 'is_grantuser' => $this->dbi->isGrantUser(), 'privileges' => $privileges, ]); + $this->render('export_modal'); } } diff --git a/libraries/classes/Controllers/Database/QueryByExampleController.php b/libraries/classes/Controllers/Database/QueryByExampleController.php index 54e1af6c33..3cb8996788 100644 --- a/libraries/classes/Controllers/Database/QueryByExampleController.php +++ b/libraries/classes/Controllers/Database/QueryByExampleController.php @@ -6,8 +6,10 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Qbe; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SavedSearches; @@ -30,81 +32,90 @@ class QueryByExampleController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->relation = $relation; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $savedSearchList, $savedSearch, $currentSearchId; - global $sql_query, $goto, $sub_part, $tables, $num_tables, $total_num_tables; - global $tooltip_truename, $tooltip_aliasname, $pos, $urlParams, $cfg, $errorUrl; + $GLOBALS['savedSearchList'] = $GLOBALS['savedSearchList'] ?? null; + $GLOBALS['savedSearch'] = $GLOBALS['savedSearch'] ?? null; + $GLOBALS['currentSearchId'] = $GLOBALS['currentSearchId'] ?? null; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $savedQbeSearchesFeature = $this->relation->getRelationParameters()->savedQueryByExampleSearchesFeature; - $savedSearchList = []; - $savedSearch = null; - $currentSearchId = null; + $GLOBALS['savedSearchList'] = []; + $GLOBALS['savedSearch'] = null; + $GLOBALS['currentSearchId'] = null; $this->addScriptFiles(['database/qbe.js']); if ($savedQbeSearchesFeature !== null) { //Get saved search list. - $savedSearch = new SavedSearches(); - $savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) - ->setDbname($db); + $GLOBALS['savedSearch'] = new SavedSearches(); + $GLOBALS['savedSearch']->setUsername($GLOBALS['cfg']['Server']['user']) + ->setDbname($GLOBALS['db']); if (! empty($_POST['searchId'])) { - $savedSearch->setId($_POST['searchId']); + $GLOBALS['savedSearch']->setId($_POST['searchId']); } //Action field is sent. if (isset($_POST['action'])) { - $savedSearch->setSearchName($_POST['searchName']); + $GLOBALS['savedSearch']->setSearchName($_POST['searchName']); if ($_POST['action'] === 'create') { - $savedSearch->setId(null) + $GLOBALS['savedSearch']->setId(null) ->setCriterias($_POST) ->save($savedQbeSearchesFeature); } elseif ($_POST['action'] === 'update') { - $savedSearch->setCriterias($_POST) + $GLOBALS['savedSearch']->setCriterias($_POST) ->save($savedQbeSearchesFeature); } elseif ($_POST['action'] === 'delete') { - $savedSearch->delete($savedQbeSearchesFeature); + $GLOBALS['savedSearch']->delete($savedQbeSearchesFeature); //After deletion, reset search. - $savedSearch = new SavedSearches(); - $savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) - ->setDbname($db); + $GLOBALS['savedSearch'] = new SavedSearches(); + $GLOBALS['savedSearch']->setUsername($GLOBALS['cfg']['Server']['user']) + ->setDbname($GLOBALS['db']); $_POST = []; } elseif ($_POST['action'] === 'load') { if (empty($_POST['searchId'])) { //when not loading a search, reset the object. - $savedSearch = new SavedSearches(); - $savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) - ->setDbname($db); + $GLOBALS['savedSearch'] = new SavedSearches(); + $GLOBALS['savedSearch']->setUsername($GLOBALS['cfg']['Server']['user']) + ->setDbname($GLOBALS['db']); $_POST = []; } else { - $savedSearch->load($savedQbeSearchesFeature); + $GLOBALS['savedSearch']->load($savedQbeSearchesFeature); } } //Else, it's an "update query" } - $savedSearchList = $savedSearch->getList($savedQbeSearchesFeature); - $currentSearchId = $savedSearch->getId(); + $GLOBALS['savedSearchList'] = $GLOBALS['savedSearch']->getList($savedQbeSearchesFeature); + $GLOBALS['currentSearchId'] = $GLOBALS['savedSearch']->getId(); } /** * A query has been submitted -> (maybe) execute it */ $hasMessageToDisplay = false; - if (isset($_POST['submit_sql']) && ! empty($sql_query)) { - if (stripos($sql_query, 'SELECT') !== 0) { + if (isset($_POST['submit_sql']) && ! empty($GLOBALS['sql_query'])) { + if (stripos($GLOBALS['sql_query'], 'SELECT') !== 0) { $hasMessageToDisplay = true; } else { - $goto = Url::getFromRoute('/database/sql'); + $GLOBALS['goto'] = Url::getFromRoute('/database/sql'); $sql = new Sql( $this->dbi, @@ -116,7 +127,7 @@ class QueryByExampleController extends AbstractController ); $this->response->addHTML($sql->executeQueryAndSendQueryResponse( - null, // analyzed_sql_results + null, false, // is_gotofile $_POST['db'], // db null, // table @@ -125,42 +136,49 @@ class QueryByExampleController extends AbstractController null, // extra_data null, // message_to_show null, // sql_data - $goto, // goto + $GLOBALS['goto'], // goto null, // disp_query null, // disp_message - $sql_query, // sql_query + $GLOBALS['sql_query'], // sql_query null // complete_query )); } } - $sub_part = '_qbe'; + $GLOBALS['sub_part'] = '_qbe'; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $urlParams['goto'] = Url::getFromRoute('/database/qbe'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/database/qbe'); [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part); - - $databaseQbe = new Qbe($this->relation, $this->template, $this->dbi, $db, $savedSearchList, $savedSearch); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part']); + + $databaseQbe = new Qbe( + $this->relation, + $this->template, + $this->dbi, + $GLOBALS['db'], + $GLOBALS['savedSearchList'], + $GLOBALS['savedSearch'] + ); $this->render('database/qbe/index', [ - 'url_params' => $urlParams, + 'url_params' => $GLOBALS['urlParams'], 'has_message_to_display' => $hasMessageToDisplay, 'selection_form_html' => $databaseQbe->getSelectionForm(), ]); diff --git a/libraries/classes/Controllers/Database/RoutinesController.php b/libraries/classes/Controllers/Database/RoutinesController.php index e3e435b574..e827e5a6f1 100644 --- a/libraries/classes/Controllers/Database/RoutinesController.php +++ b/libraries/classes/Controllers/Database/RoutinesController.php @@ -5,9 +5,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\CheckUserPrivileges; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Routines; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -30,20 +32,26 @@ class RoutinesController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, CheckUserPrivileges $checkUserPrivileges, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->checkUserPrivileges = $checkUserPrivileges; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos; - global $errors, $errorUrl, $urlParams, $cfg; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; $this->addScriptFiles(['database/routines.js']); @@ -55,45 +63,45 @@ class RoutinesController extends AbstractController /** * Displays the header and tabs */ - if (! empty($table) && in_array($table, $this->dbi->getTables($db))) { - Util::checkParameters(['db', 'table']); + if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } else { - $table = ''; + $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); } - } elseif (strlen($db) > 0) { - $this->dbi->selectDb($db); + } elseif (strlen($GLOBALS['db']) > 0) { + $this->dbi->selectDb($GLOBALS['db']); } /** * Keep a list of errors that occurred while * processing an 'Add' or 'Edit' operation. */ - $errors = []; + $GLOBALS['errors'] = []; $routines = new Routines($this->dbi, $this->template, $this->response); @@ -105,7 +113,7 @@ class RoutinesController extends AbstractController $type = null; } - $items = $this->dbi->getRoutines($db, $type); + $items = Routines::getDetails($this->dbi, $GLOBALS['db'], $type); $isAjax = $this->response->isAjax() && empty($_REQUEST['ajax_page_request']); $rows = ''; @@ -114,11 +122,11 @@ class RoutinesController extends AbstractController } $this->render('database/routines/index', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'items' => $items, 'rows' => $rows, - 'has_privilege' => Util::currentUserHasPrivilege('CREATE ROUTINE', $db, $table), + 'has_privilege' => Util::currentUserHasPrivilege('CREATE ROUTINE', $GLOBALS['db'], $GLOBALS['table']), ]); } } diff --git a/libraries/classes/Controllers/Database/SearchController.php b/libraries/classes/Controllers/Database/SearchController.php index c2c699239f..112f98dc73 100644 --- a/libraries/classes/Controllers/Database/SearchController.php +++ b/libraries/classes/Controllers/Database/SearchController.php @@ -4,9 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Search; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -19,54 +21,61 @@ class SearchController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $errorUrl, $urlParams, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; $this->addScriptFiles(['database/search.js', 'sql.js', 'makegrid.js']); - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } // If config variable $cfg['UseDbSearch'] is on false : exit. - if (! $cfg['UseDbSearch']) { + if (! $GLOBALS['cfg']['UseDbSearch']) { Generator::mysqlDie( __('Access denied!'), '', false, - $errorUrl + $GLOBALS['errorUrl'] ); } - $urlParams['goto'] = Url::getFromRoute('/database/search'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/database/search'); // Create a database search instance - $databaseSearch = new Search($this->dbi, $db, $this->template); + $databaseSearch = new Search($this->dbi, $GLOBALS['db'], $this->template); // Display top links if we are not in an Ajax request if (! $this->response->isAjax()) { [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); } // Main search form has been submitted, get results diff --git a/libraries/classes/Controllers/Database/SqlAutoCompleteController.php b/libraries/classes/Controllers/Database/SqlAutoCompleteController.php index 5407d169df..23cdf87cc5 100644 --- a/libraries/classes/Controllers/Database/SqlAutoCompleteController.php +++ b/libraries/classes/Controllers/Database/SqlAutoCompleteController.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; -use function json_encode; - /** * Table/Column autocomplete in SQL editors. */ @@ -18,28 +18,25 @@ class SqlAutoCompleteController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $sql_autocomplete; - - $sql_autocomplete = true; - if ($cfg['EnableAutocompleteForTablesAndColumns']) { - $db = $_POST['db'] ?? $db; - $sql_autocomplete = []; + $sqlAutocomplete = []; + if ($GLOBALS['cfg']['EnableAutocompleteForTablesAndColumns']) { + $db = $request->getParam('db', $GLOBALS['db']); if ($db) { $tableNames = $this->dbi->getTables($db); foreach ($tableNames as $tableName) { - $sql_autocomplete[$tableName] = $this->dbi->getColumns($db, $tableName); + $sqlAutocomplete[$tableName] = $this->dbi->getColumns($db, $tableName); } } } - $this->response->addJSON(['tables' => json_encode($sql_autocomplete)]); + $this->response->addJSON(['tables' => $sqlAutocomplete]); } } diff --git a/libraries/classes/Controllers/Database/SqlController.php b/libraries/classes/Controllers/Database/SqlController.php index b5d39b41e6..43f28085ed 100644 --- a/libraries/classes/Controllers/Database/SqlController.php +++ b/libraries/classes/Controllers/Database/SqlController.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; @@ -21,15 +23,17 @@ class SqlController extends AbstractController /** @var SqlQueryForm */ private $sqlQueryForm; - public function __construct(ResponseRenderer $response, Template $template, string $db, SqlQueryForm $sqlQueryForm) + public function __construct(ResponseRenderer $response, Template $template, SqlQueryForm $sqlQueryForm) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->sqlQueryForm = $sqlQueryForm; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $goto, $back, $db, $cfg, $errorUrl; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['back'] = $GLOBALS['back'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['makegrid.js', 'vendor/jquery/jquery.uitablefilter.js', 'sql.js']); @@ -37,10 +41,10 @@ class SqlController extends AbstractController $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; @@ -50,11 +54,11 @@ class SqlController extends AbstractController * After a syntax error, we return to this script * with the typed query in the textarea. */ - $goto = Url::getFromRoute('/database/sql'); - $back = $goto; + $GLOBALS['goto'] = Url::getFromRoute('/database/sql'); + $GLOBALS['back'] = $GLOBALS['goto']; $this->response->addHTML($this->sqlQueryForm->getHtml( - $db, + $GLOBALS['db'], '', true, false, diff --git a/libraries/classes/Controllers/Database/SqlFormatController.php b/libraries/classes/Controllers/Database/SqlFormatController.php index 218e8b6959..e468687e68 100644 --- a/libraries/classes/Controllers/Database/SqlFormatController.php +++ b/libraries/classes/Controllers/Database/SqlFormatController.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\SqlParser\Utils\Formatter; use function strlen; @@ -13,7 +15,7 @@ use function strlen; */ class SqlFormatController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $params = ['sql' => $_POST['sql'] ?? null]; $query = strlen((string) $params['sql']) > 0 ? $params['sql'] : ''; diff --git a/libraries/classes/Controllers/Database/Structure/AddPrefixController.php b/libraries/classes/Controllers/Database/Structure/AddPrefixController.php index 7a7cfadc29..4f10de7532 100644 --- a/libraries/classes/Controllers/Database/Structure/AddPrefixController.php +++ b/libraries/classes/Controllers/Database/Structure/AddPrefixController.php @@ -4,16 +4,15 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use function __; final class AddPrefixController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db; - $selected = $_POST['selected_tbl'] ?? []; if (empty($selected)) { @@ -23,7 +22,7 @@ final class AddPrefixController extends AbstractController return; } - $params = ['db' => $db]; + $params = ['db' => $GLOBALS['db']]; foreach ($selected as $selectedValue) { $params['selected'][] = $selectedValue; } diff --git a/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php b/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php index fb41a5a5e8..1a4136ee18 100644 --- a/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php +++ b/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -25,22 +26,21 @@ final class AddPrefixTableController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message, $sql_query; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected'] ?? []; - $sql_query = ''; + $GLOBALS['sql_query'] = ''; $selectedCount = count($selected); for ($i = 0; $i < $selectedCount; $i++) { @@ -48,17 +48,17 @@ final class AddPrefixTableController extends AbstractController $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i]) . ' RENAME ' . Util::backquote($newTableName); - $sql_query .= $aQuery . ';' . "\n"; - $this->dbi->selectDb($db); + $GLOBALS['sql_query'] .= $aQuery . ';' . "\n"; + $this->dbi->selectDb($GLOBALS['db']); $this->dbi->query($aQuery); } - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php index 9689b976f0..6437943513 100644 --- a/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php +++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php @@ -4,10 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\Database\CentralColumns; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -25,18 +26,17 @@ final class AddController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_tbl'] ?? []; @@ -50,10 +50,10 @@ final class AddController extends AbstractController $centralColumns = new CentralColumns($this->dbi); $error = $centralColumns->syncUniqueColumns($selected); - $message = $error instanceof Message ? $error : Message::success(__('Success!')); + $GLOBALS['message'] = $error instanceof Message ? $error : Message::success(__('Success!')); unset($_POST['submit_mult']); - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php index 24b3fc4e2e..253ba17036 100644 --- a/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php +++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php @@ -4,10 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\Database\CentralColumns; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -25,18 +26,17 @@ final class MakeConsistentController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_tbl'] ?? []; @@ -48,12 +48,12 @@ final class MakeConsistentController extends AbstractController } $centralColumns = new CentralColumns($this->dbi); - $error = $centralColumns->makeConsistentWithList($db, $selected); + $error = $centralColumns->makeConsistentWithList($GLOBALS['db'], $selected); - $message = $error instanceof Message ? $error : Message::success(__('Success!')); + $GLOBALS['message'] = $error instanceof Message ? $error : Message::success(__('Success!')); unset($_POST['submit_mult']); - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php index 8c79e0d3f3..e313dc970d 100644 --- a/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php +++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php @@ -4,10 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\Database\CentralColumns; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -25,18 +26,17 @@ final class RemoveController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_tbl'] ?? []; @@ -50,10 +50,10 @@ final class RemoveController extends AbstractController $centralColumns = new CentralColumns($this->dbi); $error = $centralColumns->deleteColumnsFromList($_POST['db'], $selected); - $message = $error instanceof Message ? $error : Message::success(__('Success!')); + $GLOBALS['message'] = $error instanceof Message ? $error : Message::success(__('Success!')); unset($_POST['submit_mult']); - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php b/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php index 6529585125..d25253b868 100644 --- a/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php +++ b/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php @@ -4,16 +4,15 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use function __; final class ChangePrefixFormController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db; - $selected = $_POST['selected_tbl'] ?? []; $submitMult = $_POST['submit_mult'] ?? ''; @@ -29,7 +28,7 @@ final class ChangePrefixFormController extends AbstractController $route = '/database/structure/copy-table-with-prefix'; } - $urlParams = ['db' => $db]; + $urlParams = ['db' => $GLOBALS['db']]; foreach ($selected as $selectedValue) { $urlParams['selected'][] = $selectedValue; } diff --git a/libraries/classes/Controllers/Database/Structure/CopyFormController.php b/libraries/classes/Controllers/Database/Structure/CopyFormController.php index 70ba831009..a85421f77d 100644 --- a/libraries/classes/Controllers/Database/Structure/CopyFormController.php +++ b/libraries/classes/Controllers/Database/Structure/CopyFormController.php @@ -4,15 +4,16 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use function __; final class CopyFormController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $dblist; + $GLOBALS['dblist'] = $GLOBALS['dblist'] ?? null; $selected = $_POST['selected_tbl'] ?? []; @@ -23,14 +24,14 @@ final class CopyFormController extends AbstractController return; } - $urlParams = ['db' => $db]; + $urlParams = ['db' => $GLOBALS['db']]; foreach ($selected as $selectedValue) { $urlParams['selected'][] = $selectedValue; } - $databasesList = $dblist->databases; + $databasesList = $GLOBALS['dblist']->databases; foreach ($databasesList as $key => $databaseName) { - if ($databaseName == $db) { + if ($databaseName == $GLOBALS['db']) { $databasesList->offsetUnset($key); break; } diff --git a/libraries/classes/Controllers/Database/Structure/CopyTableController.php b/libraries/classes/Controllers/Database/Structure/CopyTableController.php index be39fe3ab8..6844c70305 100644 --- a/libraries/classes/Controllers/Database/Structure/CopyTableController.php +++ b/libraries/classes/Controllers/Database/Structure/CopyTableController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -25,18 +26,17 @@ final class CopyTableController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Operations $operations, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->operations = $operations; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected'] ?? []; $targetDb = $_POST['target_db'] ?? null; @@ -44,7 +44,7 @@ final class CopyTableController extends AbstractController for ($i = 0; $i < $selectedCount; $i++) { Table::moveCopy( - $db, + $GLOBALS['db'], $selected[$i], $targetDb, $selected[$i], @@ -58,15 +58,15 @@ final class CopyTableController extends AbstractController continue; } - $this->operations->adjustPrivilegesCopyTable($db, $selected[$i], $targetDb, $selected[$i]); + $this->operations->adjustPrivilegesCopyTable($GLOBALS['db'], $selected[$i], $targetDb, $selected[$i]); } - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php b/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php index f835680367..e34e74b944 100644 --- a/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php +++ b/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table; @@ -23,16 +24,15 @@ final class CopyTableWithPrefixController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected'] ?? []; $fromPrefix = $_POST['from_prefix'] ?? null; @@ -45,9 +45,9 @@ final class CopyTableWithPrefixController extends AbstractController $newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix)); Table::moveCopy( - $db, + $GLOBALS['db'], $current, - $db, + $GLOBALS['db'], $newTableName, 'data', false, @@ -56,12 +56,12 @@ final class CopyTableWithPrefixController extends AbstractController ); } - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/DropFormController.php b/libraries/classes/Controllers/Database/Structure/DropFormController.php index 33740e4537..16fcc7171f 100644 --- a/libraries/classes/Controllers/Database/Structure/DropFormController.php +++ b/libraries/classes/Controllers/Database/Structure/DropFormController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Util; @@ -20,16 +21,14 @@ final class DropFormController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db; - $selected = $_POST['selected_tbl'] ?? []; if (empty($selected)) { @@ -39,7 +38,7 @@ final class DropFormController extends AbstractController return; } - $views = $this->dbi->getVirtualTables($db); + $views = $this->dbi->getVirtualTables($GLOBALS['db']); $fullQueryViews = ''; $fullQuery = ''; @@ -63,7 +62,7 @@ final class DropFormController extends AbstractController $fullQuery .= $fullQueryViews . ';<br>' . "\n"; } - $urlParams = ['db' => $db]; + $urlParams = ['db' => $GLOBALS['db']]; foreach ($selected as $selectedValue) { $urlParams['selected'][] = $selectedValue; } diff --git a/libraries/classes/Controllers/Database/Structure/DropTableController.php b/libraries/classes/Controllers/Database/Structure/DropTableController.php index b00bdc6ef8..591503ae91 100644 --- a/libraries/classes/Controllers/Database/Structure/DropTableController.php +++ b/libraries/classes/Controllers/Database/Structure/DropTableController.php @@ -5,9 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; use PhpMyAdmin\ConfigStorage\RelationCleanup; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -32,29 +33,28 @@ final class DropTableController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, RelationCleanup $relationCleanup, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->relationCleanup = $relationCleanup; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message, $reload, $sql_query; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; - $reload = $_POST['reload'] ?? $reload ?? null; + $GLOBALS['reload'] = $_POST['reload'] ?? $GLOBALS['reload'] ?? null; $multBtn = $_POST['mult_btn'] ?? ''; $selected = $_POST['selected'] ?? []; - $views = $this->dbi->getVirtualTables($db); + $views = $this->dbi->getVirtualTables($GLOBALS['db']); if ($multBtn !== __('Yes')) { - $message = Message::success(__('No change')); + $GLOBALS['message'] = Message::success(__('No change')); if (empty($_POST['message'])) { $_POST['message'] = Message::success(); @@ -62,33 +62,34 @@ final class DropTableController extends AbstractController unset($_POST['mult_btn']); - ($this->structureController)(); + ($this->structureController)($request); return; } $defaultFkCheckValue = ForeignKey::handleDisableCheckInit(); - $sql_query = ''; + $GLOBALS['sql_query'] = ''; $sqlQueryViews = ''; $selectedCount = count($selected); for ($i = 0; $i < $selectedCount; $i++) { - $this->relationCleanup->table($db, $selected[$i]); + $this->relationCleanup->table($GLOBALS['db'], $selected[$i]); $current = $selected[$i]; if (! empty($views) && in_array($current, $views)) { $sqlQueryViews .= (empty($sqlQueryViews) ? 'DROP VIEW ' : ', ') . Util::backquote($current); } else { - $sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') . Util::backquote($current); + $GLOBALS['sql_query'] .= (empty($GLOBALS['sql_query']) ? 'DROP TABLE ' : ', ') + . Util::backquote($current); } - $reload = 1; + $GLOBALS['reload'] = 1; } - if (! empty($sql_query)) { - $sql_query .= ';'; + if (! empty($GLOBALS['sql_query'])) { + $GLOBALS['sql_query'] .= ';'; } elseif (! empty($sqlQueryViews)) { - $sql_query = $sqlQueryViews . ';'; + $GLOBALS['sql_query'] = $sqlQueryViews . ';'; unset($sqlQueryViews); } @@ -103,29 +104,29 @@ final class DropTableController extends AbstractController } } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if ($result && ! empty($sqlQueryViews)) { - $sql_query .= ' ' . $sqlQueryViews . ';'; + $GLOBALS['sql_query'] .= ' ' . $sqlQueryViews . ';'; $result = $this->dbi->tryQuery($sqlQueryViews); unset($sqlQueryViews); } if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue); - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } unset($_POST['mult_btn']); - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/EmptyFormController.php b/libraries/classes/Controllers/Database/Structure/EmptyFormController.php index 556d64493b..1bee1f224f 100644 --- a/libraries/classes/Controllers/Database/Structure/EmptyFormController.php +++ b/libraries/classes/Controllers/Database/Structure/EmptyFormController.php @@ -4,7 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\ForeignKey; @@ -13,10 +14,8 @@ use function htmlspecialchars; final class EmptyFormController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db; - $selected = $_POST['selected_tbl'] ?? []; if (empty($selected)) { @@ -27,7 +26,7 @@ final class EmptyFormController extends AbstractController } $fullQuery = ''; - $urlParams = ['db' => $db]; + $urlParams = ['db' => $GLOBALS['db']]; foreach ($selected as $selectedValue) { $fullQuery .= 'TRUNCATE '; diff --git a/libraries/classes/Controllers/Database/Structure/EmptyTableController.php b/libraries/classes/Controllers/Database/Structure/EmptyTableController.php index 0e3309917d..0674cf963f 100644 --- a/libraries/classes/Controllers/Database/Structure/EmptyTableController.php +++ b/libraries/classes/Controllers/Database/Structure/EmptyTableController.php @@ -6,10 +6,11 @@ namespace PhpMyAdmin\Controllers\Database\Structure; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FlashMessages; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -45,7 +46,6 @@ final class EmptyTableController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, Relation $relation, RelationCleanup $relationCleanup, @@ -53,7 +53,7 @@ final class EmptyTableController extends AbstractController FlashMessages $flash, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->relation = $relation; $this->relationCleanup = $relationCleanup; @@ -62,31 +62,31 @@ final class EmptyTableController extends AbstractController $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $message, $sql_query; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $multBtn = $_POST['mult_btn'] ?? ''; $selected = $_POST['selected'] ?? []; if ($multBtn !== __('Yes')) { $this->flash->addMessage('success', __('No change')); - $this->redirect('/database/structure', ['db' => $db]); + $this->redirect('/database/structure', ['db' => $GLOBALS['db']]); return; } $defaultFkCheckValue = ForeignKey::handleDisableCheckInit(); - $sql_query = ''; + $GLOBALS['sql_query'] = ''; $selectedCount = count($selected); for ($i = 0; $i < $selectedCount; $i++) { $aQuery = 'TRUNCATE '; $aQuery .= Util::backquote($selected[$i]); - $sql_query .= $aQuery . ';' . "\n"; - $this->dbi->selectDb($db); + $GLOBALS['sql_query'] .= $aQuery . ';' . "\n"; + $this->dbi->selectDb($GLOBALS['db']); $this->dbi->query($aQuery); } @@ -100,19 +100,19 @@ final class EmptyTableController extends AbstractController $this->template ); - $_REQUEST['pos'] = $sql->calculatePosForLastPage($db, $table, $_REQUEST['pos']); + $_REQUEST['pos'] = $sql->calculatePosForLastPage($GLOBALS['db'], $GLOBALS['table'], $_REQUEST['pos']); } ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue); - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } unset($_POST['mult_btn']); - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php index 931ca61095..1b3acd6471 100644 --- a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php +++ b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -24,15 +25,15 @@ final class FavoriteTableController extends AbstractController /** @var Relation */ private $relation; - public function __construct(ResponseRenderer $response, Template $template, string $db, Relation $relation) + public function __construct(ResponseRenderer $response, Template $template, Relation $relation) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->relation = $relation; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $parameters = [ 'favorite_table' => $_REQUEST['favorite_table'] ?? null, @@ -40,10 +41,12 @@ final class FavoriteTableController extends AbstractController 'sync_favorite_tables' => $_REQUEST['sync_favorite_tables'] ?? null, ]; - Util::checkParameters(['db']); + if ($GLOBALS['db'] === '') { + return; + } - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase() || ! $this->response->isAjax()) { return; @@ -57,7 +60,7 @@ final class FavoriteTableController extends AbstractController } // Required to keep each user's preferences separate. - $user = sha1($cfg['Server']['user']); + $user = sha1($GLOBALS['cfg']['Server']['user']); // Request for Synchronization of favorite tables. if (isset($parameters['sync_favorite_tables'])) { @@ -80,17 +83,17 @@ final class FavoriteTableController extends AbstractController if (isset($_REQUEST['remove_favorite'])) { if ($alreadyFavorite) { // If already in favorite list, remove it. - $favoriteInstance->remove($this->db, $favoriteTable); + $favoriteInstance->remove($GLOBALS['db'], $favoriteTable); $alreadyFavorite = false; // for favorite_anchor template } } elseif (isset($_REQUEST['add_favorite'])) { if (! $alreadyFavorite) { $numTables = count($favoriteInstance->getTables()); - if ($numTables == $cfg['NumFavoriteTables']) { + if ($numTables == $GLOBALS['cfg']['NumFavoriteTables']) { $changes = false; } else { // Otherwise add to favorite list. - $favoriteInstance->add($this->db, $favoriteTable); + $favoriteInstance->add($GLOBALS['db'], $favoriteTable); $alreadyFavorite = true; // for favorite_anchor template } } @@ -111,7 +114,7 @@ final class FavoriteTableController extends AbstractController // Check if current table is already in favorite list. $favoriteParams = [ - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'ajax_request' => true, 'favorite_table' => $favoriteTable, ($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true, @@ -122,7 +125,7 @@ final class FavoriteTableController extends AbstractController $json['list'] = $favoriteInstance->getHtmlList(); $json['anchor'] = $this->template->render('database/structure/favorite_anchor', [ 'table_name_hash' => md5($favoriteTable), - 'db_table_name_hash' => md5($this->db . '.' . $favoriteTable), + 'db_table_name_hash' => md5($GLOBALS['db'] . '.' . $favoriteTable), 'fav_params' => $favoriteParams, 'already_favorite' => $alreadyFavorite, ]); @@ -174,7 +177,7 @@ final class FavoriteTableController extends AbstractController RecentFavoriteTable::getInstance('favorite'); $favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? []; foreach ($favoriteTables as $value) { - if ($value['db'] == $this->db && $value['table'] == $currentTable) { + if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) { return true; } } diff --git a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php index 05017ddeac..7b8364d36f 100644 --- a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php +++ b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -21,37 +22,37 @@ final class RealRowCountController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $parameters = [ 'real_row_count_all' => $_REQUEST['real_row_count_all'] ?? null, 'table' => $_REQUEST['table'] ?? null, ]; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase() || ! $this->response->isAjax()) { return; } - [$tables] = Util::getDbInfo($this->db, '_structure'); + [$tables] = Util::getDbInfo($GLOBALS['db'], '_structure'); // If there is a request to update all table's row count. if (! isset($parameters['real_row_count_all'])) { // Get the real row count for the table. $realRowCount = (int) $this->dbi - ->getTable($this->db, (string) $parameters['table']) + ->getTable($GLOBALS['db'], (string) $parameters['table']) ->getRealRowCountTable(); // Format the number. $realRowCount = Util::formatNumber($realRowCount, 0); @@ -66,7 +67,7 @@ final class RealRowCountController extends AbstractController // Iterate over each table and fetch real row count. foreach ($tables as $table) { $rowCount = $this->dbi - ->getTable($this->db, $table['TABLE_NAME']) + ->getTable($GLOBALS['db'], $table['TABLE_NAME']) ->getRealRowCountTable(); $realRowCountAll[] = [ 'table' => $table['TABLE_NAME'], diff --git a/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php b/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php index b3d7282e82..6ea8e1dcbc 100644 --- a/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php +++ b/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -27,24 +28,23 @@ final class ReplacePrefixController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message, $sql_query; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected'] ?? []; $fromPrefix = $_POST['from_prefix'] ?? ''; $toPrefix = $_POST['to_prefix'] ?? ''; - $sql_query = ''; + $GLOBALS['sql_query'] = ''; $selectedCount = count($selected); for ($i = 0; $i < $selectedCount; $i++) { @@ -60,17 +60,17 @@ final class ReplacePrefixController extends AbstractController $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i]) . ' RENAME ' . Util::backquote($newTableName); - $sql_query .= $aQuery . ';' . "\n"; - $this->dbi->selectDb($db); + $GLOBALS['sql_query'] .= $aQuery . ';' . "\n"; + $this->dbi->selectDb($GLOBALS['db']); $this->dbi->query($aQuery); } - $message = Message::success(); + $GLOBALS['message'] = Message::success(); if (empty($_POST['message'])) { - $_POST['message'] = $message; + $_POST['message'] = $GLOBALS['message']; } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Database/Structure/ShowCreateController.php b/libraries/classes/Controllers/Database/Structure/ShowCreateController.php index 77bc2863dd..22264aef88 100644 --- a/libraries/classes/Controllers/Database/Structure/ShowCreateController.php +++ b/libraries/classes/Controllers/Database/Structure/ShowCreateController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database\Structure; -use PhpMyAdmin\Controllers\Database\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -17,13 +18,13 @@ final class ShowCreateController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $selected = $_POST['selected_tbl'] ?? []; @@ -51,7 +52,7 @@ final class ShowCreateController extends AbstractController $tables = ['tables' => [], 'views' => []]; foreach ($selected as $table) { - $object = $this->dbi->getTable($this->db, $table); + $object = $this->dbi->getTable($GLOBALS['db'], $table); $tables[$object->isView() ? 'views' : 'tables'][] = [ 'name' => Core::mimeDefaultFunction($table), diff --git a/libraries/classes/Controllers/Database/StructureController.php b/libraries/classes/Controllers/Database/StructureController.php index 14d91e0ebd..34b62ac4b3 100644 --- a/libraries/classes/Controllers/Database/StructureController.php +++ b/libraries/classes/Controllers/Database/StructureController.php @@ -9,9 +9,11 @@ use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FlashMessages; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Operations; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\Replication; @@ -90,7 +92,6 @@ class StructureController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Relation $relation, Replication $replication, RelationCleanup $relationCleanup, @@ -98,7 +99,7 @@ class StructureController extends AbstractController DatabaseInterface $dbi, FlashMessages $flash ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->relation = $relation; $this->replication = $replication; $this->relationCleanup = $relationCleanup; @@ -123,7 +124,7 @@ class StructureController extends AbstractController $isShowStats, $dbIsSystemSchema,,, $position, - ] = Util::getDbInfo($this->db, $subPart); + ] = Util::getDbInfo($GLOBALS['db'], $subPart); $this->tables = $tables; $this->numTables = $numTables; @@ -133,19 +134,19 @@ class StructureController extends AbstractController $this->isShowStats = $isShowStats; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $parameters = [ 'sort' => $_REQUEST['sort'] ?? null, 'sort_order' => $_REQUEST['sort_order'] ?? null, ]; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; @@ -161,8 +162,8 @@ class StructureController extends AbstractController // having any. if ($this->totalNumTables > 0 && $this->position > $this->totalNumTables) { $this->redirect('/database/structure', [ - 'db' => $this->db, - 'pos' => max(0, $this->totalNumTables - $cfg['MaxTableList']), + 'db' => $GLOBALS['db'], + 'pos' => max(0, $this->totalNumTables - $GLOBALS['cfg']['MaxTableList']), 'reload' => 1, ]); } @@ -177,7 +178,7 @@ class StructureController extends AbstractController if ($this->numTables > 0) { $urlParams = [ 'pos' => $this->position, - 'db' => $this->db, + 'db' => $GLOBALS['db'], ]; if (isset($parameters['sort'])) { $urlParams['sort'] = $parameters['sort']; @@ -193,7 +194,7 @@ class StructureController extends AbstractController $urlParams, Url::getFromRoute('/database/structure'), 'frame_content', - $cfg['MaxTableList'] + $GLOBALS['cfg']['MaxTableList'] ); $tableList = $this->displayTableList($replicaInfo); @@ -204,11 +205,11 @@ class StructureController extends AbstractController $checkUserPrivileges = new CheckUserPrivileges($this->dbi); $checkUserPrivileges->getPrivileges(); - $createTable = $this->template->render('database/create_table', ['db' => $this->db]); + $createTable = $this->template->render('database/create_table', ['db' => $GLOBALS['db']]); } $this->render('database/structure/index', [ - 'database' => $this->db, + 'database' => $GLOBALS['db'], 'has_tables' => $this->numTables > 0, 'list_navigator_html' => $listNavigator ?? '', 'table_list_html' => $tableList ?? '', @@ -252,7 +253,7 @@ class StructureController extends AbstractController // Sets parameters for links $tableUrlParams = [ - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'table' => $currentTable['TABLE_NAME'], ]; // do not list the previous table's size info for a view @@ -269,7 +270,7 @@ class StructureController extends AbstractController ] = $this->getStuffForEngineTypeTable($currentTable, $sumSize, $overheadSize); $curTable = $this->dbi - ->getTable($this->db, $currentTable['TABLE_NAME']); + ->getTable($GLOBALS['db'], $currentTable['TABLE_NAME']); if (! $curTable->isMerge()) { $sumEntries += $currentTable['TABLE_ROWS']; } @@ -377,7 +378,7 @@ class StructureController extends AbstractController $rowCount = 1; $html .= $this->template->render('database/structure/table_header', [ - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'db_is_system_schema' => $this->dbIsSystemSchema, 'replication' => $replicaInfo['status'], 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], @@ -399,8 +400,8 @@ class StructureController extends AbstractController $structureTableRows[] = [ 'table_name_hash' => md5($currentTable['TABLE_NAME']), - 'db_table_name_hash' => md5($this->db . '.' . $currentTable['TABLE_NAME']), - 'db' => $this->db, + 'db_table_name_hash' => md5($GLOBALS['db'] . '.' . $currentTable['TABLE_NAME']), + 'db' => $GLOBALS['db'], 'curr' => $i, 'input_class' => implode(' ', $inputClass), 'table_is_view' => $tableIsView, @@ -458,7 +459,7 @@ class StructureController extends AbstractController $collation = Charsets::findCollationByName( $this->dbi, $GLOBALS['cfg']['Server']['DisableIS'], - $this->dbi->getDbCollation($this->db) + $this->dbi->getDbCollation($GLOBALS['db']) ); if ($collation !== null) { $databaseCollation = [ @@ -471,7 +472,7 @@ class StructureController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); return $html . $this->template->render('database/structure/table_header', [ - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'db_is_system_schema' => $this->dbIsSystemSchema, 'replication' => $replicaInfo['status'], 'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'], @@ -529,10 +530,10 @@ class StructureController extends AbstractController { $trackingIcon = ''; if (Tracker::isActive()) { - $isTracked = Tracker::isTracked($this->db, $table); - if ($isTracked || Tracker::getVersion($this->db, $table) > 0) { + $isTracked = Tracker::isTracked($GLOBALS['db'], $table); + if ($isTracked || Tracker::getVersion($GLOBALS['db'], $table) > 0) { $trackingIcon = $this->template->render('database/structure/tracking_icon', [ - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'table' => $table, 'is_tracked' => $isTracked, ]); @@ -605,14 +606,14 @@ class StructureController extends AbstractController $nbServReplicaDoDb = count($replicaInfo['Do_DB']); $nbServReplicaIgnoreDb = count($replicaInfo['Ignore_DB']); $searchDoDBInTruename = array_search($table, $replicaInfo['Do_DB']); - $searchDoDBInDB = array_search($this->db, $replicaInfo['Do_DB']); + $searchDoDBInDB = array_search($GLOBALS['db'], $replicaInfo['Do_DB']); $do = (is_string($searchDoDBInTruename) && strlen($searchDoDBInTruename) > 0) || (is_string($searchDoDBInDB) && strlen($searchDoDBInDB) > 0) || ($nbServReplicaDoDb == 0 && $nbServReplicaIgnoreDb == 0) || $this->hasTable($replicaInfo['Wild_Do_Table'], $table); - $searchDb = array_search($this->db, $replicaInfo['Ignore_DB']); + $searchDb = array_search($GLOBALS['db'], $replicaInfo['Ignore_DB']); $searchTable = array_search($table, $replicaInfo['Ignore_Table']); $ignored = (is_string($searchTable) && strlen($searchTable) > 0) || (is_string($searchDb) && strlen($searchDb) > 0) @@ -636,7 +637,7 @@ class StructureController extends AbstractController RecentFavoriteTable::getInstance('favorite'); $favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? []; foreach ($favoriteTables as $value) { - if ($value['db'] == $this->db && $value['table'] == $currentTable) { + if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) { return true; } } @@ -654,7 +655,7 @@ class StructureController extends AbstractController { foreach ($db as $dbTable) { if ( - $this->db == $this->replication->extractDbOrTable($dbTable) + $GLOBALS['db'] == $this->replication->extractDbOrTable($dbTable) && preg_match( '@^' . preg_quote(mb_substr($this->replication->extractDbOrTable($dbTable, 'table'), 0, -1), '@') . '@', @@ -771,7 +772,7 @@ class StructureController extends AbstractController if ($currentTable['TABLE_TYPE'] === 'VIEW' || $currentTable['TABLE_TYPE'] === 'SYSTEM VIEW') { // countRecords() takes care of $cfg['MaxExactCountViews'] $currentTable['TABLE_ROWS'] = $this->dbi - ->getTable($this->db, $currentTable['TABLE_NAME']) + ->getTable($GLOBALS['db'], $currentTable['TABLE_NAME']) ->countRecords(true); $tableIsView = true; } @@ -812,7 +813,7 @@ class StructureController extends AbstractController ) { if ($this->dbIsSystemSchema) { $currentTable['Rows'] = $this->dbi - ->getTable($this->db, $currentTable['Name']) + ->getTable($GLOBALS['db'], $currentTable['Name']) ->countRecords(); } @@ -864,7 +865,7 @@ class StructureController extends AbstractController ) { $currentTable['COUNTED'] = true; $currentTable['TABLE_ROWS'] = $this->dbi - ->getTable($this->db, $currentTable['TABLE_NAME']) + ->getTable($GLOBALS['db'], $currentTable['TABLE_NAME']) ->countRecords(true); } else { $currentTable['COUNTED'] = false; diff --git a/libraries/classes/Controllers/Database/TrackingController.php b/libraries/classes/Controllers/Database/TrackingController.php index d0aea100a9..0eedb36532 100644 --- a/libraries/classes/Controllers/Database/TrackingController.php +++ b/libraries/classes/Controllers/Database/TrackingController.php @@ -5,8 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\CheckUserPrivileges; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -34,56 +36,63 @@ class TrackingController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, Tracking $tracking, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->tracking = $tracking; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $text_dir, $urlParams, $tables, $num_tables; - global $total_num_tables, $sub_part, $pos, $data, $cfg; - global $tooltip_truename, $tooltip_aliasname, $errorUrl; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['data'] = $GLOBALS['data'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'database/tracking.js']); - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $urlParams['goto'] = Url::getFromRoute('/table/tracking'); - $urlParams['back'] = Url::getFromRoute('/database/tracking'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/tracking'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/database/tracking'); // Get the database structure - $sub_part = '_structure'; + $GLOBALS['sub_part'] = '_structure'; [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,, + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],, $isSystemSchema, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part); + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part']); if (isset($_POST['delete_tracking'], $_POST['table'])) { - Tracker::deleteTracking($db, $_POST['table']); + Tracker::deleteTracking($GLOBALS['db'], $_POST['table']); echo Message::success( __('Tracking data deleted successfully.') )->getDisplay(); } elseif (isset($_POST['submit_create_version'])) { - $this->tracking->createTrackingForMultipleTables($db, $_POST['selected']); + $this->tracking->createTrackingForMultipleTables($GLOBALS['db'], $_POST['selected']); echo Message::success( sprintf( __( @@ -96,7 +105,7 @@ class TrackingController extends AbstractController if (! empty($_POST['selected_tbl'])) { if ($_POST['submit_mult'] === 'delete_tracking') { foreach ($_POST['selected_tbl'] as $table) { - Tracker::deleteTracking($db, $table); + Tracker::deleteTracking($GLOBALS['db'], $table); } echo Message::success( @@ -105,12 +114,12 @@ class TrackingController extends AbstractController } elseif ($_POST['submit_mult'] === 'track') { echo $this->template->render('create_tracking_version', [ 'route' => '/database/tracking', - 'url_params' => $urlParams, + 'url_params' => $GLOBALS['urlParams'], 'last_version' => 0, - 'db' => $db, + 'db' => $GLOBALS['db'], 'selected' => $_POST['selected_tbl'], 'type' => 'both', - 'default_statements' => $cfg['Server']['tracking_default_statements'], + 'default_statements' => $GLOBALS['cfg']['Server']['tracking_default_statements'], ]); return; @@ -123,31 +132,31 @@ class TrackingController extends AbstractController } // Get tracked data about the database - $data = Tracker::getTrackedData($db, '', '1'); + $GLOBALS['data'] = Tracker::getTrackedData($GLOBALS['db'], '', '1'); // No tables present and no log exist - if ($num_tables == 0 && count($data['ddlog']) === 0) { + if ($GLOBALS['num_tables'] == 0 && count($GLOBALS['data']['ddlog']) === 0) { echo '<p>' , __('No tables found in database.') , '</p>' , "\n"; if (empty($isSystemSchema)) { $checkUserPrivileges = new CheckUserPrivileges($this->dbi); $checkUserPrivileges->getPrivileges(); - echo $this->template->render('database/create_table', ['db' => $db]); + echo $this->template->render('database/create_table', ['db' => $GLOBALS['db']]); } return; } - echo $this->tracking->getHtmlForDbTrackingTables($db, $urlParams, $text_dir); + echo $this->tracking->getHtmlForDbTrackingTables($GLOBALS['db'], $GLOBALS['urlParams'], $GLOBALS['text_dir']); // If available print out database log - if (count($data['ddlog']) <= 0) { + if (count($GLOBALS['data']['ddlog']) <= 0) { return; } $log = ''; - foreach ($data['ddlog'] as $entry) { + foreach ($GLOBALS['data']['ddlog'] as $entry) { $log .= '# ' . $entry['date'] . ' ' . $entry['username'] . "\n" . $entry['statement'] . "\n"; } diff --git a/libraries/classes/Controllers/Database/TriggersController.php b/libraries/classes/Controllers/Database/TriggersController.php index 5f330369ef..7c6bfa552b 100644 --- a/libraries/classes/Controllers/Database/TriggersController.php +++ b/libraries/classes/Controllers/Database/TriggersController.php @@ -4,9 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Database; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -23,17 +25,24 @@ class TriggersController extends AbstractController /** @var DatabaseInterface */ private $dbi; - public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi) + public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi) { - parent::__construct($response, $template, $db); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos; - global $errors, $urlParams, $errorUrl, $cfg; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['database/triggers.js']); @@ -41,45 +50,45 @@ class TriggersController extends AbstractController /** * Displays the header and tabs */ - if (! empty($table) && in_array($table, $this->dbi->getTables($db))) { - Util::checkParameters(['db', 'table']); + if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } else { - $table = ''; + $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); } - } elseif (strlen($db) > 0) { - $this->dbi->selectDb($db); + } elseif (strlen($GLOBALS['db']) > 0) { + $this->dbi->selectDb($GLOBALS['db']); } /** * Keep a list of errors that occurred while * processing an 'Add' or 'Edit' operation. */ - $errors = []; + $GLOBALS['errors'] = []; $triggers = new Triggers($this->dbi, $this->template, $this->response); $triggers->main(); diff --git a/libraries/classes/Controllers/DatabaseController.php b/libraries/classes/Controllers/DatabaseController.php index 573dfaa917..8cbf5524fb 100644 --- a/libraries/classes/Controllers/DatabaseController.php +++ b/libraries/classes/Controllers/DatabaseController.php @@ -4,12 +4,13 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; + final class DatabaseController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $dblist; - - $this->response->addJSON(['databases' => $dblist->databases]); + $GLOBALS['dblist'] = $GLOBALS['dblist'] ?? null; + $this->response->addJSON(['databases' => $GLOBALS['dblist']->databases]); } } diff --git a/libraries/classes/Controllers/ErrorReportController.php b/libraries/classes/Controllers/ErrorReportController.php index d263a840c2..5e4feac3ce 100644 --- a/libraries/classes/Controllers/ErrorReportController.php +++ b/libraries/classes/Controllers/ErrorReportController.php @@ -46,8 +46,6 @@ class ErrorReportController extends AbstractController public function __invoke(ServerRequest $request): void { - global $cfg; - /** @var string $exceptionType */ $exceptionType = $request->getParsedBodyParam('exception_type', ''); /** @var string|null $sendErrorReport */ @@ -101,7 +99,7 @@ class ErrorReportController extends AbstractController /* Message to show to the user */ if ($success) { - if ($automatic === 'true' || $cfg['SendErrorReports'] === 'always') { + if ($automatic === 'true' || $GLOBALS['cfg']['SendErrorReports'] === 'always') { $msg = __( 'An error has been detected and an error report has been ' . 'automatically submitted based on your settings.' @@ -137,7 +135,7 @@ class ErrorReportController extends AbstractController $jsCode = 'Functions.ajaxShowMessage(\'<div class="alert alert-danger" role="alert">' . $msg . '</div>\', false);'; - $this->response->getFooter()->getScripts()->addCode($jsCode); + $this->response->getFooterScripts()->addCode($jsCode); } if ($exceptionType === 'php') { @@ -152,7 +150,7 @@ class ErrorReportController extends AbstractController } } } elseif ($getSettings) { - $this->response->addJSON('report_setting', $cfg['SendErrorReports']); + $this->response->addJSON('report_setting', $GLOBALS['cfg']['SendErrorReports']); } elseif ($exceptionType === 'js') { $this->response->addJSON('report_modal', $this->errorReport->getEmptyModal()); $this->response->addHTML($this->errorReport->getForm()); diff --git a/libraries/classes/Controllers/Export/CheckTimeOutController.php b/libraries/classes/Controllers/Export/CheckTimeOutController.php index 10da315083..281fc3f0a9 100644 --- a/libraries/classes/Controllers/Export/CheckTimeOutController.php +++ b/libraries/classes/Controllers/Export/CheckTimeOutController.php @@ -5,10 +5,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Export; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; final class CheckTimeOutController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->response->setAjax(true); diff --git a/libraries/classes/Controllers/Export/ExportController.php b/libraries/classes/Controllers/Export/ExportController.php index 24f7a7f31e..aa18144568 100644 --- a/libraries/classes/Controllers/Export/ExportController.php +++ b/libraries/classes/Controllers/Export/ExportController.php @@ -13,7 +13,6 @@ use PhpMyAdmin\Export; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; -use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sanitize; use PhpMyAdmin\SqlParser\Parser; @@ -36,8 +35,6 @@ use function register_shutdown_function; use function strlen; use function time; -use const PHP_EOL; - final class ExportController extends AbstractController { /** @var Export */ @@ -51,14 +48,48 @@ final class ExportController extends AbstractController public function __invoke(ServerRequest $request): void { - global $containerBuilder, $db, $export_type, $filename_template, $sql_query, $errorUrl, $message; - global $compression, $crlf, $asfile, $buffer_needed, $save_on_server, $file_handle, $separate_files; - global $output_charset_conversion, $output_kanji_conversion, $table, $what, $export_plugin, $single_table; - global $compression_methods, $onserver, $back_button, $refreshButton, $save_filename, $filename; - global $quick_export, $cfg, $tables, $table_select, $aliases; - global $time_start, $charset, $remember_template, $mime_type, $num_tables; - global $active_page, $do_relation, $do_comments, $do_mime, $do_dates, $whatStrucOrData, $db_select; - global $table_structure, $table_data, $lock_tables, $allrows, $limit_to, $limit_from; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; + $GLOBALS['export_type'] = $GLOBALS['export_type'] ?? null; + $GLOBALS['filename_template'] = $GLOBALS['filename_template'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['compression'] = $GLOBALS['compression'] ?? null; + $GLOBALS['asfile'] = $GLOBALS['asfile'] ?? null; + $GLOBALS['buffer_needed'] = $GLOBALS['buffer_needed'] ?? null; + $GLOBALS['save_on_server'] = $GLOBALS['save_on_server'] ?? null; + $GLOBALS['file_handle'] = $GLOBALS['file_handle'] ?? null; + $GLOBALS['separate_files'] = $GLOBALS['separate_files'] ?? null; + $GLOBALS['output_charset_conversion'] = $GLOBALS['output_charset_conversion'] ?? null; + $GLOBALS['output_kanji_conversion'] = $GLOBALS['output_kanji_conversion'] ?? null; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; + $GLOBALS['export_plugin'] = $GLOBALS['export_plugin'] ?? null; + $GLOBALS['single_table'] = $GLOBALS['single_table'] ?? null; + $GLOBALS['compression_methods'] = $GLOBALS['compression_methods'] ?? null; + $GLOBALS['onserver'] = $GLOBALS['onserver'] ?? null; + $GLOBALS['save_filename'] = $GLOBALS['save_filename'] ?? null; + $GLOBALS['filename'] = $GLOBALS['filename'] ?? null; + $GLOBALS['quick_export'] = $GLOBALS['quick_export'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['table_select'] = $GLOBALS['table_select'] ?? null; + $GLOBALS['aliases'] = $GLOBALS['aliases'] ?? null; + $GLOBALS['time_start'] = $GLOBALS['time_start'] ?? null; + $GLOBALS['charset'] = $GLOBALS['charset'] ?? null; + $GLOBALS['remember_template'] = $GLOBALS['remember_template'] ?? null; + $GLOBALS['mime_type'] = $GLOBALS['mime_type'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['do_relation'] = $GLOBALS['do_relation'] ?? null; + $GLOBALS['do_comments'] = $GLOBALS['do_comments'] ?? null; + $GLOBALS['do_mime'] = $GLOBALS['do_mime'] ?? null; + $GLOBALS['do_dates'] = $GLOBALS['do_dates'] ?? null; + $GLOBALS['whatStrucOrData'] = $GLOBALS['whatStrucOrData'] ?? null; + $GLOBALS['db_select'] = $GLOBALS['db_select'] ?? null; + $GLOBALS['table_structure'] = $GLOBALS['table_structure'] ?? null; + $GLOBALS['table_data'] = $GLOBALS['table_data'] ?? null; + $GLOBALS['lock_tables'] = $GLOBALS['lock_tables'] ?? null; + $GLOBALS['allrows'] = $GLOBALS['allrows'] ?? null; + $GLOBALS['limit_to'] = $GLOBALS['limit_to'] ?? null; + $GLOBALS['limit_from'] = $GLOBALS['limit_from'] ?? null; /** @var array<string, string> $postParams */ $postParams = $request->getParsedBody(); @@ -84,217 +115,78 @@ final class ExportController extends AbstractController $this->addScriptFiles(['export_output.js']); - /** - * Sets globals from $_POST - * - * - Please keep the parameters in order of their appearance in the form - * - Some of these parameters are not used, as the code below directly - * verifies from the superglobal $_POST or $_REQUEST - * TODO: this should be removed to avoid passing user input to GLOBALS - * without checking - */ - $allowedPostParams = [ - 'db', - 'table', - 'what', - 'single_table', - 'export_type', - 'export_method', - 'quick_or_custom', - 'db_select', - 'table_select', - 'table_structure', - 'table_data', - 'limit_to', - 'limit_from', - 'allrows', - 'lock_tables', - 'output_format', - 'filename_template', - 'maxsize', - 'remember_template', - 'charset', - 'compression', - 'as_separate_files', - 'knjenc', - 'xkana', - 'htmlword_structure_or_data', - 'htmlword_null', - 'htmlword_columns', - 'mediawiki_headers', - 'mediawiki_structure_or_data', - 'mediawiki_caption', - 'pdf_structure_or_data', - 'odt_structure_or_data', - 'odt_relation', - 'odt_comments', - 'odt_mime', - 'odt_columns', - 'odt_null', - 'codegen_structure_or_data', - 'codegen_format', - 'excel_null', - 'excel_removeCRLF', - 'excel_columns', - 'excel_edition', - 'excel_structure_or_data', - 'yaml_structure_or_data', - 'ods_null', - 'ods_structure_or_data', - 'ods_columns', - 'json_structure_or_data', - 'json_pretty_print', - 'json_unicode', - 'xml_structure_or_data', - 'xml_export_events', - 'xml_export_functions', - 'xml_export_procedures', - 'xml_export_tables', - 'xml_export_triggers', - 'xml_export_views', - 'xml_export_contents', - 'texytext_structure_or_data', - 'texytext_columns', - 'texytext_null', - 'phparray_structure_or_data', - 'sql_include_comments', - 'sql_header_comment', - 'sql_dates', - 'sql_relation', - 'sql_mime', - 'sql_use_transaction', - 'sql_disable_fk', - 'sql_compatibility', - 'sql_structure_or_data', - 'sql_create_database', - 'sql_drop_table', - 'sql_procedure_function', - 'sql_create_table', - 'sql_create_view', - 'sql_create_trigger', - 'sql_view_current_user', - 'sql_simple_view_export', - 'sql_if_not_exists', - 'sql_or_replace_view', - 'sql_auto_increment', - 'sql_backquotes', - 'sql_truncate', - 'sql_delayed', - 'sql_ignore', - 'sql_type', - 'sql_insert_syntax', - 'sql_max_query_size', - 'sql_hex_for_binary', - 'sql_utc_time', - 'sql_drop_database', - 'sql_views_as_tables', - 'sql_metadata', - 'csv_separator', - 'csv_enclosed', - 'csv_escaped', - 'csv_terminated', - 'csv_null', - 'csv_removeCRLF', - 'csv_columns', - 'csv_structure_or_data', - // csv_replace should have been here but we use it directly from $_POST - 'latex_caption', - 'latex_structure_or_data', - 'latex_structure_caption', - 'latex_structure_continued_caption', - 'latex_structure_label', - 'latex_relation', - 'latex_comments', - 'latex_mime', - 'latex_columns', - 'latex_data_caption', - 'latex_data_continued_caption', - 'latex_data_label', - 'latex_null', - 'aliases', - ]; - - foreach ($allowedPostParams as $param) { - if (! isset($postParams[$param])) { - continue; - } - - $GLOBALS[$param] = $postParams[$param]; - } - - Util::checkParameters(['what', 'export_type']); + $this->setGlobalsFromRequest($postParams); // sanitize this parameter which will be used below in a file inclusion - $what = Core::securePath($whatParam); + $GLOBALS['what'] = Core::securePath($whatParam); + + $this->checkParameters(['what', 'export_type']); // export class instance, not array of properties, as before - /** @var ExportPlugin $export_plugin */ - $export_plugin = Plugins::getPlugin('export', $what, [ - 'export_type' => (string) $export_type, - 'single_table' => isset($single_table), + $GLOBALS['export_plugin'] = Plugins::getPlugin('export', $GLOBALS['what'], [ + 'export_type' => (string) $GLOBALS['export_type'], + 'single_table' => isset($GLOBALS['single_table']), ]); // Check export type - if (empty($export_plugin)) { + if (empty($GLOBALS['export_plugin'])) { Core::fatalError(__('Bad type!')); } /** * valid compression methods */ - $compression_methods = []; + $GLOBALS['compression_methods'] = []; if ($GLOBALS['cfg']['ZipDump'] && function_exists('gzcompress')) { - $compression_methods[] = 'zip'; + $GLOBALS['compression_methods'][] = 'zip'; } if ($GLOBALS['cfg']['GZipDump'] && function_exists('gzencode')) { - $compression_methods[] = 'gzip'; + $GLOBALS['compression_methods'][] = 'gzip'; } /** * init and variable checking */ - $compression = ''; - $onserver = false; - $save_on_server = false; - $buffer_needed = false; - $back_button = ''; - $refreshButton = ''; - $save_filename = ''; - $file_handle = ''; - $errorUrl = ''; - $filename = ''; - $separate_files = ''; + $GLOBALS['compression'] = ''; + $GLOBALS['onserver'] = false; + $GLOBALS['save_on_server'] = false; + $GLOBALS['buffer_needed'] = false; + $GLOBALS['save_filename'] = ''; + $GLOBALS['file_handle'] = ''; + $GLOBALS['errorUrl'] = ''; + $GLOBALS['filename'] = ''; + $GLOBALS['separate_files'] = ''; // Is it a quick or custom export? if ($quickOrCustom === 'quick') { - $quick_export = true; + $GLOBALS['quick_export'] = true; } else { - $quick_export = false; + $GLOBALS['quick_export'] = false; } if ($outputFormat === 'astext') { - $asfile = false; + $GLOBALS['asfile'] = false; } else { - $asfile = true; + $GLOBALS['asfile'] = true; if ($asSeparateFiles && $compressionParam === 'zip') { - $separate_files = $asSeparateFiles; + $GLOBALS['separate_files'] = $asSeparateFiles; } - if (in_array($compressionParam, $compression_methods)) { - $compression = $compressionParam; - $buffer_needed = true; + if (in_array($compressionParam, $GLOBALS['compression_methods'])) { + $GLOBALS['compression'] = $compressionParam; + $GLOBALS['buffer_needed'] = true; } - if (($quick_export && $quickExportOnServer) || (! $quick_export && $onServerParam)) { - if ($quick_export) { - $onserver = $quickExportOnServer; + if (($GLOBALS['quick_export'] && $quickExportOnServer) || (! $GLOBALS['quick_export'] && $onServerParam)) { + if ($GLOBALS['quick_export']) { + $GLOBALS['onserver'] = $quickExportOnServer; } else { - $onserver = $onServerParam; + $GLOBALS['onserver'] = $onServerParam; } // Will we save dump on server? - $save_on_server = ! empty($cfg['SaveDir']); + $GLOBALS['save_on_server'] = ! empty($GLOBALS['cfg']['SaveDir']); } } @@ -302,7 +194,7 @@ final class ExportController extends AbstractController * If we are sending the export file (as opposed to just displaying it * as text), we have to bypass the usual PhpMyAdmin\Response mechanism */ - if ($outputFormat === 'sendit' && ! $save_on_server) { + if ($outputFormat === 'sendit' && ! $GLOBALS['save_on_server']) { $this->response->disable(); //Disable all active buffers (see: ob_get_status(true) at this point) do { @@ -314,21 +206,21 @@ final class ExportController extends AbstractController } while ($hasBuffer); } - $tables = []; + $GLOBALS['tables'] = []; // Generate error url and check for needed variables - if ($export_type === 'server') { - $errorUrl = Url::getFromRoute('/server/export'); - } elseif ($export_type === 'database' && strlen($db) > 0) { - $errorUrl = Url::getFromRoute('/database/export', ['db' => $db]); + if ($GLOBALS['export_type'] === 'server') { + $GLOBALS['errorUrl'] = Url::getFromRoute('/server/export'); + } elseif ($GLOBALS['export_type'] === 'database' && strlen($GLOBALS['db']) > 0) { + $GLOBALS['errorUrl'] = Url::getFromRoute('/database/export', ['db' => $GLOBALS['db']]); // Check if we have something to export - $tables = $table_select ?? []; - } elseif ($export_type === 'table' && strlen($db) > 0 && strlen($table) > 0) { - $errorUrl = Url::getFromRoute('/table/export', [ - 'db' => $db, - 'table' => $table, + $GLOBALS['tables'] = $GLOBALS['table_select'] ?? []; + } elseif ($GLOBALS['export_type'] === 'table' && strlen($GLOBALS['db']) > 0 && strlen($GLOBALS['table']) > 0) { + $GLOBALS['errorUrl'] = Url::getFromRoute('/table/export', [ + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]); - } elseif ($export_type === 'raw') { - $errorUrl = Url::getFromRoute('/server/export', ['sql_query' => $sql_query]); + } elseif ($GLOBALS['export_type'] === 'raw') { + $GLOBALS['errorUrl'] = Url::getFromRoute('/server/export', ['sql_query' => $GLOBALS['sql_query']]); } else { Core::fatalError(__('Bad parameters!')); } @@ -336,14 +228,14 @@ final class ExportController extends AbstractController // Merge SQL Query aliases with Export aliases from // export page, Export page aliases are given more // preference over SQL Query aliases. - $parser = new Parser($sql_query); - $aliases = []; + $parser = new Parser($GLOBALS['sql_query']); + $GLOBALS['aliases'] = []; if (! empty($parser->statements[0]) && ($parser->statements[0] instanceof SelectStatement)) { - $aliases = Misc::getAliases($parser->statements[0], $db); + $GLOBALS['aliases'] = Misc::getAliases($parser->statements[0], $GLOBALS['db']); } if (! empty($aliasesParam)) { - $aliases = $this->export->mergeAliases($aliases, $aliasesParam); + $GLOBALS['aliases'] = $this->export->mergeAliases($GLOBALS['aliases'], $aliasesParam); $_SESSION['tmpval']['aliases'] = $aliasesParam; } @@ -351,8 +243,8 @@ final class ExportController extends AbstractController * Increase time limit for script execution and initializes some variables */ Util::setTimeLimit(); - if (! empty($cfg['MemoryLimit'])) { - ini_set('memory_limit', $cfg['MemoryLimit']); + if (! empty($GLOBALS['cfg']['MemoryLimit'])) { + ini_set('memory_limit', $GLOBALS['cfg']['MemoryLimit']); } register_shutdown_function([$this->export, 'shutdown']); @@ -364,59 +256,59 @@ final class ExportController extends AbstractController $this->export->dumpBufferObjects = []; // We send fake headers to avoid browser timeout when buffering - $time_start = time(); + $GLOBALS['time_start'] = time(); - // Defines the default <CR><LF> format. - // For SQL always use \n as MySQL wants this on all platforms. - if ($what === 'sql') { - $crlf = "\n"; - } else { - $crlf = PHP_EOL; - } - - $output_kanji_conversion = Encoding::canConvertKanji(); + $GLOBALS['output_kanji_conversion'] = Encoding::canConvertKanji(); // Do we need to convert charset? - $output_charset_conversion = $asfile + $GLOBALS['output_charset_conversion'] = $GLOBALS['asfile'] && Encoding::isSupported() - && isset($charset) && $charset !== 'utf-8'; + && isset($GLOBALS['charset']) && $GLOBALS['charset'] !== 'utf-8'; // Use on the fly compression? $GLOBALS['onfly_compression'] = $GLOBALS['cfg']['CompressOnFly'] - && $compression === 'gzip'; + && $GLOBALS['compression'] === 'gzip'; if ($GLOBALS['onfly_compression']) { $GLOBALS['memory_limit'] = $this->export->getMemoryLimit(); } // Generate filename and mime type if needed - if ($asfile) { - if (empty($remember_template)) { - $remember_template = ''; + if ($GLOBALS['asfile']) { + if (empty($GLOBALS['remember_template'])) { + $GLOBALS['remember_template'] = ''; } - [$filename, $mime_type] = $this->export->getFilenameAndMimetype( - $export_type, - $remember_template, - $export_plugin, - $compression, - $filename_template + [$GLOBALS['filename'], $GLOBALS['mime_type']] = $this->export->getFilenameAndMimetype( + $GLOBALS['export_type'], + $GLOBALS['remember_template'], + $GLOBALS['export_plugin'], + $GLOBALS['compression'], + $GLOBALS['filename_template'] ); } else { - $mime_type = ''; + $GLOBALS['mime_type'] = ''; } // For raw query export, filename will be export.extension - if ($export_type === 'raw') { - [$filename] = $this->export->getFinalFilenameAndMimetypeForFilename($export_plugin, $compression, 'export'); + if ($GLOBALS['export_type'] === 'raw') { + [$GLOBALS['filename']] = $this->export->getFinalFilenameAndMimetypeForFilename( + $GLOBALS['export_plugin'], + $GLOBALS['compression'], + 'export' + ); } // Open file on server if needed - if ($save_on_server) { - [$save_filename, $message, $file_handle] = $this->export->openFile($filename, $quick_export); + if ($GLOBALS['save_on_server']) { + [ + $GLOBALS['save_filename'], + $GLOBALS['message'], + $GLOBALS['file_handle'], + ] = $this->export->openFile($GLOBALS['filename'], $GLOBALS['quick_export']); // problem opening export file on server? - if (! empty($message)) { - $this->export->showPage($export_type); + if (! empty($GLOBALS['message'])) { + $this->export->showPage($GLOBALS['export_type']); return; } @@ -425,37 +317,35 @@ final class ExportController extends AbstractController * Send headers depending on whether the user chose to download a dump file * or not */ - if ($asfile) { + if ($GLOBALS['asfile']) { // Download // (avoid rewriting data containing HTML with anchors and forms; // this was reported to happen under Plesk) ini_set('url_rewriter.tags', ''); - $filename = Sanitize::sanitizeFilename($filename); + $GLOBALS['filename'] = Sanitize::sanitizeFilename($GLOBALS['filename']); - Core::downloadHeader($filename, $mime_type); + Core::downloadHeader($GLOBALS['filename'], $GLOBALS['mime_type']); } else { // HTML - if ($export_type === 'database') { - $num_tables = count($tables); - if ($num_tables === 0) { - $message = Message::error( + if ($GLOBALS['export_type'] === 'database') { + $GLOBALS['num_tables'] = count($GLOBALS['tables']); + if ($GLOBALS['num_tables'] === 0) { + $GLOBALS['message'] = Message::error( __('No tables found in database.') ); - $active_page = Url::getFromRoute('/database/export'); + $GLOBALS['active_page'] = Url::getFromRoute('/database/export'); /** @var DatabaseExportController $controller */ - $controller = $containerBuilder->get(DatabaseExportController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(DatabaseExportController::class); + $controller($request); exit; } } - [$html, $back_button, $refreshButton] = $this->export->getHtmlForDisplayedExportHeader( - $export_type, - $db, - $table + echo $this->export->getHtmlForDisplayedExportHeader( + $GLOBALS['export_type'], + $GLOBALS['db'], + $GLOBALS['table'] ); - echo $html; - unset($html); } } @@ -465,175 +355,176 @@ final class ExportController extends AbstractController $this->export->dumpBufferLength = 0; // Add possibly some comments to export - if (! $export_plugin->exportHeader()) { + if (! $GLOBALS['export_plugin']->exportHeader()) { throw new ExportException('Failure during header export.'); } // Will we need relation & co. setup? - $do_relation = isset($GLOBALS[$what . '_relation']); - $do_comments = isset($GLOBALS[$what . '_include_comments']) - || isset($GLOBALS[$what . '_comments']); - $do_mime = isset($GLOBALS[$what . '_mime']); + $GLOBALS['do_relation'] = isset($GLOBALS[$GLOBALS['what'] . '_relation']); + $GLOBALS['do_comments'] = isset($GLOBALS[$GLOBALS['what'] . '_include_comments']) + || isset($GLOBALS[$GLOBALS['what'] . '_comments']); + $GLOBALS['do_mime'] = isset($GLOBALS[$GLOBALS['what'] . '_mime']); // Include dates in export? - $do_dates = isset($GLOBALS[$what . '_dates']); + $GLOBALS['do_dates'] = isset($GLOBALS[$GLOBALS['what'] . '_dates']); - $whatStrucOrData = $GLOBALS[$what . '_structure_or_data']; + $GLOBALS['whatStrucOrData'] = $GLOBALS[$GLOBALS['what'] . '_structure_or_data']; - if ($export_type === 'raw') { - $whatStrucOrData = 'raw'; + if ($GLOBALS['export_type'] === 'raw') { + $GLOBALS['whatStrucOrData'] = 'raw'; } /** * Builds the dump */ - if ($export_type === 'server') { - if (! isset($db_select)) { - $db_select = ''; + if ($GLOBALS['export_type'] === 'server') { + if (! isset($GLOBALS['db_select'])) { + $GLOBALS['db_select'] = ''; } $this->export->exportServer( - $db_select, - $whatStrucOrData, - $export_plugin, - $crlf, - $errorUrl, - $export_type, - $do_relation, - $do_comments, - $do_mime, - $do_dates, - $aliases, - $separate_files + $GLOBALS['db_select'], + $GLOBALS['whatStrucOrData'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['export_type'], + $GLOBALS['do_relation'], + $GLOBALS['do_comments'], + $GLOBALS['do_mime'], + $GLOBALS['do_dates'], + $GLOBALS['aliases'], + $GLOBALS['separate_files'] ); - } elseif ($export_type === 'database') { - if (! isset($table_structure) || ! is_array($table_structure)) { - $table_structure = []; + } elseif ($GLOBALS['export_type'] === 'database') { + if (! isset($GLOBALS['table_structure']) || ! is_array($GLOBALS['table_structure'])) { + $GLOBALS['table_structure'] = []; } - if (! isset($table_data) || ! is_array($table_data)) { - $table_data = []; + if (! isset($GLOBALS['table_data']) || ! is_array($GLOBALS['table_data'])) { + $GLOBALS['table_data'] = []; } if ($structureOrDataForced) { - $table_structure = $tables; - $table_data = $tables; + $GLOBALS['table_structure'] = $GLOBALS['tables']; + $GLOBALS['table_data'] = $GLOBALS['tables']; } - if (isset($lock_tables)) { - $this->export->lockTables($db, $tables, 'READ'); + if (isset($GLOBALS['lock_tables'])) { + $this->export->lockTables($GLOBALS['db'], $GLOBALS['tables'], 'READ'); try { $this->export->exportDatabase( - $db, - $tables, - $whatStrucOrData, - $table_structure, - $table_data, - $export_plugin, - $crlf, - $errorUrl, - $export_type, - $do_relation, - $do_comments, - $do_mime, - $do_dates, - $aliases, - $separate_files + $GLOBALS['db'], + $GLOBALS['tables'], + $GLOBALS['whatStrucOrData'], + $GLOBALS['table_structure'], + $GLOBALS['table_data'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['export_type'], + $GLOBALS['do_relation'], + $GLOBALS['do_comments'], + $GLOBALS['do_mime'], + $GLOBALS['do_dates'], + $GLOBALS['aliases'], + $GLOBALS['separate_files'] ); } finally { $this->export->unlockTables(); } } else { $this->export->exportDatabase( - $db, - $tables, - $whatStrucOrData, - $table_structure, - $table_data, - $export_plugin, - $crlf, - $errorUrl, - $export_type, - $do_relation, - $do_comments, - $do_mime, - $do_dates, - $aliases, - $separate_files + $GLOBALS['db'], + $GLOBALS['tables'], + $GLOBALS['whatStrucOrData'], + $GLOBALS['table_structure'], + $GLOBALS['table_data'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['export_type'], + $GLOBALS['do_relation'], + $GLOBALS['do_comments'], + $GLOBALS['do_mime'], + $GLOBALS['do_dates'], + $GLOBALS['aliases'], + $GLOBALS['separate_files'] ); } - } elseif ($export_type === 'raw') { - Export::exportRaw($whatStrucOrData, $export_plugin, $crlf, $errorUrl, $sql_query, $export_type); + } elseif ($GLOBALS['export_type'] === 'raw') { + Export::exportRaw( + $GLOBALS['whatStrucOrData'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['sql_query'], + $GLOBALS['export_type'] + ); } else { // We export just one table // $allrows comes from the form when "Dump all rows" has been selected - if (! isset($allrows)) { - $allrows = ''; + if (! isset($GLOBALS['allrows'])) { + $GLOBALS['allrows'] = ''; } - if (! isset($limit_to)) { - $limit_to = '0'; + if (! isset($GLOBALS['limit_to'])) { + $GLOBALS['limit_to'] = '0'; } - if (! isset($limit_from)) { - $limit_from = '0'; + if (! isset($GLOBALS['limit_from'])) { + $GLOBALS['limit_from'] = '0'; } - if (isset($lock_tables)) { + if (isset($GLOBALS['lock_tables'])) { try { - $this->export->lockTables($db, [$table], 'READ'); + $this->export->lockTables($GLOBALS['db'], [$GLOBALS['table']], 'READ'); $this->export->exportTable( - $db, - $table, - $whatStrucOrData, - $export_plugin, - $crlf, - $errorUrl, - $export_type, - $do_relation, - $do_comments, - $do_mime, - $do_dates, - $allrows, - $limit_to, - $limit_from, - $sql_query, - $aliases + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['whatStrucOrData'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['export_type'], + $GLOBALS['do_relation'], + $GLOBALS['do_comments'], + $GLOBALS['do_mime'], + $GLOBALS['do_dates'], + $GLOBALS['allrows'], + $GLOBALS['limit_to'], + $GLOBALS['limit_from'], + $GLOBALS['sql_query'], + $GLOBALS['aliases'] ); } finally { $this->export->unlockTables(); } } else { $this->export->exportTable( - $db, - $table, - $whatStrucOrData, - $export_plugin, - $crlf, - $errorUrl, - $export_type, - $do_relation, - $do_comments, - $do_mime, - $do_dates, - $allrows, - $limit_to, - $limit_from, - $sql_query, - $aliases + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['whatStrucOrData'], + $GLOBALS['export_plugin'], + $GLOBALS['errorUrl'], + $GLOBALS['export_type'], + $GLOBALS['do_relation'], + $GLOBALS['do_comments'], + $GLOBALS['do_mime'], + $GLOBALS['do_dates'], + $GLOBALS['allrows'], + $GLOBALS['limit_to'], + $GLOBALS['limit_from'], + $GLOBALS['sql_query'], + $GLOBALS['aliases'] ); } } - if (! $export_plugin->exportFooter()) { + if (! $GLOBALS['export_plugin']->exportFooter()) { throw new ExportException('Failure during footer export.'); } } catch (ExportException $e) { // Ignore } - if ($save_on_server && ! empty($message)) { - $this->export->showPage($export_type); + if ($GLOBALS['save_on_server'] && ! empty($GLOBALS['message'])) { + $this->export->showPage($GLOBALS['export_type']); return; } @@ -641,14 +532,18 @@ final class ExportController extends AbstractController /** * Send the dump as a file... */ - if (empty($asfile)) { - echo $this->export->getHtmlForDisplayedExportFooter($back_button, $refreshButton); + if (empty($GLOBALS['asfile'])) { + echo $this->export->getHtmlForDisplayedExportFooter( + $GLOBALS['export_type'], + $GLOBALS['db'], + $GLOBALS['table'] + ); return; } // Convert the charset if required. - if ($output_charset_conversion) { + if ($GLOBALS['output_charset_conversion']) { $this->export->dumpBuffer = Encoding::convertString( 'utf-8', $GLOBALS['charset'], @@ -657,26 +552,501 @@ final class ExportController extends AbstractController } // Compression needed? - if ($compression) { - if (! empty($separate_files)) { + if ($GLOBALS['compression']) { + if (! empty($GLOBALS['separate_files'])) { $this->export->dumpBuffer = $this->export->compress( $this->export->dumpBufferObjects, - $compression, - $filename + $GLOBALS['compression'], + $GLOBALS['filename'] ); } else { - $this->export->dumpBuffer = $this->export->compress($this->export->dumpBuffer, $compression, $filename); + $this->export->dumpBuffer = $this->export->compress( + $this->export->dumpBuffer, + $GLOBALS['compression'], + $GLOBALS['filename'] + ); } } /* If we saved on server, we have to close file now */ - if ($save_on_server) { - $message = $this->export->closeFile($file_handle, $this->export->dumpBuffer, $save_filename); - $this->export->showPage($export_type); + if ($GLOBALS['save_on_server']) { + $GLOBALS['message'] = $this->export->closeFile( + $GLOBALS['file_handle'], + $this->export->dumpBuffer, + $GLOBALS['save_filename'] + ); + $this->export->showPage($GLOBALS['export_type']); return; } echo $this->export->dumpBuffer; } + + /** + * Please keep the parameters in order of their appearance in the form. + * Some of these parameters are not used. + * + * @param mixed[] $postParams + */ + private function setGlobalsFromRequest(array $postParams): void + { + if (isset($postParams['single_table'])) { + $GLOBALS['single_table'] = $postParams['single_table']; + } + + if (isset($postParams['export_type'])) { + $GLOBALS['export_type'] = $postParams['export_type']; + } + + if (isset($postParams['export_method'])) { + $GLOBALS['export_method'] = $postParams['export_method']; + } + + if (isset($postParams['quick_or_custom'])) { + $GLOBALS['quick_or_custom'] = $postParams['quick_or_custom']; + } + + if (isset($postParams['db_select'])) { + $GLOBALS['db_select'] = $postParams['db_select']; + } + + if (isset($postParams['table_select'])) { + $GLOBALS['table_select'] = $postParams['table_select']; + } + + if (isset($postParams['table_structure'])) { + $GLOBALS['table_structure'] = $postParams['table_structure']; + } + + if (isset($postParams['table_data'])) { + $GLOBALS['table_data'] = $postParams['table_data']; + } + + if (isset($postParams['limit_to'])) { + $GLOBALS['limit_to'] = $postParams['limit_to']; + } + + if (isset($postParams['limit_from'])) { + $GLOBALS['limit_from'] = $postParams['limit_from']; + } + + if (isset($postParams['allrows'])) { + $GLOBALS['allrows'] = $postParams['allrows']; + } + + if (isset($postParams['lock_tables'])) { + $GLOBALS['lock_tables'] = $postParams['lock_tables']; + } + + if (isset($postParams['output_format'])) { + $GLOBALS['output_format'] = $postParams['output_format']; + } + + if (isset($postParams['filename_template'])) { + $GLOBALS['filename_template'] = $postParams['filename_template']; + } + + if (isset($postParams['maxsize'])) { + $GLOBALS['maxsize'] = $postParams['maxsize']; + } + + if (isset($postParams['remember_template'])) { + $GLOBALS['remember_template'] = $postParams['remember_template']; + } + + if (isset($postParams['charset'])) { + $GLOBALS['charset'] = $postParams['charset']; + } + + if (isset($postParams['compression'])) { + $GLOBALS['compression'] = $postParams['compression']; + } + + if (isset($postParams['as_separate_files'])) { + $GLOBALS['as_separate_files'] = $postParams['as_separate_files']; + } + + if (isset($postParams['knjenc'])) { + $GLOBALS['knjenc'] = $postParams['knjenc']; + } + + if (isset($postParams['xkana'])) { + $GLOBALS['xkana'] = $postParams['xkana']; + } + + if (isset($postParams['htmlword_structure_or_data'])) { + $GLOBALS['htmlword_structure_or_data'] = $postParams['htmlword_structure_or_data']; + } + + if (isset($postParams['htmlword_null'])) { + $GLOBALS['htmlword_null'] = $postParams['htmlword_null']; + } + + if (isset($postParams['htmlword_columns'])) { + $GLOBALS['htmlword_columns'] = $postParams['htmlword_columns']; + } + + if (isset($postParams['mediawiki_headers'])) { + $GLOBALS['mediawiki_headers'] = $postParams['mediawiki_headers']; + } + + if (isset($postParams['mediawiki_structure_or_data'])) { + $GLOBALS['mediawiki_structure_or_data'] = $postParams['mediawiki_structure_or_data']; + } + + if (isset($postParams['mediawiki_caption'])) { + $GLOBALS['mediawiki_caption'] = $postParams['mediawiki_caption']; + } + + if (isset($postParams['pdf_structure_or_data'])) { + $GLOBALS['pdf_structure_or_data'] = $postParams['pdf_structure_or_data']; + } + + if (isset($postParams['odt_structure_or_data'])) { + $GLOBALS['odt_structure_or_data'] = $postParams['odt_structure_or_data']; + } + + if (isset($postParams['odt_relation'])) { + $GLOBALS['odt_relation'] = $postParams['odt_relation']; + } + + if (isset($postParams['odt_comments'])) { + $GLOBALS['odt_comments'] = $postParams['odt_comments']; + } + + if (isset($postParams['odt_mime'])) { + $GLOBALS['odt_mime'] = $postParams['odt_mime']; + } + + if (isset($postParams['odt_columns'])) { + $GLOBALS['odt_columns'] = $postParams['odt_columns']; + } + + if (isset($postParams['odt_null'])) { + $GLOBALS['odt_null'] = $postParams['odt_null']; + } + + if (isset($postParams['codegen_structure_or_data'])) { + $GLOBALS['codegen_structure_or_data'] = $postParams['codegen_structure_or_data']; + } + + if (isset($postParams['codegen_format'])) { + $GLOBALS['codegen_format'] = $postParams['codegen_format']; + } + + if (isset($postParams['excel_null'])) { + $GLOBALS['excel_null'] = $postParams['excel_null']; + } + + if (isset($postParams['excel_removeCRLF'])) { + $GLOBALS['excel_removeCRLF'] = $postParams['excel_removeCRLF']; + } + + if (isset($postParams['excel_columns'])) { + $GLOBALS['excel_columns'] = $postParams['excel_columns']; + } + + if (isset($postParams['excel_edition'])) { + $GLOBALS['excel_edition'] = $postParams['excel_edition']; + } + + if (isset($postParams['excel_structure_or_data'])) { + $GLOBALS['excel_structure_or_data'] = $postParams['excel_structure_or_data']; + } + + if (isset($postParams['yaml_structure_or_data'])) { + $GLOBALS['yaml_structure_or_data'] = $postParams['yaml_structure_or_data']; + } + + if (isset($postParams['ods_null'])) { + $GLOBALS['ods_null'] = $postParams['ods_null']; + } + + if (isset($postParams['ods_structure_or_data'])) { + $GLOBALS['ods_structure_or_data'] = $postParams['ods_structure_or_data']; + } + + if (isset($postParams['ods_columns'])) { + $GLOBALS['ods_columns'] = $postParams['ods_columns']; + } + + if (isset($postParams['json_structure_or_data'])) { + $GLOBALS['json_structure_or_data'] = $postParams['json_structure_or_data']; + } + + if (isset($postParams['json_pretty_print'])) { + $GLOBALS['json_pretty_print'] = $postParams['json_pretty_print']; + } + + if (isset($postParams['json_unicode'])) { + $GLOBALS['json_unicode'] = $postParams['json_unicode']; + } + + if (isset($postParams['xml_structure_or_data'])) { + $GLOBALS['xml_structure_or_data'] = $postParams['xml_structure_or_data']; + } + + if (isset($postParams['xml_export_events'])) { + $GLOBALS['xml_export_events'] = $postParams['xml_export_events']; + } + + if (isset($postParams['xml_export_functions'])) { + $GLOBALS['xml_export_functions'] = $postParams['xml_export_functions']; + } + + if (isset($postParams['xml_export_procedures'])) { + $GLOBALS['xml_export_procedures'] = $postParams['xml_export_procedures']; + } + + if (isset($postParams['xml_export_tables'])) { + $GLOBALS['xml_export_tables'] = $postParams['xml_export_tables']; + } + + if (isset($postParams['xml_export_triggers'])) { + $GLOBALS['xml_export_triggers'] = $postParams['xml_export_triggers']; + } + + if (isset($postParams['xml_export_views'])) { + $GLOBALS['xml_export_views'] = $postParams['xml_export_views']; + } + + if (isset($postParams['xml_export_contents'])) { + $GLOBALS['xml_export_contents'] = $postParams['xml_export_contents']; + } + + if (isset($postParams['texytext_structure_or_data'])) { + $GLOBALS['texytext_structure_or_data'] = $postParams['texytext_structure_or_data']; + } + + if (isset($postParams['texytext_columns'])) { + $GLOBALS['texytext_columns'] = $postParams['texytext_columns']; + } + + if (isset($postParams['texytext_null'])) { + $GLOBALS['texytext_null'] = $postParams['texytext_null']; + } + + if (isset($postParams['phparray_structure_or_data'])) { + $GLOBALS['phparray_structure_or_data'] = $postParams['phparray_structure_or_data']; + } + + if (isset($postParams['sql_include_comments'])) { + $GLOBALS['sql_include_comments'] = $postParams['sql_include_comments']; + } + + if (isset($postParams['sql_header_comment'])) { + $GLOBALS['sql_header_comment'] = $postParams['sql_header_comment']; + } + + if (isset($postParams['sql_dates'])) { + $GLOBALS['sql_dates'] = $postParams['sql_dates']; + } + + if (isset($postParams['sql_relation'])) { + $GLOBALS['sql_relation'] = $postParams['sql_relation']; + } + + if (isset($postParams['sql_mime'])) { + $GLOBALS['sql_mime'] = $postParams['sql_mime']; + } + + if (isset($postParams['sql_use_transaction'])) { + $GLOBALS['sql_use_transaction'] = $postParams['sql_use_transaction']; + } + + if (isset($postParams['sql_disable_fk'])) { + $GLOBALS['sql_disable_fk'] = $postParams['sql_disable_fk']; + } + + if (isset($postParams['sql_compatibility'])) { + $GLOBALS['sql_compatibility'] = $postParams['sql_compatibility']; + } + + if (isset($postParams['sql_structure_or_data'])) { + $GLOBALS['sql_structure_or_data'] = $postParams['sql_structure_or_data']; + } + + if (isset($postParams['sql_create_database'])) { + $GLOBALS['sql_create_database'] = $postParams['sql_create_database']; + } + + if (isset($postParams['sql_drop_table'])) { + $GLOBALS['sql_drop_table'] = $postParams['sql_drop_table']; + } + + if (isset($postParams['sql_procedure_function'])) { + $GLOBALS['sql_procedure_function'] = $postParams['sql_procedure_function']; + } + + if (isset($postParams['sql_create_table'])) { + $GLOBALS['sql_create_table'] = $postParams['sql_create_table']; + } + + if (isset($postParams['sql_create_view'])) { + $GLOBALS['sql_create_view'] = $postParams['sql_create_view']; + } + + if (isset($postParams['sql_create_trigger'])) { + $GLOBALS['sql_create_trigger'] = $postParams['sql_create_trigger']; + } + + if (isset($postParams['sql_view_current_user'])) { + $GLOBALS['sql_view_current_user'] = $postParams['sql_view_current_user']; + } + + if (isset($postParams['sql_simple_view_export'])) { + $GLOBALS['sql_simple_view_export'] = $postParams['sql_simple_view_export']; + } + + if (isset($postParams['sql_if_not_exists'])) { + $GLOBALS['sql_if_not_exists'] = $postParams['sql_if_not_exists']; + } + + if (isset($postParams['sql_or_replace_view'])) { + $GLOBALS['sql_or_replace_view'] = $postParams['sql_or_replace_view']; + } + + if (isset($postParams['sql_auto_increment'])) { + $GLOBALS['sql_auto_increment'] = $postParams['sql_auto_increment']; + } + + if (isset($postParams['sql_backquotes'])) { + $GLOBALS['sql_backquotes'] = $postParams['sql_backquotes']; + } + + if (isset($postParams['sql_truncate'])) { + $GLOBALS['sql_truncate'] = $postParams['sql_truncate']; + } + + if (isset($postParams['sql_delayed'])) { + $GLOBALS['sql_delayed'] = $postParams['sql_delayed']; + } + + if (isset($postParams['sql_ignore'])) { + $GLOBALS['sql_ignore'] = $postParams['sql_ignore']; + } + + if (isset($postParams['sql_type'])) { + $GLOBALS['sql_type'] = $postParams['sql_type']; + } + + if (isset($postParams['sql_insert_syntax'])) { + $GLOBALS['sql_insert_syntax'] = $postParams['sql_insert_syntax']; + } + + if (isset($postParams['sql_max_query_size'])) { + $GLOBALS['sql_max_query_size'] = $postParams['sql_max_query_size']; + } + + if (isset($postParams['sql_hex_for_binary'])) { + $GLOBALS['sql_hex_for_binary'] = $postParams['sql_hex_for_binary']; + } + + if (isset($postParams['sql_utc_time'])) { + $GLOBALS['sql_utc_time'] = $postParams['sql_utc_time']; + } + + if (isset($postParams['sql_drop_database'])) { + $GLOBALS['sql_drop_database'] = $postParams['sql_drop_database']; + } + + if (isset($postParams['sql_views_as_tables'])) { + $GLOBALS['sql_views_as_tables'] = $postParams['sql_views_as_tables']; + } + + if (isset($postParams['sql_metadata'])) { + $GLOBALS['sql_metadata'] = $postParams['sql_metadata']; + } + + if (isset($postParams['csv_separator'])) { + $GLOBALS['csv_separator'] = $postParams['csv_separator']; + } + + if (isset($postParams['csv_enclosed'])) { + $GLOBALS['csv_enclosed'] = $postParams['csv_enclosed']; + } + + if (isset($postParams['csv_escaped'])) { + $GLOBALS['csv_escaped'] = $postParams['csv_escaped']; + } + + if (isset($postParams['csv_terminated'])) { + $GLOBALS['csv_terminated'] = $postParams['csv_terminated']; + } + + if (isset($postParams['csv_null'])) { + $GLOBALS['csv_null'] = $postParams['csv_null']; + } + + if (isset($postParams['csv_removeCRLF'])) { + $GLOBALS['csv_removeCRLF'] = $postParams['csv_removeCRLF']; + } + + if (isset($postParams['csv_columns'])) { + $GLOBALS['csv_columns'] = $postParams['csv_columns']; + } + + if (isset($postParams['csv_structure_or_data'])) { + $GLOBALS['csv_structure_or_data'] = $postParams['csv_structure_or_data']; + } + + if (isset($postParams['latex_caption'])) { + $GLOBALS['latex_caption'] = $postParams['latex_caption']; + } + + if (isset($postParams['latex_structure_or_data'])) { + $GLOBALS['latex_structure_or_data'] = $postParams['latex_structure_or_data']; + } + + if (isset($postParams['latex_structure_caption'])) { + $GLOBALS['latex_structure_caption'] = $postParams['latex_structure_caption']; + } + + if (isset($postParams['latex_structure_continued_caption'])) { + $GLOBALS['latex_structure_continued_caption'] = $postParams['latex_structure_continued_caption']; + } + + if (isset($postParams['latex_structure_label'])) { + $GLOBALS['latex_structure_label'] = $postParams['latex_structure_label']; + } + + if (isset($postParams['latex_relation'])) { + $GLOBALS['latex_relation'] = $postParams['latex_relation']; + } + + if (isset($postParams['latex_comments'])) { + $GLOBALS['latex_comments'] = $postParams['latex_comments']; + } + + if (isset($postParams['latex_mime'])) { + $GLOBALS['latex_mime'] = $postParams['latex_mime']; + } + + if (isset($postParams['latex_columns'])) { + $GLOBALS['latex_columns'] = $postParams['latex_columns']; + } + + if (isset($postParams['latex_data_caption'])) { + $GLOBALS['latex_data_caption'] = $postParams['latex_data_caption']; + } + + if (isset($postParams['latex_data_continued_caption'])) { + $GLOBALS['latex_data_continued_caption'] = $postParams['latex_data_continued_caption']; + } + + if (isset($postParams['latex_data_label'])) { + $GLOBALS['latex_data_label'] = $postParams['latex_data_label']; + } + + if (isset($postParams['latex_null'])) { + $GLOBALS['latex_null'] = $postParams['latex_null']; + } + + if (! isset($postParams['aliases'])) { + return; + } + + $GLOBALS['aliases'] = $postParams['aliases']; + } } diff --git a/libraries/classes/Controllers/Export/TablesController.php b/libraries/classes/Controllers/Export/TablesController.php index 73d56b3179..eae20fc098 100644 --- a/libraries/classes/Controllers/Export/TablesController.php +++ b/libraries/classes/Controllers/Export/TablesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Export; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\ExportController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -22,7 +23,7 @@ final class TablesController extends AbstractController $this->exportController = $exportController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (empty($_POST['selected_tbl'])) { $this->response->setRequestStatus(false); @@ -31,6 +32,6 @@ final class TablesController extends AbstractController return; } - ($this->exportController)(); + ($this->exportController)($request); } } diff --git a/libraries/classes/Controllers/Export/Template/CreateController.php b/libraries/classes/Controllers/Export/Template/CreateController.php index 91abb1beca..932aa351c5 100644 --- a/libraries/classes/Controllers/Export/Template/CreateController.php +++ b/libraries/classes/Controllers/Export/Template/CreateController.php @@ -35,8 +35,6 @@ final class CreateController extends AbstractController public function __invoke(ServerRequest $request): void { - global $cfg; - /** @var string $exportType */ $exportType = $request->getParsedBodyParam('exportType', ''); /** @var string $templateName */ @@ -52,7 +50,7 @@ final class CreateController extends AbstractController } $template = ExportTemplate::fromArray([ - 'username' => $cfg['Server']['user'], + 'username' => $GLOBALS['cfg']['Server']['user'], 'exportType' => $exportType, 'name' => $templateName, 'data' => $templateData, diff --git a/libraries/classes/Controllers/Export/Template/DeleteController.php b/libraries/classes/Controllers/Export/Template/DeleteController.php index f83c7960b3..29a7628e86 100644 --- a/libraries/classes/Controllers/Export/Template/DeleteController.php +++ b/libraries/classes/Controllers/Export/Template/DeleteController.php @@ -32,8 +32,6 @@ final class DeleteController extends AbstractController public function __invoke(ServerRequest $request): void { - global $cfg; - $templateId = (int) $request->getParsedBodyParam('templateId'); $exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature; @@ -44,7 +42,7 @@ final class DeleteController extends AbstractController $result = $this->model->delete( $exportTemplatesFeature->database, $exportTemplatesFeature->exportTemplates, - $cfg['Server']['user'], + $GLOBALS['cfg']['Server']['user'], $templateId ); diff --git a/libraries/classes/Controllers/Export/Template/LoadController.php b/libraries/classes/Controllers/Export/Template/LoadController.php index 56a8e649ac..03bd33503c 100644 --- a/libraries/classes/Controllers/Export/Template/LoadController.php +++ b/libraries/classes/Controllers/Export/Template/LoadController.php @@ -33,8 +33,6 @@ final class LoadController extends AbstractController public function __invoke(ServerRequest $request): void { - global $cfg; - $templateId = (int) $request->getParsedBodyParam('templateId'); $exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature; @@ -45,7 +43,7 @@ final class LoadController extends AbstractController $template = $this->model->load( $exportTemplatesFeature->database, $exportTemplatesFeature->exportTemplates, - $cfg['Server']['user'], + $GLOBALS['cfg']['Server']['user'], $templateId ); diff --git a/libraries/classes/Controllers/Export/Template/UpdateController.php b/libraries/classes/Controllers/Export/Template/UpdateController.php index 09d7981ad7..eb407c47af 100644 --- a/libraries/classes/Controllers/Export/Template/UpdateController.php +++ b/libraries/classes/Controllers/Export/Template/UpdateController.php @@ -33,8 +33,6 @@ final class UpdateController extends AbstractController public function __invoke(ServerRequest $request): void { - global $cfg; - $templateId = (int) $request->getParsedBodyParam('templateId'); /** @var string $templateData */ $templateData = $request->getParsedBodyParam('templateData', ''); @@ -46,7 +44,7 @@ final class UpdateController extends AbstractController $template = ExportTemplate::fromArray([ 'id' => $templateId, - 'username' => $cfg['Server']['user'], + 'username' => $GLOBALS['cfg']['Server']['user'], 'data' => $templateData, ]); $result = $this->model->update( diff --git a/libraries/classes/Controllers/GisDataEditorController.php b/libraries/classes/Controllers/GisDataEditorController.php index 565e012ece..b538d3effd 100644 --- a/libraries/classes/Controllers/GisDataEditorController.php +++ b/libraries/classes/Controllers/GisDataEditorController.php @@ -28,8 +28,20 @@ class GisDataEditorController extends AbstractController { public function __invoke(ServerRequest $request): void { - global $gis_data, $gis_types, $start, $geom_type, $gis_obj, $srid, $wkt, $wkt_with_zero; - global $result, $visualizationSettings, $data, $visualization, $open_layers, $geom_count, $dbi; + $GLOBALS['gis_data'] = $GLOBALS['gis_data'] ?? null; + $GLOBALS['gis_types'] = $GLOBALS['gis_types'] ?? null; + $GLOBALS['start'] = $GLOBALS['start'] ?? null; + $GLOBALS['geom_type'] = $GLOBALS['geom_type'] ?? null; + $GLOBALS['gis_obj'] = $GLOBALS['gis_obj'] ?? null; + $GLOBALS['srid'] = $GLOBALS['srid'] ?? null; + $GLOBALS['wkt'] = $GLOBALS['wkt'] ?? null; + $GLOBALS['wkt_with_zero'] = $GLOBALS['wkt_with_zero'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + $GLOBALS['visualizationSettings'] = $GLOBALS['visualizationSettings'] ?? null; + $GLOBALS['data'] = $GLOBALS['data'] ?? null; + $GLOBALS['visualization'] = $GLOBALS['visualization'] ?? null; + $GLOBALS['open_layers'] = $GLOBALS['open_layers'] ?? null; + $GLOBALS['geom_count'] = $GLOBALS['geom_count'] ?? null; /** @var string|null $field */ $field = $request->getParsedBodyParam('field'); @@ -49,12 +61,12 @@ class GisDataEditorController extends AbstractController } // Get data if any posted - $gis_data = []; + $GLOBALS['gis_data'] = []; if (is_array($gisDataParam)) { - $gis_data = $gisDataParam; + $GLOBALS['gis_data'] = $gisDataParam; } - $gis_types = [ + $GLOBALS['gis_types'] = [ 'POINT', 'MULTIPOINT', 'LINESTRING', @@ -66,95 +78,103 @@ class GisDataEditorController extends AbstractController // Extract type from the initial call and make sure that it's a valid one. // Extract from field's values if available, if not use the column type passed. - if (! isset($gis_data['gis_type'])) { + if (! isset($GLOBALS['gis_data']['gis_type'])) { if ($type !== '') { - $gis_data['gis_type'] = mb_strtoupper($type); + $GLOBALS['gis_data']['gis_type'] = mb_strtoupper($type); } if (isset($value) && trim($value) !== '') { - $start = substr($value, 0, 1) == "'" ? 1 : 0; - $gis_data['gis_type'] = mb_substr($value, $start, (int) mb_strpos($value, '(') - $start); + $GLOBALS['start'] = substr($value, 0, 1) == "'" ? 1 : 0; + $GLOBALS['gis_data']['gis_type'] = mb_substr( + $value, + $GLOBALS['start'], + (int) mb_strpos($value, '(') - $GLOBALS['start'] + ); } - if (! isset($gis_data['gis_type']) || (! in_array($gis_data['gis_type'], $gis_types))) { - $gis_data['gis_type'] = $gis_types[0]; + if ( + ! isset($GLOBALS['gis_data']['gis_type']) + || (! in_array($GLOBALS['gis_data']['gis_type'], $GLOBALS['gis_types'])) + ) { + $GLOBALS['gis_data']['gis_type'] = $GLOBALS['gis_types'][0]; } } - $geom_type = $gis_data['gis_type']; + $GLOBALS['geom_type'] = $GLOBALS['gis_data']['gis_type']; // Generate parameters from value passed. - $gis_obj = GisFactory::factory($geom_type); - if ($gis_obj === false) { + $GLOBALS['gis_obj'] = GisFactory::factory($GLOBALS['geom_type']); + if ($GLOBALS['gis_obj'] === false) { return; } if (isset($value)) { - $gis_data = array_merge( - $gis_data, - $gis_obj->generateParams($value) + $GLOBALS['gis_data'] = array_merge( + $GLOBALS['gis_data'], + $GLOBALS['gis_obj']->generateParams($value) ); } // Generate Well Known Text - $srid = isset($gis_data['srid']) && $gis_data['srid'] != '' ? (int) $gis_data['srid'] : 0; - $wkt = $gis_obj->generateWkt($gis_data, 0); - $wkt_with_zero = $gis_obj->generateWkt($gis_data, 0, '0'); - $result = "'" . $wkt . "'," . $srid; + $GLOBALS['srid'] = isset($GLOBALS['gis_data']['srid']) && $GLOBALS['gis_data']['srid'] != '' + ? (int) $GLOBALS['gis_data']['srid'] : 0; + $GLOBALS['wkt'] = $GLOBALS['gis_obj']->generateWkt($GLOBALS['gis_data'], 0); + $GLOBALS['wkt_with_zero'] = $GLOBALS['gis_obj']->generateWkt($GLOBALS['gis_data'], 0, '0'); + $GLOBALS['result'] = "'" . $GLOBALS['wkt'] . "'," . $GLOBALS['srid']; // Generate SVG based visualization - $visualizationSettings = [ + $GLOBALS['visualizationSettings'] = [ 'width' => 450, 'height' => 300, 'spatialColumn' => 'wkt', - 'mysqlVersion' => $dbi->getVersion(), - 'isMariaDB' => $dbi->isMariaDB(), + 'mysqlVersion' => $GLOBALS['dbi']->getVersion(), + 'isMariaDB' => $GLOBALS['dbi']->isMariaDB(), ]; - $data = [ + $GLOBALS['data'] = [ [ - 'wkt' => $wkt_with_zero, - 'srid' => $srid, + 'wkt' => $GLOBALS['wkt_with_zero'], + 'srid' => $GLOBALS['srid'], ], ]; - $visualization = GisVisualization::getByData($data, $visualizationSettings) + $GLOBALS['visualization'] = GisVisualization::getByData($GLOBALS['data'], $GLOBALS['visualizationSettings']) ->toImage('svg'); - $open_layers = GisVisualization::getByData($data, $visualizationSettings) + $GLOBALS['open_layers'] = GisVisualization::getByData($GLOBALS['data'], $GLOBALS['visualizationSettings']) ->asOl(); // If the call is to update the WKT and visualization make an AJAX response if ($generate) { $this->response->addJSON([ - 'result' => $result, - 'visualization' => $visualization, - 'openLayers' => $open_layers, + 'result' => $GLOBALS['result'], + 'visualization' => $GLOBALS['visualization'], + 'openLayers' => $GLOBALS['open_layers'], ]); return; } - $geom_count = 1; - if ($geom_type === 'GEOMETRYCOLLECTION') { - $geom_count = isset($gis_data[$geom_type]['geom_count']) - ? intval($gis_data[$geom_type]['geom_count']) : 1; - if (isset($gis_data[$geom_type]['add_geom'])) { - $geom_count++; + $GLOBALS['geom_count'] = 1; + if ($GLOBALS['geom_type'] === 'GEOMETRYCOLLECTION') { + $GLOBALS['geom_count'] = isset($GLOBALS['gis_data'][$GLOBALS['geom_type']]['geom_count']) + ? intval($GLOBALS['gis_data'][$GLOBALS['geom_type']]['geom_count']) : 1; + if (isset($GLOBALS['gis_data'][$GLOBALS['geom_type']]['add_geom'])) { + $GLOBALS['geom_count']++; } } $templateOutput = $this->template->render('gis_data_editor_form', [ - 'width' => $visualizationSettings['width'], - 'height' => $visualizationSettings['height'], + 'width' => $GLOBALS['visualizationSettings']['width'], + 'height' => $GLOBALS['visualizationSettings']['height'], 'field' => $field, 'input_name' => $inputName, - 'srid' => $srid, - 'visualization' => $visualization, - 'open_layers' => $open_layers, - 'gis_types' => $gis_types, - 'geom_type' => $geom_type, - 'geom_count' => $geom_count, - 'gis_data' => $gis_data, - 'result' => $result, + 'srid' => $GLOBALS['srid'], + 'visualization' => $GLOBALS['visualization'], + 'open_layers' => $GLOBALS['open_layers'], + 'gis_types' => $GLOBALS['gis_types'], + 'geom_type' => $GLOBALS['geom_type'], + 'geom_count' => $GLOBALS['geom_count'], + 'gis_data' => $GLOBALS['gis_data'], + 'result' => $GLOBALS['result'], ]); $this->response->addJSON(['gis_editor' => $templateOutput]); diff --git a/libraries/classes/Controllers/GitInfoController.php b/libraries/classes/Controllers/GitInfoController.php index e1250a0136..2fc4ae8df7 100644 --- a/libraries/classes/Controllers/GitInfoController.php +++ b/libraries/classes/Controllers/GitInfoController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Config; use PhpMyAdmin\Git; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Util; @@ -23,7 +24,7 @@ final class GitInfoController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! $this->response->isAjax()) { return; diff --git a/libraries/classes/Controllers/HomeController.php b/libraries/classes/Controllers/HomeController.php index 39235fdc06..22b3990735 100644 --- a/libraries/classes/Controllers/HomeController.php +++ b/libraries/classes/Controllers/HomeController.php @@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Git; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; use PhpMyAdmin\RecentFavoriteTable; @@ -64,9 +65,13 @@ class HomeController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $server, $collation_connection, $message, $show_query, $db, $table, $errorUrl; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; + $GLOBALS['collation_connection'] = $GLOBALS['collation_connection'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['show_query'] = $GLOBALS['show_query'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if ($this->response->isAjax() && ! empty($_REQUEST['access_time'])) { return; @@ -77,20 +82,20 @@ class HomeController extends AbstractController // This is for $cfg['ShowDatabasesNavigationAsTree'] = false; // See: https://github.com/phpmyadmin/phpmyadmin/issues/16520 // The DB is defined here and sent to the JS front-end to refresh the DB tree - $db = $_POST['db'] ?? ''; - $table = ''; - $show_query = '1'; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['db'] = $_POST['db'] ?? ''; + $GLOBALS['table'] = ''; + $GLOBALS['show_query'] = '1'; + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); - if ($server > 0 && $this->dbi->isSuperUser()) { + if ($GLOBALS['server'] > 0 && $this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); } $languageManager = LanguageManager::getInstance(); - if (! empty($message)) { - $displayMessage = Generator::getMessage($message); - unset($message); + if (! empty($GLOBALS['message'])) { + $displayMessage = Generator::getMessage($GLOBALS['message']); + unset($GLOBALS['message']); } if (isset($_SESSION['partial_logout'])) { @@ -104,22 +109,22 @@ class HomeController extends AbstractController $syncFavoriteTables = RecentFavoriteTable::getInstance('favorite') ->getHtmlSyncFavoriteTables(); - $hasServer = $server > 0 || count($cfg['Servers']) > 1; + $hasServer = $GLOBALS['server'] > 0 || count($GLOBALS['cfg']['Servers']) > 1; if ($hasServer) { - $hasServerSelection = $cfg['ServerDefault'] == 0 - || (! $cfg['NavigationDisplayServers'] - && (count($cfg['Servers']) > 1 - || ($server == 0 && count($cfg['Servers']) === 1))); + $hasServerSelection = $GLOBALS['cfg']['ServerDefault'] == 0 + || (! $GLOBALS['cfg']['NavigationDisplayServers'] + && (count($GLOBALS['cfg']['Servers']) > 1 + || ($GLOBALS['server'] == 0 && count($GLOBALS['cfg']['Servers']) === 1))); if ($hasServerSelection) { $serverSelection = Select::render(true, true); } - if ($server > 0) { + if ($GLOBALS['server'] > 0) { $checkUserPrivileges = new CheckUserPrivileges($this->dbi); $checkUserPrivileges->getPrivileges(); - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); + $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $charsetsList = []; foreach ($charsets as $charset) { $collationsList = []; @@ -127,7 +132,7 @@ class HomeController extends AbstractController $collationsList[] = [ 'name' => $collation->getName(), 'description' => $collation->getDescription(), - 'is_selected' => $collation_connection === $collation->getName(), + 'is_selected' => $GLOBALS['collation_connection'] === $collation->getName(), ]; } @@ -141,25 +146,23 @@ class HomeController extends AbstractController } $availableLanguages = []; - if (empty($cfg['Lang']) && $languageManager->hasChoice()) { + if (empty($GLOBALS['cfg']['Lang']) && $languageManager->hasChoice()) { $availableLanguages = $languageManager->sortedLanguages(); } $databaseServer = []; - if ($server > 0 && $cfg['ShowServerInfo']) { + if ($GLOBALS['server'] > 0 && $GLOBALS['cfg']['ShowServerInfo']) { $hostInfo = ''; - if (! empty($cfg['Server']['verbose'])) { - $hostInfo .= $cfg['Server']['verbose']; - $hostInfo .= ' ('; + if (! empty($GLOBALS['cfg']['Server']['verbose'])) { + $hostInfo .= $GLOBALS['cfg']['Server']['verbose'] . ' ('; } $hostInfo .= $this->dbi->getHostInfo(); - - if (! empty($cfg['Server']['verbose'])) { + if (! empty($GLOBALS['cfg']['Server']['verbose'])) { $hostInfo .= ')'; } - $serverCharset = Charsets::getServerCharset($this->dbi, $cfg['Server']['DisableIS']); + $serverCharset = Charsets::getServerCharset($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $databaseServer = [ 'host' => $hostInfo, 'type' => Util::getServerType(), @@ -172,10 +175,10 @@ class HomeController extends AbstractController } $webServer = []; - if ($cfg['ShowServerInfo']) { + if ($GLOBALS['cfg']['ShowServerInfo']) { $webServer['software'] = $_SERVER['SERVER_SOFTWARE'] ?? null; - if ($server > 0) { + if ($GLOBALS['server'] > 0) { $clientVersion = $this->dbi->getClientInfo(); if (preg_match('#\d+\.\d+\.\d+#', $clientVersion)) { $clientVersion = 'libmysql - ' . $clientVersion; @@ -188,15 +191,15 @@ class HomeController extends AbstractController } $relation = new Relation($this->dbi); - if ($server > 0) { + if ($GLOBALS['server'] > 0) { $relationParameters = $relation->getRelationParameters(); - if (! $relationParameters->hasAllFeatures() && $cfg['PmaNoRelation_DisableWarning'] == false) { + if (! $relationParameters->hasAllFeatures() && $GLOBALS['cfg']['PmaNoRelation_DisableWarning'] == false) { $messageText = __( 'The phpMyAdmin configuration storage is not completely ' . 'configured, some extended features have been deactivated. ' . '%sFind out why%s. ' ); - if ($cfg['ZeroConf'] == true) { + if ($GLOBALS['cfg']['ZeroConf'] == true) { $messageText .= '<br>' . __('Or alternately go to \'Operations\' tab of any database to set it up there.'); } @@ -208,7 +211,7 @@ class HomeController extends AbstractController ); $messageInstance->addParamHtml('</a>'); /* Show error if user has configured something, notice elsewhere */ - if (! empty($cfg['Servers'][$server]['pmadb'])) { + if (! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['pmadb'])) { $messageInstance->isError(true); } @@ -221,28 +224,29 @@ class HomeController extends AbstractController $git = new Git($this->config->get('ShowGitRevision') ?? true); $this->render('home/index', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'message' => $displayMessage ?? '', 'partial_logout' => $partialLogout ?? '', 'is_git_revision' => $git->isGitRevision(), - 'server' => $server, + 'server' => $GLOBALS['server'], 'sync_favorite_tables' => $syncFavoriteTables, 'has_server' => $hasServer, - 'is_demo' => $cfg['DBG']['demo'], + 'is_demo' => $GLOBALS['cfg']['DBG']['demo'], 'has_server_selection' => $hasServerSelection ?? false, 'server_selection' => $serverSelection ?? '', - 'has_change_password_link' => $cfg['Server']['auth_type'] !== 'config' && $cfg['ShowChgPassword'], + 'has_change_password_link' => $GLOBALS['cfg']['Server']['auth_type'] !== 'config' + && $GLOBALS['cfg']['ShowChgPassword'], 'charsets' => $charsetsList ?? [], 'available_languages' => $availableLanguages, 'database_server' => $databaseServer, 'web_server' => $webServer, - 'show_php_info' => $cfg['ShowPhpInfo'], - 'is_version_checked' => $cfg['VersionCheck'], + 'show_php_info' => $GLOBALS['cfg']['ShowPhpInfo'], + 'is_version_checked' => $GLOBALS['cfg']['VersionCheck'], 'phpmyadmin_version' => Version::VERSION, 'phpmyadmin_major_version' => Version::SERIES, 'config_storage_message' => $configStorageMessage ?? '', - 'has_theme_manager' => $cfg['ThemeManager'], + 'has_theme_manager' => $GLOBALS['cfg']['ThemeManager'], 'themes' => $this->themeManager->getThemesArray(), 'errors' => $this->errors, ]); @@ -250,16 +254,16 @@ class HomeController extends AbstractController private function checkRequirements(): void { - global $cfg, $server; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; $this->checkPhpExtensionsRequirements(); - if ($cfg['LoginCookieValidityDisableWarning'] == false) { + if ($GLOBALS['cfg']['LoginCookieValidityDisableWarning'] == false) { /** * Check whether session.gc_maxlifetime limits session validity. */ $gc_time = (int) ini_get('session.gc_maxlifetime'); - if ($gc_time < $cfg['LoginCookieValidity']) { + if ($gc_time < $GLOBALS['cfg']['LoginCookieValidity']) { $this->errors[] = [ 'message' => __( 'Your PHP parameter [a@https://www.php.net/manual/en/session.' . @@ -276,7 +280,10 @@ class HomeController extends AbstractController /** * Check whether LoginCookieValidity is limited by LoginCookieStore. */ - if ($cfg['LoginCookieStore'] != 0 && $cfg['LoginCookieStore'] < $cfg['LoginCookieValidity']) { + if ( + $GLOBALS['cfg']['LoginCookieStore'] != 0 + && $GLOBALS['cfg']['LoginCookieStore'] < $GLOBALS['cfg']['LoginCookieValidity'] + ) { $this->errors[] = [ 'message' => __( 'Login cookie store is lower than cookie validity configured in ' . @@ -291,10 +298,10 @@ class HomeController extends AbstractController * Warning if using the default MySQL controluser account */ if ( - isset($cfg['Server']['controluser'], $cfg['Server']['controlpass']) - && $server != 0 - && $cfg['Server']['controluser'] === 'pma' - && $cfg['Server']['controlpass'] === 'pmapass' + isset($GLOBALS['cfg']['Server']['controluser'], $GLOBALS['cfg']['Server']['controlpass']) + && $GLOBALS['server'] != 0 + && $GLOBALS['cfg']['Server']['controluser'] === 'pma' + && $GLOBALS['cfg']['Server']['controlpass'] === 'pmapass' ) { $this->errors[] = [ 'message' => __( @@ -311,7 +318,7 @@ class HomeController extends AbstractController * Check if user does not have defined blowfish secret and it is being used. */ if (! empty($_SESSION['encryption_key'])) { - $encryptionKeyLength = mb_strlen($cfg['blowfish_secret'], '8bit'); + $encryptionKeyLength = mb_strlen($GLOBALS['cfg']['blowfish_secret'], '8bit'); if ($encryptionKeyLength < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) { $this->errors[] = [ 'message' => __( @@ -357,7 +364,7 @@ class HomeController extends AbstractController * Warning about Suhosin only if its simulation mode is not enabled */ if ( - $cfg['SuhosinDisableWarning'] == false + $GLOBALS['cfg']['SuhosinDisableWarning'] == false && ini_get('suhosin.request.max_value_length') && ini_get('suhosin.simulation') == '0' ) { @@ -393,7 +400,7 @@ class HomeController extends AbstractController private function checkLanguageStats(): void { - global $cfg, $lang; + $GLOBALS['lang'] = $GLOBALS['lang'] ?? null; /** * Warning about incomplete translations. @@ -412,8 +419,8 @@ class HomeController extends AbstractController * speaking users. */ if ( - ! isset($GLOBALS['language_stats'][$lang]) - || $GLOBALS['language_stats'][$lang] >= $cfg['TranslationWarningThreshold'] + ! isset($GLOBALS['language_stats'][$GLOBALS['lang']]) + || $GLOBALS['language_stats'][$GLOBALS['lang']] >= $GLOBALS['cfg']['TranslationWarningThreshold'] ) { return; } diff --git a/libraries/classes/Controllers/Import/ImportController.php b/libraries/classes/Controllers/Import/ImportController.php index 5a60baf6c4..a317f15e55 100644 --- a/libraries/classes/Controllers/Import/ImportController.php +++ b/libraries/classes/Controllers/Import/ImportController.php @@ -6,13 +6,13 @@ namespace PhpMyAdmin\Controllers\Import; use PhpMyAdmin\Bookmark; use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Console; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Encoding; use PhpMyAdmin\File; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import; use PhpMyAdmin\Message; use PhpMyAdmin\ParseAnalyze; @@ -70,70 +70,59 @@ final class ImportController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $collation_connection, $db, $import_type, $table, $goto, $display_query; - global $format, $local_import_file, $ajax_reload, $import_text, $sql_query, $message, $errorUrl, $urlParams; - global $memory_limit, $read_limit, $finished, $offset, $charset_conversion, $charset_of_file; - global $timestamp, $maximum_time, $timeout_passed, $import_file, $go_sql, $sql_file, $error, $max_sql_len, $msg; - global $sql_query_disabled, $executed_queries, $run_query, $reset_charset; - global $result, $import_file_name, $sql_data, $import_notice, $read_multiply, $my_die, $active_page; - global $show_as_php, $reload, $charset_connection, $is_js_confirmed, $MAX_FILE_SIZE, $message_to_show; - global $noplugin, $skip_queries; - - $charset_of_file = $_POST['charset_of_file'] ?? null; - $format = $_POST['format'] ?? ''; - $import_type = $_POST['import_type'] ?? null; - $is_js_confirmed = $_POST['is_js_confirmed'] ?? null; - $MAX_FILE_SIZE = $_POST['MAX_FILE_SIZE'] ?? null; - $message_to_show = $_POST['message_to_show'] ?? null; - $noplugin = $_POST['noplugin'] ?? null; - $skip_queries = $_POST['skip_queries'] ?? null; - $local_import_file = $_POST['local_import_file'] ?? null; - $show_as_php = $_POST['show_as_php'] ?? null; - - // If it's a refresh console bookmarks request - if (isset($_GET['console_bookmark_refresh'])) { - $this->response->addJSON( - 'console_message_bookmark', - Console::getBookmarkContent() - ); - - return; - } - - // If it's a console bookmark add request - if (isset($_POST['console_bookmark_add'])) { - if (! isset($_POST['label'], $_POST['db'], $_POST['bookmark_query'], $_POST['shared'])) { - $this->response->addJSON('message', __('Incomplete params')); - - return; - } - - $bookmarkFields = [ - 'bkm_database' => $_POST['db'], - 'bkm_user' => $cfg['Server']['user'], - 'bkm_sql_query' => $_POST['bookmark_query'], - 'bkm_label' => $_POST['label'], - ]; - $isShared = ($_POST['shared'] === 'true'); - $bookmark = Bookmark::createBookmark($this->dbi, $bookmarkFields, $isShared); - if ($bookmark !== false && $bookmark->save()) { - $this->response->addJSON('message', __('Succeeded')); - $this->response->addJSON('data', $bookmarkFields); - $this->response->addJSON('isShared', $isShared); - } else { - $this->response->addJSON('message', __('Failed')); - } - - return; - } + $GLOBALS['collation_connection'] = $GLOBALS['collation_connection'] ?? null; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['display_query'] = $GLOBALS['display_query'] ?? null; + $GLOBALS['ajax_reload'] = $GLOBALS['ajax_reload'] ?? null; + $GLOBALS['import_text'] = $GLOBALS['import_text'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['memory_limit'] = $GLOBALS['memory_limit'] ?? null; + $GLOBALS['read_limit'] = $GLOBALS['read_limit'] ?? null; + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; + $GLOBALS['offset'] = $GLOBALS['offset'] ?? null; + $GLOBALS['charset_conversion'] = $GLOBALS['charset_conversion'] ?? null; + $GLOBALS['timestamp'] = $GLOBALS['timestamp'] ?? null; + $GLOBALS['maximum_time'] = $GLOBALS['maximum_time'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + $GLOBALS['import_file'] = $GLOBALS['import_file'] ?? null; + $GLOBALS['go_sql'] = $GLOBALS['go_sql'] ?? null; + $GLOBALS['sql_file'] = $GLOBALS['sql_file'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['max_sql_len'] = $GLOBALS['max_sql_len'] ?? null; + $GLOBALS['msg'] = $GLOBALS['msg'] ?? null; + $GLOBALS['sql_query_disabled'] = $GLOBALS['sql_query_disabled'] ?? null; + $GLOBALS['executed_queries'] = $GLOBALS['executed_queries'] ?? null; + $GLOBALS['run_query'] = $GLOBALS['run_query'] ?? null; + $GLOBALS['reset_charset'] = $GLOBALS['reset_charset'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + $GLOBALS['import_file_name'] = $GLOBALS['import_file_name'] ?? null; + $GLOBALS['import_notice'] = $GLOBALS['import_notice'] ?? null; + $GLOBALS['read_multiply'] = $GLOBALS['read_multiply'] ?? null; + $GLOBALS['my_die'] = $GLOBALS['my_die'] ?? null; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; + $GLOBALS['charset_connection'] = $GLOBALS['charset_connection'] ?? null; + + $GLOBALS['charset_of_file'] = $_POST['charset_of_file'] ?? null; + $GLOBALS['format'] = $_POST['format'] ?? ''; + $GLOBALS['import_type'] = $_POST['import_type'] ?? null; + $GLOBALS['is_js_confirmed'] = $_POST['is_js_confirmed'] ?? null; + $GLOBALS['MAX_FILE_SIZE'] = $_POST['MAX_FILE_SIZE'] ?? null; + $GLOBALS['message_to_show'] = $_POST['message_to_show'] ?? null; + $GLOBALS['noplugin'] = $_POST['noplugin'] ?? null; + $GLOBALS['skip_queries'] = $_POST['skip_queries'] ?? null; + $GLOBALS['local_import_file'] = $_POST['local_import_file'] ?? null; + $GLOBALS['show_as_php'] = $_POST['show_as_php'] ?? null; // reset import messages for ajax request $_SESSION['Import_message']['message'] = null; $_SESSION['Import_message']['go_back_url'] = null; // default values - $reload = false; + $GLOBALS['reload'] = false; // Use to identify current cycle is executing // a multiquery statement or stored routine @@ -141,11 +130,11 @@ final class ImportController extends AbstractController $_SESSION['is_multi_query'] = false; } - $ajax_reload = []; - $import_text = ''; + $GLOBALS['ajax_reload'] = []; + $GLOBALS['import_text'] = ''; // Are we just executing plain query or sql file? // (eg. non import, but query box/window run) - if (! empty($sql_query)) { + if (! empty($GLOBALS['sql_query'])) { // apply values for parameters if (! empty($_POST['parameterized']) && ! empty($_POST['parameters']) && is_array($_POST['parameters'])) { $parameters = $_POST['parameters']; @@ -157,76 +146,86 @@ final class ImportController extends AbstractController $quoted = preg_quote($parameter, '/'); // making sure that :param does not apply values to :param1 - $sql_query = preg_replace( + $GLOBALS['sql_query'] = preg_replace( '/' . $quoted . '([^a-zA-Z0-9_])/', $replacementValue . '${1}', - $sql_query + $GLOBALS['sql_query'] ); // for parameters the appear at the end of the string - $sql_query = preg_replace('/' . $quoted . '$/', $replacementValue, $sql_query); + $GLOBALS['sql_query'] = preg_replace( + '/' . $quoted . '$/', + $replacementValue, + $GLOBALS['sql_query'] + ); } } // run SQL query - $import_text = $sql_query; - $import_type = 'query'; - $format = 'sql'; + $GLOBALS['import_text'] = $GLOBALS['sql_query']; + $GLOBALS['import_type'] = 'query'; + $GLOBALS['format'] = 'sql'; $_SESSION['sql_from_query_box'] = true; // If there is a request to ROLLBACK when finished. if (isset($_POST['rollback_query'])) { - $this->import->handleRollbackRequest($import_text); + $this->import->handleRollbackRequest($GLOBALS['import_text']); } // refresh navigation and main panels - if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) { - $reload = true; - $ajax_reload['reload'] = true; + if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['sql_query'])) { + $GLOBALS['reload'] = true; + $GLOBALS['ajax_reload']['reload'] = true; } // refresh navigation panel only - if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) { - $ajax_reload['reload'] = true; + if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['sql_query'])) { + $GLOBALS['ajax_reload']['reload'] = true; } // do a dynamic reload if table is RENAMED // (by sending the instruction to the AJAX response handler) - if (preg_match('/^RENAME\s+TABLE\s+(.*?)\s+TO\s+(.*?)($|;|\s)/i', $sql_query, $rename_table_names)) { - $ajax_reload['reload'] = true; - $ajax_reload['table_name'] = Util::unQuote($rename_table_names[2]); + if ( + preg_match( + '/^RENAME\s+TABLE\s+(.*?)\s+TO\s+(.*?)($|;|\s)/i', + $GLOBALS['sql_query'], + $rename_table_names + ) + ) { + $GLOBALS['ajax_reload']['reload'] = true; + $GLOBALS['ajax_reload']['table_name'] = Util::unQuote($rename_table_names[2]); } - $sql_query = ''; - } elseif (! empty($sql_file)) { + $GLOBALS['sql_query'] = ''; + } elseif (! empty($GLOBALS['sql_file'])) { // run uploaded SQL file - $import_file = $sql_file; - $import_type = 'queryfile'; - $format = 'sql'; - unset($sql_file); + $GLOBALS['import_file'] = $GLOBALS['sql_file']; + $GLOBALS['import_type'] = 'queryfile'; + $GLOBALS['format'] = 'sql'; + unset($GLOBALS['sql_file']); } elseif (! empty($_POST['id_bookmark'])) { // run bookmark - $import_type = 'query'; - $format = 'sql'; + $GLOBALS['import_type'] = 'query'; + $GLOBALS['format'] = 'sql'; } // If we didn't get any parameters, either user called this directly, or // upload limit has been reached, let's assume the second possibility. if ($_POST == [] && $_GET == []) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __( 'You probably tried to upload a file that is too large. Please refer ' . 'to %sdocumentation%s for a workaround for this limit.' ) ); - $message->addParam('[doc@faq1-16]'); - $message->addParam('[/doc]'); + $GLOBALS['message']->addParam('[doc@faq1-16]'); + $GLOBALS['message']->addParam('[/doc]'); // so we can obtain the message - $_SESSION['Import_message']['message'] = $message->getDisplay(); - $_SESSION['Import_message']['go_back_url'] = $goto; + $_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay(); + $_SESSION['Import_message']['go_back_url'] = $GLOBALS['goto']; $this->response->setRequestStatus(false); - $this->response->addJSON('message', $message); + $this->response->addJSON('message', $GLOBALS['message']); return; // the footer is displayed automatically } @@ -241,7 +240,7 @@ final class ImportController extends AbstractController * We only need to load the selected plugin */ - if (! in_array($format, ['csv', 'ldi', 'mediawiki', 'ods', 'shp', 'sql', 'xml'])) { + if (! in_array($GLOBALS['format'], ['csv', 'ldi', 'mediawiki', 'ods', 'shp', 'sql', 'xml'])) { // this should not happen for a normal user // but only during an attack Core::fatalError('Incorrect format parameter'); @@ -249,82 +248,80 @@ final class ImportController extends AbstractController $post_patterns = [ '/^force_file_/', - '/^' . $format . '_/', + '/^' . $GLOBALS['format'] . '_/', ]; Core::setPostAsGlobal($post_patterns); - // Check needed parameters - Util::checkParameters(['import_type', 'format']); + $this->checkParameters(['import_type', 'format']); // We don't want anything special in format - $format = Core::securePath($format); + $GLOBALS['format'] = Core::securePath($GLOBALS['format']); - if (strlen($table) > 0 && strlen($db) > 0) { - $urlParams = [ - 'db' => $db, - 'table' => $table, + if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) { + $GLOBALS['urlParams'] = [ + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]; - } elseif (strlen($db) > 0) { - $urlParams = ['db' => $db]; + } elseif (strlen($GLOBALS['db']) > 0) { + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db']]; } else { - $urlParams = []; + $GLOBALS['urlParams'] = []; } // Create error and goto url - if ($import_type === 'table') { - $goto = Url::getFromRoute('/table/import'); - } elseif ($import_type === 'database') { - $goto = Url::getFromRoute('/database/import'); - } elseif ($import_type === 'server') { - $goto = Url::getFromRoute('/server/import'); - } elseif (empty($goto) || ! preg_match('@^index\.php$@i', $goto)) { - if (strlen($table) > 0 && strlen($db) > 0) { - $goto = Url::getFromRoute('/table/structure'); - } elseif (strlen($db) > 0) { - $goto = Url::getFromRoute('/database/structure'); + if ($GLOBALS['import_type'] === 'table') { + $GLOBALS['goto'] = Url::getFromRoute('/table/import'); + } elseif ($GLOBALS['import_type'] === 'database') { + $GLOBALS['goto'] = Url::getFromRoute('/database/import'); + } elseif ($GLOBALS['import_type'] === 'server') { + $GLOBALS['goto'] = Url::getFromRoute('/server/import'); + } elseif (empty($GLOBALS['goto']) || ! preg_match('@^index\.php$@i', $GLOBALS['goto'])) { + if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) { + $GLOBALS['goto'] = Url::getFromRoute('/table/structure'); + } elseif (strlen($GLOBALS['db']) > 0) { + $GLOBALS['goto'] = Url::getFromRoute('/database/structure'); } else { - $goto = Url::getFromRoute('/server/sql'); + $GLOBALS['goto'] = Url::getFromRoute('/server/sql'); } } - $errorUrl = $goto . Url::getCommon($urlParams, '&'); - $_SESSION['Import_message']['go_back_url'] = $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['goto'] . Url::getCommon($GLOBALS['urlParams'], '&'); + $_SESSION['Import_message']['go_back_url'] = $GLOBALS['errorUrl']; - if (strlen($db) > 0) { - $this->dbi->selectDb($db); + if (strlen($GLOBALS['db']) > 0) { + $this->dbi->selectDb($GLOBALS['db']); } Util::setTimeLimit(); - if (! empty($cfg['MemoryLimit'])) { - ini_set('memory_limit', $cfg['MemoryLimit']); + if (! empty($GLOBALS['cfg']['MemoryLimit'])) { + ini_set('memory_limit', $GLOBALS['cfg']['MemoryLimit']); } - $timestamp = time(); + $GLOBALS['timestamp'] = time(); if (isset($_POST['allow_interrupt'])) { - $maximum_time = ini_get('max_execution_time'); + $GLOBALS['maximum_time'] = ini_get('max_execution_time'); } else { - $maximum_time = 0; + $GLOBALS['maximum_time'] = 0; } // set default values - $timeout_passed = false; - $error = false; - $read_multiply = 1; - $finished = false; - $offset = 0; - $max_sql_len = 0; - $sql_query = ''; - $sql_query_disabled = false; - $go_sql = false; - $executed_queries = 0; - $run_query = true; - $charset_conversion = false; - $reset_charset = false; - $msg = 'Sorry an unexpected error happened!'; - - /** @var bool|mixed $result */ - $result = false; + $GLOBALS['timeout_passed'] = false; + $GLOBALS['error'] = false; + $GLOBALS['read_multiply'] = 1; + $GLOBALS['finished'] = false; + $GLOBALS['offset'] = 0; + $GLOBALS['max_sql_len'] = 0; + $GLOBALS['sql_query'] = ''; + $GLOBALS['sql_query_disabled'] = false; + $GLOBALS['go_sql'] = false; + $GLOBALS['executed_queries'] = 0; + $GLOBALS['run_query'] = true; + $GLOBALS['charset_conversion'] = false; + $GLOBALS['reset_charset'] = false; + $GLOBALS['msg'] = 'Sorry an unexpected error happened!'; + + $GLOBALS['result'] = false; // Bookmark Support: get a query back from bookmark if required if (! empty($_POST['id_bookmark'])) { @@ -333,8 +330,8 @@ final class ImportController extends AbstractController case 0: // bookmarked query that have to be run $bookmark = Bookmark::get( $this->dbi, - $cfg['Server']['user'], - $db, + $GLOBALS['cfg']['Server']['user'], + $GLOBALS['db'], $id_bookmark, 'id', isset($_POST['action_bookmark_all']) @@ -344,63 +341,73 @@ final class ImportController extends AbstractController } if (! empty($_POST['bookmark_variable'])) { - $import_text = $bookmark->applyVariables($_POST['bookmark_variable']); + $GLOBALS['import_text'] = $bookmark->applyVariables($_POST['bookmark_variable']); } else { - $import_text = $bookmark->getQuery(); + $GLOBALS['import_text'] = $bookmark->getQuery(); } // refresh navigation and main panels - if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) { - $reload = true; - $ajax_reload['reload'] = true; + if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['import_text'])) { + $GLOBALS['reload'] = true; + $GLOBALS['ajax_reload']['reload'] = true; } // refresh navigation panel only - if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) { - $ajax_reload['reload'] = true; + if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['import_text'])) { + $GLOBALS['ajax_reload']['reload'] = true; } break; case 1: // bookmarked query that have to be displayed - $bookmark = Bookmark::get($this->dbi, $cfg['Server']['user'], $db, $id_bookmark); + $bookmark = Bookmark::get( + $this->dbi, + $GLOBALS['cfg']['Server']['user'], + $GLOBALS['db'], + $id_bookmark + ); if (! $bookmark instanceof Bookmark) { break; } - $import_text = $bookmark->getQuery(); + $GLOBALS['import_text'] = $bookmark->getQuery(); if ($this->response->isAjax()) { - $message = Message::success(__('Showing bookmark')); - $this->response->setRequestStatus($message->isSuccess()); - $this->response->addJSON('message', $message); - $this->response->addJSON('sql_query', $import_text); + $GLOBALS['message'] = Message::success(__('Showing bookmark')); + $this->response->setRequestStatus($GLOBALS['message']->isSuccess()); + $this->response->addJSON('message', $GLOBALS['message']); + $this->response->addJSON('sql_query', $GLOBALS['import_text']); $this->response->addJSON('action_bookmark', $_POST['action_bookmark']); return; } else { - $run_query = false; + $GLOBALS['run_query'] = false; } break; case 2: // bookmarked query that have to be deleted - $bookmark = Bookmark::get($this->dbi, $cfg['Server']['user'], $db, $id_bookmark); + $bookmark = Bookmark::get( + $this->dbi, + $GLOBALS['cfg']['Server']['user'], + $GLOBALS['db'], + $id_bookmark + ); if (! $bookmark instanceof Bookmark) { break; } $bookmark->delete(); if ($this->response->isAjax()) { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('The bookmark has been deleted.') ); - $this->response->setRequestStatus($message->isSuccess()); - $this->response->addJSON('message', $message); + $this->response->setRequestStatus($GLOBALS['message']->isSuccess()); + $this->response->addJSON('message', $GLOBALS['message']); $this->response->addJSON('action_bookmark', $_POST['action_bookmark']); $this->response->addJSON('id_bookmark', $id_bookmark); return; } else { - $run_query = false; - $error = true; // this is kind of hack to skip processing the query + $GLOBALS['run_query'] = false; + $GLOBALS['error'] = true; // this is kind of hack to skip processing the query } break; @@ -408,70 +415,70 @@ final class ImportController extends AbstractController } // Do no run query if we show PHP code - if (isset($show_as_php)) { - $run_query = false; - $go_sql = true; + if (isset($GLOBALS['show_as_php'])) { + $GLOBALS['run_query'] = false; + $GLOBALS['go_sql'] = true; } // We can not read all at once, otherwise we can run out of memory - $memory_limit = trim((string) ini_get('memory_limit')); + $GLOBALS['memory_limit'] = trim((string) ini_get('memory_limit')); // 2 MB as default - if (empty($memory_limit)) { - $memory_limit = 2 * 1024 * 1024; + if (empty($GLOBALS['memory_limit'])) { + $GLOBALS['memory_limit'] = 2 * 1024 * 1024; } // In case no memory limit we work on 10MB chunks - if ($memory_limit === '-1') { - $memory_limit = 10 * 1024 * 1024; + if ($GLOBALS['memory_limit'] === '-1') { + $GLOBALS['memory_limit'] = 10 * 1024 * 1024; } // Calculate value of the limit - $memoryUnit = mb_strtolower(substr((string) $memory_limit, -1)); + $memoryUnit = mb_strtolower(substr((string) $GLOBALS['memory_limit'], -1)); if ($memoryUnit === 'm') { - $memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024 * 1024; + $GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024 * 1024; } elseif ($memoryUnit === 'k') { - $memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024; + $GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024; } elseif ($memoryUnit === 'g') { - $memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024 * 1024 * 1024; + $GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024 * 1024 * 1024; } else { - $memory_limit = (int) $memory_limit; + $GLOBALS['memory_limit'] = (int) $GLOBALS['memory_limit']; } // Just to be sure, there might be lot of memory needed for uncompression - $read_limit = $memory_limit / 8; + $GLOBALS['read_limit'] = $GLOBALS['memory_limit'] / 8; // handle filenames if (isset($_FILES['import_file'])) { - $import_file = $_FILES['import_file']['tmp_name']; - $import_file_name = $_FILES['import_file']['name']; + $GLOBALS['import_file'] = $_FILES['import_file']['tmp_name']; + $GLOBALS['import_file_name'] = $_FILES['import_file']['name']; } - if (! empty($local_import_file) && ! empty($cfg['UploadDir'])) { + if (! empty($GLOBALS['local_import_file']) && ! empty($GLOBALS['cfg']['UploadDir'])) { // sanitize $local_import_file as it comes from a POST - $local_import_file = Core::securePath($local_import_file); + $GLOBALS['local_import_file'] = Core::securePath($GLOBALS['local_import_file']); - $import_file = Util::userDir((string) $cfg['UploadDir']) - . $local_import_file; + $GLOBALS['import_file'] = Util::userDir((string) $GLOBALS['cfg']['UploadDir']) + . $GLOBALS['local_import_file']; /* * Do not allow symlinks to avoid security issues * (user can create symlink to file they can not access, * but phpMyAdmin can). */ - if (@is_link($import_file)) { - $import_file = 'none'; + if (@is_link($GLOBALS['import_file'])) { + $GLOBALS['import_file'] = 'none'; } - } elseif (empty($import_file) || ! is_uploaded_file($import_file)) { - $import_file = 'none'; + } elseif (empty($GLOBALS['import_file']) || ! is_uploaded_file($GLOBALS['import_file'])) { + $GLOBALS['import_file'] = 'none'; } // Do we have file to import? - if ($import_file !== 'none' && ! $error) { + if ($GLOBALS['import_file'] !== 'none' && ! $GLOBALS['error']) { /** * Handle file compression */ - $importHandle = new File($import_file); + $importHandle = new File($GLOBALS['import_file']); $importHandle->checkUploadedFile(); if ($importHandle->isError()) { /** @var Message $errorMessage */ @@ -504,8 +511,8 @@ final class ImportController extends AbstractController return; } - } elseif (! $error && (! isset($import_text) || empty($import_text))) { - $message = Message::error( + } elseif (! $GLOBALS['error'] && (! isset($GLOBALS['import_text']) || empty($GLOBALS['import_text']))) { + $GLOBALS['message'] = Message::error( __( 'No data was received to import. Either no file name was ' . 'submitted, or the file size exceeded the maximum size permitted ' . @@ -513,35 +520,38 @@ final class ImportController extends AbstractController ) ); - $_SESSION['Import_message']['message'] = $message->getDisplay(); + $_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay(); $this->response->setRequestStatus(false); - $this->response->addJSON('message', $message->getDisplay()); - $this->response->addHTML($message->getDisplay()); + $this->response->addJSON('message', $GLOBALS['message']->getDisplay()); + $this->response->addHTML($GLOBALS['message']->getDisplay()); return; } // Convert the file's charset if necessary - if (Encoding::isSupported() && isset($charset_of_file)) { - if ($charset_of_file !== 'utf-8') { - $charset_conversion = true; + if (Encoding::isSupported() && isset($GLOBALS['charset_of_file'])) { + if ($GLOBALS['charset_of_file'] !== 'utf-8') { + $GLOBALS['charset_conversion'] = true; } - } elseif (isset($charset_of_file) && $charset_of_file !== 'utf-8') { - $this->dbi->query('SET NAMES \'' . $charset_of_file . '\''); + } elseif (isset($GLOBALS['charset_of_file']) && $GLOBALS['charset_of_file'] !== 'utf-8') { + $this->dbi->query('SET NAMES \'' . $GLOBALS['charset_of_file'] . '\''); // We can not show query in this case, it is in different charset - $sql_query_disabled = true; - $reset_charset = true; + $GLOBALS['sql_query_disabled'] = true; + $GLOBALS['reset_charset'] = true; } // Something to skip? (because timeout has passed) - if (! $error && isset($_POST['skip'])) { + if (! $GLOBALS['error'] && isset($_POST['skip'])) { $original_skip = $skip = intval($_POST['skip']); - while ($skip > 0 && ! $finished) { - $this->import->getNextChunk($importHandle ?? null, $skip < $read_limit ? $skip : $read_limit); + while ($skip > 0 && ! $GLOBALS['finished']) { + $this->import->getNextChunk( + $importHandle ?? null, + $skip < $GLOBALS['read_limit'] ? $skip : $GLOBALS['read_limit'] + ); // Disable read progressivity, otherwise we eat all memory! - $read_multiply = 1; - $skip -= $read_limit; + $GLOBALS['read_multiply'] = 1; + $skip -= $GLOBALS['read_limit']; } unset($skip); @@ -549,26 +559,23 @@ final class ImportController extends AbstractController // This array contain the data like number of valid sql queries in the statement // and complete valid sql statement (which affected for rows) - $sql_data = [ - 'valid_sql' => [], - 'valid_queries' => 0, - ]; + $queriesToBeExecuted = []; - if (! $error) { + if (! $GLOBALS['error']) { /** * @var ImportPlugin $import_plugin */ - $import_plugin = Plugins::getPlugin('import', $format, $import_type); + $import_plugin = Plugins::getPlugin('import', $GLOBALS['format'], $GLOBALS['import_type']); if ($import_plugin == null) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Could not load import plugins, please check your installation!') ); - $_SESSION['Import_message']['message'] = $message->getDisplay(); + $_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay(); $this->response->setRequestStatus(false); - $this->response->addJSON('message', $message->getDisplay()); - $this->response->addHTML($message->getDisplay()); + $this->response->addJSON('message', $GLOBALS['message']->getDisplay()); + $this->response->addHTML($GLOBALS['message']->getDisplay()); return; } @@ -576,7 +583,7 @@ final class ImportController extends AbstractController // Do the real import $default_fk_check = ForeignKey::handleDisableCheckInit(); try { - $import_plugin->doImport($importHandle ?? null, $sql_data); + $queriesToBeExecuted = $import_plugin->doImport($importHandle ?? null); ForeignKey::handleDisableCheckCleanup($default_fk_check); } catch (Throwable $e) { ForeignKey::handleDisableCheckCleanup($default_fk_check); @@ -590,66 +597,66 @@ final class ImportController extends AbstractController } // Reset charset back, if we did some changes - if ($reset_charset) { - $this->dbi->query('SET CHARACTER SET ' . $charset_connection); - $this->dbi->setCollation($collation_connection); + if ($GLOBALS['reset_charset']) { + $this->dbi->query('SET CHARACTER SET ' . $GLOBALS['charset_connection']); + $this->dbi->setCollation($GLOBALS['collation_connection']); } // Show correct message if (! empty($id_bookmark) && $_POST['action_bookmark'] == 2) { - $message = Message::success(__('The bookmark has been deleted.')); - $display_query = $import_text; - $error = false; // unset error marker, it was used just to skip processing + $GLOBALS['message'] = Message::success(__('The bookmark has been deleted.')); + $GLOBALS['display_query'] = $GLOBALS['import_text']; + $GLOBALS['error'] = false; // unset error marker, it was used just to skip processing } elseif (! empty($id_bookmark) && $_POST['action_bookmark'] == 1) { - $message = Message::notice(__('Showing bookmark')); - } elseif ($finished && ! $error) { + $GLOBALS['message'] = Message::notice(__('Showing bookmark')); + } elseif ($GLOBALS['finished'] && ! $GLOBALS['error']) { // Do not display the query with message, we do it separately - $display_query = ';'; - if ($import_type !== 'query') { - $message = Message::success( + $GLOBALS['display_query'] = ';'; + if ($GLOBALS['import_type'] !== 'query') { + $GLOBALS['message'] = Message::success( '<em>' . _ngettext( 'Import has been successfully finished, %d query executed.', 'Import has been successfully finished, %d queries executed.', - $executed_queries + $GLOBALS['executed_queries'] ) . '</em>' ); - $message->addParam($executed_queries); + $GLOBALS['message']->addParam($GLOBALS['executed_queries']); - if (! empty($import_notice)) { - $message->addHtml($import_notice); + if (! empty($GLOBALS['import_notice'])) { + $GLOBALS['message']->addHtml($GLOBALS['import_notice']); } - if (! empty($local_import_file)) { - $message->addText('(' . $local_import_file . ')'); + if (! empty($GLOBALS['local_import_file'])) { + $GLOBALS['message']->addText('(' . $GLOBALS['local_import_file'] . ')'); } else { - $message->addText('(' . $_FILES['import_file']['name'] . ')'); + $GLOBALS['message']->addText('(' . $_FILES['import_file']['name'] . ')'); } } } // Did we hit timeout? Tell it user. - if ($timeout_passed) { - $urlParams['timeout_passed'] = '1'; - $urlParams['offset'] = $offset; - if (isset($local_import_file)) { - $urlParams['local_import_file'] = $local_import_file; + if ($GLOBALS['timeout_passed']) { + $GLOBALS['urlParams']['timeout_passed'] = '1'; + $GLOBALS['urlParams']['offset'] = $GLOBALS['offset']; + if (isset($GLOBALS['local_import_file'])) { + $GLOBALS['urlParams']['local_import_file'] = $GLOBALS['local_import_file']; } - $importUrl = $errorUrl = $goto . Url::getCommon($urlParams, '&'); + $importUrl = $GLOBALS['errorUrl'] = $GLOBALS['goto'] . Url::getCommon($GLOBALS['urlParams'], '&'); - $message = Message::error( + $GLOBALS['message'] = Message::error( __( 'Script timeout passed, if you want to finish import,' . ' please %sresubmit the same file%s and import will resume.' ) ); - $message->addParamHtml('<a href="' . $importUrl . '">'); - $message->addParamHtml('</a>'); + $GLOBALS['message']->addParamHtml('<a href="' . $importUrl . '">'); + $GLOBALS['message']->addParamHtml('</a>'); - if ($offset == 0 || (isset($original_skip) && $original_skip == $offset)) { - $message->addText( + if ($GLOBALS['offset'] == 0 || (isset($original_skip) && $original_skip == $GLOBALS['offset'])) { + $GLOBALS['message']->addText( __( 'However on last run no data has been parsed,' . ' this usually means phpMyAdmin won\'t be able to' @@ -661,63 +668,60 @@ final class ImportController extends AbstractController // if there is any message, copy it into $_SESSION as well, // so we can obtain it by AJAX call - if (isset($message)) { - $_SESSION['Import_message']['message'] = $message->getDisplay(); + if (isset($GLOBALS['message'])) { + $_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay(); } // Parse and analyze the query, for correct db and table name // in case of a query typed in the query window // (but if the query is too large, in case of an imported file, the parser // can choke on it so avoid parsing) - $sqlLength = mb_strlen($sql_query); - if ($sqlLength <= $cfg['MaxCharactersInDisplayedSQL']) { - [ - $analyzed_sql_results, - $db, - $table_from_sql, - ] = ParseAnalyze::sqlQuery($sql_query, $db); - - $reload = $analyzed_sql_results['reload']; - $offset = $analyzed_sql_results['offset']; - - if ($table != $table_from_sql && ! empty($table_from_sql)) { - $table = $table_from_sql; + $sqlLength = mb_strlen($GLOBALS['sql_query']); + if ($sqlLength <= $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { + [$statementInfo, $GLOBALS['db'], $table_from_sql] = ParseAnalyze::sqlQuery( + $GLOBALS['sql_query'], + $GLOBALS['db'] + ); + + $GLOBALS['reload'] = $statementInfo->reload; + $GLOBALS['offset'] = $statementInfo->offset; + + if ($GLOBALS['table'] != $table_from_sql && ! empty($table_from_sql)) { + $GLOBALS['table'] = $table_from_sql; } } // There was an error? - if (isset($my_die)) { - foreach ($my_die as $die) { - Generator::mysqlDie($die['error'], $die['sql'], false, $errorUrl, $error); + if (isset($GLOBALS['my_die'])) { + foreach ($GLOBALS['my_die'] as $die) { + Generator::mysqlDie($die['error'], $die['sql'], false, $GLOBALS['errorUrl'], $GLOBALS['error']); } } - if ($go_sql) { - if (! empty($sql_data) && ($sql_data['valid_queries'] > 1)) { + if ($GLOBALS['go_sql']) { + if ($queriesToBeExecuted !== []) { $_SESSION['is_multi_query'] = true; - $sql_queries = $sql_data['valid_sql']; } else { - $sql_queries = [$sql_query]; + $queriesToBeExecuted = [$GLOBALS['sql_query']]; } $html_output = ''; - foreach ($sql_queries as $sql_query) { + foreach ($queriesToBeExecuted as $GLOBALS['sql_query']) { // parse sql query - [ - $analyzed_sql_results, - $db, - $table_from_sql, - ] = ParseAnalyze::sqlQuery($sql_query, $db); + [$statementInfo, $GLOBALS['db'], $table_from_sql] = ParseAnalyze::sqlQuery( + $GLOBALS['sql_query'], + $GLOBALS['db'] + ); - $offset = $analyzed_sql_results['offset']; - $reload = $analyzed_sql_results['reload']; + $GLOBALS['offset'] = $statementInfo->offset; + $GLOBALS['reload'] = $statementInfo->reload; // Check if User is allowed to issue a 'DROP DATABASE' Statement if ( $this->sql->hasNoRightsToDropDatabase( - $analyzed_sql_results, - $cfg['AllowUserDropDatabase'], + $statementInfo, + $GLOBALS['cfg']['AllowUserDropDatabase'], $this->dbi->isSuperUser() ) ) { @@ -731,24 +735,24 @@ final class ImportController extends AbstractController return; } - if ($table != $table_from_sql && ! empty($table_from_sql)) { - $table = $table_from_sql; + if ($GLOBALS['table'] != $table_from_sql && ! empty($table_from_sql)) { + $GLOBALS['table'] = $table_from_sql; } $html_output .= $this->sql->executeQueryAndGetQueryResponse( - $analyzed_sql_results, // analyzed_sql_results + $statementInfo, false, // is_gotofile - $db, // db - $table, // table + $GLOBALS['db'], // db + $GLOBALS['table'], // table null, // find_real_end null, // sql_query_for_bookmark - see below null, // extra_data null, // message_to_show null, // sql_data - $goto, // goto + $GLOBALS['goto'], // goto null, // disp_query null, // disp_message - $sql_query, // sql_query + $GLOBALS['sql_query'], // sql_query null // complete_query ); } @@ -756,34 +760,34 @@ final class ImportController extends AbstractController // sql_query_for_bookmark is not included in Sql::executeQueryAndGetQueryResponse // since only one bookmark has to be added for all the queries submitted through // the SQL tab - if (! empty($_POST['bkm_label']) && ! empty($import_text)) { + if (! empty($_POST['bkm_label']) && ! empty($GLOBALS['import_text'])) { $relation = new Relation($this->dbi); $this->sql->storeTheQueryAsBookmark( $relation->getRelationParameters()->bookmarkFeature, - $db, - $cfg['Server']['user'], + $GLOBALS['db'], + $GLOBALS['cfg']['Server']['user'], $_POST['sql_query'], $_POST['bkm_label'], isset($_POST['bkm_replace']) ); } - $this->response->addJSON('ajax_reload', $ajax_reload); + $this->response->addJSON('ajax_reload', $GLOBALS['ajax_reload']); $this->response->addHTML($html_output); return; } - if ($result) { + if ($GLOBALS['result']) { // Save a Bookmark with more than one queries (if Bookmark label given). - if (! empty($_POST['bkm_label']) && ! empty($import_text)) { + if (! empty($_POST['bkm_label']) && ! empty($GLOBALS['import_text'])) { $relation = new Relation($this->dbi); $this->sql->storeTheQueryAsBookmark( $relation->getRelationParameters()->bookmarkFeature, - $db, - $cfg['Server']['user'], + $GLOBALS['db'], + $GLOBALS['cfg']['Server']['user'], $_POST['sql_query'], $_POST['bkm_label'], isset($_POST['bkm_replace']) @@ -791,18 +795,18 @@ final class ImportController extends AbstractController } $this->response->setRequestStatus(true); - $this->response->addJSON('message', Message::success($msg)); + $this->response->addJSON('message', Message::success($GLOBALS['msg'])); $this->response->addJSON( 'sql_query', - Generator::getMessage($msg, $sql_query, 'success') + Generator::getMessage($GLOBALS['msg'], $GLOBALS['sql_query'], 'success') ); - } elseif ($result === false) { + } elseif ($GLOBALS['result'] === false) { $this->response->setRequestStatus(false); - $this->response->addJSON('message', Message::error($msg)); + $this->response->addJSON('message', Message::error($GLOBALS['msg'])); } else { - $active_page = $goto; + $GLOBALS['active_page'] = $GLOBALS['goto']; /** @psalm-suppress UnresolvableInclude */ - include ROOT_PATH . $goto; + include ROOT_PATH . $GLOBALS['goto']; } // If there is request for ROLLBACK in the end. diff --git a/libraries/classes/Controllers/Import/SimulateDmlController.php b/libraries/classes/Controllers/Import/SimulateDmlController.php index 0d79f2185e..37fffc0fe6 100644 --- a/libraries/classes/Controllers/Import/SimulateDmlController.php +++ b/libraries/classes/Controllers/Import/SimulateDmlController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Import; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import\SimulateDml; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; @@ -32,7 +33,7 @@ final class SimulateDmlController extends AbstractController $this->simulateDml = $simulateDml; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $error = ''; $errorMsg = __('Only single-table UPDATE and DELETE queries can be simulated.'); diff --git a/libraries/classes/Controllers/Import/StatusController.php b/libraries/classes/Controllers/Import/StatusController.php index 8813e77f68..2d461e218c 100644 --- a/libraries/classes/Controllers/Import/StatusController.php +++ b/libraries/classes/Controllers/Import/StatusController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Import; use PhpMyAdmin\Core; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Message; use PhpMyAdmin\Template; @@ -30,14 +31,17 @@ class StatusController $this->template = $template; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $SESSION_KEY, $upload_id, $plugins, $timestamp; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; + $GLOBALS['upload_id'] = $GLOBALS['upload_id'] ?? null; + $GLOBALS['plugins'] = $GLOBALS['plugins'] ?? null; + $GLOBALS['timestamp'] = $GLOBALS['timestamp'] ?? null; [ - $SESSION_KEY, - $upload_id, - $plugins, + $GLOBALS['SESSION_KEY'], + $GLOBALS['upload_id'], + $GLOBALS['plugins'], ] = Ajax::uploadProgressSetup(); // $_GET["message"] is used for asking for an import message @@ -51,7 +55,7 @@ class StatusController usleep(300000); $maximumTime = ini_get('max_execution_time'); - $timestamp = time(); + $GLOBALS['timestamp'] = time(); // wait until message is available while (($_SESSION['Import_message']['message'] ?? null) == null) { // close session before sleeping @@ -61,7 +65,7 @@ class StatusController // reopen session session_start(); - if (time() - $timestamp > $maximumTime) { + if (time() - $GLOBALS['timestamp'] > $maximumTime) { $_SESSION['Import_message']['message'] = Message::error( __('Could not load the progress of the import.') )->getDisplay(); diff --git a/libraries/classes/Controllers/JavaScriptMessagesController.php b/libraries/classes/Controllers/JavaScriptMessagesController.php index 3444db0e08..952b7671aa 100644 --- a/libraries/classes/Controllers/JavaScriptMessagesController.php +++ b/libraries/classes/Controllers/JavaScriptMessagesController.php @@ -4,11 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; -use PhpMyAdmin\Theme; - use function __; use function _pgettext; use function json_encode; +use function json_last_error_msg; /** * Exporting of translated messages from PHP to JavaScript. @@ -16,27 +15,32 @@ use function json_encode; final class JavaScriptMessagesController { /** @var array<string, string> */ - private $messages = []; + private $messages; public function __construct() { - $this->setMessages(); + $this->messages = $this->setMessages(); } public function __invoke(): void { - echo 'var Messages = ' . json_encode($this->messages) . ';'; - } + $messages = json_encode($this->messages); + if ($messages === false) { + echo '// Error when encoding messages: ' . json_last_error_msg(); - private function setMessages(): void - { - global $cfg, $theme; + return; + } - $ajaxClockSmallGifPath = $theme instanceof Theme ? $theme->getImgPath('ajax_clock_small.gif') : ''; + echo 'window.Messages = ' . $messages . ';'; + } - $this->messages = [ + /** + * @return array<string, string> + */ + private function setMessages(): array + { + return [ /* For confirmations */ - 'strConfirm' => __('Confirm'), 'strDoYouReally' => __('Do you really want to execute "%s"?'), 'strDropDatabaseStrongWarning' => __('You are about to DESTROY a complete database!'), 'strDatabaseRenameToSameName' => __( @@ -578,19 +582,11 @@ final class JavaScriptMessagesController 'dropImportDropFiles' => __('Drop files here'), 'dropImportSelectDB' => __('Select database first'), - // this approach does not work when the parameter is changed via user prefs - 'strGridEditFeatureHint' => $cfg['GridEditing'] === 'double-click' - ? __('You can also edit most values<br>by double-clicking directly on them.') - : ($cfg['GridEditing'] === 'click' - ? __('You can also edit most values<br>by clicking directly on them.') - : ''), - 'strGoToLink' => __('Go to link:'), /* password generation */ 'strGeneratePassword' => __('Generate password'), 'strGenerate' => __('Generate'), - 'strChangePassword' => __('Change password'), /* navigation tabs */ 'strMore' => __('More'), @@ -640,9 +636,7 @@ final class JavaScriptMessagesController . '<br>' . __('As per your settings, they are being submitted currently, please be patient.') . '<br>' - . '<img src="' - . $ajaxClockSmallGifPath - . '" width="16" height="16" alt="ajax clock">' + . '<img src="themes/dot.gif" alt="" class="icon ic_ajax_clock_small">' . '</div>', 'strCopyColumnSuccess' => __('Column name successfully copied to clipboard!'), 'strCopyColumnFailure' => __('Column name copying to clipboard failed!'), @@ -704,6 +698,148 @@ final class JavaScriptMessagesController 'strHide' => __('Hide'), 'strShow' => __('Show'), 'strStructure' => __('Structure'), + + /* DateTime Picker */ + // l10n: Month name + 'strMonthNameJan' => __('January'), + // l10n: Month name + 'strMonthNameFeb' => __('February'), + // l10n: Month name + 'strMonthNameMar' => __('March'), + // l10n: Month name + 'strMonthNameApr' => __('April'), + // l10n: Month name + 'strMonthNameMay' => __('May'), + // l10n: Month name + 'strMonthNameJun' => __('June'), + // l10n: Month name + 'strMonthNameJul' => __('July'), + // l10n: Month name + 'strMonthNameAug' => __('August'), + // l10n: Month name + 'strMonthNameSep' => __('September'), + // l10n: Month name + 'strMonthNameOct' => __('October'), + // l10n: Month name + 'strMonthNameNov' => __('November'), + // l10n: Month name + 'strMonthNameDec' => __('December'), + /* l10n: Short month name for January */ + 'strMonthNameJanShort' => __('Jan'), + /* l10n: Short month name for February */ + 'strMonthNameFebShort' => __('Feb'), + /* l10n: Short month name for March */ + 'strMonthNameMarShort' => __('Mar'), + /* l10n: Short month name for April */ + 'strMonthNameAprShort' => __('Apr'), + /* l10n: Short month name for May */ + 'strMonthNameMayShort' => __('May'), + /* l10n: Short month name for June */ + 'strMonthNameJunShort' => __('Jun'), + /* l10n: Short month name for July */ + 'strMonthNameJulShort' => __('Jul'), + /* l10n: Short month name for August */ + 'strMonthNameAugShort' => __('Aug'), + /* l10n: Short month name for September */ + 'strMonthNameSepShort' => __('Sep'), + /* l10n: Short month name for October */ + 'strMonthNameOctShort' => __('Oct'), + /* l10n: Short month name for November */ + 'strMonthNameNovShort' => __('Nov'), + /* l10n: Short month name for December */ + 'strMonthNameDecShort' => __('Dec'), + /* l10n: Week day name */ + 'strDayNameSun' => __('Sunday'), + /* l10n: Week day name */ + 'strDayNameMon' => __('Monday'), + /* l10n: Week day name */ + 'strDayNameTue' => __('Tuesday'), + /* l10n: Week day name */ + 'strDayNameWed' => __('Wednesday'), + /* l10n: Week day name */ + 'strDayNameThu' => __('Thursday'), + /* l10n: Week day name */ + 'strDayNameFri' => __('Friday'), + /* l10n: Week day name */ + 'strDayNameSat' => __('Saturday'), + /* l10n: Short week day name for Sunday */ + 'strDayNameSunShort' => __('Sun'), + /* l10n: Short week day name for Monday */ + 'strDayNameMonShort' => __('Mon'), + /* l10n: Short week day name for Tuesday */ + 'strDayNameTueShort' => __('Tue'), + /* l10n: Short week day name for Wednesday */ + 'strDayNameWedShort' => __('Wed'), + /* l10n: Short week day name for Thursday */ + 'strDayNameThuShort' => __('Thu'), + /* l10n: Short week day name for Friday */ + 'strDayNameFriShort' => __('Fri'), + /* l10n: Short week day name for Saturday */ + 'strDayNameSatShort' => __('Sat'), + /* l10n: Minimal week day name for Sunday */ + 'strDayNameSunMin' => __('Su'), + /* l10n: Minimal week day name for Monday */ + 'strDayNameMonMin' => __('Mo'), + /* l10n: Minimal week day name for Tuesday */ + 'strDayNameTueMin' => __('Tu'), + /* l10n: Minimal week day name for Wednesday */ + 'strDayNameWedMin' => __('We'), + /* l10n: Minimal week day name for Thursday */ + 'strDayNameThuMin' => __('Th'), + /* l10n: Minimal week day name for Friday */ + 'strDayNameFriMin' => __('Fr'), + /* l10n: Minimal week day name for Saturday */ + 'strDayNameSatMin' => __('Sa'), + /* l10n: Column header for week of the year in calendar */ + 'strWeekHeader' => __('Wk'), + // phpcs:ignore Generic.Files.LineLength.TooLong + /* l10n: The month-year order in a calendar. Do not translate! Use either "calendar-month-year" or "calendar-year-month". */ + 'strMonthAfterYear' => __('calendar-month-year'), + /* l10n: Year suffix for calendar, "none" is empty. */ + 'strYearSuffix' => __('none'), + /* l10n: A specific point in the day, as shown on a clock. */ + 'strCalendarTime' => __('Time'), + /* l10n: Period of time. */ + 'strCalendarHour' => __('Hour'), + /* l10n: Period of time. */ + 'strCalendarMinute' => __('Minute'), + /* l10n: Period of time. */ + 'strCalendarSecond' => __('Second'), + /* l10n: Display text for calendar close link */ + 'strCalendarClose' => __('Done'), + /* l10n: Previous month. Display text for previous month link in calendar */ + 'strCalendarPrevious' => __('Prev'), + /* l10n: Next month. Display text for next month link in calendar */ + 'strCalendarNext' => __('Next'), + /* l10n: Display text for current month link in calendar */ + 'strCalendarCurrent' => __('Today'), + + /* Validator */ + 'strValidatorRequired' => __('This field is required'), + 'strValidatorRemote' => __('Please fix this field'), + 'strValidatorEmail' => __('Please enter a valid email address'), + 'strValidatorUrl' => __('Please enter a valid URL'), + 'strValidatorDate' => __('Please enter a valid date'), + 'strValidatorDateIso' => __('Please enter a valid date ( ISO )'), + 'strValidatorNumber' => __('Please enter a valid number'), + 'strValidatorCreditCard' => __('Please enter a valid credit card number'), + 'strValidatorDigits' => __('Please enter only digits'), + 'strValidatorEqualTo' => __('Please enter the same value again'), + 'strValidatorMaxLength' => __('Please enter no more than {0} characters'), + 'strValidatorMinLength' => __('Please enter at least {0} characters'), + 'strValidatorRangeLength' => __('Please enter a value between {0} and {1} characters long'), + 'strValidatorRange' => __('Please enter a value between {0} and {1}'), + 'strValidatorMax' => __('Please enter a value less than or equal to {0}'), + 'strValidatorMin' => __('Please enter a value greater than or equal to {0}'), + 'strValidationFunctionForDateTime' => __('Please enter a valid date or time'), + 'strValidationFunctionForHex' => __('Please enter a valid HEX input'), + /* l10n: To validate the usage of a MD5 function on the column */ + 'strValidationFunctionForMd5' => __('This column can not contain a 32 chars value'), + /* l10n: To validate the usage of an AES_ENCRYPT/DES_ENCRYPT function on the column */ + 'strValidationFunctionForAesDesEncrypt' => __( + 'These functions are meant to return a binary result; to avoid inconsistent results you should store' + . ' it in a BINARY, VARBINARY, or BLOB column.' + ), ]; } } diff --git a/libraries/classes/Controllers/LicenseController.php b/libraries/classes/Controllers/LicenseController.php index 9763af8684..ca6b9b0e7d 100644 --- a/libraries/classes/Controllers/LicenseController.php +++ b/libraries/classes/Controllers/LicenseController.php @@ -7,6 +7,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; + use function __; use function is_readable; use function printf; @@ -17,7 +19,7 @@ use function readfile; */ class LicenseController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->response->disable(); $this->response->header('Content-type: text/plain; charset=utf-8'); diff --git a/libraries/classes/Controllers/LintController.php b/libraries/classes/Controllers/LintController.php index 52790c17e6..f25651ed42 100644 --- a/libraries/classes/Controllers/LintController.php +++ b/libraries/classes/Controllers/LintController.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Linter; use function json_encode; @@ -17,7 +18,7 @@ use function json_encode; */ class LintController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $params = [ 'sql_query' => $_POST['sql_query'] ?? null, diff --git a/libraries/classes/Controllers/LogoutController.php b/libraries/classes/Controllers/LogoutController.php index 5050e42d1b..1640967d5d 100644 --- a/libraries/classes/Controllers/LogoutController.php +++ b/libraries/classes/Controllers/LogoutController.php @@ -5,19 +5,21 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; +use PhpMyAdmin\Http\ServerRequest; class LogoutController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $auth_plugin, $token_mismatch; + $GLOBALS['auth_plugin'] = $GLOBALS['auth_plugin'] ?? null; + $GLOBALS['token_mismatch'] = $GLOBALS['token_mismatch'] ?? null; - if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST' || $token_mismatch) { + if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST' || $GLOBALS['token_mismatch']) { Core::sendHeaderLocation('./index.php?route=/'); return; } - $auth_plugin->logOut(); + $GLOBALS['auth_plugin']->logOut(); } } diff --git a/libraries/classes/Controllers/NavigationController.php b/libraries/classes/Controllers/NavigationController.php index 5b79c87524..5dc0af3271 100644 --- a/libraries/classes/Controllers/NavigationController.php +++ b/libraries/classes/Controllers/NavigationController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Navigation\Navigation; use PhpMyAdmin\ResponseRenderer; @@ -38,7 +39,7 @@ class NavigationController extends AbstractController $this->relation = $relation; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! $this->response->isAjax()) { $this->response->addHTML( diff --git a/libraries/classes/Controllers/Normalization/AddNewPrimaryController.php b/libraries/classes/Controllers/Normalization/AddNewPrimaryController.php new file mode 100644 index 0000000000..bbbdd9976c --- /dev/null +++ b/libraries/classes/Controllers/Normalization/AddNewPrimaryController.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; +use PhpMyAdmin\Url; + +final class AddNewPrimaryController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $num_fields = 1; + $columnMeta = [ + 'Field' => $GLOBALS['table'] . '_id', + 'Extra' => 'auto_increment', + ]; + $html = $this->normalization->getHtmlForCreateNewColumn( + $num_fields, + $GLOBALS['db'], + $GLOBALS['table'], + $columnMeta + ); + $html .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/CreateNewColumnController.php b/libraries/classes/Controllers/Normalization/CreateNewColumnController.php new file mode 100644 index 0000000000..ae03dc1d00 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/CreateNewColumnController.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; +use PhpMyAdmin\Url; + +use function intval; +use function min; + +final class CreateNewColumnController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $num_fields = min(4096, intval($_POST['numFields'])); + $html = $this->normalization->getHtmlForCreateNewColumn($num_fields, $GLOBALS['db'], $GLOBALS['table']); + $html .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/FirstNormalForm/FirstStepController.php b/libraries/classes/Controllers/Normalization/FirstNormalForm/FirstStepController.php new file mode 100644 index 0000000000..025760d602 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/FirstNormalForm/FirstStepController.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\FirstNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function in_array; + +final class FirstStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $this->addScriptFiles(['normalization.js', 'vendor/jquery/jquery.uitablefilter.js']); + + $normalForm = '1nf'; + if (isset($_POST['normalizeTo']) && in_array($_POST['normalizeTo'], ['1nf', '2nf', '3nf'])) { + $normalForm = $_POST['normalizeTo']; + } + + $html = $this->normalization->getHtmlFor1NFStep1($GLOBALS['db'], $GLOBALS['table'], $normalForm); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/FirstNormalForm/FourthStepController.php b/libraries/classes/Controllers/Normalization/FirstNormalForm/FourthStepController.php new file mode 100644 index 0000000000..b7e18b9eee --- /dev/null +++ b/libraries/classes/Controllers/Normalization/FirstNormalForm/FourthStepController.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\FirstNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class FourthStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $res = $this->normalization->getHtmlContentsFor1NFStep4($GLOBALS['db'], $GLOBALS['table']); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/FirstNormalForm/SecondStepController.php b/libraries/classes/Controllers/Normalization/FirstNormalForm/SecondStepController.php new file mode 100644 index 0000000000..630f117182 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/FirstNormalForm/SecondStepController.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\FirstNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class SecondStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $res = $this->normalization->getHtmlContentsFor1NFStep2($GLOBALS['db'], $GLOBALS['table']); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/FirstNormalForm/ThirdStepController.php b/libraries/classes/Controllers/Normalization/FirstNormalForm/ThirdStepController.php new file mode 100644 index 0000000000..068a154d93 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/FirstNormalForm/ThirdStepController.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\FirstNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class ThirdStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $res = $this->normalization->getHtmlContentsFor1NFStep3($GLOBALS['db'], $GLOBALS['table']); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/GetColumnsController.php b/libraries/classes/Controllers/Normalization/GetColumnsController.php new file mode 100644 index 0000000000..f9d6e333b6 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/GetColumnsController.php @@ -0,0 +1,39 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function __; +use function _pgettext; + +final class GetColumnsController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $html = '<option selected disabled>' . __('Select one…') . '</option>' + . '<option value="no_such_col">' . __('No such column') . '</option>'; + //get column whose datatype falls under string category + $html .= $this->normalization->getHtmlForColumnsList( + $GLOBALS['db'], + $GLOBALS['table'], + _pgettext('string types', 'String') + ); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/MainController.php b/libraries/classes/Controllers/Normalization/MainController.php new file mode 100644 index 0000000000..91bde1300b --- /dev/null +++ b/libraries/classes/Controllers/Normalization/MainController.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; + +/** + * Normalization process (temporarily specific to 1NF). + */ +class MainController extends AbstractController +{ + public function __invoke(ServerRequest $request): void + { + $this->addScriptFiles(['normalization.js', 'vendor/jquery/jquery.uitablefilter.js']); + $this->render('table/normalization/normalization', [ + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + ]); + } +} diff --git a/libraries/classes/Controllers/Normalization/MoveRepeatingGroup.php b/libraries/classes/Controllers/Normalization/MoveRepeatingGroup.php new file mode 100644 index 0000000000..f308d9a1e0 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/MoveRepeatingGroup.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class MoveRepeatingGroup extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $repeatingColumns = $_POST['repeatingColumns']; + $newTable = $_POST['newTable']; + $newColumn = $_POST['newColumn']; + $primary_columns = $_POST['primary_columns']; + $res = $this->normalization->moveRepeatingGroup( + $repeatingColumns, + $primary_columns, + $newTable, + $newColumn, + $GLOBALS['table'], + $GLOBALS['db'] + ); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/PartialDependenciesController.php b/libraries/classes/Controllers/Normalization/PartialDependenciesController.php new file mode 100644 index 0000000000..a847ef6832 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/PartialDependenciesController.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class PartialDependenciesController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $html = $this->normalization->findPartialDependencies($GLOBALS['table'], $GLOBALS['db']); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/SecondNormalForm/CreateNewTablesController.php b/libraries/classes/Controllers/Normalization/SecondNormalForm/CreateNewTablesController.php new file mode 100644 index 0000000000..2be037c58d --- /dev/null +++ b/libraries/classes/Controllers/Normalization/SecondNormalForm/CreateNewTablesController.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\SecondNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function json_decode; + +final class CreateNewTablesController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $partialDependencies = json_decode($_POST['pd'], true); + $tablesName = json_decode($_POST['newTablesName']); + $res = $this->normalization->createNewTablesFor2NF( + $partialDependencies, + $tablesName, + $GLOBALS['table'], + $GLOBALS['db'] + ); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/SecondNormalForm/FirstStepController.php b/libraries/classes/Controllers/Normalization/SecondNormalForm/FirstStepController.php new file mode 100644 index 0000000000..e0f59b6c90 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/SecondNormalForm/FirstStepController.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\SecondNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class FirstStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $res = $this->normalization->getHtmlFor2NFstep1($GLOBALS['db'], $GLOBALS['table']); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/SecondNormalForm/NewTablesController.php b/libraries/classes/Controllers/Normalization/SecondNormalForm/NewTablesController.php new file mode 100644 index 0000000000..07232fa380 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/SecondNormalForm/NewTablesController.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\SecondNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function json_decode; + +final class NewTablesController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $partialDependencies = json_decode($_POST['pd'], true); + $html = $this->normalization->getHtmlForNewTables2NF($partialDependencies, $GLOBALS['table']); + $this->response->addHTML($html); + } +} diff --git a/libraries/classes/Controllers/Normalization/ThirdNormalForm/CreateNewTablesController.php b/libraries/classes/Controllers/Normalization/ThirdNormalForm/CreateNewTablesController.php new file mode 100644 index 0000000000..bd3e0b2c4a --- /dev/null +++ b/libraries/classes/Controllers/Normalization/ThirdNormalForm/CreateNewTablesController.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\ThirdNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function json_decode; + +final class CreateNewTablesController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $newtables = json_decode($_POST['newTables'], true); + $res = $this->normalization->createNewTablesFor3NF($newtables, $GLOBALS['db']); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/ThirdNormalForm/FirstStepController.php b/libraries/classes/Controllers/Normalization/ThirdNormalForm/FirstStepController.php new file mode 100644 index 0000000000..5b50da6a87 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/ThirdNormalForm/FirstStepController.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\ThirdNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +final class FirstStepController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $tables = $_POST['tables']; + $res = $this->normalization->getHtmlFor3NFstep1($GLOBALS['db'], $tables); + $this->response->addJSON($res); + } +} diff --git a/libraries/classes/Controllers/Normalization/ThirdNormalForm/NewTablesController.php b/libraries/classes/Controllers/Normalization/ThirdNormalForm/NewTablesController.php new file mode 100644 index 0000000000..1717a29f39 --- /dev/null +++ b/libraries/classes/Controllers/Normalization/ThirdNormalForm/NewTablesController.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Controllers\Normalization\ThirdNormalForm; + +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Normalization; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; + +use function json_decode; + +final class NewTablesController extends AbstractController +{ + /** @var Normalization */ + private $normalization; + + public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) + { + parent::__construct($response, $template); + $this->normalization = $normalization; + } + + public function __invoke(ServerRequest $request): void + { + $dependencies = json_decode($_POST['pd']); + $tables = json_decode($_POST['tables'], true); + $newTables = $this->normalization->getHtmlForNewTables3NF($dependencies, $tables, $GLOBALS['db']); + $this->response->addJSON($newTables); + } +} diff --git a/libraries/classes/Controllers/NormalizationController.php b/libraries/classes/Controllers/NormalizationController.php deleted file mode 100644 index 07625d661a..0000000000 --- a/libraries/classes/Controllers/NormalizationController.php +++ /dev/null @@ -1,166 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace PhpMyAdmin\Controllers; - -use PhpMyAdmin\Core; -use PhpMyAdmin\Normalization; -use PhpMyAdmin\ResponseRenderer; -use PhpMyAdmin\Template; -use PhpMyAdmin\Url; - -use function __; -use function _pgettext; -use function in_array; -use function intval; -use function json_decode; -use function json_encode; -use function min; - -/** - * Normalization process (temporarily specific to 1NF). - */ -class NormalizationController extends AbstractController -{ - /** @var Normalization */ - private $normalization; - - public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization) - { - parent::__construct($response, $template); - $this->normalization = $normalization; - } - - public function __invoke(): void - { - global $db, $table; - - if (isset($_POST['getColumns'])) { - $html = '<option selected disabled>' . __('Select one…') . '</option>' - . '<option value="no_such_col">' . __('No such column') . '</option>'; - //get column whose datatype falls under string category - $html .= $this->normalization->getHtmlForColumnsList( - $db, - $table, - _pgettext('string types', 'String') - ); - echo $html; - - return; - } - - if (isset($_POST['splitColumn'])) { - $num_fields = min(4096, intval($_POST['numFields'])); - $html = $this->normalization->getHtmlForCreateNewColumn($num_fields, $db, $table); - $html .= Url::getHiddenInputs($db, $table); - echo $html; - - return; - } - - if (isset($_POST['addNewPrimary'])) { - $num_fields = 1; - $columnMeta = [ - 'Field' => $table . '_id', - 'Extra' => 'auto_increment', - ]; - $html = $this->normalization->getHtmlForCreateNewColumn($num_fields, $db, $table, $columnMeta); - $html .= Url::getHiddenInputs($db, $table); - echo $html; - - return; - } - - if (isset($_POST['findPdl'])) { - $html = $this->normalization->findPartialDependencies($table, $db); - echo $html; - - return; - } - - if (isset($_POST['getNewTables2NF'])) { - $partialDependencies = json_decode($_POST['pd'], true); - $html = $this->normalization->getHtmlForNewTables2NF($partialDependencies, $table); - echo $html; - - return; - } - - if (isset($_POST['getNewTables3NF'])) { - $dependencies = json_decode($_POST['pd']); - $tables = json_decode($_POST['tables'], true); - $newTables = $this->normalization->getHtmlForNewTables3NF($dependencies, $tables, $db); - $this->response->disable(); - Core::headerJSON(); - echo json_encode($newTables); - - return; - } - - $this->addScriptFiles(['normalization.js', 'vendor/jquery/jquery.uitablefilter.js']); - - $normalForm = '1nf'; - if (isset($_POST['normalizeTo']) && in_array($_POST['normalizeTo'], ['1nf', '2nf', '3nf'])) { - $normalForm = $_POST['normalizeTo']; - } - - if (isset($_POST['createNewTables2NF'])) { - $partialDependencies = json_decode($_POST['pd'], true); - $tablesName = json_decode($_POST['newTablesName']); - $res = $this->normalization->createNewTablesFor2NF($partialDependencies, $tablesName, $table, $db); - $this->response->addJSON($res); - - return; - } - - if (isset($_POST['createNewTables3NF'])) { - $newtables = json_decode($_POST['newTables'], true); - $res = $this->normalization->createNewTablesFor3NF($newtables, $db); - $this->response->addJSON($res); - - return; - } - - if (isset($_POST['repeatingColumns'])) { - $repeatingColumns = $_POST['repeatingColumns']; - $newTable = $_POST['newTable']; - $newColumn = $_POST['newColumn']; - $primary_columns = $_POST['primary_columns']; - $res = $this->normalization->moveRepeatingGroup( - $repeatingColumns, - $primary_columns, - $newTable, - $newColumn, - $table, - $db - ); - $this->response->addJSON($res); - - return; - } - - if (isset($_POST['step1'])) { - $html = $this->normalization->getHtmlFor1NFStep1($db, $table, $normalForm); - $this->response->addHTML($html); - } elseif (isset($_POST['step2'])) { - $res = $this->normalization->getHtmlContentsFor1NFStep2($db, $table); - $this->response->addJSON($res); - } elseif (isset($_POST['step3'])) { - $res = $this->normalization->getHtmlContentsFor1NFStep3($db, $table); - $this->response->addJSON($res); - } elseif (isset($_POST['step4'])) { - $res = $this->normalization->getHtmlContentsFor1NFStep4($db, $table); - $this->response->addJSON($res); - } elseif (isset($_POST['step']) && $_POST['step'] == '2.1') { - $res = $this->normalization->getHtmlFor2NFstep1($db, $table); - $this->response->addJSON($res); - } elseif (isset($_POST['step']) && $_POST['step'] == '3.1') { - $tables = $_POST['tables']; - $res = $this->normalization->getHtmlFor3NFstep1($db, $tables); - $this->response->addJSON($res); - } else { - $this->response->addHTML($this->normalization->getHtmlForNormalizeTable()); - } - } -} diff --git a/libraries/classes/Controllers/PhpInfoController.php b/libraries/classes/Controllers/PhpInfoController.php index b1924c5adc..16a9482bb0 100644 --- a/libraries/classes/Controllers/PhpInfoController.php +++ b/libraries/classes/Controllers/PhpInfoController.php @@ -7,6 +7,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; + use function phpinfo; use const INFO_CONFIGURATION; @@ -18,14 +20,12 @@ use const INFO_MODULES; */ class PhpInfoController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg; - $this->response->disable(); $this->response->getHeader()->sendHttpHeaders(); - if (! $cfg['ShowPhpInfo']) { + if (! $GLOBALS['cfg']['ShowPhpInfo']) { return; } diff --git a/libraries/classes/Controllers/Preferences/ExportController.php b/libraries/classes/Controllers/Preferences/ExportController.php index 3acdf6c372..438c0810a8 100644 --- a/libraries/classes/Controllers/Preferences/ExportController.php +++ b/libraries/classes/Controllers/Preferences/ExportController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\ExportForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class ExportController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new ExportForm($cf, 1); + $formDisplay = new ExportForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class ExportController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/export', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/export', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class ExportController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class ExportController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/export'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/FeaturesController.php b/libraries/classes/Controllers/Preferences/FeaturesController.php index 4fb7f2d3b0..d4a8872d15 100644 --- a/libraries/classes/Controllers/Preferences/FeaturesController.php +++ b/libraries/classes/Controllers/Preferences/FeaturesController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\FeaturesForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class FeaturesController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new FeaturesForm($cf, 1); + $formDisplay = new FeaturesForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class FeaturesController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/features', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/features', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class FeaturesController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class FeaturesController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/features'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/ImportController.php b/libraries/classes/Controllers/Preferences/ImportController.php index 2d4e59ebea..4a45ef60b1 100644 --- a/libraries/classes/Controllers/Preferences/ImportController.php +++ b/libraries/classes/Controllers/Preferences/ImportController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\ImportForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class ImportController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new ImportForm($cf, 1); + $formDisplay = new ImportForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class ImportController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/import', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/import', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class ImportController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class ImportController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/import'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/MainPanelController.php b/libraries/classes/Controllers/Preferences/MainPanelController.php index 95042886a4..428030bb78 100644 --- a/libraries/classes/Controllers/Preferences/MainPanelController.php +++ b/libraries/classes/Controllers/Preferences/MainPanelController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\MainForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class MainPanelController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new MainForm($cf, 1); + $formDisplay = new MainForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class MainPanelController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/main-panel', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/main-panel', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class MainPanelController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class MainPanelController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/main-panel'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/ManageController.php b/libraries/classes/Controllers/Preferences/ManageController.php index 6452e4746f..8ba5d5977e 100644 --- a/libraries/classes/Controllers/Preferences/ManageController.php +++ b/libraries/classes/Controllers/Preferences/ManageController.php @@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\File; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -64,20 +65,31 @@ class ManageController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cf, $error, $filename, $json, $lang; - global $new_config, $return_url, $form_display, $all_ok, $params, $query, $route; - - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); - - $error = ''; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['filename'] = $GLOBALS['filename'] ?? null; + $GLOBALS['json'] = $GLOBALS['json'] ?? null; + $GLOBALS['lang'] = $GLOBALS['lang'] ?? null; + $GLOBALS['new_config'] = $GLOBALS['new_config'] ?? null; + $GLOBALS['return_url'] = $GLOBALS['return_url'] ?? null; + $GLOBALS['form_display'] = $GLOBALS['form_display'] ?? null; + $GLOBALS['all_ok'] = $GLOBALS['all_ok'] ?? null; + $GLOBALS['params'] = $GLOBALS['params'] ?? null; + $GLOBALS['query'] = $GLOBALS['query'] ?? null; + + $route = $request->getRoute(); + + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); + + $GLOBALS['error'] = ''; if (isset($_POST['submit_export'], $_POST['export_type']) && $_POST['export_type'] === 'text_file') { // export to JSON file $this->response->disable(); - $filename = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.json'; - Core::downloadHeader($filename, 'application/json'); + $GLOBALS['filename'] = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.json'; + Core::downloadHeader($GLOBALS['filename'], 'application/json'); $settings = $this->userPreferences->load(); echo json_encode($settings['config_data'], JSON_PRETTY_PRINT); @@ -87,8 +99,8 @@ class ManageController extends AbstractController if (isset($_POST['submit_export'], $_POST['export_type']) && $_POST['export_type'] === 'php_file') { // export to JSON file $this->response->disable(); - $filename = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.php'; - Core::downloadHeader($filename, 'application/php'); + $GLOBALS['filename'] = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.php'; + Core::downloadHeader($GLOBALS['filename'], 'application/php'); $settings = $this->userPreferences->load(); echo '/* ' . __('phpMyAdmin configuration snippet') . " */\n\n"; echo '/* ' . __('Paste it to your config.inc.php') . " */\n\n"; @@ -110,7 +122,7 @@ class ManageController extends AbstractController if (isset($_POST['submit_import'])) { // load from JSON file - $json = ''; + $GLOBALS['json'] = ''; if ( isset($_POST['import_type'], $_FILES['import_file']) && $_POST['import_type'] === 'text_file' @@ -120,51 +132,51 @@ class ManageController extends AbstractController $importHandle = new File($_FILES['import_file']['tmp_name']); $importHandle->checkUploadedFile(); if ($importHandle->isError()) { - $error = $importHandle->getError(); + $GLOBALS['error'] = $importHandle->getError(); } else { // read JSON from uploaded file - $json = $importHandle->getRawContent(); + $GLOBALS['json'] = $importHandle->getRawContent(); } } else { // read from POST value (json) - $json = $_POST['json'] ?? null; + $GLOBALS['json'] = $_POST['json'] ?? null; } // hide header message $_SESSION['userprefs_autoload'] = true; - $configuration = json_decode($json, true); - $return_url = $_POST['return_url'] ?? null; + $configuration = json_decode($GLOBALS['json'], true); + $GLOBALS['return_url'] = $_POST['return_url'] ?? null; if (! is_array($configuration)) { - if (! isset($error)) { - $error = __('Could not import configuration'); + if (! isset($GLOBALS['error'])) { + $GLOBALS['error'] = __('Could not import configuration'); } } else { // sanitize input values: treat them as though // they came from HTTP POST request - $form_display = new UserFormList($cf); - $new_config = $cf->getFlatDefaultConfig(); + $GLOBALS['form_display'] = new UserFormList($GLOBALS['cf']); + $GLOBALS['new_config'] = $GLOBALS['cf']->getFlatDefaultConfig(); if (! empty($_POST['import_merge'])) { - $new_config = array_merge($new_config, $cf->getConfigArray()); + $GLOBALS['new_config'] = array_merge($GLOBALS['new_config'], $GLOBALS['cf']->getConfigArray()); } - $new_config = array_merge($new_config, $configuration); + $GLOBALS['new_config'] = array_merge($GLOBALS['new_config'], $configuration); $_POST_bak = $_POST; - foreach ($new_config as $k => $v) { + foreach ($GLOBALS['new_config'] as $k => $v) { $_POST[str_replace('/', '-', (string) $k)] = $v; } - $cf->resetConfigData(); - $all_ok = $form_display->process(true, false); - $all_ok = $all_ok && ! $form_display->hasErrors(); + $GLOBALS['cf']->resetConfigData(); + $GLOBALS['all_ok'] = $GLOBALS['form_display']->process(true, false); + $GLOBALS['all_ok'] = $GLOBALS['all_ok'] && ! $GLOBALS['form_display']->hasErrors(); $_POST = $_POST_bak; - if (! $all_ok && isset($_POST['fix_errors'])) { - $form_display->fixErrors(); - $all_ok = true; + if (! $GLOBALS['all_ok'] && isset($_POST['fix_errors'])) { + $GLOBALS['form_display']->fixErrors(); + $GLOBALS['all_ok'] = true; } - if (! $all_ok) { + if (! $GLOBALS['all_ok']) { // mimic original form and post json in a hidden field $relationParameters = $this->relation->getRelationParameters(); @@ -175,17 +187,17 @@ class ManageController extends AbstractController ]); echo $this->template->render('preferences/manage/error', [ - 'form_errors' => $form_display->displayErrors(), - 'json' => $json, + 'form_errors' => $GLOBALS['form_display']->displayErrors(), + 'json' => $GLOBALS['json'], 'import_merge' => $_POST['import_merge'] ?? null, - 'return_url' => $return_url, + 'return_url' => $GLOBALS['return_url'], ]); return; } // check for ThemeDefault - $params = []; + $GLOBALS['params'] = []; $tmanager = ThemeManager::getInstance(); if ( isset($configuration['ThemeDefault']) @@ -196,50 +208,50 @@ class ManageController extends AbstractController $tmanager->setThemeCookie(); } - if (isset($configuration['lang']) && $configuration['lang'] != $lang) { - $params['lang'] = $configuration['lang']; + if (isset($configuration['lang']) && $configuration['lang'] != $GLOBALS['lang']) { + $GLOBALS['params']['lang'] = $configuration['lang']; } // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); if ($result === true) { - if ($return_url) { - $query = Util::splitURLQuery($return_url); - $return_url = parse_url($return_url, PHP_URL_PATH); + if ($GLOBALS['return_url']) { + $GLOBALS['query'] = Util::splitURLQuery($GLOBALS['return_url']); + $GLOBALS['return_url'] = parse_url($GLOBALS['return_url'], PHP_URL_PATH); - foreach ($query as $q) { + foreach ($GLOBALS['query'] as $q) { $pos = mb_strpos($q, '='); $k = mb_substr($q, 0, (int) $pos); if ($k === 'token') { continue; } - $params[$k] = mb_substr($q, $pos + 1); + $GLOBALS['params'][$k] = mb_substr($q, $pos + 1); } } else { - $return_url = 'index.php?route=/preferences/manage'; + $GLOBALS['return_url'] = 'index.php?route=/preferences/manage'; } // reload config $this->config->loadUserPreferences(); - $this->userPreferences->redirect($return_url ?? '', $params); + $this->userPreferences->redirect($GLOBALS['return_url'] ?? '', $GLOBALS['params']); return; } - $error = $result; + $GLOBALS['error'] = $result; } } elseif (isset($_POST['submit_clear'])) { $result = $this->userPreferences->save([]); if ($result === true) { - $params = []; + $GLOBALS['params'] = []; $this->config->removeCookie('pma_collaction_connection'); $this->config->removeCookie('pma_lang'); - $this->userPreferences->redirect('index.php?route=/preferences/manage', $params); + $this->userPreferences->redirect('index.php?route=/preferences/manage', $GLOBALS['params']); return; } else { - $error = $result; + $GLOBALS['error'] = $result; } return; @@ -255,16 +267,16 @@ class ManageController extends AbstractController 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); - if ($error) { - if (! $error instanceof Message) { - $error = Message::error($error); + if ($GLOBALS['error']) { + if (! $GLOBALS['error'] instanceof Message) { + $GLOBALS['error'] = Message::error($GLOBALS['error']); } - $error->getDisplay(); + $GLOBALS['error']->getDisplay(); } echo $this->template->render('preferences/manage/main', [ - 'error' => $error, + 'error' => $GLOBALS['error'], 'max_upload_size' => $GLOBALS['config']->get('max_upload_size'), 'exists_setup_and_not_exists_config' => @file_exists(ROOT_PATH . 'setup/index.php') && ! @file_exists(CONFIG_FILE), diff --git a/libraries/classes/Controllers/Preferences/NavigationController.php b/libraries/classes/Controllers/Preferences/NavigationController.php index 64b9cc7b16..e6d3edc72f 100644 --- a/libraries/classes/Controllers/Preferences/NavigationController.php +++ b/libraries/classes/Controllers/Preferences/NavigationController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\NaviForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class NavigationController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new NaviForm($cf, 1); + $formDisplay = new NaviForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class NavigationController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/navigation', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/navigation', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class NavigationController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class NavigationController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/navigation'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/SqlController.php b/libraries/classes/Controllers/Preferences/SqlController.php index 78253e518f..ff5573277e 100644 --- a/libraries/classes/Controllers/Preferences/SqlController.php +++ b/libraries/classes/Controllers/Preferences/SqlController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\ConfigFile; use PhpMyAdmin\Config\Forms\User\SqlForm; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\TwoFactor; @@ -42,14 +43,18 @@ class SqlController extends AbstractController $this->config = $config; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $cf, $error, $tabHash, $hash, $server, $route; + $GLOBALS['cf'] = $GLOBALS['cf'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['tabHash'] = $GLOBALS['tabHash'] ?? null; + $GLOBALS['hash'] = $GLOBALS['hash'] ?? null; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; - $cf = new ConfigFile($this->config->baseSettings); - $this->userPreferences->pageInit($cf); + $GLOBALS['cf'] = new ConfigFile($this->config->baseSettings); + $this->userPreferences->pageInit($GLOBALS['cf']); - $formDisplay = new SqlForm($cf, 1); + $formDisplay = new SqlForm($GLOBALS['cf'], 1); if (isset($_POST['revert'])) { // revert erroneous fields to their default values @@ -59,25 +64,25 @@ class SqlController extends AbstractController return; } - $error = null; + $GLOBALS['error'] = null; if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) { // Load 2FA settings - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); // save settings - $result = $this->userPreferences->save($cf->getConfigArray()); + $result = $this->userPreferences->save($GLOBALS['cf']->getConfigArray()); // save back the 2FA setting only $twoFactor->save(); if ($result === true) { // reload config $this->config->loadUserPreferences(); - $tabHash = $_POST['tab_hash'] ?? null; - $hash = ltrim($tabHash, '#'); - $this->userPreferences->redirect('index.php?route=/preferences/sql', null, $hash); + $GLOBALS['tabHash'] = $_POST['tab_hash'] ?? null; + $GLOBALS['hash'] = ltrim($GLOBALS['tabHash'], '#'); + $this->userPreferences->redirect('index.php?route=/preferences/sql', null, $GLOBALS['hash']); return; } - $error = $result; + $GLOBALS['error'] = $result; } $this->addScriptFiles(['config.js']); @@ -85,7 +90,7 @@ class SqlController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); $this->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); @@ -95,13 +100,13 @@ class SqlController extends AbstractController } $this->render('preferences/forms/main', [ - 'error' => $error ? $error->getDisplay() : '', + 'error' => $GLOBALS['error'] ? $GLOBALS['error']->getDisplay() : '', 'has_errors' => $formDisplay->hasErrors(), 'errors' => $formErrors ?? null, 'form' => $formDisplay->getDisplay( true, Url::getFromRoute('/preferences/sql'), - ['server' => $server] + ['server' => $GLOBALS['server']] ), ]); diff --git a/libraries/classes/Controllers/Preferences/TwoFactorController.php b/libraries/classes/Controllers/Preferences/TwoFactorController.php index ccd7ea6638..7107d56ea5 100644 --- a/libraries/classes/Controllers/Preferences/TwoFactorController.php +++ b/libraries/classes/Controllers/Preferences/TwoFactorController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Preferences; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -25,19 +26,17 @@ class TwoFactorController extends AbstractController $this->relation = $relation; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $route; - $relationParameters = $this->relation->getRelationParameters(); echo $this->template->render('preferences/header', [ - 'route' => $route, + 'route' => $request->getRoute(), 'is_saved' => ! empty($_GET['saved']), 'has_config_storage' => $relationParameters->userPreferencesFeature !== null, ]); - $twoFactor = new TwoFactor($cfg['Server']['user']); + $twoFactor = new TwoFactor($GLOBALS['cfg']['Server']['user']); if (isset($_POST['2fa_remove'])) { if (! $twoFactor->check(true)) { diff --git a/libraries/classes/Controllers/RecentTablesListController.php b/libraries/classes/Controllers/RecentTablesListController.php index 485f686984..51cbce21c2 100644 --- a/libraries/classes/Controllers/RecentTablesListController.php +++ b/libraries/classes/Controllers/RecentTablesListController.php @@ -4,11 +4,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\RecentFavoriteTable; final class RecentTablesListController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! $this->response->isAjax()) { return; diff --git a/libraries/classes/Controllers/SchemaExportController.php b/libraries/classes/Controllers/SchemaExportController.php index f06306a950..96fb90d24c 100644 --- a/libraries/classes/Controllers/SchemaExportController.php +++ b/libraries/classes/Controllers/SchemaExportController.php @@ -4,8 +4,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Core; use PhpMyAdmin\Export; -use PhpMyAdmin\Util; +use PhpMyAdmin\Html\MySQLDocumentation; +use PhpMyAdmin\Http\ServerRequest; + +use function __; /** * Schema export handler @@ -20,10 +24,15 @@ class SchemaExportController $this->export = $export; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! isset($_POST['export_type'])) { - Util::checkParameters(['export_type']); + $errorMessage = __('Missing parameter:') . ' export_type' + . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) + . '[br]'; + Core::fatalError($errorMessage); + + return; } /** diff --git a/libraries/classes/Controllers/Server/BinlogController.php b/libraries/classes/Controllers/Server/BinlogController.php index ae29440a3f..598c1087e1 100644 --- a/libraries/classes/Controllers/Server/BinlogController.php +++ b/libraries/classes/Controllers/Server/BinlogController.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -41,16 +42,16 @@ class BinlogController extends AbstractController ); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'log' => $_POST['log'] ?? null, 'pos' => $_POST['pos'] ?? null, 'is_full_query' => $_POST['is_full_query'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); @@ -69,7 +70,7 @@ class BinlogController extends AbstractController $urlParams['is_full_query'] = 1; } - $sqlQuery = $this->getSqlQuery($params['log'] ?? '', $position, (int) $cfg['MaxRows']); + $sqlQuery = $this->getSqlQuery($params['log'] ?? '', $position, (int) $GLOBALS['cfg']['MaxRows']); $result = $this->dbi->query($sqlQuery); $numRows = $result->numRows(); @@ -79,8 +80,8 @@ class BinlogController extends AbstractController $nextParams = $urlParams; if ($position > 0) { $fullQueriesParams['pos'] = $position; - if ($position > $cfg['MaxRows']) { - $previousParams['pos'] = $position - $cfg['MaxRows']; + if ($position > $GLOBALS['cfg']['MaxRows']) { + $previousParams['pos'] = $position - $GLOBALS['cfg']['MaxRows']; } } @@ -89,8 +90,8 @@ class BinlogController extends AbstractController unset($fullQueriesParams['is_full_query']); } - if ($numRows >= $cfg['MaxRows']) { - $nextParams['pos'] = $position + $cfg['MaxRows']; + if ($numRows >= $GLOBALS['cfg']['MaxRows']) { + $nextParams['pos'] = $position + $GLOBALS['cfg']['MaxRows']; } $values = $result->fetchAllAssoc(); @@ -102,7 +103,7 @@ class BinlogController extends AbstractController 'sql_message' => Generator::getMessage(Message::success(), $sqlQuery), 'values' => $values, 'has_previous' => $position > 0, - 'has_next' => $numRows >= $cfg['MaxRows'], + 'has_next' => $numRows >= $GLOBALS['cfg']['MaxRows'], 'previous_params' => $previousParams, 'full_queries_params' => $fullQueriesParams, 'next_params' => $nextParams, diff --git a/libraries/classes/Controllers/Server/CollationsController.php b/libraries/classes/Controllers/Server/CollationsController.php index 6e99068324..7528be3254 100644 --- a/libraries/classes/Controllers/Server/CollationsController.php +++ b/libraries/classes/Controllers/Server/CollationsController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Charsets\Charset; use PhpMyAdmin\Charsets\Collation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -38,20 +39,16 @@ class CollationsController extends AbstractController ?array $charsets = null, ?array $collations = null ) { - global $cfg; - parent::__construct($response, $template); $this->dbi = $dbi; - $this->charsets = $charsets ?? Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $this->collations = $collations ?? Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); + $this->charsets = $charsets ?? Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); + $this->collations = $collations ?? Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Databases/CreateController.php b/libraries/classes/Controllers/Server/Databases/CreateController.php index c130e9b00e..747ce63b8a 100644 --- a/libraries/classes/Controllers/Server/Databases/CreateController.php +++ b/libraries/classes/Controllers/Server/Databases/CreateController.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Charsets; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -32,10 +33,8 @@ final class CreateController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db; - $params = [ 'new_db' => $_POST['new_db'] ?? null, 'db_collation' => $_POST['db_collation'] ?? null, @@ -58,8 +57,8 @@ final class CreateController extends AbstractController $sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']); if (! empty($params['db_collation'])) { [$databaseCharset] = explode('_', $params['db_collation']); - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); + $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); if ( array_key_exists($databaseCharset, $charsets) && array_key_exists($params['db_collation'], $collations[$databaseCharset]) @@ -75,19 +74,19 @@ final class CreateController extends AbstractController if (! $result) { // avoid displaying the not-created db name in header or navi panel - $db = ''; + $GLOBALS['db'] = ''; $message = Message::rawError($this->dbi->getError()); $json = ['message' => $message]; $this->response->setRequestStatus(false); } else { - $db = $params['new_db']; + $GLOBALS['db'] = $params['new_db']; $message = Message::success(__('Database %1$s has been created.')); $message->addParam($params['new_db']); - $scriptName = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); + $scriptName = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $json = [ 'message' => $message, diff --git a/libraries/classes/Controllers/Server/Databases/DestroyController.php b/libraries/classes/Controllers/Server/Databases/DestroyController.php index 915f560031..d69d30d071 100644 --- a/libraries/classes/Controllers/Server/Databases/DestroyController.php +++ b/libraries/classes/Controllers/Server/Databases/DestroyController.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Controllers\Server\Databases; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -43,15 +44,18 @@ final class DestroyController extends AbstractController $this->relationCleanup = $relationCleanup; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $selected, $errorUrl, $cfg, $dblist, $reload; + $GLOBALS['selected'] = $GLOBALS['selected'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['dblist'] = $GLOBALS['dblist'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; $selected_dbs = $_POST['selected_dbs'] ?? null; if ( ! $this->response->isAjax() - || (! $this->dbi->isSuperUser() && ! $cfg['AllowUserDropDatabase']) + || (! $this->dbi->isSuperUser() && ! $GLOBALS['cfg']['AllowUserDropDatabase']) ) { $message = Message::error(); $json = ['message' => $message]; @@ -73,20 +77,20 @@ final class DestroyController extends AbstractController return; } - $errorUrl = Url::getFromRoute('/server/databases'); - $selected = $selected_dbs; + $GLOBALS['errorUrl'] = Url::getFromRoute('/server/databases'); + $GLOBALS['selected'] = $selected_dbs; $numberOfDatabases = count($selected_dbs); foreach ($selected_dbs as $database) { $this->relationCleanup->database($database); $aQuery = 'DROP DATABASE ' . Util::backquote($database); - $reload = true; + $GLOBALS['reload'] = true; $this->dbi->query($aQuery); $this->transformations->clear($database); } - $dblist->databases->build(); + $GLOBALS['dblist']->databases->build(); $message = Message::success( _ngettext( diff --git a/libraries/classes/Controllers/Server/DatabasesController.php b/libraries/classes/Controllers/Server/DatabasesController.php index 85360bbd79..e188d7c06e 100644 --- a/libraries/classes/Controllers/Server/DatabasesController.php +++ b/libraries/classes/Controllers/Server/DatabasesController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\ReplicationInfo; use PhpMyAdmin\ResponseRenderer; @@ -74,10 +75,14 @@ class DatabasesController extends AbstractController $checkUserPrivileges->getPrivileges(); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $server, $dblist, $is_create_db_priv; - global $db_to_create, $text_dir, $errorUrl; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; + $GLOBALS['dblist'] = $GLOBALS['dblist'] ?? null; + $GLOBALS['is_create_db_priv'] = $GLOBALS['is_create_db_priv'] ?? null; + $GLOBALS['db_to_create'] = $GLOBALS['db_to_create'] ?? null; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'statistics' => $_REQUEST['statistics'] ?? null, @@ -87,7 +92,7 @@ class DatabasesController extends AbstractController ]; $this->addScriptFiles(['server/databases.js']); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); @@ -106,7 +111,7 @@ class DatabasesController extends AbstractController /** * Gets the databases list */ - if ($server > 0) { + if ($GLOBALS['server'] > 0) { $this->databases = $this->dbi->getDatabasesFull( null, $this->hasStatistics, @@ -116,7 +121,7 @@ class DatabasesController extends AbstractController $this->position, true ); - $this->databaseCount = count($dblist->databases); + $this->databaseCount = count($GLOBALS['dblist']->databases); } $urlParams = [ @@ -129,9 +134,9 @@ class DatabasesController extends AbstractController $databases = $this->getDatabases($primaryInfo, $replicaInfo); $charsetsList = []; - if ($cfg['ShowCreateDb'] && $is_create_db_priv) { - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']); + if ($GLOBALS['cfg']['ShowCreateDb'] && $GLOBALS['is_create_db_priv']) { + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); + $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $serverCollation = $this->dbi->getServerCollation(); foreach ($charsets as $charset) { $collationsList = []; @@ -154,10 +159,10 @@ class DatabasesController extends AbstractController $headerStatistics = $this->getStatisticsColumns(); $this->render('server/databases/index', [ - 'is_create_database_shown' => $cfg['ShowCreateDb'], - 'has_create_database_privileges' => $is_create_db_priv, + 'is_create_database_shown' => $GLOBALS['cfg']['ShowCreateDb'], + 'has_create_database_privileges' => $GLOBALS['is_create_db_priv'], 'has_statistics' => $this->hasStatistics, - 'database_to_create' => $db_to_create, + 'database_to_create' => $GLOBALS['db_to_create'], 'databases' => $databases['databases'], 'total_statistics' => $databases['total_statistics'], 'header_statistics' => $headerStatistics, @@ -165,11 +170,11 @@ class DatabasesController extends AbstractController 'database_count' => $this->databaseCount, 'pos' => $this->position, 'url_params' => $urlParams, - 'max_db_list' => $cfg['MaxDbList'], + 'max_db_list' => $GLOBALS['cfg']['MaxDbList'], 'has_primary_replication' => $primaryInfo['status'], 'has_replica_replication' => $replicaInfo['status'], - 'is_drop_allowed' => $this->dbi->isSuperUser() || $cfg['AllowUserDropDatabase'], - 'text_dir' => $text_dir, + 'is_drop_allowed' => $this->dbi->isSuperUser() || $GLOBALS['cfg']['AllowUserDropDatabase'], + 'text_dir' => $GLOBALS['text_dir'], ]); } @@ -216,8 +221,6 @@ class DatabasesController extends AbstractController */ private function getDatabases($primaryInfo, $replicaInfo): array { - global $cfg; - $databases = []; $totalStatistics = $this->getStatisticsColumns(); foreach ($this->databases as $database) { @@ -260,7 +263,7 @@ class DatabasesController extends AbstractController } } - $url = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); + $url = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $url .= Url::getCommonRaw( ['db' => $database['SCHEMA_NAME']], ! str_contains($url, '?') ? '?' : '&' @@ -271,12 +274,12 @@ class DatabasesController extends AbstractController 'statistics' => $statistics, 'replication' => $replication, 'is_system_schema' => Utilities::isSystemSchema($database['SCHEMA_NAME'], true), - 'is_pmadb' => $database['SCHEMA_NAME'] === ($cfg['Server']['pmadb'] ?? ''), + 'is_pmadb' => $database['SCHEMA_NAME'] === ($GLOBALS['cfg']['Server']['pmadb'] ?? ''), 'url' => $url, ]; $collation = Charsets::findCollationByName( $this->dbi, - $cfg['Server']['DisableIS'], + $GLOBALS['cfg']['Server']['DisableIS'], $database['DEFAULT_COLLATION_NAME'] ); if ($collation === null) { diff --git a/libraries/classes/Controllers/Server/EnginesController.php b/libraries/classes/Controllers/Server/EnginesController.php index e9c90c34f0..234faa8c23 100644 --- a/libraries/classes/Controllers/Server/EnginesController.php +++ b/libraries/classes/Controllers/Server/EnginesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\StorageEngine; use PhpMyAdmin\Template; @@ -25,11 +26,9 @@ class EnginesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/ExportController.php b/libraries/classes/Controllers/Server/ExportController.php index fc46eb0dcd..72c18eb4ca 100644 --- a/libraries/classes/Controllers/Server/ExportController.php +++ b/libraries/classes/Controllers/Server/ExportController.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Export\Options; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\ResponseRenderer; @@ -32,12 +33,14 @@ final class ExportController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $sql_query, $num_tables, $unlim_num_rows; - global $tmp_select, $select_item, $errorUrl; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['unlim_num_rows'] = $GLOBALS['unlim_num_rows'] ?? null; + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['tmp_select'] = $GLOBALS['tmp_select'] ?? null; + $GLOBALS['select_item'] = $GLOBALS['select_item'] ?? null; if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); @@ -49,19 +52,19 @@ final class ExportController extends AbstractController $this->addScriptFiles(['export.js']); - $select_item = $tmp_select ?? ''; - $databases = $this->export->getDatabasesForSelectOptions($select_item); + $GLOBALS['select_item'] = $GLOBALS['tmp_select'] ?? ''; + $databases = $this->export->getDatabasesForSelectOptions($GLOBALS['select_item']); - if (! isset($sql_query)) { - $sql_query = ''; + if (! isset($GLOBALS['sql_query'])) { + $GLOBALS['sql_query'] = ''; } - if (! isset($num_tables)) { - $num_tables = 0; + if (! isset($GLOBALS['num_tables'])) { + $GLOBALS['num_tables'] = 0; } - if (! isset($unlim_num_rows)) { - $unlim_num_rows = 0; + if (! isset($GLOBALS['unlim_num_rows'])) { + $GLOBALS['unlim_num_rows'] = 0; } $GLOBALS['single_table'] = $_POST['single_table'] ?? $_GET['single_table'] ?? $GLOBALS['single_table'] ?? null; @@ -78,11 +81,11 @@ final class ExportController extends AbstractController $options = $this->export->getOptions( 'server', - $db, - $table, - $sql_query, - $num_tables, - $unlim_num_rows, + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['sql_query'], + $GLOBALS['num_tables'], + $GLOBALS['unlim_num_rows'], $exportList ); diff --git a/libraries/classes/Controllers/Server/ImportController.php b/libraries/classes/Controllers/Server/ImportController.php index 9463d60b00..5bae544a1e 100644 --- a/libraries/classes/Controllers/Server/ImportController.php +++ b/libraries/classes/Controllers/Server/ImportController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Encoding; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Message; @@ -34,22 +35,23 @@ final class ImportController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $SESSION_KEY, $cfg, $errorUrl; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $pageSettings = new PageSettings('Import'); $pageSettingsErrorHtml = $pageSettings->getErrorHTML(); $pageSettingsHtml = $pageSettings->getHTML(); $this->addScriptFiles(['import.js']); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); } - [$SESSION_KEY, $uploadId] = Ajax::uploadProgressSetup(); + [$GLOBALS['SESSION_KEY'], $uploadId] = Ajax::uploadProgressSetup(); $importList = Plugins::getImport('server'); @@ -70,9 +72,9 @@ final class ImportController extends AbstractController $localImportFile = $_REQUEST['local_import_file'] ?? null; $compressions = Import::getCompressions(); - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $idKey = $_SESSION[$SESSION_KEY]['handler']::getIdKey(); + $idKey = $_SESSION[$GLOBALS['SESSION_KEY']]['handler']::getIdKey(); $hiddenInputs = [ $idKey => $uploadId, 'import_type' => 'server', @@ -89,10 +91,10 @@ final class ImportController extends AbstractController 'page_settings_error_html' => $pageSettingsErrorHtml, 'page_settings_html' => $pageSettingsHtml, 'upload_id' => $uploadId, - 'handler' => $_SESSION[$SESSION_KEY]['handler'], + 'handler' => $_SESSION[$GLOBALS['SESSION_KEY']]['handler'], 'hidden_inputs' => $hiddenInputs, - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'max_upload_size' => $maxUploadSize, 'formatted_maximum_upload_size' => Util::getFormattedMaximumUploadSize($maxUploadSize), 'plugins_choice' => $choice, @@ -101,18 +103,18 @@ final class ImportController extends AbstractController 'is_allow_interrupt_checked' => $isAllowInterruptChecked, 'local_import_file' => $localImportFile, 'is_upload' => $GLOBALS['config']->get('enable_upload'), - 'upload_dir' => $cfg['UploadDir'] ?? null, + 'upload_dir' => $GLOBALS['cfg']['UploadDir'] ?? null, 'timeout_passed_global' => $GLOBALS['timeout_passed'] ?? null, 'compressions' => $compressions, 'is_encoding_supported' => Encoding::isSupported(), 'encodings' => Encoding::listEncodings(), - 'import_charset' => $cfg['Import']['charset'] ?? null, + 'import_charset' => $GLOBALS['cfg']['Import']['charset'] ?? null, 'timeout_passed' => $timeoutPassed, 'offset' => $offset, 'can_convert_kanji' => Encoding::canConvertKanji(), 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), - 'user_upload_dir' => Util::userDir((string) ($cfg['UploadDir'] ?? '')), + 'user_upload_dir' => Util::userDir((string) ($GLOBALS['cfg']['UploadDir'] ?? '')), 'local_files' => Import::getLocalFiles($importList), ]); } diff --git a/libraries/classes/Controllers/Server/PluginsController.php b/libraries/classes/Controllers/Server/PluginsController.php index bf8b01b94b..988284f0df 100644 --- a/libraries/classes/Controllers/Server/PluginsController.php +++ b/libraries/classes/Controllers/Server/PluginsController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Plugins; use PhpMyAdmin\Template; @@ -38,11 +39,9 @@ class PluginsController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/PrivilegesController.php b/libraries/classes/Controllers/Server/PrivilegesController.php index eb0bf43a52..943c8e3741 100644 --- a/libraries/classes/Controllers/Server/PrivilegesController.php +++ b/libraries/classes/Controllers/Server/PrivilegesController.php @@ -8,11 +8,10 @@ use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Controllers\AbstractController; -use PhpMyAdmin\Controllers\Database\PrivilegesController as DatabaseController; -use PhpMyAdmin\Controllers\Table\PrivilegesController as TableController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Plugins; @@ -26,8 +25,6 @@ use function header; use function implode; use function is_array; use function is_string; -use function ob_get_clean; -use function ob_start; use function str_replace; use function urlencode; @@ -53,13 +50,38 @@ class PrivilegesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $errorUrl, $message, $text_dir, $post_patterns; - global $username, $hostname, $dbname, $tablename, $routinename, $db_and_table, $dbname_is_wildcard; - global $queries, $password, $ret_message, $ret_queries, $queries_for_display, $sql_query, $_add_user_error; - global $itemType, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos, $title, $export, $grants, $one_grant, $url_dbname; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['post_patterns'] = $GLOBALS['post_patterns'] ?? null; + $GLOBALS['username'] = $GLOBALS['username'] ?? null; + $GLOBALS['hostname'] = $GLOBALS['hostname'] ?? null; + $GLOBALS['dbname'] = $GLOBALS['dbname'] ?? null; + $GLOBALS['tablename'] = $GLOBALS['tablename'] ?? null; + $GLOBALS['routinename'] = $GLOBALS['routinename'] ?? null; + $GLOBALS['db_and_table'] = $GLOBALS['db_and_table'] ?? null; + $GLOBALS['dbname_is_wildcard'] = $GLOBALS['dbname_is_wildcard'] ?? null; + $GLOBALS['queries'] = $GLOBALS['queries'] ?? null; + $GLOBALS['password'] = $GLOBALS['password'] ?? null; + $GLOBALS['ret_message'] = $GLOBALS['ret_message'] ?? null; + $GLOBALS['ret_queries'] = $GLOBALS['ret_queries'] ?? null; + $GLOBALS['queries_for_display'] = $GLOBALS['queries_for_display'] ?? null; + $GLOBALS['_add_user_error'] = $GLOBALS['_add_user_error'] ?? null; + $GLOBALS['itemType'] = $GLOBALS['itemType'] ?? null; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['title'] = $GLOBALS['title'] ?? null; + $GLOBALS['export'] = $GLOBALS['export'] ?? null; + $GLOBALS['grants'] = $GLOBALS['grants'] ?? null; + $GLOBALS['one_grant'] = $GLOBALS['one_grant'] ?? null; + $GLOBALS['url_dbname'] = $GLOBALS['url_dbname'] ?? null; $checkUserPrivileges = new CheckUserPrivileges($this->dbi); $checkUserPrivileges->getPrivileges(); @@ -77,28 +99,7 @@ class PrivilegesController extends AbstractController new Plugins($this->dbi) ); - $databaseController = new DatabaseController( - $this->response, - $this->template, - $db, - $serverPrivileges, - $this->dbi - ); - - $tableController = new TableController( - $this->response, - $this->template, - $db, - $table, - $serverPrivileges, - $this->dbi - ); - - if ( - (isset($_GET['viewing_mode']) - && $_GET['viewing_mode'] === 'server') - && $relationParameters->configurableMenusFeature !== null - ) { + if ($relationParameters->configurableMenusFeature !== null) { $this->response->addHTML('<div class="container-fluid">'); $this->render('server/privileges/subnav', [ 'active' => 'privileges', @@ -109,32 +110,32 @@ class PrivilegesController extends AbstractController /** * Sets globals from $_POST patterns, for privileges and max_* vars */ - $post_patterns = [ + $GLOBALS['post_patterns'] = [ '/_priv$/i', '/^max_/i', ]; - Core::setPostAsGlobal($post_patterns); + Core::setPostAsGlobal($GLOBALS['post_patterns']); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); } - $_add_user_error = false; + $GLOBALS['_add_user_error'] = false; /** * Get DB information: username, hostname, dbname, * tablename, db_and_table, dbname_is_wildcard */ [ - $username, - $hostname, - $dbname, - $tablename, - $routinename, - $db_and_table, - $dbname_is_wildcard, + $GLOBALS['username'], + $GLOBALS['hostname'], + $GLOBALS['dbname'], + $GLOBALS['tablename'], + $GLOBALS['routinename'], + $GLOBALS['db_and_table'], + $GLOBALS['dbname_is_wildcard'], ] = $serverPrivileges->getDataForDBInfo(); /** @@ -167,8 +168,8 @@ class PrivilegesController extends AbstractController * only to update the password */ if ( - isset($_POST['change_copy']) && $username == $_POST['old_username'] - && $hostname == $_POST['old_hostname'] + isset($_POST['change_copy']) && $GLOBALS['username'] == $_POST['old_username'] + && $GLOBALS['hostname'] == $_POST['old_hostname'] ) { $this->response->addHTML( Message::error( @@ -187,71 +188,75 @@ class PrivilegesController extends AbstractController /** * Changes / copies a user, part I */ - [$queries, $password] = $serverPrivileges->getDataForChangeOrCopyUser(); + [$GLOBALS['queries'], $GLOBALS['password']] = $serverPrivileges->getDataForChangeOrCopyUser(); /** * Adds a user * (Changes / copies a user, part II) */ [ - $ret_message, - $ret_queries, - $queries_for_display, - $sql_query, - $_add_user_error, + $GLOBALS['ret_message'], + $GLOBALS['ret_queries'], + $GLOBALS['queries_for_display'], + $GLOBALS['sql_query'], + $GLOBALS['_add_user_error'], ] = $serverPrivileges->addUser( - $dbname ?? null, - $username ?? '', - $hostname ?? '', - $password ?? null, + $GLOBALS['dbname'] ?? null, + $GLOBALS['username'] ?? '', + $GLOBALS['hostname'] ?? '', + $GLOBALS['password'] ?? null, $relationParameters->configurableMenusFeature !== null ); //update the old variables - if (isset($ret_queries)) { - $queries = $ret_queries; - unset($ret_queries); + if (isset($GLOBALS['ret_queries'])) { + $GLOBALS['queries'] = $GLOBALS['ret_queries']; + unset($GLOBALS['ret_queries']); } - if (isset($ret_message)) { - $message = $ret_message; - unset($ret_message); + if (isset($GLOBALS['ret_message'])) { + $GLOBALS['message'] = $GLOBALS['ret_message']; + unset($GLOBALS['ret_message']); } /** * Changes / copies a user, part III */ - if (isset($_POST['change_copy']) && $username !== null && $hostname !== null) { - $queries = $serverPrivileges->getDbSpecificPrivsQueriesForChangeOrCopyUser($queries, $username, $hostname); + if (isset($_POST['change_copy']) && $GLOBALS['username'] !== null && $GLOBALS['hostname'] !== null) { + $GLOBALS['queries'] = $serverPrivileges->getDbSpecificPrivsQueriesForChangeOrCopyUser( + $GLOBALS['queries'], + $GLOBALS['username'], + $GLOBALS['hostname'] + ); } - $itemType = ''; - if (! empty($routinename) && is_string($dbname)) { - $itemType = $serverPrivileges->getRoutineType($dbname, $routinename); + $GLOBALS['itemType'] = ''; + if (! empty($GLOBALS['routinename']) && is_string($GLOBALS['dbname'])) { + $GLOBALS['itemType'] = $serverPrivileges->getRoutineType($GLOBALS['dbname'], $GLOBALS['routinename']); } /** * Updates privileges */ if (! empty($_POST['update_privs'])) { - if (is_array($dbname)) { - foreach ($dbname as $key => $db_name) { - [$sql_query[$key], $message] = $serverPrivileges->updatePrivileges( - ($username ?? ''), - ($hostname ?? ''), - ($tablename ?? ($routinename ?? '')), + if (is_array($GLOBALS['dbname'])) { + foreach ($GLOBALS['dbname'] as $key => $db_name) { + [$GLOBALS['sql_query'][$key], $GLOBALS['message']] = $serverPrivileges->updatePrivileges( + ($GLOBALS['username'] ?? ''), + ($GLOBALS['hostname'] ?? ''), + ($GLOBALS['tablename'] ?? ($GLOBALS['routinename'] ?? '')), ($db_name ?? ''), - $itemType + $GLOBALS['itemType'] ); } - $sql_query = implode("\n", $sql_query); + $GLOBALS['sql_query'] = implode("\n", $GLOBALS['sql_query']); } else { - [$sql_query, $message] = $serverPrivileges->updatePrivileges( - ($username ?? ''), - ($hostname ?? ''), - ($tablename ?? ($routinename ?? '')), - ($dbname ?? ''), - $itemType + [$GLOBALS['sql_query'], $GLOBALS['message']] = $serverPrivileges->updatePrivileges( + ($GLOBALS['username'] ?? ''), + ($GLOBALS['hostname'] ?? ''), + ($GLOBALS['tablename'] ?? ($GLOBALS['routinename'] ?? '')), + ($GLOBALS['dbname'] ?? ''), + $GLOBALS['itemType'] ); } } @@ -263,20 +268,20 @@ class PrivilegesController extends AbstractController ! empty($_POST['changeUserGroup']) && $relationParameters->configurableMenusFeature !== null && $this->dbi->isSuperUser() && $this->dbi->isCreateUser() ) { - $serverPrivileges->setUserGroup($username ?? '', $_POST['userGroup']); - $message = Message::success(); + $serverPrivileges->setUserGroup($GLOBALS['username'] ?? '', $_POST['userGroup']); + $GLOBALS['message'] = Message::success(); } /** * Revokes Privileges */ if (isset($_POST['revokeall'])) { - [$message, $sql_query] = $serverPrivileges->getMessageAndSqlQueryForPrivilegesRevoke( - (is_string($dbname) ? $dbname : ''), - ($tablename ?? ($routinename ?? '')), - $username ?? '', - $hostname ?? '', - $itemType + [$GLOBALS['message'], $GLOBALS['sql_query']] = $serverPrivileges->getMessageAndSqlQueryForPrivilegesRevoke( + (is_string($GLOBALS['dbname']) ? $GLOBALS['dbname'] : ''), + ($GLOBALS['tablename'] ?? ($GLOBALS['routinename'] ?? '')), + $GLOBALS['username'] ?? '', + $GLOBALS['hostname'] ?? '', + $GLOBALS['itemType'] ); } @@ -284,7 +289,11 @@ class PrivilegesController extends AbstractController * Updates the password */ if (isset($_POST['change_pw'])) { - $message = $serverPrivileges->updatePassword($errorUrl, $username ?? '', $hostname ?? ''); + $GLOBALS['message'] = $serverPrivileges->updatePassword( + $GLOBALS['errorUrl'], + $GLOBALS['username'] ?? '', + $GLOBALS['hostname'] ?? '' + ); } /** @@ -292,9 +301,9 @@ class PrivilegesController extends AbstractController * (Changes / copies a user, part IV) */ if (isset($_POST['delete']) || (isset($_POST['change_copy']) && $_POST['mode'] < 4)) { - $queries = $serverPrivileges->getDataForDeleteUsers($queries); + $GLOBALS['queries'] = $serverPrivileges->getDataForDeleteUsers($GLOBALS['queries']); if (empty($_POST['change_copy'])) { - [$sql_query, $message] = $serverPrivileges->deleteUser($queries); + [$GLOBALS['sql_query'], $GLOBALS['message']] = $serverPrivileges->deleteUser($GLOBALS['queries']); } } @@ -302,9 +311,12 @@ class PrivilegesController extends AbstractController * Changes / copies a user, part V */ if (isset($_POST['change_copy'])) { - $queries = $serverPrivileges->getDataForQueries($queries, $queries_for_display); - $message = Message::success(); - $sql_query = implode("\n", $queries); + $GLOBALS['queries'] = $serverPrivileges->getDataForQueries( + $GLOBALS['queries'], + $GLOBALS['queries_for_display'] + ); + $GLOBALS['message'] = Message::success(); + $GLOBALS['sql_query'] = implode("\n", $GLOBALS['queries']); } /** @@ -312,7 +324,7 @@ class PrivilegesController extends AbstractController */ $message_ret = $serverPrivileges->updateMessageForReload(); if ($message_ret !== null) { - $message = $message_ret; + $GLOBALS['message'] = $message_ret; unset($message_ret); } @@ -330,15 +342,15 @@ class PrivilegesController extends AbstractController && ! isset($_GET['showall']) ) { $extra_data = $serverPrivileges->getExtraDataForAjaxBehavior( - ($password ?? ''), - ($sql_query ?? ''), - ($hostname ?? ''), - ($username ?? '') + ($GLOBALS['password'] ?? ''), + ($GLOBALS['sql_query'] ?? ''), + ($GLOBALS['hostname'] ?? ''), + ($GLOBALS['username'] ?? '') ); - if (! empty($message) && $message instanceof Message) { - $this->response->setRequestStatus($message->isSuccess()); - $this->response->addJSON('message', $message); + if (! empty($GLOBALS['message']) && $GLOBALS['message'] instanceof Message) { + $this->response->setRequestStatus($GLOBALS['message']->isSuccess()); + $this->response->addJSON('message', $GLOBALS['message']); $this->response->addJSON($extra_data); return; @@ -348,71 +360,39 @@ class PrivilegesController extends AbstractController /** * Displays the links */ - if (isset($_GET['viewing_mode']) && $_GET['viewing_mode'] === 'db') { - $db = $_REQUEST['db'] = $_GET['checkprivsdb']; - - // Gets the database structure - $sub_part = '_structure'; - ob_start(); - - [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part); - - $content = ob_get_clean(); - $this->response->addHTML($content . "\n"); - } elseif (! empty($GLOBALS['message'])) { + if (! empty($GLOBALS['message'])) { $this->response->addHTML(Generator::getMessage($GLOBALS['message'])); unset($GLOBALS['message']); } // export user definition if (isset($_GET['export']) || (isset($_POST['submit_mult']) && $_POST['submit_mult'] === 'export')) { - [$title, $export] = $serverPrivileges->getListForExportUserDefinition($username ?? '', $hostname ?? ''); + [$GLOBALS['title'], $GLOBALS['export']] = $serverPrivileges->getListForExportUserDefinition( + $GLOBALS['username'] ?? '', + $GLOBALS['hostname'] ?? '' + ); - unset($username, $hostname, $grants, $one_grant); + unset($GLOBALS['username'], $GLOBALS['hostname'], $GLOBALS['grants'], $GLOBALS['one_grant']); if ($this->response->isAjax()) { - $this->response->addJSON('message', $export); - $this->response->addJSON('title', $title); + $this->response->addJSON('message', $GLOBALS['export']); + $this->response->addJSON('title', $GLOBALS['title']); return; } - $this->response->addHTML('<h2>' . $title . '</h2>' . $export); + $this->response->addHTML('<h2>' . $GLOBALS['title'] . '</h2>' . $GLOBALS['export']); } // Show back the form if an error occurred - if (isset($_GET['adduser']) || $_add_user_error === true) { + if (isset($_GET['adduser']) || $GLOBALS['_add_user_error'] === true) { // Add user - $this->response->addHTML( - $serverPrivileges->getHtmlForAddUser(Util::escapeMysqlWildcards(is_string($dbname) ? $dbname : '')) - ); - } elseif (isset($_GET['checkprivsdb']) && is_string($_GET['checkprivsdb'])) { - if (isset($_GET['checkprivstable']) && is_string($_GET['checkprivstable'])) { - $this->response->addHTML($tableController([ - 'checkprivsdb' => $_GET['checkprivsdb'], - 'checkprivstable' => $_GET['checkprivstable'], - ])); - $this->render('export_modal'); - } elseif ($this->response->isAjax() === true && empty($_REQUEST['ajax_page_request'])) { - $message = Message::success(__('User has been added.')); - $this->response->addJSON('message', $message); - - return; - } else { - $this->response->addHTML($databaseController(['checkprivsdb' => $_GET['checkprivsdb']])); - $this->render('export_modal'); - } + $this->response->addHTML($serverPrivileges->getHtmlForAddUser( + Util::escapeMysqlWildcards(is_string($GLOBALS['dbname']) ? $GLOBALS['dbname'] : '') + )); } else { - if (isset($dbname) && ! is_array($dbname)) { - $url_dbname = urlencode( + if (isset($GLOBALS['dbname']) && ! is_array($GLOBALS['dbname'])) { + $GLOBALS['url_dbname'] = urlencode( str_replace( [ '\_', @@ -422,24 +402,24 @@ class PrivilegesController extends AbstractController '_', '%', ], - $dbname + $GLOBALS['dbname'] ) ); } - if (! isset($username)) { + if (! isset($GLOBALS['username'])) { // No username is given --> display the overview $this->response->addHTML( - $serverPrivileges->getHtmlForUserOverview($text_dir) + $serverPrivileges->getHtmlForUserOverview($GLOBALS['text_dir']) ); - } elseif (! empty($routinename)) { + } elseif (! empty($GLOBALS['routinename'])) { $this->response->addHTML( $serverPrivileges->getHtmlForRoutineSpecificPrivileges( - $username, - $hostname ?? '', - is_string($dbname) ? $dbname : '', - $routinename, - Util::escapeMysqlWildcards($url_dbname ?? '') + $GLOBALS['username'], + $GLOBALS['hostname'] ?? '', + is_string($GLOBALS['dbname']) ? $GLOBALS['dbname'] : '', + $GLOBALS['routinename'], + Util::escapeMysqlWildcards($GLOBALS['url_dbname'] ?? '') ) ); } else { @@ -451,22 +431,19 @@ class PrivilegesController extends AbstractController $this->response->addHTML( $serverPrivileges->getHtmlForUserProperties( - $dbname_is_wildcard, - Util::escapeMysqlWildcards($url_dbname ?? ''), - $username, - $hostname ?? '', - $dbname ?? '', - $tablename ?? '' + $GLOBALS['dbname_is_wildcard'], + Util::escapeMysqlWildcards($GLOBALS['url_dbname'] ?? ''), + $GLOBALS['username'], + $GLOBALS['hostname'] ?? '', + $GLOBALS['dbname'] ?? '', + $GLOBALS['tablename'] ?? '', + $request->getRoute() ) ); } } - if ( - ! isset($_GET['viewing_mode']) - || $_GET['viewing_mode'] !== 'server' - || $relationParameters->configurableMenusFeature === null - ) { + if ($relationParameters->configurableMenusFeature === null) { return; } diff --git a/libraries/classes/Controllers/Server/ReplicationController.php b/libraries/classes/Controllers/Server/ReplicationController.php index 4f974b7a82..28e6381e0e 100644 --- a/libraries/classes/Controllers/Server/ReplicationController.php +++ b/libraries/classes/Controllers/Server/ReplicationController.php @@ -9,6 +9,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ReplicationGui; use PhpMyAdmin\ReplicationInfo; use PhpMyAdmin\ResponseRenderer; @@ -39,9 +40,10 @@ class ReplicationController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $urlParams, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'url_params' => $_POST['url_params'] ?? null, @@ -49,7 +51,7 @@ class ReplicationController extends AbstractController 'replica_configure' => $_POST['replica_configure'] ?? null, 'repl_clear_scr' => $_POST['repl_clear_scr'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); @@ -64,7 +66,7 @@ class ReplicationController extends AbstractController $this->addScriptFiles(['server/privileges.js', 'replication.js', 'vendor/zxcvbn-ts.js']); if (isset($params['url_params']) && is_array($params['url_params'])) { - $urlParams = $params['url_params']; + $GLOBALS['urlParams'] = $params['url_params']; } if ($this->dbi->isSuperUser()) { @@ -93,7 +95,7 @@ class ReplicationController extends AbstractController } $this->render('server/replication/index', [ - 'url_params' => $urlParams, + 'url_params' => $GLOBALS['urlParams'], 'is_super_user' => $this->dbi->isSuperUser(), 'error_messages' => $errorMessages, 'is_primary' => $primaryInfo['status'], diff --git a/libraries/classes/Controllers/Server/ShowEngineController.php b/libraries/classes/Controllers/Server/ShowEngineController.php index 7e01099337..3aa5c6d421 100644 --- a/libraries/classes/Controllers/Server/ShowEngineController.php +++ b/libraries/classes/Controllers/Server/ShowEngineController.php @@ -32,9 +32,7 @@ final class ShowEngineController extends AbstractController */ public function __invoke(ServerRequest $request, array $params): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/SqlController.php b/libraries/classes/Controllers/Server/SqlController.php index be57f119af..67a4378b9a 100644 --- a/libraries/classes/Controllers/Server/SqlController.php +++ b/libraries/classes/Controllers/Server/SqlController.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; @@ -34,16 +35,16 @@ class SqlController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['makegrid.js', 'vendor/jquery/jquery.uitablefilter.js', 'sql.js']); $pageSettings = new PageSettings('Sql'); $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/AdvisorController.php b/libraries/classes/Controllers/Server/Status/AdvisorController.php index a016ec72dd..8e2d54eddd 100644 --- a/libraries/classes/Controllers/Server/Status/AdvisorController.php +++ b/libraries/classes/Controllers/Server/Status/AdvisorController.php @@ -4,7 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status; -use PhpMyAdmin\Advisor; +use PhpMyAdmin\Advisory\Advisor; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Template; @@ -23,7 +24,7 @@ class AdvisorController extends AbstractController $this->advisor = $advisor; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $data = []; if ($this->data->dataLoaded) { diff --git a/libraries/classes/Controllers/Server/Status/Monitor/ChartingDataController.php b/libraries/classes/Controllers/Server/Status/Monitor/ChartingDataController.php index dfdfe7739f..d7fec5332b 100644 --- a/libraries/classes/Controllers/Server/Status/Monitor/ChartingDataController.php +++ b/libraries/classes/Controllers/Server/Status/Monitor/ChartingDataController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server\Status\Monitor; use PhpMyAdmin\Controllers\Server\Status\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Monitor; @@ -32,12 +33,12 @@ final class ChartingDataController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = ['requiredData' => $_POST['requiredData'] ?? null]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/Monitor/GeneralLogController.php b/libraries/classes/Controllers/Server/Status/Monitor/GeneralLogController.php index 1fb20be619..ed3345337a 100644 --- a/libraries/classes/Controllers/Server/Status/Monitor/GeneralLogController.php +++ b/libraries/classes/Controllers/Server/Status/Monitor/GeneralLogController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server\Status\Monitor; use PhpMyAdmin\Controllers\Server\Status\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Monitor; @@ -32,9 +33,9 @@ final class GeneralLogController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'time_start' => $_POST['time_start'] ?? null, @@ -42,7 +43,7 @@ final class GeneralLogController extends AbstractController 'limitTypes' => $_POST['limitTypes'] ?? null, 'removeVariables' => $_POST['removeVariables'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/Monitor/LogVarsController.php b/libraries/classes/Controllers/Server/Status/Monitor/LogVarsController.php index 8d628996a3..e580fd0186 100644 --- a/libraries/classes/Controllers/Server/Status/Monitor/LogVarsController.php +++ b/libraries/classes/Controllers/Server/Status/Monitor/LogVarsController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server\Status\Monitor; use PhpMyAdmin\Controllers\Server\Status\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Monitor; @@ -32,15 +33,15 @@ final class LogVarsController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'varName' => $_POST['varName'] ?? null, 'varValue' => $_POST['varValue'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/Monitor/QueryAnalyzerController.php b/libraries/classes/Controllers/Server/Status/Monitor/QueryAnalyzerController.php index 93ae374ec4..03dedd612b 100644 --- a/libraries/classes/Controllers/Server/Status/Monitor/QueryAnalyzerController.php +++ b/libraries/classes/Controllers/Server/Status/Monitor/QueryAnalyzerController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server\Status\Monitor; use PhpMyAdmin\Controllers\Server\Status\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Monitor; @@ -32,15 +33,15 @@ final class QueryAnalyzerController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'database' => $_POST['database'] ?? null, 'query' => $_POST['query'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/Monitor/SlowLogController.php b/libraries/classes/Controllers/Server/Status/Monitor/SlowLogController.php index f734c66847..23acd4d8ae 100644 --- a/libraries/classes/Controllers/Server/Status/Monitor/SlowLogController.php +++ b/libraries/classes/Controllers/Server/Status/Monitor/SlowLogController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Server\Status\Monitor; use PhpMyAdmin\Controllers\Server\Status\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Monitor; @@ -32,15 +33,15 @@ final class SlowLogController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'time_start' => $_POST['time_start'] ?? null, 'time_end' => $_POST['time_end'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/MonitorController.php b/libraries/classes/Controllers/Server/Status/MonitorController.php index 74ad8a2c85..c641fac330 100644 --- a/libraries/classes/Controllers/Server/Status/MonitorController.php +++ b/libraries/classes/Controllers/Server/Status/MonitorController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\SysInfo\SysInfo; @@ -25,11 +26,9 @@ class MonitorController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/Processes/RefreshController.php b/libraries/classes/Controllers/Server/Status/Processes/RefreshController.php index 1c513aec8f..c297e3b256 100644 --- a/libraries/classes/Controllers/Server/Status/Processes/RefreshController.php +++ b/libraries/classes/Controllers/Server/Status/Processes/RefreshController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status\Processes; use PhpMyAdmin\Controllers\Server\Status\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Processes; @@ -21,7 +22,7 @@ final class RefreshController extends AbstractController $this->processes = $processes; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $params = [ 'showExecuting' => $_POST['showExecuting'] ?? null, diff --git a/libraries/classes/Controllers/Server/Status/ProcessesController.php b/libraries/classes/Controllers/Server/Status/ProcessesController.php index 5ea1a9a959..28072d5371 100644 --- a/libraries/classes/Controllers/Server/Status/ProcessesController.php +++ b/libraries/classes/Controllers/Server/Status/ProcessesController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Server\Status\Processes; @@ -31,9 +32,9 @@ class ProcessesController extends AbstractController $this->processes = $processes; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'showExecuting' => $_POST['showExecuting'] ?? null, @@ -42,7 +43,7 @@ class ProcessesController extends AbstractController 'order_by_field' => $_POST['order_by_field'] ?? null, 'sort_order' => $_POST['sort_order'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/QueriesController.php b/libraries/classes/Controllers/Server/Status/QueriesController.php index f74809735f..c112557fdb 100644 --- a/libraries/classes/Controllers/Server/Status/QueriesController.php +++ b/libraries/classes/Controllers/Server/Status/QueriesController.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Template; @@ -30,11 +31,9 @@ class QueriesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/StatusController.php b/libraries/classes/Controllers/Server/Status/StatusController.php index 8841cabdc7..7870f5c9de 100644 --- a/libraries/classes/Controllers/Server/Status/StatusController.php +++ b/libraries/classes/Controllers/Server/Status/StatusController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server\Status; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ReplicationGui; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; @@ -38,11 +39,9 @@ class StatusController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; - - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/Status/VariablesController.php b/libraries/classes/Controllers/Server/Status/VariablesController.php index ba67d62799..92da16f6c5 100644 --- a/libraries/classes/Controllers/Server/Status/VariablesController.php +++ b/libraries/classes/Controllers/Server/Status/VariablesController.php @@ -9,6 +9,7 @@ namespace PhpMyAdmin\Controllers\Server\Status; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Template; @@ -30,9 +31,9 @@ class VariablesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = [ 'flush' => $_POST['flush'] ?? null, @@ -41,7 +42,7 @@ class VariablesController extends AbstractController 'filterCategory' => $_POST['filterCategory'] ?? null, 'dontFormat' => $_POST['dontFormat'] ?? null, ]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Server/UserGroupsController.php b/libraries/classes/Controllers/Server/UserGroupsController.php index a823d2f9a7..99f49b1d71 100644 --- a/libraries/classes/Controllers/Server/UserGroupsController.php +++ b/libraries/classes/Controllers/Server/UserGroupsController.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\UserGroups; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -36,7 +37,7 @@ class UserGroupsController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $configurableMenusFeature = $this->relation->getRelationParameters()->configurableMenusFeature; if ($configurableMenusFeature === null) { diff --git a/libraries/classes/Controllers/Server/UserGroupsFormController.php b/libraries/classes/Controllers/Server/UserGroupsFormController.php index 36400628d3..9daa2c0965 100644 --- a/libraries/classes/Controllers/Server/UserGroupsFormController.php +++ b/libraries/classes/Controllers/Server/UserGroupsFormController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Features\ConfigurableMenusFeature; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Util; @@ -36,7 +37,7 @@ final class UserGroupsFormController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->response->setAjax(true); diff --git a/libraries/classes/Controllers/Server/VariablesController.php b/libraries/classes/Controllers/Server/VariablesController.php index 657bcb4fd1..6ab0afc5e5 100644 --- a/libraries/classes/Controllers/Server/VariablesController.php +++ b/libraries/classes/Controllers/Server/VariablesController.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Controllers\Server; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Providers\ServerVariables\ServerVariablesProvider; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -34,12 +35,12 @@ class VariablesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $params = ['filter' => $_GET['filter'] ?? null]; - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); diff --git a/libraries/classes/Controllers/Sql/ColumnPreferencesController.php b/libraries/classes/Controllers/Sql/ColumnPreferencesController.php index bd82f79c0f..9caa472919 100644 --- a/libraries/classes/Controllers/Sql/ColumnPreferencesController.php +++ b/libraries/classes/Controllers/Sql/ColumnPreferencesController.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Controllers\Sql; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; @@ -36,13 +37,11 @@ final class ColumnPreferencesController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table; - $this->checkUserPrivileges->getPrivileges(); - $tableObject = $this->dbi->getTable($db, $table); + $tableObject = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); $status = false; // set column order diff --git a/libraries/classes/Controllers/Sql/DefaultForeignKeyCheckValueController.php b/libraries/classes/Controllers/Sql/DefaultForeignKeyCheckValueController.php index fbba9e7f70..bbe9f9b4f8 100644 --- a/libraries/classes/Controllers/Sql/DefaultForeignKeyCheckValueController.php +++ b/libraries/classes/Controllers/Sql/DefaultForeignKeyCheckValueController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Sql; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Utils\ForeignKey; @@ -24,7 +25,7 @@ final class DefaultForeignKeyCheckValueController extends AbstractController $this->checkUserPrivileges = $checkUserPrivileges; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $this->checkUserPrivileges->getPrivileges(); $this->response->addJSON('default_fk_check_value', ForeignKey::isCheckEnabled()); diff --git a/libraries/classes/Controllers/Sql/EnumValuesController.php b/libraries/classes/Controllers/Sql/EnumValuesController.php index 843d0ca8be..4548bdfbed 100644 --- a/libraries/classes/Controllers/Sql/EnumValuesController.php +++ b/libraries/classes/Controllers/Sql/EnumValuesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Sql; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; use PhpMyAdmin\Template; @@ -37,15 +38,13 @@ final class EnumValuesController extends AbstractController /** * Get possible values for enum fields during grid edit. */ - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table; - $this->checkUserPrivileges->getPrivileges(); $column = $_POST['column']; $curr_value = $_POST['curr_value']; - $values = $this->sql->getValuesForColumn($db, $table, $column); + $values = $this->sql->getValuesForColumn($GLOBALS['db'], $GLOBALS['table'], $column); if ($values === null) { $this->response->addJSON('message', __('Error in processing request')); diff --git a/libraries/classes/Controllers/Sql/RelationalValuesController.php b/libraries/classes/Controllers/Sql/RelationalValuesController.php index 884f7590e8..28a59bf2e2 100644 --- a/libraries/classes/Controllers/Sql/RelationalValuesController.php +++ b/libraries/classes/Controllers/Sql/RelationalValuesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Sql; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; use PhpMyAdmin\Template; @@ -34,10 +35,8 @@ final class RelationalValuesController extends AbstractController * * During grid edit, if we have a relational field, show the dropdown for it. */ - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table; - $this->checkUserPrivileges->getPrivileges(); $column = $_POST['column']; @@ -51,7 +50,12 @@ final class RelationalValuesController extends AbstractController $curr_value = $_POST['curr_value']; } - $dropdown = $this->sql->getHtmlForRelationalColumnDropdown($db, $table, $column, $curr_value); + $dropdown = $this->sql->getHtmlForRelationalColumnDropdown( + $GLOBALS['db'], + $GLOBALS['table'], + $column, + $curr_value + ); $this->response->addJSON('dropdown', $dropdown); } } diff --git a/libraries/classes/Controllers/Sql/SetValuesController.php b/libraries/classes/Controllers/Sql/SetValuesController.php index 89989aa6ba..db2999df21 100644 --- a/libraries/classes/Controllers/Sql/SetValuesController.php +++ b/libraries/classes/Controllers/Sql/SetValuesController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers\Sql; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; use PhpMyAdmin\Template; @@ -37,10 +38,8 @@ final class SetValuesController extends AbstractController /** * Get possible values for SET fields during grid edit. */ - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table; - $this->checkUserPrivileges->getPrivileges(); $column = $_POST['column']; @@ -48,7 +47,7 @@ final class SetValuesController extends AbstractController $fullValues = $_POST['get_full_values'] ?? false; $whereClause = $_POST['where_clause'] ?? null; - $values = $this->sql->getValuesForColumn($db, $table, $column); + $values = $this->sql->getValuesForColumn($GLOBALS['db'], $GLOBALS['table'], $column); if ($values === null) { $this->response->addJSON('message', __('Error in processing request')); @@ -59,7 +58,12 @@ final class SetValuesController extends AbstractController // If the $currentValue was truncated, we should fetch the correct full values from the table. if ($fullValues && ! empty($whereClause)) { - $currentValue = $this->sql->getFullValuesForSetColumn($db, $table, $column, $whereClause); + $currentValue = $this->sql->getFullValuesForSetColumn( + $GLOBALS['db'], + $GLOBALS['table'], + $column, + $whereClause + ); } // Converts characters of $currentValue to HTML entities. diff --git a/libraries/classes/Controllers/Sql/SqlController.php b/libraries/classes/Controllers/Sql/SqlController.php index 869a92aec8..fbacb0a2a9 100644 --- a/libraries/classes/Controllers/Sql/SqlController.php +++ b/libraries/classes/Controllers/Sql/SqlController.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ParseAnalyze; use PhpMyAdmin\ResponseRenderer; @@ -49,12 +50,23 @@ class SqlController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $display_query, $sql_query, $table; - global $ajax_reload, $goto, $errorUrl, $find_real_end, $unlim_num_rows, $import_text, $disp_query; - global $extra_data, $message_to_show, $sql_data, $disp_message, $complete_query; - global $is_gotofile, $back, $table_from_sql; + $GLOBALS['display_query'] = $GLOBALS['display_query'] ?? null; + $GLOBALS['ajax_reload'] = $GLOBALS['ajax_reload'] ?? null; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['find_real_end'] = $GLOBALS['find_real_end'] ?? null; + $GLOBALS['unlim_num_rows'] = $GLOBALS['unlim_num_rows'] ?? null; + $GLOBALS['import_text'] = $GLOBALS['import_text'] ?? null; + $GLOBALS['disp_query'] = $GLOBALS['disp_query'] ?? null; + $GLOBALS['extra_data'] = $GLOBALS['extra_data'] ?? null; + $GLOBALS['message_to_show'] = $GLOBALS['message_to_show'] ?? null; + $GLOBALS['disp_message'] = $GLOBALS['disp_message'] ?? null; + $GLOBALS['complete_query'] = $GLOBALS['complete_query'] ?? null; + $GLOBALS['is_gotofile'] = $GLOBALS['is_gotofile'] ?? null; + $GLOBALS['back'] = $GLOBALS['back'] ?? null; + $GLOBALS['table_from_sql'] = $GLOBALS['table_from_sql'] ?? null; $this->checkUserPrivileges->getPrivileges(); @@ -73,75 +85,74 @@ class SqlController extends AbstractController /** * Set ajax_reload in the response if it was already set */ - if (isset($ajax_reload) && $ajax_reload['reload'] === true) { - $this->response->addJSON('ajax_reload', $ajax_reload); + if (isset($GLOBALS['ajax_reload']) && $GLOBALS['ajax_reload']['reload'] === true) { + $this->response->addJSON('ajax_reload', $GLOBALS['ajax_reload']); } /** * Defines the url to return to in case of error in a sql statement */ - $is_gotofile = true; - if (empty($goto)) { - if (empty($table)) { - $goto = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); + $GLOBALS['is_gotofile'] = true; + if (empty($GLOBALS['goto'])) { + if (empty($GLOBALS['table'])) { + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); } else { - $goto = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); } } - if (! isset($errorUrl)) { - $errorUrl = ! empty($back) ? $back : $goto; - $errorUrl .= Url::getCommon( + if (! isset($GLOBALS['errorUrl'])) { + $GLOBALS['errorUrl'] = ! empty($GLOBALS['back']) ? $GLOBALS['back'] : $GLOBALS['goto']; + $GLOBALS['errorUrl'] .= Url::getCommon( ['db' => $GLOBALS['db']], - ! str_contains($errorUrl, '?') ? '?' : '&' + ! str_contains($GLOBALS['errorUrl'], '?') ? '?' : '&' ); if ( - (mb_strpos(' ' . $errorUrl, 'db_') !== 1 || ! str_contains($errorUrl, '?route=/database/')) - && strlen($table) > 0 + (mb_strpos(' ' . $GLOBALS['errorUrl'], 'db_') !== 1 + || ! str_contains($GLOBALS['errorUrl'], '?route=/database/')) + && strlen($GLOBALS['table']) > 0 ) { - $errorUrl .= '&table=' . urlencode($table); + $GLOBALS['errorUrl'] .= '&table=' . urlencode($GLOBALS['table']); } } // Coming from a bookmark dialog if (isset($_POST['bkm_fields']['bkm_sql_query'])) { - $sql_query = $_POST['bkm_fields']['bkm_sql_query']; + $GLOBALS['sql_query'] = $_POST['bkm_fields']['bkm_sql_query']; } elseif (isset($_POST['sql_query'])) { - $sql_query = $_POST['sql_query']; + $GLOBALS['sql_query'] = $_POST['sql_query']; } elseif (isset($_GET['sql_query'], $_GET['sql_signature'])) { if (Core::checkSqlQuerySignature($_GET['sql_query'], $_GET['sql_signature'])) { - $sql_query = $_GET['sql_query']; + $GLOBALS['sql_query'] = $_GET['sql_query']; } } // This one is just to fill $db if (isset($_POST['bkm_fields']['bkm_database'])) { - $db = $_POST['bkm_fields']['bkm_database']; + $GLOBALS['db'] = $_POST['bkm_fields']['bkm_database']; } // Default to browse if no query set and we have table // (needed for browsing from DefaultTabTable) - if (empty($sql_query) && strlen($table) > 0 && strlen($db) > 0) { - $sql_query = $this->sql->getDefaultSqlQueryForBrowse($db, $table); + if (empty($GLOBALS['sql_query']) && strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) { + $GLOBALS['sql_query'] = $this->sql->getDefaultSqlQueryForBrowse($GLOBALS['db'], $GLOBALS['table']); // set $goto to what will be displayed if query returns 0 rows - $goto = ''; + $GLOBALS['goto'] = ''; } else { - // Now we can check the parameters - Util::checkParameters(['sql_query']); + $this->checkParameters(['sql_query']); } /** * Parse and analyze the query */ - [ - $analyzed_sql_results, - $db, - $table_from_sql, - ] = ParseAnalyze::sqlQuery($sql_query, $db); - - if ($table != $table_from_sql && ! empty($table_from_sql)) { - $table = $table_from_sql; + [$statementInfo, $GLOBALS['db'], $GLOBALS['table_from_sql']] = ParseAnalyze::sqlQuery( + $GLOBALS['sql_query'], + $GLOBALS['db'] + ); + + if ($GLOBALS['table'] != $GLOBALS['table_from_sql'] && ! empty($GLOBALS['table_from_sql'])) { + $GLOBALS['table'] = $GLOBALS['table_from_sql']; } /** @@ -153,8 +164,8 @@ class SqlController extends AbstractController */ if ( $this->sql->hasNoRightsToDropDatabase( - $analyzed_sql_results, - $cfg['AllowUserDropDatabase'], + $statementInfo, + $GLOBALS['cfg']['AllowUserDropDatabase'], $this->dbi->isSuperUser() ) ) { @@ -162,22 +173,22 @@ class SqlController extends AbstractController __('"DROP DATABASE" statements are disabled.'), '', false, - $errorUrl + $GLOBALS['errorUrl'] ); } /** * Need to find the real end of rows? */ - if (isset($find_real_end) && $find_real_end) { - $unlim_num_rows = $this->sql->findRealEndOfRows($db, $table); + if (isset($GLOBALS['find_real_end']) && $GLOBALS['find_real_end']) { + $GLOBALS['unlim_num_rows'] = $this->sql->findRealEndOfRows($GLOBALS['db'], $GLOBALS['table']); } /** * Bookmark add */ if (isset($_POST['store_bkm'])) { - $this->addBookmark($goto); + $this->addBookmark($GLOBALS['goto']); return; } @@ -185,30 +196,30 @@ class SqlController extends AbstractController /** * Sets or modifies the $goto variable if required */ - if ($goto === Url::getFromRoute('/sql')) { - $is_gotofile = false; - $goto = Url::getFromRoute('/sql', [ - 'db' => $db, - 'table' => $table, - 'sql_query' => $sql_query, + if ($GLOBALS['goto'] === Url::getFromRoute('/sql')) { + $GLOBALS['is_gotofile'] = false; + $GLOBALS['goto'] = Url::getFromRoute('/sql', [ + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'sql_query' => $GLOBALS['sql_query'], ]); } $this->response->addHTML($this->sql->executeQueryAndSendQueryResponse( - $analyzed_sql_results, - $is_gotofile, - $db, - $table, - $find_real_end ?? null, - $import_text ?? null, - $extra_data ?? null, - $message_to_show ?? null, - $sql_data ?? null, - $goto, - isset($disp_query) ? $display_query : null, - $disp_message ?? null, - $sql_query, - $complete_query ?? null + $statementInfo, + $GLOBALS['is_gotofile'], + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['find_real_end'] ?? null, + $GLOBALS['import_text'] ?? null, + $GLOBALS['extra_data'] ?? null, + $GLOBALS['message_to_show'] ?? null, + null, + $GLOBALS['goto'], + isset($GLOBALS['disp_query']) ? $GLOBALS['display_query'] : null, + $GLOBALS['disp_message'] ?? null, + $GLOBALS['sql_query'], + $GLOBALS['complete_query'] ?? null )); } diff --git a/libraries/classes/Controllers/Table/AbstractController.php b/libraries/classes/Controllers/Table/AbstractController.php deleted file mode 100644 index 8b2dd05f7f..0000000000 --- a/libraries/classes/Controllers/Table/AbstractController.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace PhpMyAdmin\Controllers\Table; - -use PhpMyAdmin\Controllers\AbstractController as Controller; -use PhpMyAdmin\ResponseRenderer; -use PhpMyAdmin\Template; - -abstract class AbstractController extends Controller -{ - /** @var string */ - protected $db; - - /** @var string */ - protected $table; - - public function __construct(ResponseRenderer $response, Template $template, string $db, string $table) - { - parent::__construct($response, $template); - $this->db = $db; - $this->table = $table; - } -} diff --git a/libraries/classes/Controllers/Table/AddFieldController.php b/libraries/classes/Controllers/Table/AddFieldController.php index 0c3501997b..0cd8d30567 100644 --- a/libraries/classes/Controllers/Table/AddFieldController.php +++ b/libraries/classes/Controllers/Table/AddFieldController.php @@ -5,12 +5,13 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Config; -use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\CreateAddField; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\ColumnsDefinition; @@ -22,6 +23,7 @@ use PhpMyAdmin\Util; use function __; use function intval; use function is_array; +use function is_numeric; use function min; use function strlen; @@ -36,47 +38,51 @@ class AddFieldController extends AbstractController /** @var Config */ private $config; - /** @var Relation */ - private $relation; - /** @var DatabaseInterface */ private $dbi; + /** @var ColumnsDefinition */ + private $columnsDefinition; + public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Transformations $transformations, Config $config, - Relation $relation, - DatabaseInterface $dbi + DatabaseInterface $dbi, + ColumnsDefinition $columnsDefinition ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->transformations = $transformations; $this->config = $config; - $this->relation = $relation; $this->dbi = $dbi; + $this->columnsDefinition = $columnsDefinition; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl, $message, $action, $active_page, $sql_query; - global $num_fields, $regenerate, $result, $db, $table; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['num_fields'] = $GLOBALS['num_fields'] ?? null; + $GLOBALS['regenerate'] = $GLOBALS['regenerate'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + + /** @var string|null $numberOfFields */ + $numberOfFields = $request->getParsedBodyParam('num_fields'); $this->addScriptFiles(['table/structure.js']); - // Check parameters - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $cfg = $this->config->settings; /** * Defines the url to return to in case of error in a sql statement */ - $errorUrl = Url::getFromRoute('/table/sql', [ - 'db' => $db, - 'table' => $table, + $GLOBALS['errorUrl'] = Url::getFromRoute('/table/sql', [ + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]); // check number of fields to be created @@ -89,15 +95,15 @@ class AddFieldController extends AbstractController $_POST['field_where'] = $_POST['orig_field_where']; } - $num_fields = min( + $GLOBALS['num_fields'] = min( intval($_POST['orig_num_fields']) + intval($_POST['added_fields']), 4096 ); - $regenerate = true; - } elseif (isset($_POST['num_fields']) && intval($_POST['num_fields']) > 0) { - $num_fields = min(4096, intval($_POST['num_fields'])); + $GLOBALS['regenerate'] = true; + } elseif (is_numeric($numberOfFields) && $numberOfFields > 0) { + $GLOBALS['num_fields'] = min(4096, (int) $numberOfFields); } else { - $num_fields = 1; + $GLOBALS['num_fields'] = 1; } if (isset($_POST['do_save_data'])) { @@ -107,19 +113,23 @@ class AddFieldController extends AbstractController $createAddField = new CreateAddField($this->dbi); - $sql_query = $createAddField->getColumnCreationQuery($table); + $GLOBALS['sql_query'] = $createAddField->getColumnCreationQuery($GLOBALS['table']); // If there is a request for SQL previewing. if (isset($_POST['preview_sql'])) { - Core::previewSQL($sql_query); + Core::previewSQL($GLOBALS['sql_query']); return; } - $result = $createAddField->tryColumnCreationQuery($db, $sql_query, $errorUrl); + $GLOBALS['result'] = $createAddField->tryColumnCreationQuery( + $GLOBALS['db'], + $GLOBALS['sql_query'], + $GLOBALS['errorUrl'] + ); - if ($result !== true) { - $error_message_html = Generator::mysqlDie('', '', false, $errorUrl, false); + if ($GLOBALS['result'] !== true) { + $error_message_html = Generator::mysqlDie('', '', false, $GLOBALS['errorUrl'], false); $this->response->addHTML($error_message_html ?? ''); $this->response->setRequestStatus(false); @@ -134,8 +144,8 @@ class AddFieldController extends AbstractController } $this->transformations->setMime( - $db, - $table, + $GLOBALS['db'], + $GLOBALS['table'], $_POST['field_name'][$fieldindex], $mimetype, $_POST['field_transformation'][$fieldindex], @@ -147,21 +157,21 @@ class AddFieldController extends AbstractController } // Go back to the structure sub-page - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Table %1$s has been altered successfully.') ); - $message->addParam($table); + $GLOBALS['message']->addParam($GLOBALS['table']); $this->response->addJSON( 'message', - Generator::getMessage($message, $sql_query, 'success') + Generator::getMessage($GLOBALS['message'], $GLOBALS['sql_query'], 'success') ); // Give an URL to call and use to appends the structure after the success message $this->response->addJSON( 'structure_refresh_route', Url::getFromRoute('/table/structure', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'ajax_request' => '1', ]) ); @@ -169,27 +179,22 @@ class AddFieldController extends AbstractController return; } - $url_params = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($url_params, '&'); + $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($url_params, '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $active_page = Url::getFromRoute('/table/structure'); - /** - * Display the form - */ - $action = Url::getFromRoute('/table/add-field'); + $GLOBALS['active_page'] = Url::getFromRoute('/table/structure'); $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); - $templateData = ColumnsDefinition::displayForm( - $this->transformations, - $this->relation, - $this->dbi, - $action, - $num_fields, - $regenerate + $this->checkParameters(['server', 'db', 'table', 'num_fields']); + + $templateData = $this->columnsDefinition->displayForm( + '/table/add-field', + $GLOBALS['num_fields'], + $GLOBALS['regenerate'] ); $this->render('columns_definitions/column_definitions_form', $templateData); diff --git a/libraries/classes/Controllers/Table/ChangeController.php b/libraries/classes/Controllers/Table/ChangeController.php index 11509b14f6..6e882563d5 100644 --- a/libraries/classes/Controllers/Table/ChangeController.php +++ b/libraries/classes/Controllers/Table/ChangeController.php @@ -6,8 +6,10 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\InsertEdit; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -17,6 +19,7 @@ use function __; use function array_fill; use function count; use function is_array; +use function is_string; use function str_contains; use function strlen; use function strpos; @@ -35,47 +38,71 @@ class ChangeController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, InsertEdit $insertEdit, Relation $relation ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->insertEdit = $insertEdit; $this->relation = $relation; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $db, $table, $text_dir, $disp_message, $urlParams; - global $errorUrl, $where_clause, $unsaved_values, $insert_mode, $where_clause_array, $where_clauses; - global $result, $rows, $found_unique_key, $after_insert, $comments_map, $table_columns; - global $chg_evt_handler, $timestamp_seen, $columns_cnt, $tabindex; - global $tabindex_for_value, $o_rows, $biggest_max_file_size, $has_blob_field; - global $jsvkey, $vkey, $current_result, $repopulate, $checked; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['disp_message'] = $GLOBALS['disp_message'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['where_clause'] = $GLOBALS['where_clause'] ?? null; + $GLOBALS['unsaved_values'] = $GLOBALS['unsaved_values'] ?? null; + $GLOBALS['insert_mode'] = $GLOBALS['insert_mode'] ?? null; + $GLOBALS['where_clause_array'] = $GLOBALS['where_clause_array'] ?? null; + $GLOBALS['where_clauses'] = $GLOBALS['where_clauses'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + $GLOBALS['rows'] = $GLOBALS['rows'] ?? null; + $GLOBALS['found_unique_key'] = $GLOBALS['found_unique_key'] ?? null; + $GLOBALS['after_insert'] = $GLOBALS['after_insert'] ?? null; + $GLOBALS['comments_map'] = $GLOBALS['comments_map'] ?? null; + $GLOBALS['table_columns'] = $GLOBALS['table_columns'] ?? null; + $GLOBALS['chg_evt_handler'] = $GLOBALS['chg_evt_handler'] ?? null; + $GLOBALS['timestamp_seen'] = $GLOBALS['timestamp_seen'] ?? null; + $GLOBALS['columns_cnt'] = $GLOBALS['columns_cnt'] ?? null; + $GLOBALS['tabindex'] = $GLOBALS['tabindex'] ?? null; + $GLOBALS['tabindex_for_value'] = $GLOBALS['tabindex_for_value'] ?? null; + $GLOBALS['o_rows'] = $GLOBALS['o_rows'] ?? null; + $GLOBALS['biggest_max_file_size'] = $GLOBALS['biggest_max_file_size'] ?? null; + $GLOBALS['has_blob_field'] = $GLOBALS['has_blob_field'] ?? null; + $GLOBALS['jsvkey'] = $GLOBALS['jsvkey'] ?? null; + $GLOBALS['vkey'] = $GLOBALS['vkey'] ?? null; + $GLOBALS['current_result'] = $GLOBALS['current_result'] ?? null; + $GLOBALS['repopulate'] = $GLOBALS['repopulate'] ?? null; + $GLOBALS['checked'] = $GLOBALS['checked'] ?? null; $pageSettings = new PageSettings('Edit'); $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); /** * Determine whether Insert or Edit and set global variables */ [ - $insert_mode, - $where_clause, - $where_clause_array, - $where_clauses, - $result, - $rows, - $found_unique_key, - $after_insert, - ] = $this->insertEdit->determineInsertOrEdit($where_clause ?? null, $db, $table); + $GLOBALS['insert_mode'], + $GLOBALS['where_clause'], + $GLOBALS['where_clause_array'], + $GLOBALS['where_clauses'], + $GLOBALS['result'], + $GLOBALS['rows'], + $GLOBALS['found_unique_key'], + $GLOBALS['after_insert'], + ] = $this->insertEdit->determineInsertOrEdit( + $GLOBALS['where_clause'] ?? null, + $GLOBALS['db'], + $GLOBALS['table'] + ); // Increase number of rows if unsaved rows are more - if (! empty($unsaved_values) && count($rows) < count($unsaved_values)) { - $rows = array_fill(0, count($unsaved_values), false); + if (! empty($GLOBALS['unsaved_values']) && count($GLOBALS['rows']) < count($GLOBALS['unsaved_values'])) { + $GLOBALS['rows'] = array_fill(0, count($GLOBALS['unsaved_values']), false); } /** @@ -83,7 +110,7 @@ class ChangeController extends AbstractController * (at this point, $GLOBALS['goto'] will be set but could be empty) */ if (empty($GLOBALS['goto'])) { - if (strlen($table) > 0) { + if (strlen($GLOBALS['table']) > 0) { // avoid a problem (see bug #2202709) $GLOBALS['goto'] = Url::getFromRoute('/table/sql'); } else { @@ -91,22 +118,21 @@ class ChangeController extends AbstractController } } - $urlParams = [ - 'db' => $db, - 'sql_query' => $_POST['sql_query'] ?? '', - ]; + /** @var mixed $sqlQuery */ + $sqlQuery = $request->getParsedBodyParam('sql_query'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'sql_query' => is_string($sqlQuery) ? $sqlQuery : '']; if (strpos($GLOBALS['goto'] ?? '', 'index.php?route=/table') === 0) { - $urlParams['table'] = $table; + $GLOBALS['urlParams']['table'] = $GLOBALS['table']; } - $errorUrl = $GLOBALS['goto'] . Url::getCommon( - $urlParams, + $GLOBALS['errorUrl'] = $GLOBALS['goto'] . Url::getCommon( + $GLOBALS['urlParams'], ! str_contains($GLOBALS['goto'], '?') ? '?' : '&' ); - unset($urlParams); + unset($GLOBALS['urlParams']); - $comments_map = $this->insertEdit->getCommentsMap($db, $table); + $GLOBALS['comments_map'] = $this->insertEdit->getCommentsMap($GLOBALS['db'], $GLOBALS['table']); /** * START REGULAR OUTPUT @@ -125,22 +151,22 @@ class ChangeController extends AbstractController * * $disp_message come from /table/replace */ - if (! empty($disp_message)) { - $this->response->addHTML(Generator::getMessage($disp_message, null)); + if (! empty($GLOBALS['disp_message'])) { + $this->response->addHTML(Generator::getMessage($GLOBALS['disp_message'], null)); } - $table_columns = $this->insertEdit->getTableColumns($db, $table); + $GLOBALS['table_columns'] = $this->insertEdit->getTableColumns($GLOBALS['db'], $GLOBALS['table']); // retrieve keys into foreign fields, if any - $foreigners = $this->relation->getForeigners($db, $table); + $foreigners = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table']); // Retrieve form parameters for insert/edit form $_form_params = $this->insertEdit->getFormParametersForInsertForm( - $db, - $table, - $where_clauses, - $where_clause_array, - $errorUrl + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['where_clauses'], + $GLOBALS['where_clause_array'], + $GLOBALS['errorUrl'] ); /** @@ -148,28 +174,31 @@ class ChangeController extends AbstractController */ // autocomplete feature of IE kills the "onchange" event handler and it // must be replaced by the "onpropertychange" one in this case - $chg_evt_handler = 'onchange'; + $GLOBALS['chg_evt_handler'] = 'onchange'; // Had to put the URI because when hosted on an https server, // some browsers send wrongly this form to the http server. $html_output = ''; // Set if we passed the first timestamp field - $timestamp_seen = false; - $columns_cnt = count($table_columns); - - $tabindex = 0; - $tabindex_for_value = 0; - $o_rows = 0; - $biggest_max_file_size = 0; - - $urlParams['db'] = $db; - $urlParams['table'] = $table; - $urlParams = $this->insertEdit->urlParamsInEditMode($urlParams, $where_clause_array); + $GLOBALS['timestamp_seen'] = false; + $GLOBALS['columns_cnt'] = count($GLOBALS['table_columns']); + + $GLOBALS['tabindex'] = 0; + $GLOBALS['tabindex_for_value'] = 0; + $GLOBALS['o_rows'] = 0; + $GLOBALS['biggest_max_file_size'] = 0; + + $GLOBALS['urlParams']['db'] = $GLOBALS['db']; + $GLOBALS['urlParams']['table'] = $GLOBALS['table']; + $GLOBALS['urlParams'] = $this->insertEdit->urlParamsInEditMode( + $GLOBALS['urlParams'], + $GLOBALS['where_clause_array'] + ); - $has_blob_field = false; - foreach ($table_columns as $column) { + $GLOBALS['has_blob_field'] = false; + foreach ($GLOBALS['table_columns'] as $column) { if ($this->insertEdit->isColumn($column, ['blob', 'tinyblob', 'mediumblob', 'longblob'])) { - $has_blob_field = true; + $GLOBALS['has_blob_field'] = true; break; } } @@ -177,92 +206,94 @@ class ChangeController extends AbstractController //Insert/Edit form //If table has blob fields we have to disable ajax. $isUpload = $GLOBALS['config']->get('enable_upload'); - $html_output .= $this->insertEdit->getHtmlForInsertEditFormHeader($has_blob_field, $isUpload); + $html_output .= $this->insertEdit->getHtmlForInsertEditFormHeader($GLOBALS['has_blob_field'], $isUpload); $html_output .= Url::getHiddenInputs($_form_params); // user can toggle the display of Function column and column types // (currently does not work for multi-edits) - if (! $cfg['ShowFunctionFields'] || ! $cfg['ShowFieldTypesInDataEditView']) { + if (! $GLOBALS['cfg']['ShowFunctionFields'] || ! $GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { $html_output .= __('Show'); } - if (! $cfg['ShowFunctionFields']) { - $html_output .= $this->insertEdit->showTypeOrFunction('function', $urlParams, false); + if (! $GLOBALS['cfg']['ShowFunctionFields']) { + $html_output .= $this->insertEdit->showTypeOrFunction('function', $GLOBALS['urlParams'], false); } - if (! $cfg['ShowFieldTypesInDataEditView']) { - $html_output .= $this->insertEdit->showTypeOrFunction('type', $urlParams, false); + if (! $GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { + $html_output .= $this->insertEdit->showTypeOrFunction('type', $GLOBALS['urlParams'], false); } $GLOBALS['plugin_scripts'] = []; - foreach ($rows as $row_id => $current_row) { + foreach ($GLOBALS['rows'] as $row_id => $current_row) { if (empty($current_row)) { $current_row = []; } - $jsvkey = $row_id; - $vkey = '[multi_edit][' . $jsvkey . ']'; - - $current_result = (isset($result) && is_array($result) && isset($result[$row_id]) - ? $result[$row_id] - : $result); - $repopulate = []; - $checked = true; - if (isset($unsaved_values[$row_id])) { - $repopulate = $unsaved_values[$row_id]; - $checked = false; + $GLOBALS['jsvkey'] = $row_id; + $GLOBALS['vkey'] = '[multi_edit][' . $GLOBALS['jsvkey'] . ']'; + + $GLOBALS['current_result'] = (isset($GLOBALS['result']) + && is_array($GLOBALS['result']) && isset($GLOBALS['result'][$row_id]) + ? $GLOBALS['result'][$row_id] + : $GLOBALS['result']); + $GLOBALS['repopulate'] = []; + $GLOBALS['checked'] = true; + if (isset($GLOBALS['unsaved_values'][$row_id])) { + $GLOBALS['repopulate'] = $GLOBALS['unsaved_values'][$row_id]; + $GLOBALS['checked'] = false; } - if ($insert_mode && $row_id > 0) { - $html_output .= $this->insertEdit->getHtmlForIgnoreOption($row_id, $checked); + if ($GLOBALS['insert_mode'] && $row_id > 0) { + $html_output .= $this->insertEdit->getHtmlForIgnoreOption($row_id, $GLOBALS['checked']); } $html_output .= $this->insertEdit->getHtmlForInsertEditRow( - $urlParams, - $table_columns, - $comments_map, - $timestamp_seen, - $current_result, - $chg_evt_handler, - $jsvkey, - $vkey, - $insert_mode, + $GLOBALS['urlParams'], + $GLOBALS['table_columns'], + $GLOBALS['comments_map'], + $GLOBALS['timestamp_seen'], + $GLOBALS['current_result'], + $GLOBALS['chg_evt_handler'], + $GLOBALS['jsvkey'], + $GLOBALS['vkey'], + $GLOBALS['insert_mode'], $current_row, - $o_rows, - $tabindex, - $columns_cnt, + $GLOBALS['o_rows'], + $GLOBALS['tabindex'], + $GLOBALS['columns_cnt'], $isUpload, $foreigners, - $tabindex_for_value, - $table, - $db, + $GLOBALS['tabindex_for_value'], + $GLOBALS['table'], + $GLOBALS['db'], $row_id, - $biggest_max_file_size, - $text_dir, - $repopulate, - $where_clause_array + $GLOBALS['biggest_max_file_size'], + $GLOBALS['text_dir'], + $GLOBALS['repopulate'], + $GLOBALS['where_clause_array'] ); } $this->addScriptFiles($GLOBALS['plugin_scripts']); - unset($unsaved_values, $checked, $repopulate, $GLOBALS['plugin_scripts']); + unset($GLOBALS['unsaved_values'], $GLOBALS['checked'], $GLOBALS['repopulate'], $GLOBALS['plugin_scripts']); - if (! isset($after_insert)) { - $after_insert = 'back'; + if (! isset($GLOBALS['after_insert'])) { + $GLOBALS['after_insert'] = 'back'; } - $isNumeric = InsertEdit::isWhereClauseNumeric($where_clause); + $isNumeric = InsertEdit::isWhereClauseNumeric($GLOBALS['where_clause']); $html_output .= $this->template->render('table/insert/actions_panel', [ - 'where_clause' => $where_clause, - 'after_insert' => $after_insert, - 'found_unique_key' => $found_unique_key, + 'where_clause' => $GLOBALS['where_clause'], + 'after_insert' => $GLOBALS['after_insert'], + 'found_unique_key' => $GLOBALS['found_unique_key'], 'is_numeric' => $isNumeric, ]); - if ($biggest_max_file_size > 0) { - $html_output .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . $biggest_max_file_size . '">' . "\n"; + if ($GLOBALS['biggest_max_file_size'] > 0) { + $html_output .= '<input type="hidden" name="MAX_FILE_SIZE" value="' + . $GLOBALS['biggest_max_file_size'] . '">' . "\n"; } $html_output .= '</form>'; @@ -270,9 +301,14 @@ class ChangeController extends AbstractController $html_output .= $this->insertEdit->getHtmlForGisEditor(); // end Insert/Edit form - if ($insert_mode) { + if ($GLOBALS['insert_mode']) { //Continue insertion form - $html_output .= $this->insertEdit->getContinueInsertionForm($table, $db, $where_clause_array, $errorUrl); + $html_output .= $this->insertEdit->getContinueInsertionForm( + $GLOBALS['table'], + $GLOBALS['db'], + $GLOBALS['where_clause_array'], + $GLOBALS['errorUrl'] + ); } $this->response->addHTML($html_output); diff --git a/libraries/classes/Controllers/Table/ChangeRowsController.php b/libraries/classes/Controllers/Table/ChangeRowsController.php index 0c3a6a684d..427ae52566 100644 --- a/libraries/classes/Controllers/Table/ChangeRowsController.php +++ b/libraries/classes/Controllers/Table/ChangeRowsController.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -19,17 +21,16 @@ final class ChangeRowsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, ChangeController $changeController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->changeController = $changeController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $active_page, $where_clause; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['where_clause'] = $GLOBALS['where_clause'] ?? null; if (isset($_POST['goto']) && (! isset($_POST['rows_to_delete']) || ! is_array($_POST['rows_to_delete']))) { $this->response->setRequestStatus(false); @@ -42,15 +43,15 @@ final class ChangeRowsController extends AbstractController // 'rows_to_delete' checkbox, we use the index of it as the // indicating WHERE clause. Then we build the array which is used // for the /table/change script. - $where_clause = []; + $GLOBALS['where_clause'] = []; if (isset($_POST['rows_to_delete']) && is_array($_POST['rows_to_delete'])) { foreach ($_POST['rows_to_delete'] as $i_where_clause) { - $where_clause[] = $i_where_clause; + $GLOBALS['where_clause'][] = $i_where_clause; } } - $active_page = Url::getFromRoute('/table/change'); + $GLOBALS['active_page'] = Url::getFromRoute('/table/change'); - ($this->changeController)(); + ($this->changeController)($request); } } diff --git a/libraries/classes/Controllers/Table/ChartController.php b/libraries/classes/Controllers/Table/ChartController.php index 12a26cd7a2..d1e935a57f 100644 --- a/libraries/classes/Controllers/Table/ChartController.php +++ b/libraries/classes/Controllers/Table/ChartController.php @@ -4,10 +4,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Components\Limit; @@ -35,17 +37,15 @@ class ChartController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $cfg, $sql_query, $errorUrl; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if (isset($_REQUEST['pos'], $_REQUEST['session_max_rows']) && $this->response->isAjax()) { $this->ajax(); @@ -54,7 +54,7 @@ class ChartController extends AbstractController } // Throw error if no sql query is set - if (! isset($sql_query) || $sql_query == '') { + if (! isset($GLOBALS['sql_query']) || $GLOBALS['sql_query'] == '') { $this->response->setRequestStatus(false); $this->response->addHTML( Message::error(__('No SQL query was set to fetch data.'))->getDisplay() @@ -83,41 +83,41 @@ class ChartController extends AbstractController /** * Runs common work */ - if (strlen($table) > 0) { - Util::checkParameters(['db', 'table']); + if (strlen($GLOBALS['table']) > 0) { + $this->checkParameters(['db', 'table']); - $url_params = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($url_params, '&'); + $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($url_params, '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $url_params['goto'] = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + $url_params['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $url_params['back'] = Url::getFromRoute('/table/sql'); - $this->dbi->selectDb($db); - } elseif (strlen($db) > 0) { - $url_params['goto'] = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); + $this->dbi->selectDb($GLOBALS['db']); + } elseif (strlen($GLOBALS['db']) > 0) { + $url_params['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $url_params['back'] = Url::getFromRoute('/sql'); - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } } else { - $url_params['goto'] = Util::getScriptNameForOption($cfg['DefaultTabServer'], 'server'); + $url_params['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabServer'], 'server'); $url_params['back'] = Url::getFromRoute('/sql'); - $errorUrl = Url::getFromRoute('/'); + $GLOBALS['errorUrl'] = Url::getFromRoute('/'); if ($this->dbi->isSuperUser()) { $this->dbi->selectDb('mysql'); } } - $result = $this->dbi->tryQuery($sql_query); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); $fields_meta = $row = []; if ($result !== false) { $fields_meta = $this->dbi->getFieldsMeta($result); @@ -148,10 +148,10 @@ class ChartController extends AbstractController return; } - $url_params['db'] = $db; + $url_params['db'] = $GLOBALS['db']; $url_params['reload'] = 1; - $startAndNumberOfRowsFieldset = Generator::getStartAndNumberOfRowsFieldsetData($sql_query); + $startAndNumberOfRowsFieldset = Generator::getStartAndNumberOfRowsFieldsetData($GLOBALS['sql_query']); /** * Displays the page @@ -170,19 +170,19 @@ class ChartController extends AbstractController */ public function ajax(): void { - global $db, $table, $sql_query, $urlParams, $errorUrl, $cfg; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) { + $this->checkParameters(['db', 'table']); - if (strlen($table) > 0 && strlen($db) > 0) { - Util::checkParameters(['db', 'table']); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); - - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } - $parser = new Parser($sql_query); + $parser = new Parser($GLOBALS['sql_query']); /** * @var SelectStatement $statement */ diff --git a/libraries/classes/Controllers/Table/CreateController.php b/libraries/classes/Controllers/Table/CreateController.php index b70c875814..4edd0b565a 100644 --- a/libraries/classes/Controllers/Table/CreateController.php +++ b/libraries/classes/Controllers/Table/CreateController.php @@ -5,17 +5,17 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Config; -use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\CreateAddField; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\ColumnsDefinition; use PhpMyAdmin\Template; use PhpMyAdmin\Transformations; use PhpMyAdmin\Url; -use PhpMyAdmin\Util; use function __; use function htmlspecialchars; @@ -35,39 +35,35 @@ class CreateController extends AbstractController /** @var Config */ private $config; - /** @var Relation */ - private $relation; - /** @var DatabaseInterface */ private $dbi; + /** @var ColumnsDefinition */ + private $columnsDefinition; + public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Transformations $transformations, Config $config, - Relation $relation, - DatabaseInterface $dbi + DatabaseInterface $dbi, + ColumnsDefinition $columnsDefinition ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->transformations = $transformations; $this->config = $config; - $this->relation = $relation; $this->dbi = $dbi; + $this->columnsDefinition = $columnsDefinition; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $num_fields, $action, $sql_query, $result, $db, $table; - - Util::checkParameters(['db']); + $this->checkParameters(['db']); $cfg = $this->config->settings; /* Check if database name is empty */ - if (strlen($db) === 0) { + if ($GLOBALS['db'] === '') { Generator::mysqlDie( __('The database name is empty!'), '', @@ -79,30 +75,28 @@ class CreateController extends AbstractController /** * Selects the database to work with */ - if (! $this->dbi->selectDb($db)) { + if (! $this->dbi->selectDb($GLOBALS['db'])) { Generator::mysqlDie( - sprintf(__('\'%s\' database does not exist.'), htmlspecialchars($db)), + sprintf(__('\'%s\' database does not exist.'), htmlspecialchars($GLOBALS['db'])), '', false, 'index.php' ); } - if ($this->dbi->getColumns($db, $table)) { + if ($this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'])) { // table exists already Generator::mysqlDie( - sprintf(__('Table %s already exists!'), htmlspecialchars($table)), + sprintf(__('Table %s already exists!'), htmlspecialchars($GLOBALS['table'])), '', false, - Url::getFromRoute('/database/structure', ['db' => $db]) + Url::getFromRoute('/database/structure', ['db' => $GLOBALS['db']]) ); } $createAddField = new CreateAddField($this->dbi); - $num_fields = $createAddField->getNumberOfFieldsFromRequest(); - - $action = Url::getFromRoute('/table/create'); + $numFields = $createAddField->getNumberOfFieldsFromRequest(); /** * The form used to define the structure of the table has been submitted @@ -110,21 +104,21 @@ class CreateController extends AbstractController if (isset($_POST['do_save_data'])) { // lower_case_table_names=1 `DB` becomes `db` if ($this->dbi->getLowerCaseNames() === '1') { - $db = mb_strtolower($db); - $table = mb_strtolower($table); + $GLOBALS['db'] = mb_strtolower($GLOBALS['db']); + $GLOBALS['table'] = mb_strtolower($GLOBALS['table']); } - $sql_query = $createAddField->getTableCreationQuery($db, $table); + $GLOBALS['sql_query'] = $createAddField->getTableCreationQuery($GLOBALS['db'], $GLOBALS['table']); // If there is a request for SQL previewing. if (isset($_POST['preview_sql'])) { - Core::previewSQL($sql_query); + Core::previewSQL($GLOBALS['sql_query']); return; } // Executes the query - $result = $this->dbi->tryQuery($sql_query); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if ($result) { // Update comment table for mime types [MIME] @@ -138,8 +132,8 @@ class CreateController extends AbstractController } $this->transformations->setMime( - $db, - $table, + $GLOBALS['db'], + $GLOBALS['table'], $_POST['field_name'][$fieldindex], $mimetype, $_POST['field_transformation'][$fieldindex], @@ -162,13 +156,9 @@ class CreateController extends AbstractController $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); - $templateData = ColumnsDefinition::displayForm( - $this->transformations, - $this->relation, - $this->dbi, - $action, - $num_fields - ); + $this->checkParameters(['server', 'db']); + + $templateData = $this->columnsDefinition->displayForm('/table/create', $numFields); $this->render('columns_definitions/column_definitions_form', $templateData); } diff --git a/libraries/classes/Controllers/Table/DeleteConfirmController.php b/libraries/classes/Controllers/Table/DeleteConfirmController.php index b2a1ea80d7..383ef8bf35 100644 --- a/libraries/classes/Controllers/Table/DeleteConfirmController.php +++ b/libraries/classes/Controllers/Table/DeleteConfirmController.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Url; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\ForeignKey; @@ -14,9 +16,10 @@ use function is_array; final class DeleteConfirmController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $sql_query, $urlParams, $errorUrl, $cfg; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $selected = $_POST['rows_to_delete'] ?? null; @@ -27,19 +30,19 @@ final class DeleteConfirmController extends AbstractController return; } - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); $this->render('table/delete/confirm', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'selected' => $selected, - 'sql_query' => $sql_query, + 'sql_query' => $GLOBALS['sql_query'], 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), ]); } diff --git a/libraries/classes/Controllers/Table/DeleteRowsController.php b/libraries/classes/Controllers/Table/DeleteRowsController.php index a65183718b..d48ad4346f 100644 --- a/libraries/classes/Controllers/Table/DeleteRowsController.php +++ b/libraries/classes/Controllers/Table/DeleteRowsController.php @@ -6,7 +6,9 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; @@ -27,17 +29,18 @@ final class DeleteRowsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $goto, $sql_query, $table, $disp_message, $disp_query, $active_page; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['disp_message'] = $GLOBALS['disp_message'] ?? null; + $GLOBALS['disp_query'] = $GLOBALS['disp_query'] ?? null; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; $mult_btn = $_POST['mult_btn'] ?? ''; $original_sql_query = $_POST['original_sql_query'] ?? ''; @@ -55,52 +58,52 @@ final class DeleteRowsController extends AbstractController if ($mult_btn === __('Yes')) { $default_fk_check_value = ForeignKey::handleDisableCheckInit(); - $sql_query = ''; + $GLOBALS['sql_query'] = ''; foreach ($selected as $row) { $query = sprintf( 'DELETE FROM %s WHERE %s LIMIT 1;', - Util::backquote($table), + Util::backquote($GLOBALS['table']), $row ); - $sql_query .= $query . "\n"; - $this->dbi->selectDb($db); + $GLOBALS['sql_query'] .= $query . "\n"; + $this->dbi->selectDb($GLOBALS['db']); $this->dbi->query($query); } if (! empty($_REQUEST['pos'])) { - $_REQUEST['pos'] = $sql->calculatePosForLastPage($db, $table, $_REQUEST['pos']); + $_REQUEST['pos'] = $sql->calculatePosForLastPage($GLOBALS['db'], $GLOBALS['table'], $_REQUEST['pos']); } ForeignKey::handleDisableCheckCleanup($default_fk_check_value); - $disp_message = __('Your SQL query has been executed successfully.'); - $disp_query = $sql_query; + $GLOBALS['disp_message'] = __('Your SQL query has been executed successfully.'); + $GLOBALS['disp_query'] = $GLOBALS['sql_query']; } $_url_params = $GLOBALS['urlParams']; $_url_params['goto'] = Url::getFromRoute('/table/sql'); if (isset($original_sql_query)) { - $sql_query = $original_sql_query; + $GLOBALS['sql_query'] = $original_sql_query; } - $active_page = Url::getFromRoute('/sql'); + $GLOBALS['active_page'] = Url::getFromRoute('/sql'); $this->response->addHTML($sql->executeQueryAndSendQueryResponse( null, false, - $db, - $table, + $GLOBALS['db'], + $GLOBALS['table'], null, null, null, null, null, - $goto, - null, - null, - $sql_query, + $GLOBALS['goto'], + $GLOBALS['disp_query'] ?? null, + $GLOBALS['disp_message'] ?? null, + $GLOBALS['sql_query'], null )); } diff --git a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php index 1e7ca25b07..8d8f30a0f9 100644 --- a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php +++ b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php @@ -4,39 +4,42 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; +use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\DbTableExists; -use PhpMyAdmin\Url; -use PhpMyAdmin\Util; +use PhpMyAdmin\Http\ServerRequest; +use Webmozart\Assert\Assert; +use Webmozart\Assert\InvalidArgumentException; use function __; final class DropColumnConfirmationController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $urlParams, $errorUrl, $cfg; + $fields = $request->getParsedBodyParam('selected_fld'); + try { + $db = DatabaseName::fromValue($request->getParsedBodyParam('db')); + $table = TableName::fromValue($request->getParsedBodyParam('table')); + Assert::allStringNotEmpty($fields); + } catch (InvalidIdentifierName $exception) { + $this->sendErrorResponse($exception->getMessage()); - $selected = $_POST['selected_fld'] ?? null; - - if (empty($selected)) { - $this->response->setRequestStatus(false); - $this->response->addJSON('message', __('No column selected.')); + return; + } catch (InvalidArgumentException $exception) { + $this->sendErrorResponse(__('No column selected.')); return; } - Util::checkParameters(['db', 'table']); - - $urlParams = ['db' => $this->db, 'table' => $this->table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); - - DbTableExists::check(); + DbTableExists::check($db->getName(), $table->getName()); $this->render('table/structure/drop_confirm', [ - 'db' => $this->db, - 'table' => $this->table, - 'fields' => $selected, + 'db' => $db->getName(), + 'table' => $table->getName(), + 'fields' => $fields, ]); } } diff --git a/libraries/classes/Controllers/Table/DropColumnController.php b/libraries/classes/Controllers/Table/DropColumnController.php index 730b6b930a..77f0ace8bb 100644 --- a/libraries/classes/Controllers/Table/DropColumnController.php +++ b/libraries/classes/Controllers/Table/DropColumnController.php @@ -5,8 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FlashMessages; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -30,19 +32,17 @@ final class DropColumnController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, FlashMessages $flash, RelationCleanup $relationCleanup ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->flash = $flash; $this->relationCleanup = $relationCleanup; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $selected = $_POST['selected'] ?? []; @@ -56,15 +56,15 @@ final class DropColumnController extends AbstractController $selectedCount = count($selected); if (($_POST['mult_btn'] ?? '') === __('Yes')) { $i = 1; - $statement = 'ALTER TABLE ' . Util::backquote($this->table); + $statement = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']); foreach ($selected as $field) { - $this->relationCleanup->column($this->db, $this->table, $field); + $this->relationCleanup->column($GLOBALS['db'], $GLOBALS['table'], $field); $statement .= ' DROP ' . Util::backquote($field); $statement .= $i++ === $selectedCount ? ';' : ','; } - $this->dbi->selectDb($this->db); + $this->dbi->selectDb($GLOBALS['db']); $result = $this->dbi->tryQuery($statement); if (! $result) { @@ -86,6 +86,6 @@ final class DropColumnController extends AbstractController } $this->flash->addMessage($message->isError() ? 'danger' : 'success', $message->getMessage()); - $this->redirect('/table/structure', ['db' => $this->db, 'table' => $this->table]); + $this->redirect('/table/structure', ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]); } } diff --git a/libraries/classes/Controllers/Table/ExportController.php b/libraries/classes/Controllers/Table/ExportController.php index 4140025374..70963a6f63 100644 --- a/libraries/classes/Controllers/Table/ExportController.php +++ b/libraries/classes/Controllers/Table/ExportController.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Export\Options; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\ResponseRenderer; @@ -29,18 +31,20 @@ class ExportController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Options $export ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->export = $export; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $urlParams, $table, $replaces, $cfg, $errorUrl; - global $sql_query, $where_clause, $num_tables, $unlim_num_rows; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['replaces'] = $GLOBALS['replaces'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['where_clause'] = $GLOBALS['where_clause'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['unlim_num_rows'] = $GLOBALS['unlim_num_rows'] ?? null; $pageSettings = new PageSettings('Export'); $pageSettingsErrorHtml = $pageSettings->getErrorHTML(); @@ -48,51 +52,55 @@ class ExportController extends AbstractController $this->addScriptFiles(['export.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - $urlParams['goto'] = Url::getFromRoute('/table/export'); - $urlParams['back'] = Url::getFromRoute('/table/export'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/export'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/export'); // When we have some query, we need to remove LIMIT from that and possibly // generate WHERE clause (if we are asked to export specific rows) - if (! empty($sql_query)) { - $parser = new Parser($sql_query); + if (! empty($GLOBALS['sql_query'])) { + $parser = new Parser($GLOBALS['sql_query']); if (! empty($parser->statements[0]) && ($parser->statements[0] instanceof SelectStatement)) { // Checking if the WHERE clause has to be replaced. - if (! empty($where_clause) && is_array($where_clause)) { - $replaces[] = [ + if (! empty($GLOBALS['where_clause']) && is_array($GLOBALS['where_clause'])) { + $GLOBALS['replaces'][] = [ 'WHERE', - 'WHERE (' . implode(') OR (', $where_clause) . ')', + 'WHERE (' . implode(') OR (', $GLOBALS['where_clause']) . ')', ]; } // Preparing to remove the LIMIT clause. - $replaces[] = [ + $GLOBALS['replaces'][] = [ 'LIMIT', '', ]; // Replacing the clauses. - $sql_query = Query::replaceClauses($parser->statements[0], $parser->list, $replaces); + $GLOBALS['sql_query'] = Query::replaceClauses( + $parser->statements[0], + $parser->list, + $GLOBALS['replaces'] + ); } } - if (! isset($sql_query)) { - $sql_query = ''; + if (! isset($GLOBALS['sql_query'])) { + $GLOBALS['sql_query'] = ''; } - if (! isset($num_tables)) { - $num_tables = 0; + if (! isset($GLOBALS['num_tables'])) { + $GLOBALS['num_tables'] = 0; } - if (! isset($unlim_num_rows)) { - $unlim_num_rows = 0; + if (! isset($GLOBALS['unlim_num_rows'])) { + $GLOBALS['unlim_num_rows'] = 0; } $GLOBALS['single_table'] = $_POST['single_table'] ?? $_GET['single_table'] ?? $GLOBALS['single_table'] ?? null; @@ -115,11 +123,11 @@ class ExportController extends AbstractController $options = $this->export->getOptions( $exportType, - $db, - $table, - $sql_query, - $num_tables, - $unlim_num_rows, + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['sql_query'], + $GLOBALS['num_tables'], + $GLOBALS['unlim_num_rows'], $exportList ); diff --git a/libraries/classes/Controllers/Table/ExportRowsController.php b/libraries/classes/Controllers/Table/ExportRowsController.php index be0a42a37c..ae4a891234 100644 --- a/libraries/classes/Controllers/Table/ExportRowsController.php +++ b/libraries/classes/Controllers/Table/ExportRowsController.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -19,17 +21,17 @@ final class ExportRowsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, ExportController $exportController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->exportController = $exportController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $active_page, $single_table, $where_clause; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['single_table'] = $GLOBALS['single_table'] ?? null; + $GLOBALS['where_clause'] = $GLOBALS['where_clause'] ?? null; if (isset($_POST['goto']) && (! isset($_POST['rows_to_delete']) || ! is_array($_POST['rows_to_delete']))) { $this->response->setRequestStatus(false); @@ -39,21 +41,21 @@ final class ExportRowsController extends AbstractController } // Needed to allow SQL export - $single_table = true; + $GLOBALS['single_table'] = true; // As we got the rows to be exported from the // 'rows_to_delete' checkbox, we use the index of it as the // indicating WHERE clause. Then we build the array which is used // for the /table/change script. - $where_clause = []; + $GLOBALS['where_clause'] = []; if (isset($_POST['rows_to_delete']) && is_array($_POST['rows_to_delete'])) { foreach ($_POST['rows_to_delete'] as $i_where_clause) { - $where_clause[] = $i_where_clause; + $GLOBALS['where_clause'][] = $i_where_clause; } } - $active_page = Url::getFromRoute('/table/export'); + $GLOBALS['active_page'] = Url::getFromRoute('/table/export'); - ($this->exportController)(); + ($this->exportController)($request); } } diff --git a/libraries/classes/Controllers/Table/FindReplaceController.php b/libraries/classes/Controllers/Table/FindReplaceController.php index 1f0ec7f360..a4b1d944f6 100644 --- a/libraries/classes/Controllers/Table/FindReplaceController.php +++ b/libraries/classes/Controllers/Table/FindReplaceController.php @@ -4,9 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -46,11 +48,9 @@ class FindReplaceController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->columnNames = []; @@ -59,17 +59,17 @@ class FindReplaceController extends AbstractController $this->connectionCharSet = (string) $this->dbi->fetchValue('SELECT @@character_set_connection'); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $urlParams, $cfg, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $this->checkParameters(['db', 'table']); - Util::checkParameters(['db', 'table']); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); - - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); if (isset($_POST['find'])) { $this->findAction(); @@ -93,7 +93,7 @@ class FindReplaceController extends AbstractController private function loadTableInfo(): void { // Gets the list and number of columns - $columns = $this->dbi->getColumns($this->db, $this->table, true); + $columns = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'], true); foreach ($columns as $row) { // set column name @@ -128,10 +128,8 @@ class FindReplaceController extends AbstractController */ public function displaySelectionFormAction(): void { - global $goto; - - if (! isset($goto)) { - $goto = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + if (! isset($GLOBALS['goto'])) { + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); } $column_names = $this->columnNames; @@ -143,9 +141,9 @@ class FindReplaceController extends AbstractController } $this->render('table/find_replace/index', [ - 'db' => $this->db, - 'table' => $this->table, - 'goto' => $goto, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'goto' => $GLOBALS['goto'], 'column_names' => $column_names, 'types' => $types, 'sql_types' => $this->dbi->types, @@ -214,8 +212,8 @@ class FindReplaceController extends AbstractController . $replaceWith . "')," . ' COUNT(*)' - . ' FROM ' . Util::backquote($this->db) - . '.' . Util::backquote($this->table) + . ' FROM ' . Util::backquote($GLOBALS['db']) + . '.' . Util::backquote($GLOBALS['table']) . ' WHERE ' . Util::backquote($column) . " LIKE '%" . $find . "%' COLLATE " . $charSet . '_bin'; // here we // change the collation of the 2nd operand to a case sensitive @@ -228,8 +226,8 @@ class FindReplaceController extends AbstractController } return $this->template->render('table/find_replace/replace_preview', [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'column_index' => $columnIndex, 'find' => $find, 'replace_with' => $replaceWith, @@ -259,8 +257,8 @@ class FindReplaceController extends AbstractController . Util::backquote($column) . ',' . ' 1,' // to add an extra column that will have replaced value . ' COUNT(*)' - . ' FROM ' . Util::backquote($this->db) - . '.' . Util::backquote($this->table) + . ' FROM ' . Util::backquote($GLOBALS['db']) + . '.' . Util::backquote($GLOBALS['table']) . ' WHERE ' . Util::backquote($column) . " RLIKE '" . $this->dbi->escapeString($find) . "' COLLATE " . $charSet . '_bin'; // here we @@ -323,7 +321,7 @@ class FindReplaceController extends AbstractController $column = $this->columnNames[$columnIndex]; if ($useRegex) { $toReplace = $this->getRegexReplaceRows($columnIndex, $find, $replaceWith, $charSet); - $sql_query = 'UPDATE ' . Util::backquote($this->table) + $sql_query = 'UPDATE ' . Util::backquote($GLOBALS['table']) . ' SET ' . Util::backquote($column); if (is_array($toReplace)) { @@ -348,7 +346,7 @@ class FindReplaceController extends AbstractController // binary collation to make sure that the comparison // is case sensitive } else { - $sql_query = 'UPDATE ' . Util::backquote($this->table) + $sql_query = 'UPDATE ' . Util::backquote($GLOBALS['table']) . ' SET ' . Util::backquote($column) . ' =' . ' REPLACE(' . Util::backquote($column) . ", '" . $find . "', '" diff --git a/libraries/classes/Controllers/Table/GetFieldController.php b/libraries/classes/Controllers/Table/GetFieldController.php index bbc574a4f3..306a7cf090 100644 --- a/libraries/classes/Controllers/Table/GetFieldController.php +++ b/libraries/classes/Controllers/Table/GetFieldController.php @@ -4,9 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Mime; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -15,8 +17,8 @@ use PhpMyAdmin\Util; use function __; use function htmlspecialchars; use function ini_set; +use function mb_strlen; use function sprintf; -use function strlen; /** * Provides download to a given field defined in parameters. @@ -29,37 +31,29 @@ class GetFieldController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table; - $this->response->disable(); - /* Check parameters */ - Util::checkParameters([ - 'db', - 'table', - ]); + $this->checkParameters(['db', 'table']); /* Select database */ - if (! $this->dbi->selectDb($db)) { + if (! $this->dbi->selectDb($GLOBALS['db'])) { Generator::mysqlDie( - sprintf(__('\'%s\' database does not exist.'), htmlspecialchars($db)), + sprintf(__('\'%s\' database does not exist.'), htmlspecialchars($GLOBALS['db'])), '', false ); } /* Check if table exists */ - if (! $this->dbi->getColumns($db, $table)) { + if (! $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'])) { Generator::mysqlDie(__('Invalid table name')); } @@ -76,7 +70,7 @@ class GetFieldController extends AbstractController /* Grab data */ $sql = 'SELECT ' . Util::backquote($_GET['transform_key']) - . ' FROM ' . Util::backquote($table) + . ' FROM ' . Util::backquote($GLOBALS['table']) . ' WHERE ' . $_GET['where_clause'] . ';'; $result = $this->dbi->fetchValue($sql); @@ -94,9 +88,9 @@ class GetFieldController extends AbstractController ini_set('url_rewriter.tags', ''); Core::downloadHeader( - $table . '-' . $_GET['transform_key'] . '.bin', + $GLOBALS['table'] . '-' . $_GET['transform_key'] . '.bin', Mime::detect($result), - strlen($result) + mb_strlen($result, '8bit') ); echo $result; } diff --git a/libraries/classes/Controllers/Table/GisVisualizationController.php b/libraries/classes/Controllers/Table/GisVisualizationController.php index 1f3021c952..2cdfb6c691 100644 --- a/libraries/classes/Controllers/Table/GisVisualizationController.php +++ b/libraries/classes/Controllers/Table/GisVisualizationController.php @@ -4,10 +4,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Gis\GisVisualization; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -32,22 +34,20 @@ final class GisVisualizationController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $urlParams, $db, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $this->checkParameters(['db']); - Util::checkParameters(['db']); - - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; @@ -160,12 +160,12 @@ final class GisVisualizationController extends AbstractController /** * Displays the page */ - $urlParams['goto'] = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $urlParams['back'] = Url::getFromRoute('/sql'); - $urlParams['sql_query'] = $sqlQuery; - $urlParams['sql_signature'] = Core::signSqlQuery($sqlQuery); + $GLOBALS['urlParams']['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/sql'); + $GLOBALS['urlParams']['sql_query'] = $sqlQuery; + $GLOBALS['urlParams']['sql_signature'] = Core::signSqlQuery($sqlQuery); $downloadUrl = Url::getFromRoute('/table/gis-visualization', array_merge( - $urlParams, + $GLOBALS['urlParams'], [ 'saveToFile' => true, 'session_max_rows' => $rows, @@ -178,7 +178,7 @@ final class GisVisualizationController extends AbstractController $startAndNumberOfRowsFieldset = Generator::getStartAndNumberOfRowsFieldsetData($sqlQuery); $html = $this->template->render('table/gis_visualization/gis_visualization', [ - 'url_params' => $urlParams, + 'url_params' => $GLOBALS['urlParams'], 'download_url' => $downloadUrl, 'label_candidates' => $labelCandidates, 'spatial_candidates' => $spatialCandidates, diff --git a/libraries/classes/Controllers/Table/ImportController.php b/libraries/classes/Controllers/Table/ImportController.php index 2903f880e4..67bb6e090b 100644 --- a/libraries/classes/Controllers/Table/ImportController.php +++ b/libraries/classes/Controllers/Table/ImportController.php @@ -6,9 +6,11 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Charsets; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Encoding; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Import; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Message; @@ -31,17 +33,17 @@ final class ImportController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $urlParams, $SESSION_KEY, $cfg, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $pageSettings = new PageSettings('Import'); $pageSettingsErrorHtml = $pageSettings->getErrorHTML(); @@ -49,18 +51,18 @@ final class ImportController extends AbstractController $this->addScriptFiles(['import.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $urlParams['goto'] = Url::getFromRoute('/table/import'); - $urlParams['back'] = Url::getFromRoute('/table/import'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/import'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/import'); - [$SESSION_KEY, $uploadId] = Ajax::uploadProgressSetup(); + [$GLOBALS['SESSION_KEY'], $uploadId] = Ajax::uploadProgressSetup(); $importList = Plugins::getImport('table'); @@ -81,14 +83,14 @@ final class ImportController extends AbstractController $localImportFile = $_REQUEST['local_import_file'] ?? null; $compressions = Import::getCompressions(); - $charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $idKey = $_SESSION[$SESSION_KEY]['handler']::getIdKey(); + $idKey = $_SESSION[$GLOBALS['SESSION_KEY']]['handler']::getIdKey(); $hiddenInputs = [ $idKey => $uploadId, 'import_type' => 'table', - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]; $default = isset($_GET['format']) ? (string) $_GET['format'] : Plugins::getDefault('Import', 'format'); @@ -102,10 +104,10 @@ final class ImportController extends AbstractController 'page_settings_error_html' => $pageSettingsErrorHtml, 'page_settings_html' => $pageSettingsHtml, 'upload_id' => $uploadId, - 'handler' => $_SESSION[$SESSION_KEY]['handler'], + 'handler' => $_SESSION[$GLOBALS['SESSION_KEY']]['handler'], 'hidden_inputs' => $hiddenInputs, - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'max_upload_size' => $maxUploadSize, 'formatted_maximum_upload_size' => Util::getFormattedMaximumUploadSize($maxUploadSize), 'plugins_choice' => $choice, @@ -114,18 +116,18 @@ final class ImportController extends AbstractController 'is_allow_interrupt_checked' => $isAllowInterruptChecked, 'local_import_file' => $localImportFile, 'is_upload' => $GLOBALS['config']->get('enable_upload'), - 'upload_dir' => $cfg['UploadDir'] ?? null, + 'upload_dir' => $GLOBALS['cfg']['UploadDir'] ?? null, 'timeout_passed_global' => $GLOBALS['timeout_passed'] ?? null, 'compressions' => $compressions, 'is_encoding_supported' => Encoding::isSupported(), 'encodings' => Encoding::listEncodings(), - 'import_charset' => $cfg['Import']['charset'] ?? null, + 'import_charset' => $GLOBALS['cfg']['Import']['charset'] ?? null, 'timeout_passed' => $timeoutPassed, 'offset' => $offset, 'can_convert_kanji' => Encoding::canConvertKanji(), 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), - 'user_upload_dir' => Util::userDir((string) ($cfg['UploadDir'] ?? '')), + 'user_upload_dir' => Util::userDir((string) ($GLOBALS['cfg']['UploadDir'] ?? '')), 'local_files' => Import::getLocalFiles($importList), ]); } diff --git a/libraries/classes/Controllers/Table/IndexRenameController.php b/libraries/classes/Controllers/Table/IndexRenameController.php index 181ba2a18f..6f8d4cefe7 100644 --- a/libraries/classes/Controllers/Table/IndexRenameController.php +++ b/libraries/classes/Controllers/Table/IndexRenameController.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Indexes; @@ -26,28 +28,27 @@ final class IndexRenameController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, Indexes $indexes ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->indexes = $indexes; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $urlParams, $cfg, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if (! isset($_POST['create_edit_table'])) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } if (isset($_POST['index'])) { @@ -55,14 +56,14 @@ final class IndexRenameController extends AbstractController // coming already from form $index = new Index($_POST['index']); } else { - $index = $this->dbi->getTable($this->db, $this->table)->getIndex($_POST['index']); + $index = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->getIndex($_POST['index']); } } else { $index = new Index(); } if (isset($_POST['do_save_data'])) { - $this->indexes->doSaveData($index, true, $this->db, $this->table); + $this->indexes->doSaveData($index, true, $GLOBALS['db'], $GLOBALS['table']); return; } @@ -80,8 +81,8 @@ final class IndexRenameController extends AbstractController $this->dbi->selectDb($GLOBALS['db']); $formParams = [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]; if (isset($_POST['old_index'])) { diff --git a/libraries/classes/Controllers/Table/IndexesController.php b/libraries/classes/Controllers/Table/IndexesController.php index 686bf0714e..4382d40bbc 100644 --- a/libraries/classes/Controllers/Table/IndexesController.php +++ b/libraries/classes/Controllers/Table/IndexesController.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Indexes; @@ -33,28 +35,27 @@ class IndexesController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, Indexes $indexes ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->indexes = $indexes; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $urlParams, $cfg, $errorUrl; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; if (! isset($_POST['create_edit_table'])) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } if (isset($_POST['index'])) { @@ -62,14 +63,14 @@ class IndexesController extends AbstractController // coming already from form $index = new Index($_POST['index']); } else { - $index = $this->dbi->getTable($this->db, $this->table)->getIndex($_POST['index']); + $index = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->getIndex($_POST['index']); } } else { $index = new Index(); } if (isset($_POST['do_save_data'])) { - $this->indexes->doSaveData($index, false, $this->db, $this->table); + $this->indexes->doSaveData($index, false, $GLOBALS['db'], $GLOBALS['table']); return; } @@ -121,13 +122,13 @@ class IndexesController extends AbstractController $index->set($index_params); $add_fields = count($fields); } else { - $fields = $this->dbi->getTable($this->db, $this->table) + $fields = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']) ->getNameAndTypeOfTheColumns(); } $form_params = [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]; if (isset($_POST['create_index'])) { diff --git a/libraries/classes/Controllers/Table/Maintenance/AnalyzeController.php b/libraries/classes/Controllers/Table/Maintenance/AnalyzeController.php index 9ba749110c..11b3519d4b 100644 --- a/libraries/classes/Controllers/Table/Maintenance/AnalyzeController.php +++ b/libraries/classes/Controllers/Table/Maintenance/AnalyzeController.php @@ -5,8 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Maintenance; use PhpMyAdmin\Config; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -31,12 +32,10 @@ final class AnalyzeController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $model, Config $config ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $model; $this->config = $config; } @@ -62,7 +61,7 @@ final class AnalyzeController extends AbstractController foreach ($selectedTablesParam as $table) { $selectedTables[] = TableName::fromValue($table); } - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName $exception) { $message = Message::error($exception->getMessage()); $this->response->setRequestStatus(false); $this->response->addJSON('message', $message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Maintenance/CheckController.php b/libraries/classes/Controllers/Table/Maintenance/CheckController.php index c0527d3dc4..f5bd549304 100644 --- a/libraries/classes/Controllers/Table/Maintenance/CheckController.php +++ b/libraries/classes/Controllers/Table/Maintenance/CheckController.php @@ -5,8 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Maintenance; use PhpMyAdmin\Config; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -31,12 +32,10 @@ final class CheckController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $model, Config $config ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $model; $this->config = $config; } @@ -62,7 +61,7 @@ final class CheckController extends AbstractController foreach ($selectedTablesParam as $table) { $selectedTables[] = TableName::fromValue($table); } - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName $exception) { $message = Message::error($exception->getMessage()); $this->response->setRequestStatus(false); $this->response->addJSON('message', $message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Maintenance/ChecksumController.php b/libraries/classes/Controllers/Table/Maintenance/ChecksumController.php index 811a10b0f2..d0d34b9a2c 100644 --- a/libraries/classes/Controllers/Table/Maintenance/ChecksumController.php +++ b/libraries/classes/Controllers/Table/Maintenance/ChecksumController.php @@ -5,8 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Maintenance; use PhpMyAdmin\Config; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -31,12 +32,10 @@ final class ChecksumController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $model, Config $config ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $model; $this->config = $config; } @@ -62,7 +61,7 @@ final class ChecksumController extends AbstractController foreach ($selectedTablesParam as $table) { $selectedTables[] = TableName::fromValue($table); } - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName $exception) { $message = Message::error($exception->getMessage()); $this->response->setRequestStatus(false); $this->response->addJSON('message', $message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Maintenance/OptimizeController.php b/libraries/classes/Controllers/Table/Maintenance/OptimizeController.php index 498c459e60..85af0f2e67 100644 --- a/libraries/classes/Controllers/Table/Maintenance/OptimizeController.php +++ b/libraries/classes/Controllers/Table/Maintenance/OptimizeController.php @@ -5,8 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Maintenance; use PhpMyAdmin\Config; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -31,12 +32,10 @@ final class OptimizeController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $model, Config $config ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $model; $this->config = $config; } @@ -62,7 +61,7 @@ final class OptimizeController extends AbstractController foreach ($selectedTablesParam as $table) { $selectedTables[] = TableName::fromValue($table); } - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName $exception) { $message = Message::error($exception->getMessage()); $this->response->setRequestStatus(false); $this->response->addJSON('message', $message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Maintenance/RepairController.php b/libraries/classes/Controllers/Table/Maintenance/RepairController.php index 3976121d9a..c3754e9639 100644 --- a/libraries/classes/Controllers/Table/Maintenance/RepairController.php +++ b/libraries/classes/Controllers/Table/Maintenance/RepairController.php @@ -5,8 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Maintenance; use PhpMyAdmin\Config; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -31,12 +32,10 @@ final class RepairController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $model, Config $config ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $model; $this->config = $config; } @@ -62,7 +61,7 @@ final class RepairController extends AbstractController foreach ($selectedTablesParam as $table) { $selectedTables[] = TableName::fromValue($table); } - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName $exception) { $message = Message::error($exception->getMessage()); $this->response->setRequestStatus(false); $this->response->addJSON('message', $message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/OperationsController.php b/libraries/classes/Controllers/Table/OperationsController.php index 19a585d162..e0cf459d11 100644 --- a/libraries/classes/Controllers/Table/OperationsController.php +++ b/libraries/classes/Controllers/Table/OperationsController.php @@ -7,9 +7,11 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Charsets; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; @@ -49,76 +51,95 @@ class OperationsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Operations $operations, CheckUserPrivileges $checkUserPrivileges, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->operations = $operations; $this->checkUserPrivileges = $checkUserPrivileges; $this->relation = $relation; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $urlParams, $reread_info, $tbl_is_view, $tbl_storage_engine; - global $show_comment, $tbl_collation, $table_info_num_rows, $row_format, $auto_increment, $create_options; - global $table_alters, $warning_messages, $lowerCaseNames, $db, $table, $reload, $result; - global $new_tbl_storage_engine, $sql_query, $message_to_show, $columns, $hideOrderTable, $indexes; - global $notNull, $comment, $errorUrl, $cfg; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['reread_info'] = $GLOBALS['reread_info'] ?? null; + $GLOBALS['tbl_is_view'] = $GLOBALS['tbl_is_view'] ?? null; + $GLOBALS['tbl_storage_engine'] = $GLOBALS['tbl_storage_engine'] ?? null; + $GLOBALS['show_comment'] = $GLOBALS['show_comment'] ?? null; + $GLOBALS['tbl_collation'] = $GLOBALS['tbl_collation'] ?? null; + $GLOBALS['table_info_num_rows'] = $GLOBALS['table_info_num_rows'] ?? null; + $GLOBALS['row_format'] = $GLOBALS['row_format'] ?? null; + $GLOBALS['auto_increment'] = $GLOBALS['auto_increment'] ?? null; + $GLOBALS['create_options'] = $GLOBALS['create_options'] ?? null; + $GLOBALS['table_alters'] = $GLOBALS['table_alters'] ?? null; + $GLOBALS['warning_messages'] = $GLOBALS['warning_messages'] ?? null; + $GLOBALS['lowerCaseNames'] = $GLOBALS['lowerCaseNames'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + $GLOBALS['new_tbl_storage_engine'] = $GLOBALS['new_tbl_storage_engine'] ?? null; + $GLOBALS['message_to_show'] = $GLOBALS['message_to_show'] ?? null; + $GLOBALS['columns'] = $GLOBALS['columns'] ?? null; + $GLOBALS['hideOrderTable'] = $GLOBALS['hideOrderTable'] ?? null; + $GLOBALS['indexes'] = $GLOBALS['indexes'] ?? null; + $GLOBALS['notNull'] = $GLOBALS['notNull'] ?? null; + $GLOBALS['comment'] = $GLOBALS['comment'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->checkUserPrivileges->getPrivileges(); // lower_case_table_names=1 `DB` becomes `db` - $lowerCaseNames = $this->dbi->getLowerCaseNames() === '1'; + $GLOBALS['lowerCaseNames'] = $this->dbi->getLowerCaseNames() === '1'; - if ($lowerCaseNames) { - $table = mb_strtolower($table); + if ($GLOBALS['lowerCaseNames']) { + $GLOBALS['table'] = mb_strtolower($GLOBALS['table']); } - $pma_table = $this->dbi->getTable($db, $table); + $pma_table = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); $this->addScriptFiles(['table/operations.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $isSystemSchema = Utilities::isSystemSchema($db); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $isSystemSchema = Utilities::isSystemSchema($GLOBALS['db']); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $urlParams['goto'] = $urlParams['back'] = Url::getFromRoute('/table/operations'); + $GLOBALS['urlParams']['goto'] = $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/operations'); $relationParameters = $this->relation->getRelationParameters(); /** * Reselect current db (needed in some cases probably due to the calling of {@link Relation}) */ - $this->dbi->selectDb($db); + $this->dbi->selectDb($GLOBALS['db']); - $reread_info = $pma_table->getStatusInfo(null, false); - $GLOBALS['showtable'] = $pma_table->getStatusInfo(null, (isset($reread_info) && $reread_info)); + $GLOBALS['reread_info'] = $pma_table->getStatusInfo(null, false); + $GLOBALS['showtable'] = $pma_table->getStatusInfo( + null, + (isset($GLOBALS['reread_info']) && $GLOBALS['reread_info']) + ); if ($pma_table->isView()) { - $tbl_is_view = true; - $tbl_storage_engine = __('View'); - $show_comment = null; + $GLOBALS['tbl_is_view'] = true; + $GLOBALS['tbl_storage_engine'] = __('View'); + $GLOBALS['show_comment'] = null; } else { - $tbl_is_view = false; - $tbl_storage_engine = $pma_table->getStorageEngine(); - $show_comment = $pma_table->getComment(); + $GLOBALS['tbl_is_view'] = false; + $GLOBALS['tbl_storage_engine'] = $pma_table->getStorageEngine(); + $GLOBALS['show_comment'] = $pma_table->getComment(); } - $tbl_collation = $pma_table->getCollation(); - $table_info_num_rows = $pma_table->getNumRows(); - $row_format = $pma_table->getRowFormat(); - $auto_increment = $pma_table->getAutoIncrement(); - $create_options = $pma_table->getCreateOptions(); + $GLOBALS['tbl_collation'] = $pma_table->getCollation(); + $GLOBALS['table_info_num_rows'] = $pma_table->getNumRows(); + $GLOBALS['row_format'] = $pma_table->getRowFormat(); + $GLOBALS['auto_increment'] = $pma_table->getAutoIncrement(); + $GLOBALS['create_options'] = $pma_table->getCreateOptions(); // set initial value of these variables, based on the current table engine if ($pma_table->isEngine('ARIA')) { @@ -127,21 +148,21 @@ class OperationsController extends AbstractController // or explicit (option found with a value of 0 or 1) // ($create_options['transactional'] may have been set by Table class, // from the $create_options) - $create_options['transactional'] = ($create_options['transactional'] ?? '') == '0' + $GLOBALS['create_options']['transactional'] = ($GLOBALS['create_options']['transactional'] ?? '') == '0' ? '0' : '1'; - $create_options['page_checksum'] = $create_options['page_checksum'] ?? ''; + $GLOBALS['create_options']['page_checksum'] = $GLOBALS['create_options']['page_checksum'] ?? ''; } - $pma_table = $this->dbi->getTable($db, $table); - $reread_info = false; - $table_alters = []; + $pma_table = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); + $GLOBALS['reread_info'] = false; + $GLOBALS['table_alters'] = []; /** * If the table has to be moved to some other database */ if (isset($_POST['submit_move']) || isset($_POST['submit_copy'])) { - $message = $this->operations->moveOrCopyTable($db, $table); + $message = $this->operations->moveOrCopyTable($GLOBALS['db'], $GLOBALS['table']); if (! $this->response->isAjax()) { return; @@ -151,10 +172,10 @@ class OperationsController extends AbstractController if ($message->isSuccess()) { if (isset($_POST['submit_move'], $_POST['target_db'])) { - $db = $_POST['target_db'];// Used in Header::getJsParams() + $GLOBALS['db'] = $_POST['target_db'];// Used in Header::getJsParams() } - $this->response->addJSON('db', $db); + $this->response->addJSON('db', $GLOBALS['db']); return; } @@ -169,11 +190,11 @@ class OperationsController extends AbstractController */ if (isset($_POST['submitoptions'])) { $_message = ''; - $warning_messages = []; + $GLOBALS['warning_messages'] = []; if (isset($_POST['new_name'])) { // lower_case_table_names=1 `DB` becomes `db` - if ($lowerCaseNames) { + if ($GLOBALS['lowerCaseNames']) { $_POST['new_name'] = mb_strtolower($_POST['new_name']); } @@ -192,62 +213,66 @@ class OperationsController extends AbstractController } // Reselect the original DB - $db = $oldDb; + $GLOBALS['db'] = $oldDb; $this->dbi->selectDb($oldDb); $_message .= $pma_table->getLastMessage(); - $result = true; - $table = $pma_table->getName(); - $reread_info = true; - $reload = true; + $GLOBALS['result'] = true; + $GLOBALS['table'] = $pma_table->getName(); + $GLOBALS['reread_info'] = true; + $GLOBALS['reload'] = true; } else { $_message .= $pma_table->getLastError(); - $result = false; + $GLOBALS['result'] = false; } } if ( ! empty($_POST['new_tbl_storage_engine']) - && mb_strtoupper($_POST['new_tbl_storage_engine']) !== $tbl_storage_engine + && mb_strtoupper($_POST['new_tbl_storage_engine']) !== $GLOBALS['tbl_storage_engine'] ) { - $new_tbl_storage_engine = mb_strtoupper($_POST['new_tbl_storage_engine']); + $GLOBALS['new_tbl_storage_engine'] = mb_strtoupper($_POST['new_tbl_storage_engine']); if ($pma_table->isEngine('ARIA')) { - $create_options['transactional'] = ($create_options['transactional'] ?? '') == '0' - ? '0' - : '1'; - $create_options['page_checksum'] = $create_options['page_checksum'] ?? ''; + $GLOBALS['create_options']['transactional'] = ($GLOBALS['create_options']['transactional'] ?? '') + == '0' ? '0' : '1'; + $GLOBALS['create_options']['page_checksum'] = $GLOBALS['create_options']['page_checksum'] ?? ''; } } else { - $new_tbl_storage_engine = ''; + $GLOBALS['new_tbl_storage_engine'] = ''; } - $row_format = $create_options['row_format'] ?? $pma_table->getRowFormat(); + $GLOBALS['row_format'] = $GLOBALS['create_options']['row_format'] ?? $pma_table->getRowFormat(); - $table_alters = $this->operations->getTableAltersArray( + $GLOBALS['table_alters'] = $this->operations->getTableAltersArray( $pma_table, - $create_options['pack_keys'], - (empty($create_options['checksum']) ? '0' : '1'), - ($create_options['page_checksum'] ?? ''), - (empty($create_options['delay_key_write']) ? '0' : '1'), - $row_format, - $new_tbl_storage_engine, - (isset($create_options['transactional']) && $create_options['transactional'] == '0' ? '0' : '1'), - $tbl_collation + $GLOBALS['create_options']['pack_keys'], + (empty($GLOBALS['create_options']['checksum']) ? '0' : '1'), + ($GLOBALS['create_options']['page_checksum'] ?? ''), + (empty($GLOBALS['create_options']['delay_key_write']) ? '0' : '1'), + $GLOBALS['row_format'], + $GLOBALS['new_tbl_storage_engine'], + (isset($GLOBALS['create_options']['transactional']) + && $GLOBALS['create_options']['transactional'] == '0' ? '0' : '1'), + $GLOBALS['tbl_collation'] ); - if (count($table_alters) > 0) { - $sql_query = 'ALTER TABLE ' - . Util::backquote($table); - $sql_query .= "\r\n" . implode("\r\n", $table_alters); - $sql_query .= ';'; - $result = (bool) $this->dbi->query($sql_query); - $reread_info = true; - unset($table_alters); - $warning_messages = $this->operations->getWarningMessagesArray(); + if (count($GLOBALS['table_alters']) > 0) { + $GLOBALS['sql_query'] = 'ALTER TABLE ' + . Util::backquote($GLOBALS['table']); + $GLOBALS['sql_query'] .= "\r\n" . implode("\r\n", $GLOBALS['table_alters']); + $GLOBALS['sql_query'] .= ';'; + $GLOBALS['result'] = (bool) $this->dbi->query($GLOBALS['sql_query']); + $GLOBALS['reread_info'] = true; + unset($GLOBALS['table_alters']); + $GLOBALS['warning_messages'] = $this->operations->getWarningMessagesArray(); } if (! empty($_POST['tbl_collation']) && ! empty($_POST['change_all_collations'])) { - $this->operations->changeAllColumnsCollation($db, $table, $_POST['tbl_collation']); + $this->operations->changeAllColumnsCollation( + $GLOBALS['db'], + $GLOBALS['table'], + $_POST['tbl_collation'] + ); } if (isset($_POST['tbl_collation']) && empty($_POST['tbl_collation'])) { @@ -267,57 +292,57 @@ class OperationsController extends AbstractController * Reordering the table has been requested by the user */ if (isset($_POST['submitorderby']) && ! empty($_POST['order_field'])) { - $sql_query = QueryGenerator::getQueryForReorderingTable( - $table, + $GLOBALS['sql_query'] = QueryGenerator::getQueryForReorderingTable( + $GLOBALS['table'], urldecode($_POST['order_field']), $_POST['order_order'] ?? null ); - $result = $this->dbi->query($sql_query); + $GLOBALS['result'] = $this->dbi->query($GLOBALS['sql_query']); } /** * A partition operation has been requested by the user */ if (isset($_POST['submit_partition']) && ! empty($_POST['partition_operation'])) { - $sql_query = QueryGenerator::getQueryForPartitioningTable( - $table, + $GLOBALS['sql_query'] = QueryGenerator::getQueryForPartitioningTable( + $GLOBALS['table'], $_POST['partition_operation'], $_POST['partition_name'] ); - $result = $this->dbi->query($sql_query); + $GLOBALS['result'] = $this->dbi->query($GLOBALS['sql_query']); } - if ($reread_info) { + if ($GLOBALS['reread_info']) { // to avoid showing the old value (for example the AUTO_INCREMENT) after // a change, clear the cache $this->dbi->getCache()->clearTableCache(); - $this->dbi->selectDb($db); + $this->dbi->selectDb($GLOBALS['db']); $GLOBALS['showtable'] = $pma_table->getStatusInfo(null, true); if ($pma_table->isView()) { - $tbl_is_view = true; - $tbl_storage_engine = __('View'); - $show_comment = null; + $GLOBALS['tbl_is_view'] = true; + $GLOBALS['tbl_storage_engine'] = __('View'); + $GLOBALS['show_comment'] = null; } else { - $tbl_is_view = false; - $tbl_storage_engine = $pma_table->getStorageEngine(); - $show_comment = $pma_table->getComment(); + $GLOBALS['tbl_is_view'] = false; + $GLOBALS['tbl_storage_engine'] = $pma_table->getStorageEngine(); + $GLOBALS['show_comment'] = $pma_table->getComment(); } - $tbl_collation = $pma_table->getCollation(); - $table_info_num_rows = $pma_table->getNumRows(); - $row_format = $pma_table->getRowFormat(); - $auto_increment = $pma_table->getAutoIncrement(); - $create_options = $pma_table->getCreateOptions(); + $GLOBALS['tbl_collation'] = $pma_table->getCollation(); + $GLOBALS['table_info_num_rows'] = $pma_table->getNumRows(); + $GLOBALS['row_format'] = $pma_table->getRowFormat(); + $GLOBALS['auto_increment'] = $pma_table->getAutoIncrement(); + $GLOBALS['create_options'] = $pma_table->getCreateOptions(); } - unset($reread_info); + unset($GLOBALS['reread_info']); - if (isset($result) && empty($message_to_show)) { + if (isset($GLOBALS['result']) && empty($GLOBALS['message_to_show'])) { if (empty($_message)) { - if (empty($sql_query)) { + if (empty($GLOBALS['sql_query'])) { $_message = Message::success(__('No change')); } else { - $_message = $result + $_message = $GLOBALS['result'] ? Message::success() : Message::error(); } @@ -325,67 +350,67 @@ class OperationsController extends AbstractController if ($this->response->isAjax()) { $this->response->setRequestStatus($_message->isSuccess()); $this->response->addJSON('message', $_message); - if (! empty($sql_query)) { + if (! empty($GLOBALS['sql_query'])) { $this->response->addJSON( 'sql_query', - Generator::getMessage('', $sql_query) + Generator::getMessage('', $GLOBALS['sql_query']) ); } return; } } else { - $_message = $result + $_message = $GLOBALS['result'] ? Message::success($_message) : Message::error($_message); } - if (! empty($warning_messages)) { + if (! empty($GLOBALS['warning_messages'])) { $_message = new Message(); - $_message->addMessagesString($warning_messages); + $_message->addMessagesString($GLOBALS['warning_messages']); $_message->isError(true); if ($this->response->isAjax()) { $this->response->setRequestStatus(false); $this->response->addJSON('message', $_message); - if (! empty($sql_query)) { + if (! empty($GLOBALS['sql_query'])) { $this->response->addJSON( 'sql_query', - Generator::getMessage('', $sql_query) + Generator::getMessage('', $GLOBALS['sql_query']) ); } return; } - unset($warning_messages); + unset($GLOBALS['warning_messages']); } - if (empty($sql_query)) { + if (empty($GLOBALS['sql_query'])) { $this->response->addHTML( $_message->getDisplay() ); } else { $this->response->addHTML( - Generator::getMessage($_message, $sql_query) + Generator::getMessage($_message, $GLOBALS['sql_query']) ); } unset($_message); } - $urlParams['goto'] = $urlParams['back'] = Url::getFromRoute('/table/operations'); + $GLOBALS['urlParams']['goto'] = $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/operations'); - $columns = $this->dbi->getColumns($db, $table); + $GLOBALS['columns'] = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table']); - $hideOrderTable = false; + $GLOBALS['hideOrderTable'] = false; // `ALTER TABLE ORDER BY` does not make sense for InnoDB tables that contain // a user-defined clustered index (PRIMARY KEY or NOT NULL UNIQUE index). // InnoDB always orders table rows according to such an index if one is present. - if ($tbl_storage_engine === 'INNODB') { - $indexes = Index::getFromTable($table, $db); - foreach ($indexes as $name => $idx) { + if ($GLOBALS['tbl_storage_engine'] === 'INNODB') { + $GLOBALS['indexes'] = Index::getFromTable($this->dbi, $GLOBALS['table'], $GLOBALS['db']); + foreach ($GLOBALS['indexes'] as $name => $idx) { if ($name === 'PRIMARY') { - $hideOrderTable = true; + $GLOBALS['hideOrderTable'] = true; break; } @@ -393,33 +418,33 @@ class OperationsController extends AbstractController continue; } - $notNull = true; + $GLOBALS['notNull'] = true; foreach ($idx->getColumns() as $column) { if ($column->getNull()) { - $notNull = false; + $GLOBALS['notNull'] = false; break; } } - if ($notNull) { - $hideOrderTable = true; + if ($GLOBALS['notNull']) { + $GLOBALS['hideOrderTable'] = true; break; } } } - $comment = ''; - if (mb_strstr((string) $show_comment, '; InnoDB free') === false) { - if (mb_strstr((string) $show_comment, 'InnoDB free') === false) { + $GLOBALS['comment'] = ''; + if (mb_strstr((string) $GLOBALS['show_comment'], '; InnoDB free') === false) { + if (mb_strstr((string) $GLOBALS['show_comment'], 'InnoDB free') === false) { // only user entered comment - $comment = (string) $show_comment; + $GLOBALS['comment'] = (string) $GLOBALS['show_comment']; } else { // here we have just InnoDB generated part - $comment = ''; + $GLOBALS['comment'] = ''; } } else { // remove InnoDB comment from end, just the minimal part (*? is non greedy) - $comment = preg_replace('@; InnoDB free:.*?$@', '', (string) $show_comment); + $GLOBALS['comment'] = preg_replace('@; InnoDB free:.*?$@', '', (string) $GLOBALS['show_comment']); } $storageEngines = StorageEngine::getArray(); @@ -427,11 +452,11 @@ class OperationsController extends AbstractController $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); - $hasPackKeys = isset($create_options['pack_keys']) + $hasPackKeys = isset($GLOBALS['create_options']['pack_keys']) && $pma_table->isEngine(['MYISAM', 'ARIA', 'ISAM']); $hasChecksumAndDelayKeyWrite = $pma_table->isEngine(['MYISAM', 'ARIA']); $hasTransactionalAndPageChecksum = $pma_table->isEngine('ARIA'); - $hasAutoIncrement = strlen((string) $auto_increment) > 0 + $hasAutoIncrement = strlen((string) $GLOBALS['auto_increment']) > 0 && $pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB']); $possibleRowFormats = $this->operations->getPossibleRowFormat(); @@ -441,7 +466,7 @@ class OperationsController extends AbstractController $databaseList = $GLOBALS['dblist']->databases->getList(); } - $hasForeignKeys = ! empty($this->relation->getForeigners($db, $table, '', 'foreign')); + $hasForeignKeys = ! empty($this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign')); $hasPrivileges = $GLOBALS['table_priv'] && $GLOBALS['col_priv'] && $GLOBALS['is_reload_priv']; $switchToNew = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new']; @@ -449,7 +474,7 @@ class OperationsController extends AbstractController $partitionsChoices = []; if (Partition::havePartitioning()) { - $partitionNames = Partition::getPartitionNames($db, $table); + $partitionNames = Partition::getPartitionNames($GLOBALS['db'], $GLOBALS['table']); if (isset($partitionNames[0])) { $partitions = $partitionNames; $partitionsChoices = $this->operations->getPartitionMaintenanceChoices(); @@ -457,40 +482,40 @@ class OperationsController extends AbstractController } $foreigners = $this->operations->getForeignersForReferentialIntegrityCheck( - $urlParams, + $GLOBALS['urlParams'], $relationParameters->relationFeature !== null ); $this->render('table/operations/index', [ - 'db' => $db, - 'table' => $table, - 'url_params' => $urlParams, - 'columns' => $columns, - 'hide_order_table' => $hideOrderTable, - 'table_comment' => $comment, - 'storage_engine' => $tbl_storage_engine, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'url_params' => $GLOBALS['urlParams'], + 'columns' => $GLOBALS['columns'], + 'hide_order_table' => $GLOBALS['hideOrderTable'], + 'table_comment' => $GLOBALS['comment'], + 'storage_engine' => $GLOBALS['tbl_storage_engine'], 'storage_engines' => $storageEngines, 'charsets' => $charsets, 'collations' => $collations, - 'tbl_collation' => $tbl_collation, - 'row_formats' => $possibleRowFormats[$tbl_storage_engine] ?? [], + 'tbl_collation' => $GLOBALS['tbl_collation'], + 'row_formats' => $possibleRowFormats[$GLOBALS['tbl_storage_engine']] ?? [], 'row_format_current' => $GLOBALS['showtable']['Row_format'], 'has_auto_increment' => $hasAutoIncrement, - 'auto_increment' => $auto_increment, + 'auto_increment' => $GLOBALS['auto_increment'], 'has_pack_keys' => $hasPackKeys, - 'pack_keys' => $create_options['pack_keys'] ?? '', + 'pack_keys' => $GLOBALS['create_options']['pack_keys'] ?? '', 'has_transactional_and_page_checksum' => $hasTransactionalAndPageChecksum, 'has_checksum_and_delay_key_write' => $hasChecksumAndDelayKeyWrite, - 'delay_key_write' => empty($create_options['delay_key_write']) ? '0' : '1', - 'transactional' => ($create_options['transactional'] ?? '') == '0' ? '0' : '1', - 'page_checksum' => $create_options['page_checksum'] ?? '', - 'checksum' => empty($create_options['checksum']) ? '0' : '1', + 'delay_key_write' => empty($GLOBALS['create_options']['delay_key_write']) ? '0' : '1', + 'transactional' => ($GLOBALS['create_options']['transactional'] ?? '') == '0' ? '0' : '1', + 'page_checksum' => $GLOBALS['create_options']['page_checksum'] ?? '', + 'checksum' => empty($GLOBALS['create_options']['checksum']) ? '0' : '1', 'database_list' => $databaseList, 'has_foreign_keys' => $hasForeignKeys, 'has_privileges' => $hasPrivileges, 'switch_to_new' => $switchToNew, 'is_system_schema' => $isSystemSchema, - 'is_view' => $tbl_is_view, + 'is_view' => $GLOBALS['tbl_is_view'], 'partitions' => $partitions, 'partitions_choices' => $partitionsChoices, 'foreigners' => $foreigners, diff --git a/libraries/classes/Controllers/Table/Partition/AnalyzeController.php b/libraries/classes/Controllers/Table/Partition/AnalyzeController.php index ee36f56eb9..e43496c998 100644 --- a/libraries/classes/Controllers/Table/Partition/AnalyzeController.php +++ b/libraries/classes/Controllers/Table/Partition/AnalyzeController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class AnalyzeController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class AnalyzeController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/CheckController.php b/libraries/classes/Controllers/Table/Partition/CheckController.php index 7d51c3b0c0..d82e851344 100644 --- a/libraries/classes/Controllers/Table/Partition/CheckController.php +++ b/libraries/classes/Controllers/Table/Partition/CheckController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class CheckController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class CheckController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/DropController.php b/libraries/classes/Controllers/Table/Partition/DropController.php index 73e28246cf..2bdb12103d 100644 --- a/libraries/classes/Controllers/Table/Partition/DropController.php +++ b/libraries/classes/Controllers/Table/Partition/DropController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class DropController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class DropController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/OptimizeController.php b/libraries/classes/Controllers/Table/Partition/OptimizeController.php index bfd1a97b8b..a143aed147 100644 --- a/libraries/classes/Controllers/Table/Partition/OptimizeController.php +++ b/libraries/classes/Controllers/Table/Partition/OptimizeController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class OptimizeController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class OptimizeController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/RebuildController.php b/libraries/classes/Controllers/Table/Partition/RebuildController.php index b02e1a5e13..aa612cc412 100644 --- a/libraries/classes/Controllers/Table/Partition/RebuildController.php +++ b/libraries/classes/Controllers/Table/Partition/RebuildController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class RebuildController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class RebuildController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/RepairController.php b/libraries/classes/Controllers/Table/Partition/RepairController.php index 917d777d08..453ac2bae5 100644 --- a/libraries/classes/Controllers/Table/Partition/RepairController.php +++ b/libraries/classes/Controllers/Table/Partition/RepairController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class RepairController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class RepairController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/Partition/TruncateController.php b/libraries/classes/Controllers/Table/Partition/TruncateController.php index abba02626f..b87f076ba3 100644 --- a/libraries/classes/Controllers/Table/Partition/TruncateController.php +++ b/libraries/classes/Controllers/Table/Partition/TruncateController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Partition; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; @@ -26,11 +27,9 @@ final class TruncateController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Maintenance $maintenance ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->model = $maintenance; } @@ -39,10 +38,10 @@ final class TruncateController extends AbstractController $partitionName = $request->getParsedBodyParam('partition_name'); try { - Assert::stringNotEmpty($partitionName); + Assert::stringNotEmpty($partitionName, __('The partition name must be a non-empty string.')); $database = DatabaseName::fromValue($request->getParam('db')); $table = TableName::fromValue($request->getParam('table')); - } catch (InvalidArgumentException $exception) { + } catch (InvalidIdentifierName | InvalidArgumentException $exception) { $message = Message::error($exception->getMessage()); $this->response->addHTML($message->getDisplay()); diff --git a/libraries/classes/Controllers/Table/PrivilegesController.php b/libraries/classes/Controllers/Table/PrivilegesController.php index 37e5379a19..d3682a8445 100644 --- a/libraries/classes/Controllers/Table/PrivilegesController.php +++ b/libraries/classes/Controllers/Table/PrivilegesController.php @@ -7,12 +7,17 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\CheckUserPrivileges; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Privileges; use PhpMyAdmin\Template; use PhpMyAdmin\Util; +use function __; use function mb_strtolower; /** @@ -29,31 +34,55 @@ class PrivilegesController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Privileges $privileges, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->privileges = $privileges; $this->dbi = $dbi; } - /** - * @param string[] $params Request parameters - * @psalm-param array{checkprivsdb: string, checkprivstable: string} $params - */ - public function __invoke(array $params): string + public function __invoke(ServerRequest $request): void { - global $cfg, $text_dir; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; - $scriptName = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + $checkUserPrivileges = new CheckUserPrivileges($this->dbi); + $checkUserPrivileges->getPrivileges(); - $db = $params['checkprivsdb']; - $table = $params['checkprivstable']; + $this->addScriptFiles(['server/privileges.js', 'vendor/zxcvbn-ts.js']); + + /** + * Checks if the user is allowed to do what they try to... + */ + $isGrantUser = $this->dbi->isGrantUser(); + $isCreateUser = $this->dbi->isCreateUser(); + + if (! $this->dbi->isSuperUser() && ! $isGrantUser && ! $isCreateUser) { + $this->render('server/sub_page_header', [ + 'type' => 'privileges', + 'is_image' => false, + ]); + $this->response->addHTML( + Message::error(__('No Privileges')) + ->getDisplay() + ); + + return; + } + + if (! $isGrantUser && ! $isCreateUser) { + $this->response->addHTML(Message::notice( + __('You do not have the privileges to administrate the users!') + )->getDisplay()); + } + + $scriptName = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + + $db = $GLOBALS['db']; + $table = $GLOBALS['table']; if ($this->dbi->getLowerCaseNames() === '1') { - $db = mb_strtolower($params['checkprivsdb']); - $table = mb_strtolower($params['checkprivstable']); + $db = mb_strtolower($GLOBALS['db']); + $table = mb_strtolower($GLOBALS['table']); } $privileges = []; @@ -61,15 +90,16 @@ class PrivilegesController extends AbstractController $privileges = $this->privileges->getAllPrivileges($db, $table); } - return $this->template->render('table/privileges/index', [ + $this->render('table/privileges/index', [ 'db' => $db, 'table' => $table, 'is_superuser' => $this->dbi->isSuperUser(), 'table_url' => $scriptName, - 'text_dir' => $text_dir, + 'text_dir' => $GLOBALS['text_dir'], 'is_createuser' => $this->dbi->isCreateUser(), 'is_grantuser' => $this->dbi->isGrantUser(), 'privileges' => $privileges, ]); + $this->render('export_modal'); } } diff --git a/libraries/classes/Controllers/Table/RecentFavoriteController.php b/libraries/classes/Controllers/Table/RecentFavoriteController.php index 6e22ba7e46..2d4770adb0 100644 --- a/libraries/classes/Controllers/Table/RecentFavoriteController.php +++ b/libraries/classes/Controllers/Table/RecentFavoriteController.php @@ -4,24 +4,30 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Sql\SqlController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\RecentFavoriteTable; +use function is_string; + /** * Browse recent and favorite tables chosen from navigation. */ class RecentFavoriteController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $containerBuilder; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; - RecentFavoriteTable::getInstance('recent')->removeIfInvalid($_REQUEST['db'], $_REQUEST['table']); + $db = isset($_REQUEST['db']) && is_string($_REQUEST['db']) ? $_REQUEST['db'] : ''; + $table = isset($_REQUEST['table']) && is_string($_REQUEST['table']) ? $_REQUEST['table'] : ''; - RecentFavoriteTable::getInstance('favorite')->removeIfInvalid($_REQUEST['db'], $_REQUEST['table']); + RecentFavoriteTable::getInstance('recent')->removeIfInvalid($db, $table); + RecentFavoriteTable::getInstance('favorite')->removeIfInvalid($db, $table); /** @var SqlController $controller */ - $controller = $containerBuilder->get(SqlController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(SqlController::class); + $controller($request); } } diff --git a/libraries/classes/Controllers/Table/RelationController.php b/libraries/classes/Controllers/Table/RelationController.php index dca69b8a22..48d94bb7ad 100644 --- a/libraries/classes/Controllers/Table/RelationController.php +++ b/libraries/classes/Controllers/Table/RelationController.php @@ -7,9 +7,11 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\Features\DisplayFeature; use PhpMyAdmin\ConfigStorage\Features\RelationFeature; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table; @@ -43,12 +45,10 @@ final class RelationController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->relation = $relation; $this->dbi = $dbi; } @@ -56,10 +56,8 @@ final class RelationController extends AbstractController /** * Index */ - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $route; - $options = [ 'CASCADE' => 'CASCADE', 'SET_NULL' => 'SET NULL', @@ -67,19 +65,19 @@ final class RelationController extends AbstractController 'RESTRICT' => 'RESTRICT', ]; - $table = $this->dbi->getTable($this->db, $this->table); + $table = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); $storageEngine = mb_strtoupper((string) $table->getStatusInfo('Engine')); $relationParameters = $this->relation->getRelationParameters(); $relations = []; if ($relationParameters->relationFeature !== null) { - $relations = $this->relation->getForeigners($this->db, $this->table, '', 'internal'); + $relations = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'internal'); } $relationsForeign = []; if (ForeignKey::isSupported($storageEngine)) { - $relationsForeign = $this->relation->getForeigners($this->db, $this->table, '', 'foreign'); + $relationsForeign = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign'); } // Send table of column names to populate corresponding dropdowns depending @@ -98,7 +96,7 @@ final class RelationController extends AbstractController $this->addScriptFiles(['table/relation.js', 'indexes.js']); // Set the database - $this->dbi->selectDb($this->db); + $this->dbi->selectDb($GLOBALS['db']); // updates for Internal relations if (isset($_POST['destination_db']) && $relationParameters->relationFeature !== null) { @@ -115,11 +113,11 @@ final class RelationController extends AbstractController // If we did an update, refresh our data if (isset($_POST['destination_db']) && $relationParameters->relationFeature !== null) { - $relations = $this->relation->getForeigners($this->db, $this->table, '', 'internal'); + $relations = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'internal'); } if (isset($_POST['destination_foreign_db']) && ForeignKey::isSupported($storageEngine)) { - $relationsForeign = $this->relation->getForeigners($this->db, $this->table, '', 'foreign'); + $relationsForeign = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign'); } /** @@ -128,7 +126,7 @@ final class RelationController extends AbstractController // Now find out the columns of our $table // need to use DatabaseInterface::QUERY_BUFFERED with $this->dbi->numRows() // in mysqli - $columns = $this->dbi->getColumns($this->db, $this->table); + $columns = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table']); $column_array = []; $column_hash_array = []; @@ -146,18 +144,76 @@ final class RelationController extends AbstractController uksort($column_array, 'strnatcasecmp'); } + $foreignKeyRow = ''; + $existrelForeign = array_key_exists('foreign_keys_data', $relationsForeign) + ? $relationsForeign['foreign_keys_data'] + : []; + $i = 0; + + foreach ($existrelForeign as $key => $oneKey) { + $foreignDb = $oneKey['ref_db_name'] ?? $GLOBALS['db']; + $foreignTable = false; + if ($foreignDb) { + $foreignTable = $oneKey['ref_table_name'] ?? false; + $tables = $this->relation->getTables($foreignDb, $storageEngine); + } else { + $tables = $this->relation->getTables($GLOBALS['db'], $storageEngine); + } + + $uniqueColumns = []; + if ($foreignDb && $foreignTable) { + $tableObject = Table::get( + $foreignTable, + $foreignDb + ); + $uniqueColumns = $tableObject->getUniqueColumns(false, false); + } + + $foreignKeyRow .= $this->template->render('table/relation/foreign_key_row', [ + 'i' => $i, + 'one_key' => $oneKey, + 'column_array' => $column_array, + 'options_array' => $options, + 'tbl_storage_engine' => $storageEngine, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'url_params' => $GLOBALS['urlParams'], + 'databases' => $GLOBALS['dblist']->databases, + 'foreign_db' => $foreignDb, + 'foreign_table' => $foreignTable, + 'unique_columns' => $uniqueColumns, + 'tables' => $tables, + ]); + $i++; + } + + $tables = $this->relation->getTables($GLOBALS['db'], $storageEngine); + $foreignKeyRow .= $this->template->render('table/relation/foreign_key_row', [ + 'i' => $i, + 'one_key' => [], + 'column_array' => $column_array, + 'options_array' => $options, + 'tbl_storage_engine' => $storageEngine, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'url_params' => $GLOBALS['urlParams'], + 'databases' => $GLOBALS['dblist']->databases, + 'foreign_db' => false, + 'foreign_table' => false, + 'unique_columns' => [], + 'tables' => $tables, + ]); + // common form - $engine = $this->dbi->getTable($this->db, $this->table)->getStorageEngine(); + $engine = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->getStorageEngine(); $this->render('table/relation/common_form', [ 'is_foreign_key_supported' => ForeignKey::isSupported($engine), - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'relation_parameters' => $relationParameters, 'tbl_storage_engine' => $storageEngine, 'existrel' => $relations, - 'existrel_foreign' => array_key_exists('foreign_keys_data', $relationsForeign) - ? $relationsForeign['foreign_keys_data'] - : [], + 'existrel_foreign' => $existrelForeign, 'options_array' => $options, 'column_array' => $column_array, 'column_hash_array' => $column_hash_array, @@ -166,7 +222,9 @@ final class RelationController extends AbstractController 'databases' => $GLOBALS['dblist']->databases, 'dbi' => $this->dbi, 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], - 'route' => $route, + 'route' => $request->getRoute(), + 'display_field' => $this->relation->getDisplayField($GLOBALS['db'], $GLOBALS['table']), + 'foreign_key_row' => $foreignKeyRow, ]); } @@ -216,7 +274,7 @@ final class RelationController extends AbstractController $_POST['destination_foreign_table'], $_POST['destination_foreign_column'], $options, - $this->table, + $GLOBALS['table'], array_key_exists('foreign_keys_data', $relationsForeign) ? $relationsForeign['foreign_keys_data'] : [] @@ -300,9 +358,8 @@ final class RelationController extends AbstractController $this->response->addJSON('columns', $columnList); - // @todo should be: $server->db($db)->table($table)->primary() - $primary = Index::getPrimary($foreignTable, $_POST['foreignDb']); - if ($primary === false) { + $primary = Index::getPrimary($this->dbi, $foreignTable, $_POST['foreignDb']); + if ($primary === null) { return; } diff --git a/libraries/classes/Controllers/Table/ReplaceController.php b/libraries/classes/Controllers/Table/ReplaceController.php index a841b1c333..ed49fc32df 100644 --- a/libraries/classes/Controllers/Table/ReplaceController.php +++ b/libraries/classes/Controllers/Table/ReplaceController.php @@ -5,13 +5,16 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Database\SqlController as DatabaseSqlController; use PhpMyAdmin\Controllers\Sql\SqlController; use PhpMyAdmin\Controllers\Table\SqlController as TableSqlController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\EditField; use PhpMyAdmin\File; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\InsertEdit; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins\IOTransformationsPlugin; @@ -22,12 +25,11 @@ use PhpMyAdmin\Transformations; use PhpMyAdmin\Util; use function __; -use function array_keys; use function array_values; use function class_exists; -use function count; use function implode; use function in_array; +use function is_array; use function is_file; use function is_numeric; use function method_exists; @@ -54,37 +56,33 @@ final class ReplaceController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, InsertEdit $insertEdit, Transformations $transformations, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->insertEdit = $insertEdit; $this->transformations = $transformations; $this->relation = $relation; $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $containerBuilder, $db, $table, $urlParams, $message; - global $errorUrl, $mime_map, $unsaved_values, $active_page, $disp_query, $disp_message; - global $goto_include, $loop_array, $using_key, $is_insert, $is_insertignore, $query; - global $value_sets, $func_no_param, $func_optional_param, $gis_from_text_functions, $gis_from_wkb_functions; - global $query_fields, $insert_errors, $row_skipped, $query_values; - global $total_affected_rows, $last_messages, $warning_messages, $error_messages, $return_to_sql_query; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $this->checkParameters(['db', 'table', 'goto']); - Util::checkParameters(['db', 'table', 'goto']); + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['unsaved_values'] = $GLOBALS['unsaved_values'] ?? null; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['disp_query'] = $GLOBALS['disp_query'] ?? null; + $GLOBALS['disp_message'] = $GLOBALS['disp_message'] ?? null; + $GLOBALS['query'] = $GLOBALS['query'] ?? null; - $this->dbi->selectDb($db); - - /** - * Initializes some variables - */ - $goto_include = false; + $this->dbi->selectDb($GLOBALS['db']); $this->addScriptFiles(['makegrid.js', 'sql.js', 'indexes.js', 'gis_data_editor.js']); @@ -97,8 +95,8 @@ final class ReplaceController extends AbstractController ]); $GLOBALS['cfg']['InsertRows'] = $_POST['insert_rows']; /** @var ChangeController $controller */ - $controller = $containerBuilder->get(ChangeController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(ChangeController::class); + $controller($request); return; } @@ -109,11 +107,11 @@ final class ReplaceController extends AbstractController 'edit_next', ]; if (isset($_POST['after_insert']) && in_array($_POST['after_insert'], $after_insert_actions)) { - $urlParams['after_insert'] = $_POST['after_insert']; + $GLOBALS['urlParams']['after_insert'] = $_POST['after_insert']; if (isset($_POST['where_clause'])) { foreach ($_POST['where_clause'] as $one_where_clause) { if ($_POST['after_insert'] === 'same_insert') { - $urlParams['where_clause'][] = $one_where_clause; + $GLOBALS['urlParams']['where_clause'][] = $one_where_clause; } elseif ($_POST['after_insert'] === 'edit_next') { $this->insertEdit->setSessionForEditNext($one_where_clause); } @@ -122,142 +120,71 @@ final class ReplaceController extends AbstractController } //get $goto_include for different cases - $goto_include = $this->insertEdit->getGotoInclude($goto_include); + $gotoInclude = $this->insertEdit->getGotoInclude(false); // Defines the url to return in case of failure of the query - $errorUrl = $this->insertEdit->getErrorUrl($urlParams); + $GLOBALS['errorUrl'] = $this->insertEdit->getErrorUrl($GLOBALS['urlParams']); /** * Prepares the update/insert of a row */ [ - $loop_array, - $using_key, - $is_insert, - $is_insertignore, + $loopArray, + $usingKey, + $isInsert, + $isInsertignore, ] = $this->insertEdit->getParamsForUpdateOrInsert(); - $query = []; - $value_sets = []; - $func_no_param = [ - 'CONNECTION_ID', - 'CURRENT_USER', - 'CURDATE', - 'CURTIME', - 'CURRENT_DATE', - 'CURRENT_TIME', - 'DATABASE', - 'LAST_INSERT_ID', - 'NOW', - 'PI', - 'RAND', - 'SYSDATE', - 'UNIX_TIMESTAMP', - 'USER', - 'UTC_DATE', - 'UTC_TIME', - 'UTC_TIMESTAMP', - 'UUID', - 'UUID_SHORT', - 'VERSION', - ]; - $func_optional_param = [ - 'RAND', - 'UNIX_TIMESTAMP', - ]; - - $gis_from_text_functions = [ - 'GeomFromText', - 'GeomCollFromText', - 'LineFromText', - 'MLineFromText', - 'PointFromText', - 'MPointFromText', - 'PolyFromText', - 'MPolyFromText', - ]; - $gis_from_wkb_functions = [ - 'GeomFromWKB', - 'GeomCollFromWKB', - 'LineFromWKB', - 'MLineFromWKB', - 'PointFromWKB', - 'MPointFromWKB', - 'PolyFromWKB', - 'MPolyFromWKB', - ]; - if ($this->dbi->getVersion() >= 50600) { - $gis_from_text_functions = [ - 'ST_GeomFromText', - 'ST_GeomCollFromText', - 'ST_LineFromText', - 'ST_MLineFromText', - 'ST_PointFromText', - 'ST_MPointFromText', - 'ST_PolyFromText', - 'ST_MPolyFromText', - ]; - $gis_from_wkb_functions = [ - 'ST_GeomFromWKB', - 'ST_GeomCollFromWKB', - 'ST_LineFromWKB', - 'ST_MLineFromWKB', - 'ST_PointFromWKB', - 'ST_MPointFromWKB', - 'ST_PolyFromWKB', - 'ST_MPolyFromWKB', - ]; - } + $GLOBALS['query'] = []; + $valueSets = []; - $mime_map = $this->transformations->getMime($db, $table); - if ($mime_map === null) { - $mime_map = []; - } + $mimeMap = $this->transformations->getMime($GLOBALS['db'], $GLOBALS['table']) ?? []; - $query_fields = []; - $insert_errors = []; - $row_skipped = false; - $unsaved_values = []; - foreach ($loop_array as $rownumber => $where_clause) { + $queryFields = []; + $insertErrors = []; + $rowSkipped = false; + $GLOBALS['unsaved_values'] = []; + /** @var string|int $where_clause */ + foreach ($loopArray as $rownumber => $where_clause) { // skip fields to be ignored - if (! $using_key && isset($_POST['insert_ignore_' . $where_clause])) { + if (! $usingKey && isset($_POST['insert_ignore_' . $where_clause])) { continue; } // Defines the SET part of the sql query - $query_values = []; + $queryValues = []; // Map multi-edit keys to single-level arrays, dependent on how we got the fields $multi_edit_columns = $_POST['fields']['multi_edit'][$rownumber] ?? []; $multi_edit_columns_name = $_POST['fields_name']['multi_edit'][$rownumber] ?? []; - $multi_edit_columns_prev = $_POST['fields_prev']['multi_edit'][$rownumber] ?? null; - $multi_edit_funcs = $_POST['funcs']['multi_edit'][$rownumber] ?? null; - $multi_edit_salt = $_POST['salt']['multi_edit'][$rownumber] ?? null; - $multi_edit_columns_type = $_POST['fields_type']['multi_edit'][$rownumber] ?? null; - $multi_edit_columns_null = $_POST['fields_null']['multi_edit'][$rownumber] ?? null; - $multi_edit_columns_null_prev = $_POST['fields_null_prev']['multi_edit'][$rownumber] ?? null; - $multi_edit_auto_increment = $_POST['auto_increment']['multi_edit'][$rownumber] ?? null; - $multi_edit_virtual = $_POST['virtual']['multi_edit'][$rownumber] ?? null; - - // When a select field is nullified, it's not present in $_POST - // so initialize it; this way, the foreach($multi_edit_columns) will process it - foreach (array_keys($multi_edit_columns_name) as $key) { - if (isset($multi_edit_columns[$key])) { - continue; - } - - $multi_edit_columns[$key] = ''; - } + $multi_edit_columns_prev = $_POST['fields_prev']['multi_edit'][$rownumber] ?? []; + $multi_edit_funcs = $_POST['funcs']['multi_edit'][$rownumber] ?? []; + $multi_edit_salt = $_POST['salt']['multi_edit'][$rownumber] ?? []; + $multi_edit_columns_type = $_POST['fields_type']['multi_edit'][$rownumber] ?? []; + $multi_edit_columns_null = $_POST['fields_null']['multi_edit'][$rownumber] ?? []; + $multi_edit_columns_null_prev = $_POST['fields_null_prev']['multi_edit'][$rownumber] ?? []; + $multi_edit_auto_increment = $_POST['auto_increment']['multi_edit'][$rownumber] ?? []; + $multi_edit_virtual = $_POST['virtual']['multi_edit'][$rownumber] ?? []; // Iterate in the order of $multi_edit_columns_name, // not $multi_edit_columns, to avoid problems // when inserting multiple entries $insert_fail = false; + /** @var int|string $key */ foreach ($multi_edit_columns_name as $key => $column_name) { - $current_value = $multi_edit_columns[$key]; // Note: $key is an md5 of the fieldname. The actual fieldname is // available in $multi_edit_columns_name[$key] + // When a select field is nullified, it's not present in $_POST so initialize it + $multi_edit_columns[$key] = $multi_edit_columns[$key] ?? ''; + + /** @var string[]|string $current_value */ + $current_value = $multi_edit_columns[$key]; + if (is_array($current_value)) { + // Some column types accept comma-separated values e.g. set + $current_value = implode(',', $current_value); + } + $file_to_insert = new File(); $file_to_insert->checkTblChangeForm((string) $key, (string) $rownumber); @@ -267,16 +194,19 @@ final class ReplaceController extends AbstractController } // Apply Input Transformation if defined - if (! empty($mime_map[$column_name]) && ! empty($mime_map[$column_name]['input_transformation'])) { + if ( + ! empty($mimeMap[$column_name]) + && ! empty($mimeMap[$column_name]['input_transformation']) + ) { $filename = 'libraries/classes/Plugins/Transformations/' - . $mime_map[$column_name]['input_transformation']; + . $mimeMap[$column_name]['input_transformation']; if (is_file(ROOT_PATH . $filename)) { $classname = $this->transformations->getClassName($filename); if (class_exists($classname)) { /** @var IOTransformationsPlugin $transformation_plugin */ $transformation_plugin = new $classname(); $transformation_options = $this->transformations->getOptions( - $mime_map[$column_name]['input_transformation_options'] + $mimeMap[$column_name]['input_transformation_options'] ); $current_value = $transformation_plugin->applyTransformation( $current_value, @@ -289,8 +219,8 @@ final class ReplaceController extends AbstractController && ! $transformation_plugin->isSuccess() ) { $insert_fail = true; - $row_skipped = true; - $insert_errors[] = sprintf( + $rowSkipped = true; + $insertErrors[] = sprintf( __('Row: %1$s, Column: %2$s, Error: %3$s'), $rownumber, $column_name, @@ -302,86 +232,68 @@ final class ReplaceController extends AbstractController } if ($file_to_insert->isError()) { - $insert_errors[] = $file_to_insert->getError(); + $insertErrors[] = $file_to_insert->getError(); } // delete $file_to_insert temporary variable $file_to_insert->cleanUp(); - if (empty($multi_edit_funcs[$key])) { - $current_value_as_an_array = $this->insertEdit->getCurrentValueForDifferentTypes( - $possibly_uploaded_val, - $key, - $multi_edit_columns_type, - $current_value, - $multi_edit_auto_increment, - $rownumber, - $multi_edit_columns_name, - $multi_edit_columns_null, - $multi_edit_columns_null_prev, - $is_insert, - $using_key, - $where_clause, - $table, - $multi_edit_funcs - ); - } else { - $current_value_as_an_array = $this->insertEdit->getCurrentValueAsAnArrayForMultipleEdit( - $multi_edit_funcs, - $multi_edit_salt, - $gis_from_text_functions, - $current_value, - $gis_from_wkb_functions, - $func_optional_param, - $func_no_param, - $key - ); - } + $editField = new EditField( + $column_name, + $current_value, + $multi_edit_columns_type[$key] ?? '', + isset($multi_edit_auto_increment[$key]), + ! empty($multi_edit_columns_null[$key]), + ! empty($multi_edit_columns_null_prev[$key]), + $multi_edit_funcs[$key] ?? '', + $multi_edit_salt[$key] ?? null, + $multi_edit_columns_prev[$key] ?? null, + $possibly_uploaded_val !== false + ); + + if (! isset($multi_edit_virtual[$key])) { + if ($isInsert) { + $queryPart = $this->insertEdit->getQueryValueForInsert( + $editField, + $usingKey, + $where_clause + ); + if ($queryPart !== '' && $valueSets === []) { + // first inserted row so prepare the list of fields + $queryFields[] = Util::backquote($editField->columnName); + } + } else { + $queryPart = $this->insertEdit->getQueryValueForUpdate($editField); + } - if (! isset($multi_edit_virtual, $multi_edit_virtual[$key])) { - [ - $query_values, - $query_fields, - ] = $this->insertEdit->getQueryValuesForInsertAndUpdateInMultipleEdit( - $multi_edit_columns_name, - $multi_edit_columns_null, - $current_value, - $multi_edit_columns_prev, - $multi_edit_funcs, - $is_insert, - $query_values, - $query_fields, - $current_value_as_an_array, - $value_sets, - $key, - $multi_edit_columns_null_prev - ); + if ($queryPart !== '') { + $queryValues[] = $queryPart; + } } - if (! isset($multi_edit_columns_null[$key])) { - continue; + // phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed + if ($editField->isNull) { + $multi_edit_columns[$key] = null; } - - $multi_edit_columns[$key] = null; } // temporarily store rows not inserted // so that they can be populated again. if ($insert_fail) { - $unsaved_values[$rownumber] = $multi_edit_columns; + $GLOBALS['unsaved_values'][$rownumber] = $multi_edit_columns; } - if ($insert_fail || count($query_values) <= 0) { + if ($insert_fail || $queryValues === []) { continue; } - if ($is_insert) { - $value_sets[] = implode(', ', $query_values); + if ($isInsert) { + $valueSets[] = implode(', ', $queryValues); } else { // build update query $clauseIsUnique = $_POST['clause_is_unique'] ?? '';// Should contain 0 or 1 - $query[] = 'UPDATE ' . Util::backquote($table) - . ' SET ' . implode(', ', $query_values) + $GLOBALS['query'][] = 'UPDATE ' . Util::backquote($GLOBALS['table']) + . ' SET ' . implode(', ', $queryValues) . ' WHERE ' . $where_clause . ($clauseIsUnique ? '' : ' LIMIT 1'); } @@ -393,76 +305,36 @@ final class ReplaceController extends AbstractController $multi_edit_funcs, $multi_edit_columns_type, $multi_edit_columns_null, - $func_no_param, $multi_edit_auto_increment, - $current_value_as_an_array, $key, $current_value, - $loop_array, $where_clause, - $using_key, $multi_edit_columns_null_prev, - $insert_fail + $insert_fail, + $multi_edit_columns ); // Builds the sql query - if ($is_insert && count($value_sets) > 0) { - $query = $this->insertEdit->buildSqlQuery($is_insertignore, $query_fields, $value_sets); - } elseif (empty($query) && ! isset($_POST['preview_sql']) && ! $row_skipped) { + if ($isInsert && $valueSets !== []) { + $GLOBALS['query'] = $this->insertEdit->buildSqlQuery($isInsertignore, $queryFields, $valueSets); + } elseif (empty($GLOBALS['query']) && ! isset($_POST['preview_sql']) && ! $rowSkipped) { // No change -> move back to the calling script // // Note: logic passes here for inline edit - $message = Message::success(__('No change')); + $GLOBALS['message'] = Message::success(__('No change')); // Avoid infinite recursion - if ($goto_include === '/table/replace') { - $goto_include = '/table/change'; - } - - $active_page = $goto_include; - - if ($goto_include === '/sql') { - /** @var SqlController $controller */ - $controller = $containerBuilder->get(SqlController::class); - $controller(); - - return; - } - - if ($goto_include === '/database/sql') { - /** @var DatabaseSqlController $controller */ - $controller = $containerBuilder->get(DatabaseSqlController::class); - $controller(); - - return; + if ($gotoInclude === '/table/replace') { + $gotoInclude = '/table/change'; } - if ($goto_include === '/table/change') { - /** @var ChangeController $controller */ - $controller = $containerBuilder->get(ChangeController::class); - $controller(); - - return; - } - - if ($goto_include === '/table/sql') { - /** @var TableSqlController $controller */ - $controller = $containerBuilder->get(TableSqlController::class); - $controller(); - - return; - } - - /** @psalm-suppress UnresolvableInclude */ - include ROOT_PATH . Core::securePath($goto_include); + $this->moveBackToCallingScript($gotoInclude, $request); return; } - unset($multi_edit_columns, $is_insertignore); - // If there is a request for SQL previewing. if (isset($_POST['preview_sql'])) { - Core::previewSQL($query); + Core::previewSQL($GLOBALS['query']); return; } @@ -472,48 +344,39 @@ final class ReplaceController extends AbstractController * page */ [ - $urlParams, - $total_affected_rows, - $last_messages, - $warning_messages, - $error_messages, - $return_to_sql_query, - ] = $this->insertEdit->executeSqlQuery($urlParams, $query); - - if ($is_insert && (count($value_sets) > 0 || $row_skipped)) { - $message = Message::getMessageForInsertedRows($total_affected_rows); - $unsaved_values = array_values($unsaved_values); + $GLOBALS['urlParams'], + $totalAffectedRows, + $lastMessages, + $warningMessages, + $errorMessages, + $returnToSqlQuery, + ] = $this->insertEdit->executeSqlQuery($GLOBALS['urlParams'], $GLOBALS['query']); + + if ($isInsert && ($valueSets !== [] || $rowSkipped)) { + $GLOBALS['message'] = Message::getMessageForInsertedRows($totalAffectedRows); + $GLOBALS['unsaved_values'] = array_values($GLOBALS['unsaved_values']); } else { - $message = Message::getMessageForAffectedRows($total_affected_rows); + $GLOBALS['message'] = Message::getMessageForAffectedRows($totalAffectedRows); } - if ($row_skipped) { - $goto_include = '/table/change'; - $message->addMessagesString($insert_errors, '<br>'); - $message->isError(true); + if ($rowSkipped) { + $gotoInclude = '/table/change'; + $GLOBALS['message']->addMessagesString($insertErrors, '<br>'); + $GLOBALS['message']->isError(true); } - $message->addMessages($last_messages, '<br>'); + $GLOBALS['message']->addMessages($lastMessages, '<br>'); - if (! empty($warning_messages)) { - $message->addMessagesString($warning_messages, '<br>'); - $message->isError(true); + if (! empty($warningMessages)) { + $GLOBALS['message']->addMessagesString($warningMessages, '<br>'); + $GLOBALS['message']->isError(true); } - if (! empty($error_messages)) { - $message->addMessagesString($error_messages); - $message->isError(true); + if (! empty($errorMessages)) { + $GLOBALS['message']->addMessagesString($errorMessages); + $GLOBALS['message']->isError(true); } - unset( - $error_messages, - $warning_messages, - $total_affected_rows, - $last_messages, - $row_skipped, - $insert_errors - ); - /** * The following section only applies to grid editing. * However, verifying isAjax() is not enough to ensure we are coming from @@ -526,99 +389,20 @@ final class ReplaceController extends AbstractController * transformed fields, if they were edited. After that, output the correct * link/transformed value and exit */ - if (isset($_POST['rel_fields_list']) && $_POST['rel_fields_list'] != '') { - $map = $this->relation->getForeigners($db, $table, '', 'both'); - - /** @var array<int,array> $relation_fields */ - $relation_fields = []; - parse_str($_POST['rel_fields_list'], $relation_fields); - - // loop for each relation cell - foreach ($relation_fields as $cell_index => $curr_rel_field) { - foreach ($curr_rel_field as $relation_field => $relation_field_value) { - $where_comparison = "='" . $relation_field_value . "'"; - $dispval = $this->insertEdit->getDisplayValueForForeignTableColumn( - $where_comparison, - $map, - $relation_field - ); - - $extra_data['relations'][$cell_index] = $this->insertEdit->getLinkForRelationalDisplayField( - $map, - $relation_field, - $where_comparison, - $dispval, - $relation_field_value - ); - } - } - } - - if (isset($_POST['do_transformations']) && $_POST['do_transformations'] == true) { - $edited_values = []; - parse_str($_POST['transform_fields_list'], $edited_values); - - if (! isset($extra_data)) { - $extra_data = []; - } - - $transformation_types = [ - 'input_transformation', - 'transformation', - ]; - foreach ($mime_map as $transformation) { - $column_name = $transformation['column_name']; - foreach ($transformation_types as $type) { - $file = Core::securePath($transformation[$type]); - $extra_data = $this->insertEdit->transformEditedValues( - $db, - $table, - $transformation, - $edited_values, - $file, - $column_name, - $extra_data, - $type - ); - } - } - } - - // Need to check the inline edited value can be truncated by MySQL - // without informing while saving - $column_name = $_POST['fields_name']['multi_edit'][0][0]; - - $this->insertEdit->verifyWhetherValueCanBeTruncatedAndAppendExtraData( - $db, - $table, - $column_name, - $extra_data - ); - - /**Get the total row count of the table*/ - $_table = new Table($_POST['table'], $_POST['db']); - $extra_data['row_count'] = $_table->countRecords(); - - $extra_data['sql_query'] = Generator::getMessage($message, $GLOBALS['display_query']); - - $this->response->setRequestStatus($message->isSuccess()); - $this->response->addJSON('message', $message); - $this->response->addJSON($extra_data); + $this->doTransformations($mimeMap); return; } - if (! empty($return_to_sql_query)) { - $disp_query = $GLOBALS['sql_query']; - $disp_message = $message; - unset($message); - $GLOBALS['sql_query'] = $return_to_sql_query; + if (! empty($returnToSqlQuery)) { + $GLOBALS['disp_query'] = $GLOBALS['sql_query']; + $GLOBALS['disp_message'] = $GLOBALS['message']; + unset($GLOBALS['message']); + $GLOBALS['sql_query'] = $returnToSqlQuery; } $this->addScriptFiles(['vendor/jquery/additional-methods.js', 'table/change.js']); - $active_page = $goto_include; - /** * If user asked for "and then Insert another new row" we have to remove * WHERE clause information so that /table/change does not go back @@ -628,34 +412,126 @@ final class ReplaceController extends AbstractController unset($_POST['where_clause']); } - if ($goto_include === '/sql') { + $this->moveBackToCallingScript($gotoInclude, $request); + } + + /** + * @param string[][] $mimeMap + */ + private function doTransformations(array $mimeMap): void + { + if (isset($_POST['rel_fields_list']) && $_POST['rel_fields_list'] != '') { + $map = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table']); + + /** @var array<int,array> $relation_fields */ + $relation_fields = []; + parse_str($_POST['rel_fields_list'], $relation_fields); + + // loop for each relation cell + foreach ($relation_fields as $cell_index => $curr_rel_field) { + foreach ($curr_rel_field as $relation_field => $relation_field_value) { + $where_comparison = "='" . $relation_field_value . "'"; + $dispval = $this->insertEdit->getDisplayValueForForeignTableColumn( + $where_comparison, + $map, + $relation_field + ); + + $extra_data['relations'][$cell_index] = $this->insertEdit->getLinkForRelationalDisplayField( + $map, + $relation_field, + $where_comparison, + $dispval, + $relation_field_value + ); + } + } + } + + if (isset($_POST['do_transformations']) && $_POST['do_transformations'] == true) { + $edited_values = []; + parse_str($_POST['transform_fields_list'], $edited_values); + + if (! isset($extra_data)) { + $extra_data = []; + } + + $transformation_types = [ + 'input_transformation', + 'transformation', + ]; + foreach ($mimeMap as $transformation) { + $column_name = $transformation['column_name']; + foreach ($transformation_types as $type) { + $file = Core::securePath($transformation[$type]); + $extra_data = $this->insertEdit->transformEditedValues( + $GLOBALS['db'], + $GLOBALS['table'], + $transformation, + $edited_values, + $file, + $column_name, + $extra_data, + $type + ); + } + } + } + + // Need to check the inline edited value can be truncated by MySQL + // without informing while saving + $column_name = $_POST['fields_name']['multi_edit'][0][0]; + + $this->insertEdit->verifyWhetherValueCanBeTruncatedAndAppendExtraData( + $GLOBALS['db'], + $GLOBALS['table'], + $column_name, + $extra_data + ); + + /**Get the total row count of the table*/ + $_table = new Table($_POST['table'], $_POST['db']); + $extra_data['row_count'] = $_table->countRecords(); + + $extra_data['sql_query'] = Generator::getMessage($GLOBALS['message'], $GLOBALS['display_query']); + + $this->response->setRequestStatus($GLOBALS['message']->isSuccess()); + $this->response->addJSON('message', $GLOBALS['message']); + $this->response->addJSON($extra_data); + } + + private function moveBackToCallingScript(string $gotoInclude, ServerRequest $request): void + { + $GLOBALS['active_page'] = $gotoInclude; + + if ($gotoInclude === '/sql') { /** @var SqlController $controller */ - $controller = $containerBuilder->get(SqlController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(SqlController::class); + $controller($request); return; } - if ($goto_include === '/database/sql') { + if ($gotoInclude === '/database/sql') { /** @var DatabaseSqlController $controller */ - $controller = $containerBuilder->get(DatabaseSqlController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(DatabaseSqlController::class); + $controller($request); return; } - if ($goto_include === '/table/change') { + if ($gotoInclude === '/table/change') { /** @var ChangeController $controller */ - $controller = $containerBuilder->get(ChangeController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(ChangeController::class); + $controller($request); return; } - if ($goto_include === '/table/sql') { + if ($gotoInclude === '/table/sql') { /** @var TableSqlController $controller */ - $controller = $containerBuilder->get(TableSqlController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(TableSqlController::class); + $controller($request); return; } @@ -664,6 +540,6 @@ final class ReplaceController extends AbstractController * Load target page. */ /** @psalm-suppress UnresolvableInclude */ - require ROOT_PATH . Core::securePath($goto_include); + require ROOT_PATH . Core::securePath($gotoInclude); } } diff --git a/libraries/classes/Controllers/Table/SearchController.php b/libraries/classes/Controllers/Table/SearchController.php index 7c6e9cf6cb..85bb4c9560 100644 --- a/libraries/classes/Controllers/Table/SearchController.php +++ b/libraries/classes/Controllers/Table/SearchController.php @@ -6,9 +6,11 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; @@ -21,6 +23,7 @@ use PhpMyAdmin\Utils\Gis; use function in_array; use function intval; +use function is_array; use function mb_strtolower; use function md5; use function preg_match; @@ -93,13 +96,11 @@ class SearchController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Search $search, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->search = $search; $this->relation = $relation; $this->dbi = $dbi; @@ -121,7 +122,7 @@ class SearchController extends AbstractController private function loadTableInfo(): void { // Gets the list and number of columns - $columns = $this->dbi->getColumns($this->db, $this->table, true); + $columns = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'], true); // Get details about the geometry functions $geom_types = Gis::getDataTypes(); @@ -164,23 +165,21 @@ class SearchController extends AbstractController } // Retrieve foreign keys - $this->foreigners = $this->relation->getForeigners($this->db, $this->table); + $this->foreigners = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table']); } /** * Index action */ - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $urlParams, $cfg, $errorUrl; + $this->checkParameters(['db', 'table']); - Util::checkParameters(['db', 'table']); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); - - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); $this->addScriptFiles([ 'makegrid.js', @@ -261,10 +260,10 @@ class SearchController extends AbstractController ); $this->response->addHTML($sql->executeQueryAndSendQueryResponse( - null, // analyzed_sql_results + null, false, // is_gotofile - $this->db, // db - $this->table, // table + $GLOBALS['db'], // db + $GLOBALS['table'], // table null, // find_real_end null, // sql_query_for_bookmark null, // extra_data @@ -283,23 +282,21 @@ class SearchController extends AbstractController */ public function displaySelectionFormAction(): void { - global $goto, $cfg; - - if (! isset($goto)) { - $goto = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); + if (! isset($GLOBALS['goto'])) { + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); } $this->render('table/search/index', [ - 'db' => $this->db, - 'table' => $this->table, - 'goto' => $goto, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'goto' => $GLOBALS['goto'], 'self' => $this, 'geom_column_flag' => $this->geomColumnFlag, 'column_names' => $this->columnNames, 'column_types' => $this->columnTypes, 'column_collations' => $this->columnCollations, - 'default_sliders_state' => $cfg['InitialSlidersState'], - 'max_rows' => intval($cfg['MaxRows']), + 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], + 'max_rows' => intval($GLOBALS['cfg']['MaxRows']), ]); } @@ -323,8 +320,8 @@ class SearchController extends AbstractController { $sql_query = 'SELECT MIN(' . Util::backquote($column) . ') AS `min`, ' . 'MAX(' . Util::backquote($column) . ') AS `max` ' - . 'FROM ' . Util::backquote($this->db) . '.' - . Util::backquote($this->table); + . 'FROM ' . Util::backquote($GLOBALS['db']) . '.' + . Util::backquote($GLOBALS['table']); return $this->dbi->fetchSingleRow($sql_query); } @@ -376,6 +373,27 @@ class SearchController extends AbstractController $htmlAttributes .= ' onfocus="return ' . 'verifyAfterSearchFieldChange(' . $search_index . ', \'#tbl_search_form\')"'; + $foreignDropdown = ''; + + $searchColumnInForeigners = $this->relation->searchColumnInForeigners( + $this->foreigners, + $this->columnNames[$column_index] + ); + + if ( + $this->foreigners + && $searchColumnInForeigners + && is_array($foreignData['disp_row']) + ) { + $foreignDropdown = $this->relation->foreignDropdown( + $foreignData['disp_row'], + $foreignData['foreign_field'], + $foreignData['foreign_display'], + '', + $GLOBALS['cfg']['ForeignKeyMaxLimit'] + ); + } + $value = $this->template->render('table/search/input_box', [ 'str' => '', 'column_type' => (string) $type, @@ -387,12 +405,13 @@ class SearchController extends AbstractController 'column_name' => $this->columnNames[$column_index], 'column_name_hash' => md5($this->columnNames[$column_index]), 'foreign_data' => $foreignData, - 'table' => $this->table, + 'table' => $GLOBALS['table'], 'column_index' => $search_index, - 'foreign_max_limit' => $GLOBALS['cfg']['ForeignKeyMaxLimit'], 'criteria_values' => $entered_value, - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'in_fbs' => true, + 'foreign_dropdown' => $foreignDropdown, + 'search_column_in_foreigners' => $searchColumnInForeigners, ]); return [ diff --git a/libraries/classes/Controllers/Table/SqlController.php b/libraries/classes/Controllers/Table/SqlController.php index d78ea87de2..814a506111 100644 --- a/libraries/classes/Controllers/Table/SqlController.php +++ b/libraries/classes/Controllers/Table/SqlController.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Config\PageSettings; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; @@ -25,17 +27,17 @@ final class SqlController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, SqlQueryForm $sqlQueryForm ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->sqlQueryForm = $sqlQueryForm; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $errorUrl, $goto, $back, $db, $table, $cfg; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['back'] = $GLOBALS['back'] ?? null; $this->addScriptFiles(['makegrid.js', 'vendor/jquery/jquery.uitablefilter.js', 'sql.js']); @@ -43,24 +45,24 @@ final class SqlController extends AbstractController $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $url_params = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($url_params, '&'); + $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($url_params, '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); /** * After a syntax error, we return to this script * with the typed query in the textarea. */ - $goto = Url::getFromRoute('/table/sql'); - $back = Url::getFromRoute('/table/sql'); + $GLOBALS['goto'] = Url::getFromRoute('/table/sql'); + $GLOBALS['back'] = Url::getFromRoute('/table/sql'); $this->response->addHTML($this->sqlQueryForm->getHtml( - $db, - $table, + $GLOBALS['db'], + $GLOBALS['table'], $_GET['sql_query'] ?? true, false, isset($_POST['delimiter']) diff --git a/libraries/classes/Controllers/Table/Structure/AddIndexController.php b/libraries/classes/Controllers/Table/Structure/AddIndexController.php index 8384beb687..cc80e547b7 100644 --- a/libraries/classes/Controllers/Table/Structure/AddIndexController.php +++ b/libraries/classes/Controllers/Table/Structure/AddIndexController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,19 +27,17 @@ final class AddIndexController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $sql_query, $db, $table, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -51,24 +50,24 @@ final class AddIndexController extends AbstractController $i = 1; $selectedCount = count($selected); - $sql_query = 'ALTER TABLE ' . Util::backquote($table) . ' ADD INDEX('; + $GLOBALS['sql_query'] = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' ADD INDEX('; foreach ($selected as $field) { - $sql_query .= Util::backquote($field); - $sql_query .= $i++ === $selectedCount ? ');' : ', '; + $GLOBALS['sql_query'] .= Util::backquote($field); + $GLOBALS['sql_query'] .= $i++ === $selectedCount ? ');' : ', '; } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/AddKeyController.php b/libraries/classes/Controllers/Table/Structure/AddKeyController.php index 59f92f16b6..04c58cb0d9 100644 --- a/libraries/classes/Controllers/Table/Structure/AddKeyController.php +++ b/libraries/classes/Controllers/Table/Structure/AddKeyController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Sql\SqlController; -use PhpMyAdmin\Controllers\Table\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -21,24 +22,22 @@ final class AddKeyController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, SqlController $sqlController, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->sqlController = $sqlController; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $reload; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; - ($this->sqlController)(); + ($this->sqlController)($request); - $reload = true; + $GLOBALS['reload'] = true; - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/BrowseController.php b/libraries/classes/Controllers/Table/Structure/BrowseController.php index 2a79b26017..56ffb8b1a5 100644 --- a/libraries/classes/Controllers/Table/Structure/BrowseController.php +++ b/libraries/classes/Controllers/Table/Structure/BrowseController.php @@ -4,7 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ParseAnalyze; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; @@ -21,13 +22,13 @@ final class BrowseController extends AbstractController /** @var Sql */ private $sql; - public function __construct(ResponseRenderer $response, Template $template, string $db, string $table, Sql $sql) + public function __construct(ResponseRenderer $response, Template $template, Sql $sql) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->sql = $sql; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (empty($_POST['selected_fld'])) { $this->response->setRequestStatus(false); @@ -55,19 +56,19 @@ final class BrowseController extends AbstractController $sql_query = sprintf( 'SELECT %s FROM %s.%s', implode(', ', $fields), - Util::backquote($this->db), - Util::backquote($this->table) + Util::backquote($GLOBALS['db']), + Util::backquote($GLOBALS['table']) ); // Parse and analyze the query - [$analyzed_sql_results, $this->db] = ParseAnalyze::sqlQuery($sql_query, $this->db); + [$statementInfo, $GLOBALS['db']] = ParseAnalyze::sqlQuery($sql_query, $GLOBALS['db']); $this->response->addHTML( $this->sql->executeQueryAndGetQueryResponse( - $analyzed_sql_results ?? '', + $statementInfo, false, // is_gotofile - $this->db, // db - $this->table, // table + $GLOBALS['db'], // db + $GLOBALS['table'], // table null, // find_real_end null, // sql_query_for_bookmark null, // extra_data diff --git a/libraries/classes/Controllers/Table/Structure/CentralColumnsAddController.php b/libraries/classes/Controllers/Table/Structure/CentralColumnsAddController.php index 0e51b157cb..6607f36d0a 100644 --- a/libraries/classes/Controllers/Table/Structure/CentralColumnsAddController.php +++ b/libraries/classes/Controllers/Table/Structure/CentralColumnsAddController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\Database\CentralColumns; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -24,19 +25,17 @@ final class CentralColumnsAddController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, CentralColumns $centralColumns, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->centralColumns = $centralColumns; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -50,13 +49,13 @@ final class CentralColumnsAddController extends AbstractController $centralColsError = $this->centralColumns->syncUniqueColumns($selected, false); if ($centralColsError instanceof Message) { - $message = $centralColsError; + $GLOBALS['message'] = $centralColsError; } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/CentralColumnsRemoveController.php b/libraries/classes/Controllers/Table/Structure/CentralColumnsRemoveController.php index 23f311a7ac..aa1962d4bb 100644 --- a/libraries/classes/Controllers/Table/Structure/CentralColumnsRemoveController.php +++ b/libraries/classes/Controllers/Table/Structure/CentralColumnsRemoveController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\Database\CentralColumns; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -24,19 +25,17 @@ final class CentralColumnsRemoveController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, CentralColumns $centralColumns, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->centralColumns = $centralColumns; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -47,16 +46,16 @@ final class CentralColumnsRemoveController extends AbstractController return; } - $centralColsError = $this->centralColumns->deleteColumnsFromList($db, $selected, false); + $centralColsError = $this->centralColumns->deleteColumnsFromList($GLOBALS['db'], $selected, false); if ($centralColsError instanceof Message) { - $message = $centralColsError; + $GLOBALS['message'] = $centralColsError; } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/ChangeController.php b/libraries/classes/Controllers/Table/Structure/ChangeController.php index bb7c2cba21..4f894deca2 100644 --- a/libraries/classes/Controllers/Table/Structure/ChangeController.php +++ b/libraries/classes/Controllers/Table/Structure/ChangeController.php @@ -5,46 +5,37 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; use PhpMyAdmin\CheckUserPrivileges; -use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\ColumnsDefinition; use PhpMyAdmin\Template; -use PhpMyAdmin\Transformations; -use PhpMyAdmin\Url; use function __; use function count; final class ChangeController extends AbstractController { - /** @var Relation */ - private $relation; - - /** @var Transformations */ - private $transformations; - /** @var DatabaseInterface */ private $dbi; + /** @var ColumnsDefinition */ + private $columnsDefinition; + public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, - Relation $relation, - Transformations $transformations, - DatabaseInterface $dbi + DatabaseInterface $dbi, + ColumnsDefinition $columnsDefinition ) { - parent::__construct($response, $template, $db, $table); - $this->relation = $relation; - $this->transformations = $transformations; + parent::__construct($response, $template); $this->dbi = $dbi; + $this->columnsDefinition = $columnsDefinition; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (isset($_GET['change_column'])) { $this->displayHtmlForColumnChange(null); @@ -71,7 +62,7 @@ final class ChangeController extends AbstractController */ private function displayHtmlForColumnChange(?array $selected): void { - global $action, $num_fields; + $GLOBALS['num_fields'] = $GLOBALS['num_fields'] ?? null; if (empty($selected)) { $selected[] = $_REQUEST['field']; @@ -85,7 +76,7 @@ final class ChangeController extends AbstractController */ $fields_meta = []; for ($i = 0; $i < $selected_cnt; $i++) { - $value = $this->dbi->getColumn($this->db, $this->table, $selected[$i], true); + $value = $this->dbi->getColumn($GLOBALS['db'], $GLOBALS['table'], $selected[$i], true); if (count($value) === 0) { $message = Message::error( __('Failed to get description of column %s!') @@ -97,9 +88,7 @@ final class ChangeController extends AbstractController } } - $num_fields = count($fields_meta); - - $action = Url::getFromRoute('/table/structure/save'); + $GLOBALS['num_fields'] = count($fields_meta); /** * Form for changing properties. @@ -109,12 +98,11 @@ final class ChangeController extends AbstractController $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); - $templateData = ColumnsDefinition::displayForm( - $this->transformations, - $this->relation, - $this->dbi, - $action, - $num_fields, + $this->checkParameters(['server', 'db', 'table', 'num_fields']); + + $templateData = $this->columnsDefinition->displayForm( + '/table/structure/save', + $GLOBALS['num_fields'], null, $selected, $fields_meta diff --git a/libraries/classes/Controllers/Table/Structure/FulltextController.php b/libraries/classes/Controllers/Table/Structure/FulltextController.php index 55d6ea0c93..d5fcbd3c67 100644 --- a/libraries/classes/Controllers/Table/Structure/FulltextController.php +++ b/libraries/classes/Controllers/Table/Structure/FulltextController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,19 +27,17 @@ final class FulltextController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $sql_query, $db, $table, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -51,24 +50,24 @@ final class FulltextController extends AbstractController $i = 1; $selectedCount = count($selected); - $sql_query = 'ALTER TABLE ' . Util::backquote($table) . ' ADD FULLTEXT('; + $GLOBALS['sql_query'] = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' ADD FULLTEXT('; foreach ($selected as $field) { - $sql_query .= Util::backquote($field); - $sql_query .= $i++ === $selectedCount ? ');' : ', '; + $GLOBALS['sql_query'] .= Util::backquote($field); + $GLOBALS['sql_query'] .= $i++ === $selectedCount ? ');' : ', '; } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/MoveColumnsController.php b/libraries/classes/Controllers/Table/Structure/MoveColumnsController.php index 8f81d239b8..0302953c59 100644 --- a/libraries/classes/Controllers/Table/Structure/MoveColumnsController.php +++ b/libraries/classes/Controllers/Table/Structure/MoveColumnsController.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table; @@ -34,27 +35,25 @@ final class MoveColumnsController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; - $this->tableObj = $this->dbi->getTable($this->db, $this->table); + $this->tableObj = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! isset($_POST['move_columns']) || ! is_array($_POST['move_columns']) || ! $this->response->isAjax()) { return; } - $this->dbi->selectDb($this->db); + $this->dbi->selectDb($GLOBALS['db']); /** * load the definitions for all columns */ - $columns = $this->dbi->getColumnsFull($this->db, $this->table); + $columns = $this->dbi->getColumnsFull($GLOBALS['db'], $GLOBALS['table']); $column_names = array_keys($columns); $changes = []; @@ -146,7 +145,7 @@ final class MoveColumnsController extends AbstractController // query for moving the columns $sql_query = sprintf( 'ALTER TABLE %s %s', - Util::backquote($this->table), + Util::backquote($GLOBALS['table']), implode(', ', $changes) ); diff --git a/libraries/classes/Controllers/Table/Structure/PartitioningController.php b/libraries/classes/Controllers/Table/Structure/PartitioningController.php index 1c945e6d73..6984903742 100644 --- a/libraries/classes/Controllers/Table/Structure/PartitioningController.php +++ b/libraries/classes/Controllers/Table/Structure/PartitioningController.php @@ -5,11 +5,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; use PhpMyAdmin\Config\PageSettings; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\CreateAddField; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Partitioning\TablePartitionDefinition; use PhpMyAdmin\ResponseRenderer; @@ -41,24 +42,22 @@ final class PartitioningController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, CreateAddField $createAddField, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->createAddField = $createAddField; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (isset($_POST['save_partitioning'])) { - $this->dbi->selectDb($this->db); + $this->dbi->selectDb($GLOBALS['db']); $this->updatePartitioning(); - ($this->structureController)(); + ($this->structureController)($request); return; } @@ -78,8 +77,8 @@ final class PartitioningController extends AbstractController $partitionDetails = TablePartitionDefinition::getDetails($partitionDetails); $this->render('table/structure/partition_definition_form', [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'partition_details' => $partitionDetails, 'storage_engines' => $storageEngines, ]); @@ -92,7 +91,7 @@ final class PartitioningController extends AbstractController */ private function extractPartitionDetails(): ?array { - $createTable = (new Table($this->table, $this->db))->showCreate(); + $createTable = (new Table($GLOBALS['table'], $GLOBALS['db']))->showCreate(); if (! $createTable) { return null; } @@ -253,7 +252,7 @@ final class PartitioningController extends AbstractController private function updatePartitioning(): void { - $sql_query = 'ALTER TABLE ' . Util::backquote($this->table) . ' ' + $sql_query = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' ' . $this->createAddField->getPartitionsDefinition(); // Execute alter query @@ -274,7 +273,7 @@ final class PartitioningController extends AbstractController $message = Message::success( __('Table %1$s has been altered successfully.') ); - $message->addParam($this->table); + $message->addParam($GLOBALS['table']); $this->response->addHTML( Generator::getMessage($message, $sql_query, 'success') ); diff --git a/libraries/classes/Controllers/Table/Structure/PrimaryController.php b/libraries/classes/Controllers/Table/Structure/PrimaryController.php index a554b68829..f77ed101e6 100644 --- a/libraries/classes/Controllers/Table/Structure/PrimaryController.php +++ b/libraries/classes/Controllers/Table/Structure/PrimaryController.php @@ -4,10 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -28,19 +29,19 @@ final class PrimaryController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $message, $sql_query, $urlParams, $errorUrl, $cfg; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $selected = $_POST['selected'] ?? []; $selected_fld = $_POST['selected_fld'] ?? []; @@ -62,17 +63,17 @@ final class PrimaryController extends AbstractController $mult_btn = $_POST['mult_btn'] ?? $mult_btn ?? ''; if (! empty($selected_fld) && ! empty($primary)) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); $this->render('table/structure/primary', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'selected' => $selected_fld, ]); @@ -80,33 +81,33 @@ final class PrimaryController extends AbstractController } if ($mult_btn === __('Yes')) { - $sql_query = 'ALTER TABLE ' . Util::backquote($table); + $GLOBALS['sql_query'] = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']); if (! empty($primary)) { - $sql_query .= ' DROP PRIMARY KEY,'; + $GLOBALS['sql_query'] .= ' DROP PRIMARY KEY,'; } - $sql_query .= ' ADD PRIMARY KEY('; + $GLOBALS['sql_query'] .= ' ADD PRIMARY KEY('; $i = 1; $selectedCount = count($selected); foreach ($selected as $field) { - $sql_query .= Util::backquote($field); - $sql_query .= $i++ === $selectedCount ? ');' : ', '; + $GLOBALS['sql_query'] .= Util::backquote($field); + $GLOBALS['sql_query'] .= $i++ === $selectedCount ? ');' : ', '; } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } /** @@ -116,9 +117,9 @@ final class PrimaryController extends AbstractController */ private function getKeyForTablePrimary() { - $this->dbi->selectDb($this->db); + $this->dbi->selectDb($GLOBALS['db']); $result = $this->dbi->query( - 'SHOW KEYS FROM ' . Util::backquote($this->table) . ';' + 'SHOW KEYS FROM ' . Util::backquote($GLOBALS['table']) . ';' ); $primary = ''; foreach ($result as $row) { diff --git a/libraries/classes/Controllers/Table/Structure/ReservedWordCheckController.php b/libraries/classes/Controllers/Table/Structure/ReservedWordCheckController.php index 606cce4e1d..2ce478cf4e 100644 --- a/libraries/classes/Controllers/Table/Structure/ReservedWordCheckController.php +++ b/libraries/classes/Controllers/Table/Structure/ReservedWordCheckController.php @@ -4,7 +4,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\SqlParser\Context; use function _ngettext; @@ -15,7 +16,7 @@ use function trim; final class ReservedWordCheckController extends AbstractController { - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if ($GLOBALS['cfg']['ReservedWordDisableWarning'] !== false) { $this->response->setRequestStatus(false); @@ -33,8 +34,8 @@ final class ReservedWordCheckController extends AbstractController $reserved_keywords_names[] = trim($column); } - if (Context::isKeyword(trim($this->table), true)) { - $reserved_keywords_names[] = trim($this->table); + if (Context::isKeyword(trim($GLOBALS['table']), true)) { + $reserved_keywords_names[] = trim($GLOBALS['table']); } if (count($reserved_keywords_names) === 0) { diff --git a/libraries/classes/Controllers/Table/Structure/SaveController.php b/libraries/classes/Controllers/Table/Structure/SaveController.php index c7b62c6c51..63f266eaa9 100644 --- a/libraries/classes/Controllers/Table/Structure/SaveController.php +++ b/libraries/classes/Controllers/Table/Structure/SaveController.php @@ -5,11 +5,12 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; @@ -48,23 +49,21 @@ final class SaveController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Relation $relation, Transformations $transformations, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->relation = $relation; $this->transformations = $transformations; $this->dbi = $dbi; $this->structureController = $structureController; - $this->tableObj = $this->dbi->getTable($this->db, $this->table); + $this->tableObj = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $regenerate = $this->updateColumns(); if (! $regenerate) { @@ -72,7 +71,7 @@ final class SaveController extends AbstractController unset($_POST['selected']); } - ($this->structureController)(); + ($this->structureController)($request); } /** @@ -83,15 +82,15 @@ final class SaveController extends AbstractController private function updateColumns(): bool { $err_url = Url::getFromRoute('/table/structure', [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], ]); $regenerate = false; $field_cnt = count($_POST['field_name'] ?? []); $changes = []; $adjust_privileges = []; $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) + ->getTable($GLOBALS['db'], $GLOBALS['table']) ->getColumnsWithIndex(Index::PRIMARY | Index::UNIQUE); for ($i = 0; $i < $field_cnt; $i++) { if (! $this->columnNeedsAlterTable($i)) { @@ -148,16 +147,16 @@ final class SaveController extends AbstractController // To allow replication, we first select the db to use // and then run queries on this db. - if (! $this->dbi->selectDb($this->db)) { + if (! $this->dbi->selectDb($GLOBALS['db'])) { Generator::mysqlDie( $this->dbi->getError(), - 'USE ' . Util::backquote($this->db) . ';', + 'USE ' . Util::backquote($GLOBALS['db']) . ';', false, $err_url ); } - $sql_query = 'ALTER TABLE ' . Util::backquote($this->table) . ' '; + $sql_query = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' '; $sql_query .= implode(', ', $changes) . $key_query; if (isset($_POST['online_transaction'])) { $sql_query .= ', ALGORITHM=INPLACE, LOCK=NONE'; @@ -173,7 +172,7 @@ final class SaveController extends AbstractController } $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) + ->getTable($GLOBALS['db'], $GLOBALS['table']) ->getColumnsWithIndex(Index::PRIMARY | Index::UNIQUE | Index::INDEX | Index::SPATIAL | Index::FULLTEXT); $changedToBlob = []; @@ -185,7 +184,7 @@ final class SaveController extends AbstractController && $_POST['field_collation'][$i] !== $_POST['field_collation_orig'][$i] && ! in_array($_POST['field_orig'][$i], $columns_with_index) ) { - $secondary_query = 'ALTER TABLE ' . Util::backquote($this->table) + $secondary_query = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' CHANGE ' . Util::backquote($_POST['field_orig'][$i]) . ' ' . Util::backquote($_POST['field_orig'][$i]) . ' BLOB'; @@ -224,7 +223,7 @@ final class SaveController extends AbstractController ); } - $message->addParam($this->table); + $message->addParam($GLOBALS['table']); $this->response->addHTML( Generator::getMessage($message, $sql_query, 'success') @@ -260,7 +259,7 @@ final class SaveController extends AbstractController ); } - $revert_query = 'ALTER TABLE ' . Util::backquote($this->table) + $revert_query = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' '; $revert_query .= implode(', ', $changes_revert) . ''; $revert_query .= ';'; @@ -286,7 +285,12 @@ final class SaveController extends AbstractController continue; } - $this->relation->renameField($this->db, $this->table, $fieldcontent, $_POST['field_name'][$fieldindex]); + $this->relation->renameField( + $GLOBALS['db'], + $GLOBALS['table'], + $fieldcontent, + $_POST['field_name'][$fieldindex] + ); } } @@ -298,8 +302,8 @@ final class SaveController extends AbstractController } $this->transformations->setMime( - $this->db, - $this->table, + $GLOBALS['db'], + $GLOBALS['table'], $_POST['field_name'][$fieldindex], $mimetype, $_POST['field_transformation'][$fieldindex], @@ -365,10 +369,7 @@ final class SaveController extends AbstractController { $changed = false; - if ( - Util::getValueByKey($GLOBALS, 'col_priv', false) - && Util::getValueByKey($GLOBALS, 'is_reload_priv', false) - ) { + if (($GLOBALS['col_priv'] ?? false) && ($GLOBALS['is_reload_priv'] ?? false)) { $this->dbi->selectDb('mysql'); // For Column specific privileges @@ -381,8 +382,8 @@ final class SaveController extends AbstractController AND Column_name = "%s";', Util::backquote('columns_priv'), $newCol, - $this->db, - $this->table, + $GLOBALS['db'], + $GLOBALS['table'], $oldCol ) ); diff --git a/libraries/classes/Controllers/Table/Structure/SpatialController.php b/libraries/classes/Controllers/Table/Structure/SpatialController.php index 4faea84138..74ab766bc8 100644 --- a/libraries/classes/Controllers/Table/Structure/SpatialController.php +++ b/libraries/classes/Controllers/Table/Structure/SpatialController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,19 +27,17 @@ final class SpatialController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $sql_query, $db, $table, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -51,24 +50,24 @@ final class SpatialController extends AbstractController $i = 1; $selectedCount = count($selected); - $sql_query = 'ALTER TABLE ' . Util::backquote($table) . ' ADD SPATIAL('; + $GLOBALS['sql_query'] = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' ADD SPATIAL('; foreach ($selected as $field) { - $sql_query .= Util::backquote($field); - $sql_query .= $i++ === $selectedCount ? ');' : ', '; + $GLOBALS['sql_query'] .= Util::backquote($field); + $GLOBALS['sql_query'] .= $i++ === $selectedCount ? ');' : ', '; } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/Structure/UniqueController.php b/libraries/classes/Controllers/Table/Structure/UniqueController.php index 6772cc1c45..3767f834e9 100644 --- a/libraries/classes/Controllers/Table/Structure/UniqueController.php +++ b/libraries/classes/Controllers/Table/Structure/UniqueController.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table\Structure; -use PhpMyAdmin\Controllers\Table\AbstractController; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,19 +27,17 @@ final class UniqueController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi, StructureController $structureController ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; $this->structureController = $structureController; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $sql_query, $db, $table, $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $selected = $_POST['selected_fld'] ?? []; @@ -51,24 +50,24 @@ final class UniqueController extends AbstractController $i = 1; $selectedCount = count($selected); - $sql_query = 'ALTER TABLE ' . Util::backquote($table) . ' ADD UNIQUE('; + $GLOBALS['sql_query'] = 'ALTER TABLE ' . Util::backquote($GLOBALS['table']) . ' ADD UNIQUE('; foreach ($selected as $field) { - $sql_query .= Util::backquote($field); - $sql_query .= $i++ === $selectedCount ? ');' : ', '; + $GLOBALS['sql_query'] .= Util::backquote($field); + $GLOBALS['sql_query'] .= $i++ === $selectedCount ? ');' : ', '; } - $this->dbi->selectDb($db); - $result = $this->dbi->tryQuery($sql_query); + $this->dbi->selectDb($GLOBALS['db']); + $result = $this->dbi->tryQuery($GLOBALS['sql_query']); if (! $result) { - $message = Message::error($this->dbi->getError()); + $GLOBALS['message'] = Message::error($this->dbi->getError()); } - if (empty($message)) { - $message = Message::success(); + if (empty($GLOBALS['message'])) { + $GLOBALS['message'] = Message::success(); } - ($this->structureController)(); + ($this->structureController)($request); } } diff --git a/libraries/classes/Controllers/Table/StructureController.php b/libraries/classes/Controllers/Table/StructureController.php index 1c7507aa38..e9b7628d33 100644 --- a/libraries/classes/Controllers/Table/StructureController.php +++ b/libraries/classes/Controllers/Table/StructureController.php @@ -10,6 +10,7 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\ConfigStorage\RelationParameters; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\CreateAddField; use PhpMyAdmin\Database\CentralColumns; use PhpMyAdmin\DatabaseInterface; @@ -17,6 +18,7 @@ use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Engines\Innodb; use PhpMyAdmin\FlashMessages; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Index; use PhpMyAdmin\Partitioning\Partition; use PhpMyAdmin\Query\Utilities; @@ -66,8 +68,6 @@ class StructureController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Relation $relation, Transformations $transformations, CreateAddField $createAddField, @@ -75,7 +75,7 @@ class StructureController extends AbstractController DatabaseInterface $dbi, FlashMessages $flash ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->createAddField = $createAddField; $this->relation = $relation; $this->transformations = $transformations; @@ -83,28 +83,36 @@ class StructureController extends AbstractController $this->dbi = $dbi; $this->flash = $flash; - $this->tableObj = $this->dbi->getTable($this->db, $this->table); + $this->tableObj = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $reread_info, $showtable, $db, $table, $cfg, $errorUrl; - global $tbl_is_view, $tbl_storage_engine, $tbl_collation, $table_info_num_rows; - - $this->dbi->selectDb($this->db); - $reread_info = $this->tableObj->getStatusInfo(null, true); - $showtable = $this->tableObj->getStatusInfo(null, (isset($reread_info) && $reread_info)); + $GLOBALS['reread_info'] = $GLOBALS['reread_info'] ?? null; + $GLOBALS['showtable'] = $GLOBALS['showtable'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['tbl_is_view'] = $GLOBALS['tbl_is_view'] ?? null; + $GLOBALS['tbl_storage_engine'] = $GLOBALS['tbl_storage_engine'] ?? null; + $GLOBALS['tbl_collation'] = $GLOBALS['tbl_collation'] ?? null; + $GLOBALS['table_info_num_rows'] = $GLOBALS['table_info_num_rows'] ?? null; + + $this->dbi->selectDb($GLOBALS['db']); + $GLOBALS['reread_info'] = $this->tableObj->getStatusInfo(null, true); + $GLOBALS['showtable'] = $this->tableObj->getStatusInfo( + null, + (isset($GLOBALS['reread_info']) && $GLOBALS['reread_info']) + ); if ($this->tableObj->isView()) { - $tbl_is_view = true; - $tbl_storage_engine = __('View'); + $GLOBALS['tbl_is_view'] = true; + $GLOBALS['tbl_storage_engine'] = __('View'); } else { - $tbl_is_view = false; - $tbl_storage_engine = $this->tableObj->getStorageEngine(); + $GLOBALS['tbl_is_view'] = false; + $GLOBALS['tbl_storage_engine'] = $this->tableObj->getStorageEngine(); } - $tbl_collation = $this->tableObj->getCollation(); - $table_info_num_rows = $this->tableObj->getNumRows(); + $GLOBALS['tbl_collation'] = $this->tableObj->getCollation(); + $GLOBALS['table_info_num_rows'] = $this->tableObj->getNumRows(); $pageSettings = new PageSettings('TableStructure'); $this->response->addHTML($pageSettings->getErrorHTML()); @@ -117,24 +125,24 @@ class StructureController extends AbstractController $relationParameters = $this->relation->getRelationParameters(); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $isSystemSchema = Utilities::isSystemSchema($db); - $url_params = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($url_params, '&'); + $isSystemSchema = Utilities::isSystemSchema($GLOBALS['db']); + $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($url_params, '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $primary = Index::getPrimary($this->table, $this->db); + $primary = Index::getPrimary($this->dbi, $GLOBALS['table'], $GLOBALS['db']); $columns_with_index = $this->dbi - ->getTable($this->db, $this->table) + ->getTable($GLOBALS['db'], $GLOBALS['table']) ->getColumnsWithIndex(Index::UNIQUE | Index::INDEX | Index::SPATIAL | Index::FULLTEXT); $columns_with_unique_index = $this->dbi - ->getTable($this->db, $this->table) + ->getTable($GLOBALS['db'], $GLOBALS['table']) ->getColumnsWithIndex(Index::UNIQUE); - $fields = $this->dbi->getColumns($this->db, $this->table, true); + $fields = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'], true); $this->response->addHTML($this->displayStructure( $relationParameters, @@ -142,43 +150,46 @@ class StructureController extends AbstractController $primary, $fields, $columns_with_index, - $isSystemSchema + $isSystemSchema, + $request->getRoute() )); } /** * Displays the table structure ('show table' works correct since 3.23.03) * - * @param array $columns_with_unique_index Columns with unique index - * @param Index|false $primary_index primary index or false if no one exists - * @param array $fields Fields - * @param array $columns_with_index Columns with index + * @param array $columns_with_unique_index Columns with unique index + * @param array $fields Fields + * @param array $columns_with_index Columns with index + * @psalm-param non-empty-string $route * * @return string */ protected function displayStructure( RelationParameters $relationParameters, array $columns_with_unique_index, - $primary_index, + ?Index $primaryIndex, array $fields, array $columns_with_index, - bool $isSystemSchema + bool $isSystemSchema, + string $route ) { - global $route, $tbl_is_view, $tbl_storage_engine; + $GLOBALS['tbl_is_view'] = $GLOBALS['tbl_is_view'] ?? null; + $GLOBALS['tbl_storage_engine'] = $GLOBALS['tbl_storage_engine'] ?? null; // prepare comments $comments_map = []; $mime_map = []; if ($GLOBALS['cfg']['ShowPropertyComments']) { - $comments_map = $this->relation->getComments($this->db, $this->table); + $comments_map = $this->relation->getComments($GLOBALS['db'], $GLOBALS['table']); if ($relationParameters->browserTransformationFeature !== null && $GLOBALS['cfg']['BrowseMIME']) { - $mime_map = $this->transformations->getMime($this->db, $this->table, true); + $mime_map = $this->transformations->getMime($GLOBALS['db'], $GLOBALS['table'], true); } } $centralColumns = new CentralColumns($this->dbi); - $central_list = $centralColumns->getFromTable($this->db, $this->table); + $central_list = $centralColumns->getFromTable($GLOBALS['db'], $GLOBALS['table']); /** * Displays Space usage and row statistics @@ -222,7 +233,7 @@ class StructureController extends AbstractController $row_comments[$rownum] = $comments_map[$field['Field']]; } - if ($primary_index && $primary_index->hasColumn($field['Field'])) { + if ($primaryIndex !== null && $primaryIndex->hasColumn($field['Field'])) { $displayed_fields[$rownum]->icon .= Generator::getImage('b_primary', __('Primary')); } @@ -250,17 +261,17 @@ class StructureController extends AbstractController return $this->template->render('table/structure/display_structure', [ 'collations' => $collations, 'is_foreign_key_supported' => ForeignKey::isSupported($engine), - 'indexes' => Index::getFromTable($this->table, $this->db), - 'indexes_duplicates' => Index::findDuplicates($this->table, $this->db), + 'indexes' => Index::getFromTable($this->dbi, $GLOBALS['table'], $GLOBALS['db']), + 'indexes_duplicates' => Index::findDuplicates($GLOBALS['table'], $GLOBALS['db']), 'relation_parameters' => $relationParameters, 'hide_structure_actions' => $GLOBALS['cfg']['HideStructureActions'] === true, - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'db_is_system_schema' => $isSystemSchema, - 'tbl_is_view' => $tbl_is_view, + 'tbl_is_view' => $GLOBALS['tbl_is_view'], 'mime_map' => $mime_map, - 'tbl_storage_engine' => $tbl_storage_engine, - 'primary' => $primary_index, + 'tbl_storage_engine' => $GLOBALS['tbl_storage_engine'], + 'primary' => $primaryIndex, 'columns_with_unique_index' => $columns_with_unique_index, 'columns_list' => $columns_list, 'table_stats' => $tablestats ?? null, @@ -277,8 +288,8 @@ class StructureController extends AbstractController 'text_dir' => $GLOBALS['text_dir'], 'is_active' => Tracker::isActive(), 'have_partitioning' => Partition::havePartitioning(), - 'partitions' => Partition::getPartitions($this->db, $this->table), - 'partition_names' => Partition::getPartitionNames($this->db, $this->table), + 'partitions' => Partition::getPartitions($GLOBALS['db'], $GLOBALS['table']), + 'partition_names' => Partition::getPartitionNames($GLOBALS['db'], $GLOBALS['table']), 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], 'attributes' => $attributes, 'displayed_fields' => $displayed_fields, @@ -294,69 +305,75 @@ class StructureController extends AbstractController */ protected function getTableStats(bool $isSystemSchema) { - global $showtable, $tbl_is_view; - global $tbl_storage_engine, $table_info_num_rows, $tbl_collation; + $GLOBALS['tbl_is_view'] = $GLOBALS['tbl_is_view'] ?? null; + $GLOBALS['tbl_storage_engine'] = $GLOBALS['tbl_storage_engine'] ?? null; + $GLOBALS['table_info_num_rows'] = $GLOBALS['table_info_num_rows'] ?? null; + $GLOBALS['tbl_collation'] = $GLOBALS['tbl_collation'] ?? null; - if (empty($showtable)) { - $showtable = $this->dbi->getTable($this->db, $this->table)->getStatusInfo(null, true); + if (empty($GLOBALS['showtable'])) { + $GLOBALS['showtable'] = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->getStatusInfo(null, true); } - if (is_string($showtable)) { - $showtable = []; + if (is_string($GLOBALS['showtable'])) { + $GLOBALS['showtable'] = []; } - if (empty($showtable['Data_length'])) { - $showtable['Data_length'] = 0; + if (empty($GLOBALS['showtable']['Data_length'])) { + $GLOBALS['showtable']['Data_length'] = 0; } - if (empty($showtable['Index_length'])) { - $showtable['Index_length'] = 0; + if (empty($GLOBALS['showtable']['Index_length'])) { + $GLOBALS['showtable']['Index_length'] = 0; } - $is_innodb = (isset($showtable['Type']) - && $showtable['Type'] === 'InnoDB'); + $is_innodb = (isset($GLOBALS['showtable']['Type']) + && $GLOBALS['showtable']['Type'] === 'InnoDB'); $mergetable = $this->tableObj->isMerge(); // this is to display for example 261.2 MiB instead of 268k KiB $max_digits = 3; $decimals = 1; - [$data_size, $data_unit] = Util::formatByteDown($showtable['Data_length'], $max_digits, $decimals); + [$data_size, $data_unit] = Util::formatByteDown($GLOBALS['showtable']['Data_length'], $max_digits, $decimals); if ($mergetable === false) { - [$index_size, $index_unit] = Util::formatByteDown($showtable['Index_length'], $max_digits, $decimals); + [$index_size, $index_unit] = Util::formatByteDown( + $GLOBALS['showtable']['Index_length'], + $max_digits, + $decimals + ); } - if (isset($showtable['Data_free'])) { - [$free_size, $free_unit] = Util::formatByteDown($showtable['Data_free'], $max_digits, $decimals); + if (isset($GLOBALS['showtable']['Data_free'])) { + [$free_size, $free_unit] = Util::formatByteDown($GLOBALS['showtable']['Data_free'], $max_digits, $decimals); [$effect_size, $effect_unit] = Util::formatByteDown( - $showtable['Data_length'] - + $showtable['Index_length'] - - $showtable['Data_free'], + $GLOBALS['showtable']['Data_length'] + + $GLOBALS['showtable']['Index_length'] + - $GLOBALS['showtable']['Data_free'], $max_digits, $decimals ); } else { [$effect_size, $effect_unit] = Util::formatByteDown( - $showtable['Data_length'] - + $showtable['Index_length'], + $GLOBALS['showtable']['Data_length'] + + $GLOBALS['showtable']['Index_length'], $max_digits, $decimals ); } [$tot_size, $tot_unit] = Util::formatByteDown( - $showtable['Data_length'] + $showtable['Index_length'], + $GLOBALS['showtable']['Data_length'] + $GLOBALS['showtable']['Index_length'], $max_digits, $decimals ); $avg_size = ''; $avg_unit = ''; - if ($table_info_num_rows > 0) { + if ($GLOBALS['table_info_num_rows'] > 0) { [$avg_size, $avg_unit] = Util::formatByteDown( - ($showtable['Data_length'] - + $showtable['Index_length']) - / $showtable['Rows'], + ($GLOBALS['showtable']['Data_length'] + + $GLOBALS['showtable']['Index_length']) + / $GLOBALS['showtable']['Rows'], 6, 1 ); @@ -367,7 +384,11 @@ class StructureController extends AbstractController $innodb_file_per_table = $innodbEnginePlugin->supportsFilePerTable(); $tableCollation = []; - $collation = Charsets::findCollationByName($this->dbi, $GLOBALS['cfg']['Server']['DisableIS'], $tbl_collation); + $collation = Charsets::findCollationByName( + $this->dbi, + $GLOBALS['cfg']['Server']['DisableIS'], + $GLOBALS['tbl_collation'] + ); if ($collation !== null) { $tableCollation = [ 'name' => $collation->getName(), @@ -378,11 +399,11 @@ class StructureController extends AbstractController return $this->template->render('table/structure/display_table_stats', [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], - 'showtable' => $showtable, - 'table_info_num_rows' => $table_info_num_rows, - 'tbl_is_view' => $tbl_is_view, + 'showtable' => $GLOBALS['showtable'], + 'table_info_num_rows' => $GLOBALS['table_info_num_rows'], + 'tbl_is_view' => $GLOBALS['tbl_is_view'], 'db_is_system_schema' => $isSystemSchema, - 'tbl_storage_engine' => $tbl_storage_engine, + 'tbl_storage_engine' => $GLOBALS['tbl_storage_engine'], 'table_collation' => $tableCollation, 'is_innodb' => $is_innodb, 'mergetable' => $mergetable, diff --git a/libraries/classes/Controllers/Table/TrackingController.php b/libraries/classes/Controllers/Table/TrackingController.php index 085edc5fd7..125b848067 100644 --- a/libraries/classes/Controllers/Table/TrackingController.php +++ b/libraries/classes/Controllers/Table/TrackingController.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -29,31 +31,38 @@ final class TrackingController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Tracking $tracking ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->tracking = $tracking; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $text_dir, $urlParams, $msg, $errorUrl; - global $data, $entries, $filter_ts_from, $filter_ts_to, $filter_users, $selection_schema; - global $selection_data, $selection_both, $db, $table, $cfg; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['msg'] = $GLOBALS['msg'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $GLOBALS['data'] = $GLOBALS['data'] ?? null; + $GLOBALS['entries'] = $GLOBALS['entries'] ?? null; + $GLOBALS['filter_ts_from'] = $GLOBALS['filter_ts_from'] ?? null; + $GLOBALS['filter_ts_to'] = $GLOBALS['filter_ts_to'] ?? null; + $GLOBALS['filter_users'] = $GLOBALS['filter_users'] ?? null; + $GLOBALS['selection_schema'] = $GLOBALS['selection_schema'] ?? null; + $GLOBALS['selection_data'] = $GLOBALS['selection_data'] ?? null; + $GLOBALS['selection_both'] = $GLOBALS['selection_both'] ?? null; $this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'table/tracking.js']); define('TABLE_MAY_BE_ABSENT', true); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); $activeMessage = ''; if ( @@ -64,68 +73,73 @@ final class TrackingController extends AbstractController && ! (isset($_POST['report_export']) && $_POST['export_type'] === 'sqldumpfile') ) { - $msg = Message::notice( + $GLOBALS['msg'] = Message::notice( sprintf( __('Tracking of %s is activated.'), htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']) ) ); - $activeMessage = $msg->getDisplay(); + $activeMessage = $GLOBALS['msg']->getDisplay(); } - $urlParams['goto'] = Url::getFromRoute('/table/tracking'); - $urlParams['back'] = Url::getFromRoute('/table/tracking'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/tracking'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/tracking'); - $data = []; - $entries = []; - $filter_ts_from = null; - $filter_ts_to = null; - $filter_users = []; - $selection_schema = false; - $selection_data = false; - $selection_both = false; + $GLOBALS['data'] = []; + $GLOBALS['entries'] = []; + $GLOBALS['filter_ts_from'] = null; + $GLOBALS['filter_ts_to'] = null; + $GLOBALS['filter_users'] = []; + $GLOBALS['selection_schema'] = false; + $GLOBALS['selection_data'] = false; + $GLOBALS['selection_both'] = false; // Init vars for tracking report if (isset($_POST['report']) || isset($_POST['report_export'])) { - $data = Tracker::getTrackedData($GLOBALS['db'], $GLOBALS['table'], $_POST['version']); + $GLOBALS['data'] = Tracker::getTrackedData($GLOBALS['db'], $GLOBALS['table'], $_POST['version']); if (! isset($_POST['logtype'])) { $_POST['logtype'] = 'schema_and_data'; } if ($_POST['logtype'] === 'schema') { - $selection_schema = true; + $GLOBALS['selection_schema'] = true; } elseif ($_POST['logtype'] === 'data') { - $selection_data = true; + $GLOBALS['selection_data'] = true; } else { - $selection_both = true; + $GLOBALS['selection_both'] = true; } if (! isset($_POST['date_from'])) { - $_POST['date_from'] = $data['date_from']; + $_POST['date_from'] = $GLOBALS['data']['date_from']; } if (! isset($_POST['date_to'])) { - $_POST['date_to'] = $data['date_to']; + $_POST['date_to'] = $GLOBALS['data']['date_to']; } if (! isset($_POST['users'])) { $_POST['users'] = '*'; } - $filter_ts_from = strtotime($_POST['date_from']); - $filter_ts_to = strtotime($_POST['date_to']); - $filter_users = array_map('trim', explode(',', $_POST['users'])); + $GLOBALS['filter_ts_from'] = strtotime($_POST['date_from']); + $GLOBALS['filter_ts_to'] = strtotime($_POST['date_to']); + $GLOBALS['filter_users'] = array_map('trim', explode(',', $_POST['users'])); } // Prepare export if (isset($_POST['report_export'])) { - $entries = $this->tracking->getEntries($data, (int) $filter_ts_from, (int) $filter_ts_to, $filter_users); + $GLOBALS['entries'] = $this->tracking->getEntries( + $GLOBALS['data'], + (int) $GLOBALS['filter_ts_from'], + (int) $GLOBALS['filter_ts_to'], + $GLOBALS['filter_users'] + ); } // Export as file download if (isset($_POST['report_export']) && $_POST['export_type'] === 'sqldumpfile') { - $this->tracking->exportAsFileDownload($entries); + $this->tracking->exportAsFileDownload($GLOBALS['entries']); } $actionMessage = ''; @@ -133,7 +147,7 @@ final class TrackingController extends AbstractController if (! empty($_POST['selected_versions'])) { if ($_POST['submit_mult'] === 'delete_version') { foreach ($_POST['selected_versions'] as $version) { - $this->tracking->deleteTrackingVersion($db, $table, $version); + $this->tracking->deleteTrackingVersion($GLOBALS['db'], $GLOBALS['table'], $version); } $actionMessage = Message::success( @@ -149,62 +163,76 @@ final class TrackingController extends AbstractController $deleteVersion = ''; if (isset($_POST['submit_delete_version'])) { - $deleteVersion = $this->tracking->deleteTrackingVersion($db, $table, $_POST['version']); + $deleteVersion = $this->tracking->deleteTrackingVersion( + $GLOBALS['db'], + $GLOBALS['table'], + $_POST['version'] + ); } $createVersion = ''; if (isset($_POST['submit_create_version'])) { - $createVersion = $this->tracking->createTrackingVersion($db, $table); + $createVersion = $this->tracking->createTrackingVersion($GLOBALS['db'], $GLOBALS['table']); } $deactivateTracking = ''; if (isset($_POST['toggle_activation']) && $_POST['toggle_activation'] === 'deactivate_now') { - $deactivateTracking = $this->tracking->changeTracking($db, $table, 'deactivate'); + $deactivateTracking = $this->tracking->changeTracking($GLOBALS['db'], $GLOBALS['table'], 'deactivate'); } $activateTracking = ''; if (isset($_POST['toggle_activation']) && $_POST['toggle_activation'] === 'activate_now') { - $activateTracking = $this->tracking->changeTracking($db, $table, 'activate'); + $activateTracking = $this->tracking->changeTracking($GLOBALS['db'], $GLOBALS['table'], 'activate'); } // Export as SQL execution $message = ''; if (isset($_POST['report_export']) && $_POST['export_type'] === 'execution') { - $this->tracking->exportAsSqlExecution($entries); - $msg = Message::success(__('SQL statements executed.')); - $message = $msg->getDisplay(); + $this->tracking->exportAsSqlExecution($GLOBALS['entries']); + $GLOBALS['msg'] = Message::success(__('SQL statements executed.')); + $message = $GLOBALS['msg']->getDisplay(); } $sqlDump = ''; if (isset($_POST['report_export']) && $_POST['export_type'] === 'sqldump') { - $sqlDump = $this->tracking->exportAsSqlDump($db, $table, $entries); + $this->addScriptFiles(['sql.js']); + $sqlDump = $this->tracking->exportAsSqlDump($GLOBALS['db'], $GLOBALS['table'], $GLOBALS['entries']); } $schemaSnapshot = ''; if (isset($_POST['snapshot'])) { - $schemaSnapshot = $this->tracking->getHtmlForSchemaSnapshot($urlParams); + $schemaSnapshot = $this->tracking->getHtmlForSchemaSnapshot($GLOBALS['urlParams']); } $trackingReportRows = ''; if (isset($_POST['report']) && (isset($_POST['delete_ddlog']) || isset($_POST['delete_dmlog']))) { - $trackingReportRows = $this->tracking->deleteTrackingReportRows($db, $table, $data); + $trackingReportRows = $this->tracking->deleteTrackingReportRows( + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['data'] + ); } $trackingReport = ''; if (isset($_POST['report']) || isset($_POST['report_export'])) { $trackingReport = $this->tracking->getHtmlForTrackingReport( - $data, - $urlParams, - $selection_schema, - $selection_data, - $selection_both, - (int) $filter_ts_to, - (int) $filter_ts_from, - $filter_users + $GLOBALS['data'], + $GLOBALS['urlParams'], + $GLOBALS['selection_schema'], + $GLOBALS['selection_data'], + $GLOBALS['selection_both'], + (int) $GLOBALS['filter_ts_to'], + (int) $GLOBALS['filter_ts_from'], + $GLOBALS['filter_users'] ); } - $main = $this->tracking->getHtmlForMainPage($db, $table, $urlParams, $text_dir); + $main = $this->tracking->getHtmlForMainPage( + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['urlParams'], + $GLOBALS['text_dir'] + ); $this->render('table/tracking/index', [ 'active_message' => $activeMessage, diff --git a/libraries/classes/Controllers/Table/TriggersController.php b/libraries/classes/Controllers/Table/TriggersController.php index 5a6d5046b0..6f95d6ed8b 100644 --- a/libraries/classes/Controllers/Table/TriggersController.php +++ b/libraries/classes/Controllers/Table/TriggersController.php @@ -4,9 +4,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -26,19 +28,24 @@ class TriggersController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $db, $table, $tables, $num_tables, $total_num_tables, $sub_part; - global $tooltip_truename, $tooltip_aliasname, $pos; - global $errors, $urlParams, $errorUrl, $cfg; + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + $GLOBALS['num_tables'] = $GLOBALS['num_tables'] ?? null; + $GLOBALS['total_num_tables'] = $GLOBALS['total_num_tables'] ?? null; + $GLOBALS['sub_part'] = $GLOBALS['sub_part'] ?? null; + $GLOBALS['tooltip_truename'] = $GLOBALS['tooltip_truename'] ?? null; + $GLOBALS['tooltip_aliasname'] = $GLOBALS['tooltip_aliasname'] ?? null; + $GLOBALS['pos'] = $GLOBALS['pos'] ?? null; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['database/triggers.js']); @@ -46,45 +53,45 @@ class TriggersController extends AbstractController /** * Displays the header and tabs */ - if (! empty($table) && in_array($table, $this->dbi->getTables($db))) { - Util::checkParameters(['db', 'table']); + if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); } else { - $table = ''; + $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } [ - $tables, - $num_tables, - $total_num_tables, - $sub_part,,, - $tooltip_truename, - $tooltip_aliasname, - $pos, - ] = Util::getDbInfo($db, $sub_part ?? ''); + $GLOBALS['tables'], + $GLOBALS['num_tables'], + $GLOBALS['total_num_tables'], + $GLOBALS['sub_part'],,, + $GLOBALS['tooltip_truename'], + $GLOBALS['tooltip_aliasname'], + $GLOBALS['pos'], + ] = Util::getDbInfo($GLOBALS['db'], $GLOBALS['sub_part'] ?? ''); } - } elseif (strlen($db) > 0) { - $this->dbi->selectDb($db); + } elseif (strlen($GLOBALS['db']) > 0) { + $this->dbi->selectDb($GLOBALS['db']); } /** * Keep a list of errors that occurred while * processing an 'Add' or 'Edit' operation. */ - $errors = []; + $GLOBALS['errors'] = []; $triggers = new Triggers($this->dbi, $this->template, $this->response); $triggers->main(); diff --git a/libraries/classes/Controllers/Table/ZoomSearchController.php b/libraries/classes/Controllers/Table/ZoomSearchController.php index 5a65bdbce4..5d87f73030 100644 --- a/libraries/classes/Controllers/Table/ZoomSearchController.php +++ b/libraries/classes/Controllers/Table/ZoomSearchController.php @@ -5,9 +5,11 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Search; use PhpMyAdmin\Template; @@ -21,6 +23,7 @@ use function count; use function htmlspecialchars; use function in_array; use function intval; +use function is_array; use function is_numeric; use function json_encode; use function mb_strtolower; @@ -72,13 +75,11 @@ class ZoomSearchController extends AbstractController public function __construct( ResponseRenderer $response, Template $template, - string $db, - string $table, Search $search, Relation $relation, DatabaseInterface $dbi ) { - parent::__construct($response, $template, $db, $table); + parent::__construct($response, $template); $this->search = $search; $this->relation = $relation; $this->dbi = $dbi; @@ -93,17 +94,18 @@ class ZoomSearchController extends AbstractController $this->loadTableInfo(); } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $goto, $db, $table, $urlParams, $cfg, $errorUrl; + $GLOBALS['goto'] = $GLOBALS['goto'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $this->checkParameters(['db', 'table']); - Util::checkParameters(['db', 'table']); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); - - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); $this->addScriptFiles([ 'makegrid.js', @@ -139,7 +141,7 @@ class ZoomSearchController extends AbstractController //Set default datalabel if not selected if (! isset($_POST['zoom_submit']) || $_POST['dataLabel'] == '') { - $dataLabel = $this->relation->getDisplayField($this->db, $this->table); + $dataLabel = $this->relation->getDisplayField($GLOBALS['db'], $GLOBALS['table']); } else { $dataLabel = $_POST['dataLabel']; } @@ -160,11 +162,11 @@ class ZoomSearchController extends AbstractController return; } - if (! isset($goto)) { - $goto = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + if (! isset($GLOBALS['goto'])) { + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); } - $this->zoomSubmitAction($dataLabel, $goto); + $this->zoomSubmitAction($dataLabel, $GLOBALS['goto']); } /** @@ -174,7 +176,7 @@ class ZoomSearchController extends AbstractController private function loadTableInfo(): void { // Gets the list and number of columns - $columns = $this->dbi->getColumns($this->db, $this->table, true); + $columns = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'], true); // Get details about the geometry functions $geom_types = Gis::getDataTypes(); @@ -217,7 +219,7 @@ class ZoomSearchController extends AbstractController } // Retrieve foreign keys - $this->foreigners = $this->relation->getForeigners($this->db, $this->table); + $this->foreigners = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table']); } /** @@ -227,10 +229,8 @@ class ZoomSearchController extends AbstractController */ public function displaySelectionFormAction($dataLabel = null): void { - global $goto; - - if (! isset($goto)) { - $goto = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + if (! isset($GLOBALS['goto'])) { + $GLOBALS['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); } $column_names = $this->columnNames; @@ -249,9 +249,9 @@ class ZoomSearchController extends AbstractController } $this->render('table/zoom_search/index', [ - 'db' => $this->db, - 'table' => $this->table, - 'goto' => $goto, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'goto' => $GLOBALS['goto'], 'self' => $this, 'geom_column_flag' => $this->geomColumnFlag, 'column_names' => $column_names, @@ -370,14 +370,37 @@ class ZoomSearchController extends AbstractController unset($tmpData); $column_names_hashes = []; + $foreignDropdown = []; + $searchColumnInForeigners = []; + $foreignData = []; - foreach ($this->columnNames as $columnName) { + foreach ($this->columnNames as $columnIndex => $columnName) { $column_names_hashes[$columnName] = md5($columnName); + $foreignData[$columnIndex] = $this->relation->getForeignData($this->foreigners, $columnName, false, '', ''); + $searchColumnInForeigners[$columnIndex] = $this->relation->searchColumnInForeigners( + $this->foreigners, + $columnName + ); + if ( + ! $this->foreigners + || ! $searchColumnInForeigners[$columnIndex] + || ! is_array($foreignData[$columnIndex]['disp_row']) + ) { + continue; + } + + $foreignDropdown[$columnIndex] = $this->relation->foreignDropdown( + $foreignData[$columnIndex]['disp_row'], + (string) $foreignData[$columnIndex]['foreign_field'], + $foreignData[$columnIndex]['foreign_display'], + '', + $GLOBALS['cfg']['ForeignKeyMaxLimit'] + ); } $this->render('table/zoom_search/result_form', [ - 'db' => $this->db, - 'table' => $this->table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'column_names' => $this->columnNames, 'column_names_hashes' => $column_names_hashes, 'foreigners' => $this->foreigners, @@ -387,7 +410,9 @@ class ZoomSearchController extends AbstractController 'data' => $data, 'data_json' => json_encode($data), 'zoom_submit' => isset($_POST['zoom_submit']), - 'foreign_max_limit' => $GLOBALS['cfg']['ForeignKeyMaxLimit'], + 'foreign_dropdown' => $foreignDropdown, + 'search_columns_in_foreigners' => $searchColumnInForeigners, + 'foreign_data' => $foreignData, ]); } @@ -438,6 +463,22 @@ class ZoomSearchController extends AbstractController $htmlAttributes .= ' onfocus="return ' . 'verifyAfterSearchFieldChange(' . $search_index . ', \'#zoom_search_form\')"'; + $foreignDropdown = ''; + + if ( + $this->foreigners + && $this->relation->searchColumnInForeigners($this->foreigners, $this->columnNames[$column_index]) + && is_array($foreignData['disp_row']) + ) { + $foreignDropdown = $this->relation->foreignDropdown( + $foreignData['disp_row'], + $foreignData['foreign_field'], + $foreignData['foreign_display'], + '', + $GLOBALS['cfg']['ForeignKeyMaxLimit'] + ); + } + $value = $this->template->render('table/search/input_box', [ 'str' => '', 'column_type' => (string) $type, @@ -449,12 +490,12 @@ class ZoomSearchController extends AbstractController 'column_name' => $this->columnNames[$column_index], 'column_name_hash' => md5($this->columnNames[$column_index]), 'foreign_data' => $foreignData, - 'table' => $this->table, + 'table' => $GLOBALS['table'], 'column_index' => $search_index, - 'foreign_max_limit' => $GLOBALS['cfg']['ForeignKeyMaxLimit'], 'criteria_values' => $entered_value, - 'db' => $this->db, + 'db' => $GLOBALS['db'], 'in_fbs' => true, + 'foreign_dropdown' => $foreignDropdown, ]); return [ diff --git a/libraries/classes/Controllers/TableController.php b/libraries/classes/Controllers/TableController.php index c3ee04058c..27f74d46c7 100644 --- a/libraries/classes/Controllers/TableController.php +++ b/libraries/classes/Controllers/TableController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -20,7 +21,7 @@ final class TableController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { if (! isset($_POST['db'])) { $this->response->setRequestStatus(false); diff --git a/libraries/classes/Controllers/ThemeSetController.php b/libraries/classes/Controllers/ThemeSetController.php index 90ad6ecbbb..8edf98bf49 100644 --- a/libraries/classes/Controllers/ThemeSetController.php +++ b/libraries/classes/Controllers/ThemeSetController.php @@ -4,40 +4,49 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\ThemeManager; use PhpMyAdmin\Url; use PhpMyAdmin\UserPreferences; +use function is_string; + final class ThemeSetController extends AbstractController { /** @var ThemeManager */ private $themeManager; - public function __construct(ResponseRenderer $response, Template $template, ThemeManager $themeManager) - { + /** @var UserPreferences */ + private $userPreferences; + + public function __construct( + ResponseRenderer $response, + Template $template, + ThemeManager $themeManager, + UserPreferences $userPreferences + ) { parent::__construct($response, $template); $this->themeManager = $themeManager; + $this->userPreferences = $userPreferences; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg; - - if (! $cfg['ThemeManager'] || ! isset($_POST['set_theme'])) { + $theme = $request->getParsedBodyParam('set_theme'); + if (! $GLOBALS['cfg']['ThemeManager'] || ! is_string($theme) || $theme === '') { $this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&')); return; } - $this->themeManager->setActiveTheme($_POST['set_theme']); + $this->themeManager->setActiveTheme($theme); $this->themeManager->setThemeCookie(); - $userPreferences = new UserPreferences(); - $preferences = $userPreferences->load(); - $preferences['config_data']['ThemeDefault'] = $_POST['set_theme']; - $userPreferences->save($preferences['config_data']); + $preferences = $this->userPreferences->load(); + $preferences['config_data']['ThemeDefault'] = $theme; + $this->userPreferences->save($preferences['config_data']); $this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&')); } diff --git a/libraries/classes/Controllers/ThemesController.php b/libraries/classes/Controllers/ThemesController.php index caf3d9f6fe..3d8f4a7f43 100644 --- a/libraries/classes/Controllers/ThemesController.php +++ b/libraries/classes/Controllers/ThemesController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\ThemeManager; @@ -19,7 +20,7 @@ class ThemesController extends AbstractController $this->themeManager = $themeManager; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $themes = $this->themeManager->getThemesArray(); $themesList = $this->template->render('home/themes', ['themes' => $themes]); diff --git a/libraries/classes/Controllers/Transformation/OverviewController.php b/libraries/classes/Controllers/Transformation/OverviewController.php index 4d125454ee..4e261d168d 100644 --- a/libraries/classes/Controllers/Transformation/OverviewController.php +++ b/libraries/classes/Controllers/Transformation/OverviewController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Transformation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Transformations; @@ -25,7 +26,7 @@ class OverviewController extends AbstractController $this->transformations = $transformations; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { $header = $this->response->getHeader(); $header->disableMenuAndConsole(); diff --git a/libraries/classes/Controllers/Transformation/WrapperController.php b/libraries/classes/Controllers/Transformation/WrapperController.php index 7c850e6ea5..653dd2cee3 100644 --- a/libraries/classes/Controllers/Transformation/WrapperController.php +++ b/libraries/classes/Controllers/Transformation/WrapperController.php @@ -8,7 +8,11 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Dbal\DatabaseName; +use PhpMyAdmin\Dbal\InvalidIdentifierName; +use PhpMyAdmin\Dbal\TableName; use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Image\ImageWrapper; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -16,14 +20,16 @@ use PhpMyAdmin\Transformations; use PhpMyAdmin\Util; use function __; -use function define; use function htmlspecialchars; -use function in_array; use function intval; +use function is_numeric; +use function is_string; use function round; +use function sprintf; +use function str_contains; use function str_replace; -use function stripos; -use function substr; +use function str_starts_with; +use function strtolower; /** * Wrapper script for rendering transformations @@ -52,168 +58,176 @@ class WrapperController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cn, $db, $table, $transform_key, $request_params, $size_params, $where_clause, $row; - global $default_ct, $mime_map, $mime_options, $ct, $mime_type, $srcImage, $srcWidth, $srcHeight; - global $ratioWidth, $ratioHeight, $destWidth, $destHeight, $destImage; + $this->response->getHeader()->setIsTransformationWrapper(true); - define('IS_TRANSFORMATION_WRAPPER', true); - - $relationParameters = $this->relation->getRelationParameters(); - - DbTableExists::check(); - - /** - * Sets globals from $_REQUEST - */ - $request_params = [ - 'cn', - 'ct', - 'sql_query', - 'transform_key', - 'where_clause', - ]; - $size_params = [ - 'newHeight', - 'newWidth', - ]; - foreach ($request_params as $one_request_param) { - if (! isset($_REQUEST[$one_request_param])) { - continue; - } - - if (in_array($one_request_param, $size_params)) { - $GLOBALS[$one_request_param] = intval($_REQUEST[$one_request_param]); - if ($GLOBALS[$one_request_param] > 2000) { - $GLOBALS[$one_request_param] = 2000; - } - } else { - $GLOBALS[$one_request_param] = $_REQUEST[$one_request_param]; - } + try { + $db = DatabaseName::fromValue($request->getParam('db')); + $table = TableName::fromValue($request->getParam('table')); + } catch (InvalidIdentifierName $exception) { + return; } - /** - * Get the list of the fields of the current table - */ + DbTableExists::check($db->getName(), $table->getName(), true); $this->dbi->selectDb($db); - if (isset($where_clause)) { - if (! Core::checkSqlQuerySignature($where_clause, $_GET['where_clause_sign'] ?? '')) { - /* l10n: In case a SQL query did not pass a security check */ - Core::fatalError(__('There is an issue with your request.')); - return; - } + $query = $this->getQuery($table, $request->getParam('where_clause'), $request->getParam('where_clause_sign')); + if ($query === null) { + /* l10n: In case a SQL query did not pass a security check */ + Core::fatalError(__('There is an issue with your request.')); - $result = $this->dbi->query( - 'SELECT * FROM ' . Util::backquote($table) - . ' WHERE ' . $where_clause . ';' - ); - $row = $result->fetchAssoc(); - } else { - $result = $this->dbi->query( - 'SELECT * FROM ' . Util::backquote($table) . ' LIMIT 1;' - ); - $row = $result->fetchAssoc(); + return; } - // No row returned + $row = $this->dbi->query($query)->fetchAssoc(); if ($row === []) { return; } - $default_ct = 'application/octet-stream'; + $transformKey = $request->getParam('transform_key'); + if ( + ! is_string($transformKey) || $transformKey === '' + || ! isset($row[$transformKey]) || $row[$transformKey] === '' + ) { + return; + } + $mediaTypeMap = []; + $mediaTypeOptions = []; + $relationParameters = $this->relation->getRelationParameters(); if ( $relationParameters->columnCommentsFeature !== null && $relationParameters->browserTransformationFeature !== null ) { - $mime_map = $this->transformations->getMime($db, $table) ?? []; - - $mime_options = $this->transformations->getOptions( - $mime_map[$transform_key]['transformation_options'] ?? '' + $mediaTypeMap = $this->transformations->getMime($db->getName(), $table->getName()) ?? []; + $mediaTypeOptions = $this->transformations->getOptions( + $mediaTypeMap[$transformKey]['transformation_options'] ?? '' ); - foreach ($mime_options as $option) { - if (substr($option, 0, 10) !== '; charset=') { + foreach ($mediaTypeOptions as $option) { + if (! str_starts_with($option, '; charset=')) { continue; } - $mime_options['charset'] = $option; + $mediaTypeOptions['charset'] = $option; } } $this->response->getHeader()->sendHttpHeaders(); - // [MIME] - if (isset($ct) && ! empty($ct)) { - $mime_type = $ct; + /** @psalm-suppress MixedAssignment */ + $contentType = $request->getParam('ct'); + if (is_string($contentType) && $contentType !== '') { + $contentMediaType = $contentType; } else { - $mime_type = (! empty($mime_map[$transform_key]['mimetype']) - ? str_replace('_', '/', $mime_map[$transform_key]['mimetype']) - : $default_ct) - . ($mime_options['charset'] ?? ''); + $contentMediaType = 'application/octet-stream'; + if (! empty($mediaTypeMap[$transformKey]['mimetype'])) { + $contentMediaType = str_replace('_', '/', $mediaTypeMap[$transformKey]['mimetype']); + } + + $contentMediaType .= $mediaTypeOptions['charset'] ?? ''; } - Core::downloadHeader($cn ?? '', $mime_type ?? ''); + /** @psalm-suppress MixedAssignment */ + $contentName = $request->getParam('cn'); + $contentName = is_string($contentName) ? $contentName : ''; - if (! isset($_REQUEST['resize'])) { - if (stripos($mime_type ?? '', 'html') === false) { - echo $row[$transform_key]; - } else { - echo htmlspecialchars($row[$transform_key]); - } - } else { - // if image_*__inline.inc.php finds that we can resize, - // it sets the resize parameter to jpeg or png + Core::downloadHeader($contentName, $contentMediaType); + + $resize = $request->getParam('resize'); + if ($resize !== 'jpeg' && $resize !== 'png') { + if (str_contains(strtolower($contentMediaType), 'html')) { + echo htmlspecialchars($row[$transformKey]); - $srcImage = ImageWrapper::fromString($row[$transform_key]); - if ($srcImage === null) { return; } - $srcWidth = $srcImage->width(); - $srcHeight = $srcImage->height(); + echo $row[$transformKey]; + + return; + } + + $srcImage = ImageWrapper::fromString($row[$transformKey]); + if ($srcImage === null) { + return; + } - // Check to see if the width > height or if width < height - // if so adjust accordingly to make sure the image - // stays smaller than the new width and new height + $newHeight = $this->formatSize($request->getParam('newHeight')); + $newWidth = $this->formatSize($request->getParam('newWidth')); - $ratioWidth = $srcWidth / $_REQUEST['newWidth']; - $ratioHeight = $srcHeight / $_REQUEST['newHeight']; + $srcWidth = $srcImage->width(); + $srcHeight = $srcImage->height(); - if ($ratioWidth < $ratioHeight) { - $destWidth = intval(round($srcWidth / $ratioHeight)); - $destHeight = intval($_REQUEST['newHeight']); - } else { - $destWidth = intval($_REQUEST['newWidth']); - $destHeight = intval(round($srcHeight / $ratioWidth)); - } + $ratioWidth = $srcWidth / $newWidth; + $ratioHeight = $srcHeight / $newHeight; - if ($_REQUEST['resize']) { - $destImage = ImageWrapper::create($destWidth, $destHeight); - if ($destImage === null) { - $srcImage->destroy(); + /** + * Check to see if the width > height or if width < height + * if so adjust accordingly to make sure the image + * stays smaller than the new width and new height + */ + if ($ratioWidth < $ratioHeight) { + $destWidth = intval(round($srcWidth / $ratioHeight)); + $destHeight = $newHeight; + } else { + $destWidth = $newWidth; + $destHeight = intval(round($srcHeight / $ratioWidth)); + } - return; - } + $destImage = ImageWrapper::create($destWidth, $destHeight); + if ($destImage === null) { + $srcImage->destroy(); - // ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, - // $destWidth, $destHeight, $srcWidth, $srcHeight); - // better quality but slower: - $destImage->copyResampled($srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); - if ($_REQUEST['resize'] === 'jpeg') { - $destImage->jpeg(null, 75); - } + return; + } - if ($_REQUEST['resize'] === 'png') { - $destImage->png(); - } + $destImage->copyResampled($srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); - $destImage->destroy(); - } + if ($resize === 'jpeg') { + $destImage->jpeg(null, 75); + } else { + $destImage->png(); + } - $srcImage->destroy(); + $destImage->destroy(); + $srcImage->destroy(); + } + + /** + * @param mixed $size + */ + private function formatSize($size): int + { + if (! is_numeric($size) || $size < 2) { + return 1; + } + + if ($size >= 2000) { + return 2000; + } + + return (int) $size; + } + + /** + * @param mixed $whereClause + * @param mixed $whereClauseSign + */ + private function getQuery(TableName $table, $whereClause, $whereClauseSign): ?string + { + if ($whereClause === null) { + return sprintf('SELECT * FROM %s LIMIT 1;', Util::backquote($table)); + } + + if ( + ! is_string($whereClause) || $whereClause === '' + || ! is_string($whereClauseSign) || $whereClauseSign === '' + || ! Core::checkSqlQuerySignature($whereClause, $whereClauseSign) + ) { + return null; } + + return sprintf('SELECT * FROM %s WHERE %s;', Util::backquote($table), $whereClause); } } diff --git a/libraries/classes/Controllers/UserPasswordController.php b/libraries/classes/Controllers/UserPasswordController.php index e8a14170a6..0f126547c2 100644 --- a/libraries/classes/Controllers/UserPasswordController.php +++ b/libraries/classes/Controllers/UserPasswordController.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Controllers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -35,9 +36,13 @@ class UserPasswordController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $cfg, $hostname, $username, $password, $change_password_message, $msg; + $GLOBALS['hostname'] = $GLOBALS['hostname'] ?? null; + $GLOBALS['username'] = $GLOBALS['username'] ?? null; + $GLOBALS['password'] = $GLOBALS['password'] ?? null; + $GLOBALS['change_password_message'] = $GLOBALS['change_password_message'] ?? null; + $GLOBALS['msg'] = $GLOBALS['msg'] ?? null; $this->addScriptFiles(['server/privileges.js', 'vendor/zxcvbn-ts.js']); @@ -45,11 +50,11 @@ class UserPasswordController extends AbstractController * Displays an error message and exits if the user isn't allowed to use this * script */ - if (! $cfg['ShowChgPassword']) { - $cfg['ShowChgPassword'] = $this->dbi->selectDb('mysql'); + if (! $GLOBALS['cfg']['ShowChgPassword']) { + $GLOBALS['cfg']['ShowChgPassword'] = $this->dbi->selectDb('mysql'); } - if ($cfg['Server']['auth_type'] === 'config' || ! $cfg['ShowChgPassword']) { + if ($GLOBALS['cfg']['Server']['auth_type'] === 'config' || ! $GLOBALS['cfg']['ShowChgPassword']) { $this->response->addHTML(Message::error( __('You don\'t have sufficient privileges to be here right now!') )->getDisplay()); @@ -63,33 +68,37 @@ class UserPasswordController extends AbstractController */ if (isset($_POST['nopass'])) { if ($_POST['nopass'] == '1') { - $password = ''; + $GLOBALS['password'] = ''; } else { - $password = $_POST['pma_pw']; + $GLOBALS['password'] = $_POST['pma_pw']; } - $change_password_message = $this->userPassword->setChangePasswordMsg(); - $msg = $change_password_message['msg']; + $GLOBALS['change_password_message'] = $this->userPassword->setChangePasswordMsg(); + $GLOBALS['msg'] = $GLOBALS['change_password_message']['msg']; - if (! $change_password_message['error']) { - $sql_query = $this->userPassword->changePassword($password); + if (! $GLOBALS['change_password_message']['error']) { + $sql_query = $this->userPassword->changePassword($GLOBALS['password']); if ($this->response->isAjax()) { - $sql_query = Generator::getMessage($change_password_message['msg'], $sql_query, 'success'); + $sql_query = Generator::getMessage( + $GLOBALS['change_password_message']['msg'], + $sql_query, + 'success' + ); $this->response->addJSON('message', $sql_query); return; } $this->response->addHTML('<h1>' . __('Change password') . '</h1>' . "\n\n"); - $this->response->addHTML(Generator::getMessage($msg, $sql_query, 'success')); + $this->response->addHTML(Generator::getMessage($GLOBALS['msg'], $sql_query, 'success')); $this->render('user_password'); return; } if ($this->response->isAjax()) { - $this->response->addJSON('message', $change_password_message['msg']); + $this->response->addJSON('message', $GLOBALS['change_password_message']['msg']); $this->response->setRequestStatus(false); return; @@ -102,10 +111,14 @@ class UserPasswordController extends AbstractController */ // Displays an error message if required - if (isset($msg)) { - $this->response->addHTML($msg->getDisplay()); + if (isset($GLOBALS['msg'])) { + $this->response->addHTML($GLOBALS['msg']->getDisplay()); } - $this->response->addHTML($this->userPassword->getFormForChangePassword($username, $hostname)); + $this->response->addHTML($this->userPassword->getFormForChangePassword( + $GLOBALS['username'], + $GLOBALS['hostname'], + $request->getRoute() + )); } } diff --git a/libraries/classes/Controllers/VersionCheckController.php b/libraries/classes/Controllers/VersionCheckController.php index 60d51bc2ba..9f8f30ec7b 100644 --- a/libraries/classes/Controllers/VersionCheckController.php +++ b/libraries/classes/Controllers/VersionCheckController.php @@ -5,6 +5,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; +use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; use PhpMyAdmin\VersionInformation; use function json_encode; @@ -14,7 +17,16 @@ use function json_encode; */ class VersionCheckController extends AbstractController { - public function __invoke(): void + /** @var VersionInformation */ + private $versionInformation; + + public function __construct(ResponseRenderer $response, Template $template, VersionInformation $versionInformation) + { + parent::__construct($response, $template); + $this->versionInformation = $versionInformation; + } + + public function __invoke(ServerRequest $request): void { $_GET['ajax_request'] = 'true'; @@ -24,8 +36,7 @@ class VersionCheckController extends AbstractController // Always send the correct headers Core::headerJSON(); - $versionInformation = new VersionInformation(); - $versionDetails = $versionInformation->getLatestVersion(); + $versionDetails = $this->versionInformation->getLatestVersion(); if (empty($versionDetails)) { echo json_encode([]); @@ -33,7 +44,7 @@ class VersionCheckController extends AbstractController return; } - $latestCompatible = $versionInformation->getLatestCompatibleVersion($versionDetails->releases); + $latestCompatible = $this->versionInformation->getLatestCompatibleVersion($versionDetails->releases); $version = ''; $date = ''; if ($latestCompatible != null) { diff --git a/libraries/classes/Controllers/View/CreateController.php b/libraries/classes/Controllers/View/CreateController.php index e84c7ce806..29160c747f 100644 --- a/libraries/classes/Controllers/View/CreateController.php +++ b/libraries/classes/Controllers/View/CreateController.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Parser; @@ -42,44 +43,58 @@ class CreateController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $text_dir, $urlParams, $view_algorithm_options, $view_with_options, $view_security_options; - global $message, $sep, $sql_query, $arr, $view_columns, $column_map, $systemDb, $pma_transformation_data; - global $containerBuilder, $new_transformations_sql, $view, $item, $parts, $db, $cfg, $errorUrl; - - Util::checkParameters(['db']); - - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $errorUrl .= Url::getCommon(['db' => $db], '&'); + $this->checkParameters(['db']); + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['view_algorithm_options'] = $GLOBALS['view_algorithm_options'] ?? null; + $GLOBALS['view_with_options'] = $GLOBALS['view_with_options'] ?? null; + $GLOBALS['view_security_options'] = $GLOBALS['view_security_options'] ?? null; + + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['sep'] = $GLOBALS['sep'] ?? null; + $GLOBALS['arr'] = $GLOBALS['arr'] ?? null; + $GLOBALS['view_columns'] = $GLOBALS['view_columns'] ?? null; + $GLOBALS['column_map'] = $GLOBALS['column_map'] ?? null; + $GLOBALS['systemDb'] = $GLOBALS['systemDb'] ?? null; + $GLOBALS['pma_transformation_data'] = $GLOBALS['pma_transformation_data'] ?? null; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; + $GLOBALS['new_transformations_sql'] = $GLOBALS['new_transformations_sql'] ?? null; + $GLOBALS['view'] = $GLOBALS['view'] ?? null; + $GLOBALS['item'] = $GLOBALS['item'] ?? null; + $GLOBALS['parts'] = $GLOBALS['parts'] ?? null; + + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); if (! $this->hasDatabase()) { return; } - $urlParams['goto'] = Url::getFromRoute('/table/structure'); - $urlParams['back'] = Url::getFromRoute('/view/create'); + $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/structure'); + $GLOBALS['urlParams']['back'] = Url::getFromRoute('/view/create'); - $view_algorithm_options = [ + $GLOBALS['view_algorithm_options'] = [ 'UNDEFINED', 'MERGE', 'TEMPTABLE', ]; - $view_with_options = [ + $GLOBALS['view_with_options'] = [ 'CASCADED', 'LOCAL', ]; - $view_security_options = [ + $GLOBALS['view_security_options'] = [ 'DEFINER', 'INVOKER', ]; // View name is a compulsory field if (isset($_POST['view']['name']) && empty($_POST['view']['name'])) { - $message = Message::error(__('View name can not be empty!')); - $this->response->addJSON('message', $message); + $GLOBALS['message'] = Message::error(__('View name can not be empty!')); + $this->response->addJSON('message', $GLOBALS['message']); $this->response->setRequestStatus(false); return; @@ -89,56 +104,59 @@ class CreateController extends AbstractController /** * Creates the view */ - $sep = "\r\n"; + $GLOBALS['sep'] = "\r\n"; if (isset($_POST['createview'])) { - $sql_query = 'CREATE'; + $GLOBALS['sql_query'] = 'CREATE'; if (isset($_POST['view']['or_replace'])) { - $sql_query .= ' OR REPLACE'; + $GLOBALS['sql_query'] .= ' OR REPLACE'; } } else { - $sql_query = 'ALTER'; + $GLOBALS['sql_query'] = 'ALTER'; } - if (isset($_POST['view']['algorithm']) && in_array($_POST['view']['algorithm'], $view_algorithm_options)) { - $sql_query .= $sep . ' ALGORITHM = ' . $_POST['view']['algorithm']; + if ( + isset($_POST['view']['algorithm']) + && in_array($_POST['view']['algorithm'], $GLOBALS['view_algorithm_options']) + ) { + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' ALGORITHM = ' . $_POST['view']['algorithm']; } if (! empty($_POST['view']['definer'])) { if (! str_contains($_POST['view']['definer'], '@')) { - $sql_query .= $sep . 'DEFINER=' + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . 'DEFINER=' . Util::backquote($_POST['view']['definer']); } else { - $arr = explode('@', $_POST['view']['definer']); - $sql_query .= $sep . 'DEFINER=' . Util::backquote($arr[0]); - $sql_query .= '@' . Util::backquote($arr[1]) . ' '; + $GLOBALS['arr'] = explode('@', $_POST['view']['definer']); + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . 'DEFINER=' . Util::backquote($GLOBALS['arr'][0]); + $GLOBALS['sql_query'] .= '@' . Util::backquote($GLOBALS['arr'][1]) . ' '; } } if ( isset($_POST['view']['sql_security']) - && in_array($_POST['view']['sql_security'], $view_security_options) + && in_array($_POST['view']['sql_security'], $GLOBALS['view_security_options']) ) { - $sql_query .= $sep . ' SQL SECURITY ' + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' SQL SECURITY ' . $_POST['view']['sql_security']; } - $sql_query .= $sep . ' VIEW ' + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' VIEW ' . Util::backquote($_POST['view']['name']); if (! empty($_POST['view']['column_names'])) { - $sql_query .= $sep . ' (' . $_POST['view']['column_names'] . ')'; + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' (' . $_POST['view']['column_names'] . ')'; } - $sql_query .= $sep . ' AS ' . $_POST['view']['as']; + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' AS ' . $_POST['view']['as']; - if (isset($_POST['view']['with']) && in_array($_POST['view']['with'], $view_with_options)) { - $sql_query .= $sep . ' WITH ' . $_POST['view']['with'] . ' CHECK OPTION'; + if (isset($_POST['view']['with']) && in_array($_POST['view']['with'], $GLOBALS['view_with_options'])) { + $GLOBALS['sql_query'] .= $GLOBALS['sep'] . ' WITH ' . $_POST['view']['with'] . ' CHECK OPTION'; } - if (! $this->dbi->tryQuery($sql_query)) { + if (! $this->dbi->tryQuery($GLOBALS['sql_query'])) { if (! isset($_POST['ajax_dialog'])) { - $message = Message::rawError($this->dbi->getError()); + $GLOBALS['message'] = Message::rawError($this->dbi->getError()); return; } @@ -146,7 +164,7 @@ class CreateController extends AbstractController $this->response->addJSON( 'message', Message::error( - '<i>' . htmlspecialchars($sql_query) . '</i><br><br>' + '<i>' . htmlspecialchars($GLOBALS['sql_query']) . '</i><br><br>' . $this->dbi->getError() ) ); @@ -156,44 +174,44 @@ class CreateController extends AbstractController } // If different column names defined for VIEW - $view_columns = []; + $GLOBALS['view_columns'] = []; if (isset($_POST['view']['column_names'])) { - $view_columns = explode(',', $_POST['view']['column_names']); + $GLOBALS['view_columns'] = explode(',', $_POST['view']['column_names']); } - $column_map = $this->dbi->getColumnMapFromSql($_POST['view']['as'], $view_columns); + $GLOBALS['column_map'] = $this->dbi->getColumnMapFromSql($_POST['view']['as'], $GLOBALS['view_columns']); - $systemDb = $this->dbi->getSystemDatabase(); - $pma_transformation_data = $systemDb->getExistingTransformationData($db); + $GLOBALS['systemDb'] = $this->dbi->getSystemDatabase(); + $GLOBALS['pma_transformation_data'] = $GLOBALS['systemDb']->getExistingTransformationData($GLOBALS['db']); - if ($pma_transformation_data !== false) { + if ($GLOBALS['pma_transformation_data'] !== false) { // SQL for store new transformation details of VIEW - $new_transformations_sql = $systemDb->getNewTransformationDataSql( - $pma_transformation_data, - $column_map, + $GLOBALS['new_transformations_sql'] = $GLOBALS['systemDb']->getNewTransformationDataSql( + $GLOBALS['pma_transformation_data'], + $GLOBALS['column_map'], $_POST['view']['name'], - $db + $GLOBALS['db'] ); // Store new transformations - if ($new_transformations_sql != '') { - $this->dbi->tryQuery($new_transformations_sql); + if ($GLOBALS['new_transformations_sql'] != '') { + $this->dbi->tryQuery($GLOBALS['new_transformations_sql']); } } - unset($pma_transformation_data); + unset($GLOBALS['pma_transformation_data']); if (! isset($_POST['ajax_dialog'])) { - $message = Message::success(); + $GLOBALS['message'] = Message::success(); /** @var StructureController $controller */ - $controller = $containerBuilder->get(StructureController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(StructureController::class); + $controller($request); } else { $this->response->addJSON( 'message', Generator::getMessage( Message::success(), - $sql_query + $GLOBALS['sql_query'] ) ); $this->response->setRequestStatus(true); @@ -202,10 +220,10 @@ class CreateController extends AbstractController return; } - $sql_query = ! empty($_POST['sql_query']) ? $_POST['sql_query'] : ''; + $GLOBALS['sql_query'] = ! empty($_POST['sql_query']) ? $_POST['sql_query'] : ''; // prefill values if not already filled from former submission - $view = [ + $GLOBALS['view'] = [ 'operation' => 'create', 'or_replace' => '', 'algorithm' => '', @@ -213,13 +231,13 @@ class CreateController extends AbstractController 'sql_security' => '', 'name' => '', 'column_names' => '', - 'as' => $sql_query, + 'as' => $GLOBALS['sql_query'], 'with' => '', ]; // Used to prefill the fields when editing a view if (isset($_GET['db'], $_GET['table'])) { - $item = $this->dbi->fetchSingleRow( + $GLOBALS['item'] = $this->dbi->fetchSingleRow( sprintf( "SELECT `VIEW_DEFINITION`, `CHECK_OPTION`, `DEFINER`, `SECURITY_TYPE` @@ -234,43 +252,45 @@ class CreateController extends AbstractController ->showCreate(); // CREATE ALGORITHM=<ALGORITHM> DE... - $parts = explode(' ', substr($createView, 17)); - $item['ALGORITHM'] = $parts[0]; + $GLOBALS['parts'] = explode(' ', substr($createView, 17)); + $GLOBALS['item']['ALGORITHM'] = $GLOBALS['parts'][0]; - $view['operation'] = 'alter'; - $view['definer'] = $item['DEFINER']; - $view['sql_security'] = $item['SECURITY_TYPE']; - $view['name'] = $_GET['table']; - $view['as'] = $item['VIEW_DEFINITION']; - $view['with'] = $item['CHECK_OPTION']; - $view['algorithm'] = $item['ALGORITHM']; + $GLOBALS['view']['operation'] = 'alter'; + $GLOBALS['view']['definer'] = $GLOBALS['item']['DEFINER']; + $GLOBALS['view']['sql_security'] = $GLOBALS['item']['SECURITY_TYPE']; + $GLOBALS['view']['name'] = $_GET['table']; + $GLOBALS['view']['as'] = $GLOBALS['item']['VIEW_DEFINITION']; + $GLOBALS['view']['with'] = $GLOBALS['item']['CHECK_OPTION']; + $GLOBALS['view']['algorithm'] = $GLOBALS['item']['ALGORITHM']; // MySQL 8.0+ - issue #16194 - if (empty($view['as']) && is_string($createView)) { + if (empty($GLOBALS['view']['as']) && is_string($createView)) { $parser = new Parser($createView); /** * @var CreateStatement $stmt */ $stmt = $parser->statements[0]; - $view['as'] = isset($stmt->body) ? TokensList::build($stmt->body) : $view['as']; + $GLOBALS['view']['as'] = isset($stmt->body) ? TokensList::build($stmt->body) : $GLOBALS['view']['as']; } } if (isset($_POST['view']) && is_array($_POST['view'])) { - $view = array_merge($view, $_POST['view']); + $GLOBALS['view'] = array_merge($GLOBALS['view'], $_POST['view']); } - $urlParams['db'] = $db; - $urlParams['reload'] = 1; + $GLOBALS['urlParams']['db'] = $GLOBALS['db']; + $GLOBALS['urlParams']['reload'] = 1; + + $this->addScriptFiles(['sql.js']); echo $this->template->render('view_create', [ 'ajax_dialog' => isset($_POST['ajax_dialog']), - 'text_dir' => $text_dir, - 'url_params' => $urlParams, - 'view' => $view, - 'view_algorithm_options' => $view_algorithm_options, - 'view_with_options' => $view_with_options, - 'view_security_options' => $view_security_options, + 'text_dir' => $GLOBALS['text_dir'], + 'url_params' => $GLOBALS['urlParams'], + 'view' => $GLOBALS['view'], + 'view_algorithm_options' => $GLOBALS['view_algorithm_options'], + 'view_with_options' => $GLOBALS['view_with_options'], + 'view_security_options' => $GLOBALS['view_security_options'], ]); } } diff --git a/libraries/classes/Controllers/View/OperationsController.php b/libraries/classes/Controllers/View/OperationsController.php index f411b2fc13..2e63851452 100644 --- a/libraries/classes/Controllers/View/OperationsController.php +++ b/libraries/classes/Controllers/View/OperationsController.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -39,24 +40,26 @@ class OperationsController extends AbstractController $this->dbi = $dbi; } - public function __invoke(): void + public function __invoke(ServerRequest $request): void { - global $sql_query, $urlParams, $reload, $result, $warning_messages; - global $db, $table, $cfg, $errorUrl; - - $tableObject = $this->dbi->getTable($db, $table); + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; + $GLOBALS['result'] = $GLOBALS['result'] ?? null; + $GLOBALS['warning_messages'] = $GLOBALS['warning_messages'] ?? null; + $tableObject = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table']); + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; $this->addScriptFiles(['table/operations.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); - $urlParams = ['db' => $db, 'table' => $table]; - $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $errorUrl .= Url::getCommon($urlParams, '&'); + $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; + $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check(); + DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); - $urlParams['goto'] = $urlParams['back'] = Url::getFromRoute('/view/operations'); + $GLOBALS['urlParams']['goto'] = $GLOBALS['urlParams']['back'] = Url::getFromRoute('/view/operations'); $message = new Message(); $type = 'success'; @@ -64,25 +67,25 @@ class OperationsController extends AbstractController if (isset($_POST['new_name'])) { if ($tableObject->rename($_POST['new_name'])) { $message->addText($tableObject->getLastMessage()); - $result = true; - $table = $tableObject->getName(); + $GLOBALS['result'] = true; + $GLOBALS['table'] = $tableObject->getName(); /* Force reread after rename */ $tableObject->getStatusInfo(null, true); - $reload = true; + $GLOBALS['reload'] = true; } else { $message->addText($tableObject->getLastError()); - $result = false; + $GLOBALS['result'] = false; } } - $warning_messages = $this->operations->getWarningMessagesArray(); + $GLOBALS['warning_messages'] = $this->operations->getWarningMessagesArray(); } - if (isset($result)) { + if (isset($GLOBALS['result'])) { // set to success by default, because result set could be empty // (for example, a table rename) if (empty($message->getString())) { - if ($result) { + if ($GLOBALS['result']) { $message->addText( __('Your SQL query has been executed successfully.') ); @@ -91,25 +94,25 @@ class OperationsController extends AbstractController } // $result should exist, regardless of $_message - $type = $result ? 'success' : 'error'; + $type = $GLOBALS['result'] ? 'success' : 'error'; } - if (! empty($warning_messages)) { - $message->addMessagesString($warning_messages); + if (! empty($GLOBALS['warning_messages'])) { + $message->addMessagesString($GLOBALS['warning_messages']); $message->isError(true); } $this->response->addHTML(Generator::getMessage( $message, - $sql_query, + $GLOBALS['sql_query'], $type )); } $this->render('table/operations/view', [ - 'db' => $db, - 'table' => $table, - 'url_params' => $urlParams, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], + 'url_params' => $GLOBALS['urlParams'], ]); } } diff --git a/libraries/classes/Core.php b/libraries/classes/Core.php index 81990aa0a1..94b5b6ff3d 100644 --- a/libraries/classes/Core.php +++ b/libraries/classes/Core.php @@ -90,8 +90,6 @@ class Core string $error_message, $message_args = null ): void { - global $dbi; - /* Use format string if applicable */ if (is_string($message_args)) { $error_message = sprintf($error_message, $message_args); @@ -104,7 +102,7 @@ class Core * (this can happen on early fatal error) */ if ( - isset($dbi, $GLOBALS['config']) + isset($GLOBALS['dbi'], $GLOBALS['config']) && $GLOBALS['config']->get('is_setup') === false && ResponseRenderer::getInstance()->isAjax() ) { @@ -195,7 +193,7 @@ class Core bool $fatal = false, string $extra = '' ): void { - global $errorHandler; + $GLOBALS['errorHandler'] = $GLOBALS['errorHandler'] ?? null; $message = 'The %s extension is missing. Please check your PHP configuration.'; @@ -216,7 +214,7 @@ class Core return; } - $errorHandler->addError($message, E_USER_WARNING, '', 0, false); + $GLOBALS['errorHandler']->addError($message, E_USER_WARNING, '', 0, false); } /** @@ -228,9 +226,7 @@ class Core */ public static function getTableCount(string $db): int { - global $dbi; - - $tables = $dbi->tryQuery('SHOW TABLES FROM ' . Util::backquote($db) . ';'); + $tables = $GLOBALS['dbi']->tryQuery('SHOW TABLES FROM ' . Util::backquote($db) . ';'); if ($tables) { return $tables->numRows(); @@ -637,10 +633,10 @@ class Core $query = http_build_query(['url' => $vars['url']]); if ($GLOBALS['config'] !== null && $GLOBALS['config']->get('is_setup')) { - return '../url.php?' . $query; + return '../index.php?route=/url&' . $query; } - return './url.php?' . $query; + return 'index.php?route=/url&' . $query; } /** @@ -651,30 +647,17 @@ class Core */ public static function isAllowedDomain(string $url): bool { - $arr = parse_url($url); - - if (! is_array($arr)) { - $arr = []; - } - - // We need host to be set - if (! isset($arr['host']) || strlen($arr['host']) == 0) { + $parsedUrl = parse_url($url); + if ( + ! is_array($parsedUrl) + || ! isset($parsedUrl['host']) + || isset($parsedUrl['user']) + || isset($parsedUrl['pass']) + || isset($parsedUrl['port']) + ) { return false; } - // We do not want these to be present - $blocked = [ - 'user', - 'pass', - 'port', - ]; - foreach ($blocked as $part) { - if (isset($arr[$part]) && strlen((string) $arr[$part]) != 0) { - return false; - } - } - - $domain = $arr['host']; $domainAllowList = [ /* Include current domain */ $_SERVER['SERVER_NAME'], @@ -702,7 +685,7 @@ class Core 'mysqldatabaseadministration.blogspot.com', ]; - return in_array($domain, $domainAllowList); + return in_array($parsedUrl['host'], $domainAllowList, true); } /** @@ -775,7 +758,7 @@ class Core */ public static function setPostAsGlobal(array $post_patterns): void { - global $containerBuilder; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; foreach (array_keys($_POST) as $post_key) { foreach ($post_patterns as $one_post_pattern) { @@ -784,7 +767,7 @@ class Core } $GLOBALS[$post_key] = $_POST[$post_key]; - $containerBuilder->setParameter($post_key, $GLOBALS[$post_key]); + $GLOBALS['containerBuilder']->setParameter($post_key, $GLOBALS[$post_key]); } } } @@ -961,11 +944,9 @@ class Core */ public static function signSqlQuery($sqlQuery) { - global $cfg; - $secret = $_SESSION[' HMAC_secret '] ?? ''; - return hash_hmac('sha256', $sqlQuery, $secret . $cfg['blowfish_secret']); + return hash_hmac('sha256', $sqlQuery, $secret . $GLOBALS['cfg']['blowfish_secret']); } /** @@ -976,10 +957,8 @@ class Core */ public static function checkSqlQuerySignature($sqlQuery, $signature): bool { - global $cfg; - $secret = $_SESSION[' HMAC_secret '] ?? ''; - $hmac = hash_hmac('sha256', $sqlQuery, $secret . $cfg['blowfish_secret']); + $hmac = hash_hmac('sha256', $sqlQuery, $secret . $GLOBALS['cfg']['blowfish_secret']); return hash_equals($hmac, $signature); } diff --git a/libraries/classes/Crypto/Crypto.php b/libraries/classes/Crypto/Crypto.php index 04f37d42c0..f7b7d26498 100644 --- a/libraries/classes/Crypto/Crypto.php +++ b/libraries/classes/Crypto/Crypto.php @@ -20,9 +20,9 @@ final class Crypto { private function getEncryptionKey(): string { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; - $key = $config->get('URLQueryEncryptionSecretKey'); + $key = $GLOBALS['config']->get('URLQueryEncryptionSecretKey'); if (is_string($key) && mb_strlen($key, '8bit') === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) { return $key; } diff --git a/libraries/classes/Database/Designer.php b/libraries/classes/Database/Designer.php index 7ec6272c46..38299108db 100644 --- a/libraries/classes/Database/Designer.php +++ b/libraries/classes/Database/Designer.php @@ -158,8 +158,6 @@ class Designer */ private function getSideMenuParamsArray() { - global $dbi; - $params = []; $databaseDesignerSettingsFeature = $this->relation->getRelationParameters()->databaseDesignerSettingsFeature; @@ -168,7 +166,7 @@ class Designer . Util::backquote($databaseDesignerSettingsFeature->database) . '.' . Util::backquote($databaseDesignerSettingsFeature->designerSettings) . ' WHERE ' . Util::backquote('username') . ' = "' - . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) + . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) . '";'; $result = $this->dbi->fetchSingleRow($query); @@ -251,7 +249,7 @@ class Designer array $tables_all_keys, array $tables_pk_or_unique_keys ) { - global $text_dir; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; $columns_type = []; foreach ($designerTables as $designerTable) { @@ -288,7 +286,7 @@ class Designer return $this->template->render('database/designer/database_tables', [ 'db' => $GLOBALS['db'], - 'text_dir' => $text_dir, + 'text_dir' => $GLOBALS['text_dir'], 'get_db' => $db, 'has_query' => isset($_REQUEST['query']), 'tab_pos' => $tab_pos, @@ -337,7 +335,7 @@ class Designer array $tablesAllKeys, array $tablesPkOrUniqueKeys ): string { - global $text_dir; + $GLOBALS['text_dir'] = $GLOBALS['text_dir'] ?? null; $relationParameters = $this->relation->getRelationParameters(); $columnsType = []; @@ -393,7 +391,7 @@ class Designer return $this->template->render('database/designer/main', [ 'db' => $db, - 'text_dir' => $text_dir, + 'text_dir' => $GLOBALS['text_dir'], 'get_db' => $getDb, 'designer_config' => json_encode($designerConfig), 'display_page' => (int) $displayPage, diff --git a/libraries/classes/Database/Designer/Common.php b/libraries/classes/Database/Designer/Common.php index 1aa210d4b3..b8606b52ed 100644 --- a/libraries/classes/Database/Designer/Common.php +++ b/libraries/classes/Database/Designer/Common.php @@ -221,7 +221,7 @@ class Common foreach ($designerTables as $designerTable) { $schema = $designerTable->getDatabaseName(); // for now, take into account only the first index segment - foreach (Index::getFromTable($designerTable->getTableName(), $schema) as $index) { + foreach (Index::getFromTable($this->dbi, $designerTable->getTableName(), $schema) as $index) { if ($unique_only && ! $index->isUnique()) { continue; } diff --git a/libraries/classes/Database/Events.php b/libraries/classes/Database/Events.php index 9240c7ee66..496024b4d0 100644 --- a/libraries/classes/Database/Events.php +++ b/libraries/classes/Database/Events.php @@ -7,22 +7,28 @@ namespace PhpMyAdmin\Database; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Message; +use PhpMyAdmin\Query\Generator as QueryGenerator; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Util; use function __; +use function array_column; +use function array_multisort; use function count; use function explode; use function htmlspecialchars; use function in_array; use function intval; +use function is_string; use function mb_strtoupper; use function sprintf; use function str_contains; use function strtoupper; use function trim; +use const SORT_ASC; + /** * Functions for event management. */ @@ -82,7 +88,8 @@ class Events */ public function handleEditor(): void { - global $db, $table, $errors, $message; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; if (! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit'])) { $sql_query = ''; @@ -90,17 +97,17 @@ class Events $item_query = $this->getQueryFromRequest(); // set by getQueryFromRequest() - if (! count($errors)) { + if (! count($GLOBALS['errors'])) { // Execute the created query if (! empty($_POST['editor_process_edit'])) { // Backup the old trigger, in case something goes wrong - $create_item = $this->dbi->getDefinition($db, 'EVENT', $_POST['item_original_name']); + $create_item = self::getDefinition($this->dbi, $GLOBALS['db'], $_POST['item_original_name']); $drop_item = 'DROP EVENT IF EXISTS ' . Util::backquote($_POST['item_original_name']) . ";\n"; $result = $this->dbi->tryQuery($drop_item); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($drop_item) ) @@ -109,7 +116,7 @@ class Events } else { $result = $this->dbi->tryQuery($item_query); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) @@ -119,13 +126,13 @@ class Events // the new one. Try to restore the backup query $result = $this->dbi->tryQuery($create_item); if (! $result) { - $errors = $this->checkResult($create_item, $errors); + $GLOBALS['errors'] = $this->checkResult($create_item, $GLOBALS['errors']); } } else { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Event %1$s has been modified.') ); - $message->addParam( + $GLOBALS['message']->addParam( Util::backquote($_POST['item_name']) ); $sql_query = $drop_item . $item_query; @@ -135,17 +142,17 @@ class Events // 'Add a new item' mode $result = $this->dbi->tryQuery($item_query); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '<br><br>' . __('MySQL said: ') . $this->dbi->getError(); } else { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Event %1$s has been created.') ); - $message->addParam( + $GLOBALS['message']->addParam( Util::backquote($_POST['item_name']) ); $sql_query = $item_query; @@ -153,27 +160,27 @@ class Events } } - if (count($errors)) { - $message = Message::error( + if (count($GLOBALS['errors'])) { + $GLOBALS['message'] = Message::error( '<b>' . __( 'One or more errors have occurred while processing your request:' ) . '</b>' ); - $message->addHtml('<ul>'); - foreach ($errors as $string) { - $message->addHtml('<li>' . $string . '</li>'); + $GLOBALS['message']->addHtml('<ul>'); + foreach ($GLOBALS['errors'] as $string) { + $GLOBALS['message']->addHtml('<li>' . $string . '</li>'); } - $message->addHtml('</ul>'); + $GLOBALS['message']->addHtml('</ul>'); } - $output = Generator::getMessage($message, $sql_query); + $output = Generator::getMessage($GLOBALS['message'], $sql_query); if ($this->response->isAjax()) { - if ($message->isSuccess()) { - $events = $this->dbi->getEvents($db, $_POST['item_name']); + if ($GLOBALS['message']->isSuccess()) { + $events = $this->getDetails($GLOBALS['db'], $_POST['item_name']); $event = $events[0]; $this->response->addJSON( 'name', @@ -189,10 +196,10 @@ class Events $this->response->addJSON( 'new_row', $this->template->render('database/events/row', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'event' => $event, - 'has_privilege' => Util::currentUserHasPrivilege('EVENT', $db), + 'has_privilege' => Util::currentUserHasPrivilege('EVENT', $GLOBALS['db']), 'sql_drop' => $sqlDrop, 'row_class' => '', ]) @@ -203,7 +210,7 @@ class Events $this->response->addJSON('message', $output); } else { $this->response->setRequestStatus(false); - $this->response->addJSON('message', $message); + $this->response->addJSON('message', $GLOBALS['message']); } $this->response->addJSON('tableType', 'events'); @@ -215,7 +222,7 @@ class Events * Display a form used to add/edit a trigger, if necessary */ if ( - ! count($errors) + ! count($GLOBALS['errors']) && (! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit']) || (empty($_REQUEST['add_item']) @@ -257,7 +264,7 @@ class Events $mode = 'edit'; } - $this->sendEditor($mode, $item, $title, $db, $operation); + $this->sendEditor($mode, $item, $title, $GLOBALS['db'], $operation); } /** @@ -306,14 +313,12 @@ class Events */ public function getDataFromName($name): ?array { - global $db; - $retval = []; $columns = '`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, ' . '`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, ' . '`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`'; $where = 'EVENT_SCHEMA ' . Util::getCollateForIS() . '=' - . "'" . $this->dbi->escapeString($db) . "' " + . "'" . $this->dbi->escapeString($GLOBALS['db']) . "' " . "AND EVENT_NAME='" . $this->dbi->escapeString($name) . "'"; $query = 'SELECT ' . $columns . ' FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE ' . $where . ';'; $item = $this->dbi->fetchSingleRow($query); @@ -362,8 +367,6 @@ class Events */ public function getEditorForm($mode, $operation, array $item) { - global $db; - if ($operation === 'change') { if ($item['item_type'] === 'RECURRING') { $item['item_type'] = 'ONE TIME'; @@ -375,7 +378,7 @@ class Events } return $this->template->render('database/events/editor_form', [ - 'db' => $db, + 'db' => $GLOBALS['db'], 'event' => $item, 'mode' => $mode, 'is_ajax' => $this->response->isAjax(), @@ -392,7 +395,7 @@ class Events */ public function getQueryFromRequest() { - global $errors; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; $query = 'CREATE '; if (! empty($_POST['item_definer'])) { @@ -401,7 +404,7 @@ class Events $query .= 'DEFINER=' . Util::backquote($arr[0]); $query .= '@' . Util::backquote($arr[1]) . ' '; } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); + $GLOBALS['errors'][] = __('The definer must be in the "username@hostname" format!'); } } @@ -409,7 +412,7 @@ class Events if (! empty($_POST['item_name'])) { $query .= Util::backquote($_POST['item_name']) . ' '; } else { - $errors[] = __('You must provide an event name!'); + $GLOBALS['errors'][] = __('You must provide an event name!'); } $query .= 'ON SCHEDULE '; @@ -423,7 +426,7 @@ class Events $query .= 'EVERY ' . intval($_POST['item_interval_value']) . ' '; $query .= $_POST['item_interval_field'] . ' '; } else { - $errors[] = __('You must provide a valid interval value for the event.'); + $GLOBALS['errors'][] = __('You must provide a valid interval value for the event.'); } if (! empty($_POST['item_starts'])) { @@ -443,11 +446,11 @@ class Events . $this->dbi->escapeString($_POST['item_execute_at']) . "' "; } else { - $errors[] = __('You must provide a valid execution time for the event.'); + $GLOBALS['errors'][] = __('You must provide a valid execution time for the event.'); } } } else { - $errors[] = __('You must provide a valid type for the event.'); + $GLOBALS['errors'][] = __('You must provide a valid type for the event.'); } $query .= 'ON COMPLETION '; @@ -473,7 +476,7 @@ class Events if (! empty($_POST['item_definition'])) { $query .= $_POST['item_definition']; } else { - $errors[] = __('You must provide an event definition.'); + $GLOBALS['errors'][] = __('You must provide an event definition.'); } return $query; @@ -549,14 +552,12 @@ class Events public function export(): void { - global $db; - if (empty($_GET['export_item']) || empty($_GET['item_name'])) { return; } $itemName = $_GET['item_name']; - $exportData = $this->dbi->getDefinition($db, 'EVENT', $itemName); + $exportData = self::getDefinition($this->dbi, $GLOBALS['db'], $itemName); if (! $exportData) { $exportData = false; @@ -588,7 +589,7 @@ class Events $message = sprintf( __('Error in processing request: No event with name %1$s found in database %2$s.'), $itemName, - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); @@ -601,4 +602,55 @@ class Events $this->response->addHTML($message->getDisplay()); } + + /** + * Returns details about the EVENTs for a specific database. + * + * @param string $db db name + * @param string $name event name + * + * @return array information about EVENTs + */ + public function getDetails(string $db, string $name = ''): array + { + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = QueryGenerator::getInformationSchemaEventsRequest( + $this->dbi->escapeString($db), + empty($name) ? null : $this->dbi->escapeString($name) + ); + } else { + $query = 'SHOW EVENTS FROM ' . Util::backquote($db); + if ($name) { + $query .= " WHERE `Name` = '" + . $this->dbi->escapeString($name) . "'"; + } + } + + $result = []; + $events = $this->dbi->fetchResult($query); + + foreach ($events as $event) { + $result[] = [ + 'name' => $event['Name'], + 'type' => $event['Type'], + 'status' => $event['Status'], + ]; + } + + // Sort results by name + $name = array_column($result, 'name'); + array_multisort($name, SORT_ASC, $result); + + return $result; + } + + public static function getDefinition(DatabaseInterface $dbi, string $db, string $name): ?string + { + $result = $dbi->fetchValue( + 'SHOW CREATE EVENT ' . Util::backquote($db) . '.' . Util::backquote($name), + 'Create Event' + ); + + return is_string($result) ? $result : null; + } } diff --git a/libraries/classes/Database/MultiTableQuery.php b/libraries/classes/Database/MultiTableQuery.php index 9eea9adba9..5bf67a81de 100644 --- a/libraries/classes/Database/MultiTableQuery.php +++ b/libraries/classes/Database/MultiTableQuery.php @@ -107,24 +107,22 @@ class MultiTableQuery */ public static function displayResults($sqlQuery, $db): string { - global $dbi; - [, $db] = ParseAnalyze::sqlQuery($sqlQuery, $db); $goto = Url::getFromRoute('/database/multi-table-query'); - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $sql = new Sql( - $dbi, + $GLOBALS['dbi'], $relation, - new RelationCleanup($dbi, $relation), - new Operations($dbi, $relation), + new RelationCleanup($GLOBALS['dbi'], $relation), + new Operations($GLOBALS['dbi'], $relation), new Transformations(), new Template() ); return $sql->executeQueryAndSendQueryResponse( - null, // analyzed_sql_results + null, false, // is_gotofile $db, // db null, // table diff --git a/libraries/classes/Database/Routines.php b/libraries/classes/Database/Routines.php index e0040139ff..9e41943696 100644 --- a/libraries/classes/Database/Routines.php +++ b/libraries/classes/Database/Routines.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Charsets; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Message; +use PhpMyAdmin\Query\Generator as QueryGenerator; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; @@ -18,7 +19,9 @@ use PhpMyAdmin\Util; use function __; use function _ngettext; +use function array_column; use function array_merge; +use function array_multisort; use function count; use function explode; use function htmlentities; @@ -38,6 +41,7 @@ use function substr; use function trim; use const ENT_QUOTES; +use const SORT_ASC; /** * Functions for routine management. @@ -79,16 +83,15 @@ class Routines */ public function handleEditor(): void { - global $db, $errors; - - $errors = $this->handleRequestCreateOrEdit($errors, $db); + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['errors'] = $this->handleRequestCreateOrEdit($GLOBALS['errors'], $GLOBALS['db']); /** * Display a form used to add/edit a routine, if necessary */ // FIXME: this must be simpler than that if ( - ! count($errors) + ! count($GLOBALS['errors']) && ( ! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit']) || (empty($_REQUEST['add_item']) && empty($_REQUEST['edit_item']) @@ -157,7 +160,7 @@ class Routines htmlspecialchars( Util::backquote($_REQUEST['item_name']) ), - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); @@ -180,7 +183,7 @@ class Routines */ public function handleRequestCreateOrEdit(array $errors, $db) { - global $message; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; if (empty($_POST['editor_process_add']) && empty($_POST['editor_process_edit'])) { return $errors; @@ -193,26 +196,18 @@ class Routines if (! count($errors)) { // Execute the created query if (! empty($_POST['editor_process_edit'])) { - $isProcOrFunc = in_array( - $_POST['item_original_type'], - [ - 'PROCEDURE', - 'FUNCTION', - ] - ); - - if (! $isProcOrFunc) { + if (! in_array($_POST['item_original_type'], ['PROCEDURE', 'FUNCTION'], true)) { $errors[] = sprintf( __('Invalid routine type: "%s"'), htmlspecialchars($_POST['item_original_type']) ); } else { // Backup the old routine, in case something goes wrong - $create_routine = $this->dbi->getDefinition( - $db, - $_POST['item_original_type'], - $_POST['item_original_name'] - ); + if ($_POST['item_original_type'] === 'FUNCTION') { + $create_routine = self::getFunctionDefinition($this->dbi, $db, $_POST['item_original_name']); + } else { + $create_routine = self::getProcedureDefinition($this->dbi, $db, $_POST['item_original_name']); + } $privilegesBackup = $this->backupPrivileges(); @@ -228,7 +223,11 @@ class Routines . '<br>' . __('MySQL said: ') . $this->dbi->getError(); } else { - [$newErrors, $message] = $this->create($routine_query, $create_routine, $privilegesBackup); + [$newErrors, $GLOBALS['message']] = $this->create( + $routine_query, + $create_routine, + $privilegesBackup + ); if (empty($newErrors)) { $sql_query = $drop_routine . $routine_query; } else { @@ -249,10 +248,10 @@ class Routines . '<br><br>' . __('MySQL said: ') . $this->dbi->getError(); } else { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Routine %1$s has been created.') ); - $message->addParam( + $GLOBALS['message']->addParam( Util::backquote($_POST['item_name']) ); $sql_query = $routine_query; @@ -261,32 +260,32 @@ class Routines } if (count($errors)) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __( 'One or more errors have occurred while processing your request:' ) ); - $message->addHtml('<ul>'); + $GLOBALS['message']->addHtml('<ul>'); foreach ($errors as $string) { - $message->addHtml('<li>' . $string . '</li>'); + $GLOBALS['message']->addHtml('<li>' . $string . '</li>'); } - $message->addHtml('</ul>'); + $GLOBALS['message']->addHtml('</ul>'); } - $output = Generator::getMessage($message, $sql_query); + $output = Generator::getMessage($GLOBALS['message'], $sql_query); if (! $this->response->isAjax()) { return $errors; } - if (! $message->isSuccess()) { + if (! $GLOBALS['message']->isSuccess()) { $this->response->setRequestStatus(false); $this->response->addJSON('message', $output); exit; } - $routines = $this->dbi->getRoutines($db, $_POST['item_type'], $_POST['item_name']); + $routines = self::getDetails($this->dbi, $db, $_POST['item_type'], $_POST['item_name']); $routine = $routines[0]; $this->response->addJSON( 'name', @@ -554,8 +553,6 @@ class Routines */ public function getDataFromName($name, $type, $all = true): ?array { - global $db; - $retval = []; // Build and execute the query @@ -563,7 +560,7 @@ class Routines . 'ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, ' . 'ROUTINE_COMMENT, SECURITY_TYPE'; $where = 'ROUTINE_SCHEMA ' . Util::getCollateForIS() . '=' - . "'" . $this->dbi->escapeString($db) . "' " + . "'" . $this->dbi->escapeString($GLOBALS['db']) . "' " . "AND SPECIFIC_NAME='" . $this->dbi->escapeString($name) . "'" . "AND ROUTINE_TYPE='" . $this->dbi->escapeString($type) . "'"; $query = 'SELECT ' . $fields . ' FROM INFORMATION_SCHEMA.ROUTINES WHERE ' . $where . ';'; @@ -578,7 +575,11 @@ class Routines $retval['item_name'] = $routine['SPECIFIC_NAME']; $retval['item_type'] = $routine['ROUTINE_TYPE']; - $definition = $this->dbi->getDefinition($db, $routine['ROUTINE_TYPE'], $routine['SPECIFIC_NAME']); + if ($routine['ROUTINE_TYPE'] === 'FUNCTION') { + $definition = self::getFunctionDefinition($this->dbi, $GLOBALS['db'], $routine['SPECIFIC_NAME']); + } else { + $definition = self::getProcedureDefinition($this->dbi, $GLOBALS['db'], $routine['SPECIFIC_NAME']); + } if ($definition === null) { return null; @@ -737,7 +738,7 @@ class Routines */ public function getEditorForm($mode, $operation, array $routine) { - global $db, $errors; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; for ($i = 0; $i < $routine['item_num_params']; $i++) { $routine['item_param_name'][$i] = htmlentities($routine['item_param_name'][$i], ENT_QUOTES); @@ -753,7 +754,10 @@ class Routines $routine['item_type'] = 'PROCEDURE'; $routine['item_type_toggle'] = 'FUNCTION'; } - } elseif ($operation === 'add' || ($routine['item_num_params'] == 0 && $mode === 'add' && ! $errors)) { + } elseif ( + $operation === 'add' + || ($routine['item_num_params'] == 0 && $mode === 'add' && ! $GLOBALS['errors']) + ) { $routine['item_param_dir'][] = ''; $routine['item_param_name'][] = ''; $routine['item_param_type'][] = ''; @@ -781,7 +785,7 @@ class Routines $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); return $this->template->render('database/routines/editor_form', [ - 'db' => $db, + 'db' => $GLOBALS['db'], 'routine' => $routine, 'is_edit_mode' => $mode === 'edit', 'is_ajax' => $this->response->isAjax(), @@ -815,14 +819,14 @@ class Routines string $itemType, bool &$warnedAboutLength ): string { - global $errors, $dbi; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; $params = ''; $warnedAboutDir = false; for ($i = 0, $nb = count($itemParamName); $i < $nb; $i++) { if (empty($itemParamName[$i]) || empty($itemParamType[$i])) { - $errors[] = __('You must provide a name and a type for each routine parameter.'); + $GLOBALS['errors'][] = __('You must provide a name and a type for each routine parameter.'); break; } @@ -839,7 +843,7 @@ class Routines . ' ' . $itemParamType[$i]; } elseif (! $warnedAboutDir) { $warnedAboutDir = true; - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('Invalid direction "%s" given for parameter.'), htmlspecialchars($itemParamDir[$i]) ); @@ -859,7 +863,7 @@ class Routines ) { if (! $warnedAboutLength) { $warnedAboutLength = true; - $errors[] = __( + $GLOBALS['errors'][] = __( 'You must provide length/values for routine parameters' . ' of type ENUM, SET, VARCHAR and VARBINARY.' ); @@ -867,7 +871,7 @@ class Routines } if (! empty($itemParamOpsText[$i])) { - if ($dbi->types->getTypeClass($itemParamType[$i]) === 'CHAR') { + if ($GLOBALS['dbi']->types->getTypeClass($itemParamType[$i]) === 'CHAR') { if (! in_array($itemParamType[$i], ['VARBINARY', 'BINARY'])) { $params .= ' CHARSET ' . mb_strtolower($itemParamOpsText[$i]); @@ -876,7 +880,7 @@ class Routines } if (! empty($itemParamOpsNum[$i])) { - if ($dbi->types->getTypeClass($itemParamType[$i]) === 'NUMBER') { + if ($GLOBALS['dbi']->types->getTypeClass($itemParamType[$i]) === 'NUMBER') { $params .= ' ' . mb_strtoupper($itemParamOpsNum[$i]); } @@ -902,14 +906,14 @@ class Routines string $query, bool $warnedAboutLength ): string { - global $errors, $dbi; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; $itemReturnType = $_POST['item_returntype'] ?? null; if (! empty($itemReturnType) && in_array($itemReturnType, Util::getSupportedDatatypes())) { $query .= 'RETURNS ' . $itemReturnType; } else { - $errors[] = __('You must provide a valid return type for the routine.'); + $GLOBALS['errors'][] = __('You must provide a valid return type for the routine.'); } if ( @@ -926,21 +930,21 @@ class Routines && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $itemReturnType) ) { if (! $warnedAboutLength) { - $errors[] = __( + $GLOBALS['errors'][] = __( 'You must provide length/values for routine parameters of type ENUM, SET, VARCHAR and VARBINARY.' ); } } if (! empty($_POST['item_returnopts_text'])) { - if ($dbi->types->getTypeClass($itemReturnType) === 'CHAR') { + if ($GLOBALS['dbi']->types->getTypeClass($itemReturnType) === 'CHAR') { $query .= ' CHARSET ' . mb_strtolower($_POST['item_returnopts_text']); } } if (! empty($_POST['item_returnopts_num'])) { - if ($dbi->types->getTypeClass($itemReturnType) === 'NUMBER') { + if ($GLOBALS['dbi']->types->getTypeClass($itemReturnType) === 'NUMBER') { $query .= ' ' . mb_strtoupper($_POST['item_returnopts_num']); } @@ -956,7 +960,7 @@ class Routines */ public function getQueryFromRequest(): string { - global $errors; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; $itemType = $_POST['item_type'] ?? ''; $itemDefiner = $_POST['item_definer'] ?? ''; @@ -981,14 +985,14 @@ class Routines $query .= '@' . Util::backquoteCompat($arr[1], 'NONE', $do_backquote) . ' '; } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); + $GLOBALS['errors'][] = __('The definer must be in the "username@hostname" format!'); } } if ($itemType === 'FUNCTION' || $itemType === 'PROCEDURE') { $query .= $itemType . ' '; } else { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('Invalid routine type: "%s"'), htmlspecialchars($itemType) ); @@ -997,7 +1001,7 @@ class Routines if (! empty($itemName)) { $query .= Util::backquote($itemName); } else { - $errors[] = __('You must provide a routine name!'); + $GLOBALS['errors'][] = __('You must provide a routine name!'); } $warnedAboutLength = false; @@ -1062,7 +1066,7 @@ class Routines if (! empty($itemDefinition)) { $query .= $itemDefinition; } else { - $errors[] = __('You must provide a routine definition.'); + $GLOBALS['errors'][] = __('You must provide a routine definition.'); } return $query; @@ -1135,8 +1139,6 @@ class Routines private function handleExecuteRoutine(): void { - global $db; - // Build the queries $routine = $this->getDataFromName($_POST['item_name'], $_POST['item_type'], false); if ($routine === null) { @@ -1144,7 +1146,7 @@ class Routines $message .= sprintf( __('No routine with name %1$s found in database %2$s.'), htmlspecialchars(Util::backquote($_POST['item_name'])), - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); if ($this->response->isAjax()) { @@ -1279,8 +1281,6 @@ class Routines */ public function handleExecute(): void { - global $db; - /** * Handle all user requests other than the default of listing routines */ @@ -1313,7 +1313,7 @@ class Routines $message .= sprintf( __('No routine with name %1$s found in database %2$s.'), htmlspecialchars(Util::backquote($_GET['item_name'])), - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); @@ -1355,8 +1355,6 @@ class Routines */ public function getExecuteForm(array $routine): string { - global $db, $cfg; - // Escape special characters $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES); for ($i = 0; $i < $routine['item_num_params']; $i++) { @@ -1373,7 +1371,7 @@ class Routines continue; } - if ($cfg['ShowFunctionFields']) { + if ($GLOBALS['cfg']['ShowFunctionFields']) { if ( stripos($routine['item_param_type'][$i], 'enum') !== false || stripos($routine['item_param_type'][$i], 'set') !== false @@ -1423,10 +1421,10 @@ class Routines } return $this->template->render('database/routines/execute_form', [ - 'db' => $db, + 'db' => $GLOBALS['db'], 'routine' => $routine, 'ajax' => $this->response->isAjax(), - 'show_function_fields' => $cfg['ShowFunctionFields'], + 'show_function_fields' => $GLOBALS['cfg']['ShowFunctionFields'], 'params' => $params, ]); } @@ -1441,8 +1439,6 @@ class Routines */ public function getRow(array $routine, $rowClass = '') { - global $db, $table; - $sqlDrop = sprintf( 'DROP %s IF EXISTS %s', $routine['type'], @@ -1452,7 +1448,7 @@ class Routines // this is for our purpose to decide whether to // show the edit link or not, so we need the DEFINER for the routine $where = 'ROUTINE_SCHEMA ' . Util::getCollateForIS() . '=' - . "'" . $this->dbi->escapeString($db) . "' " + . "'" . $this->dbi->escapeString($GLOBALS['db']) . "' " . "AND SPECIFIC_NAME='" . $this->dbi->escapeString($routine['name']) . "'" . "AND ROUTINE_TYPE='" . $this->dbi->escapeString($routine['type']) . "'"; $query = 'SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE ' . $where . ';'; @@ -1463,12 +1459,12 @@ class Routines // Since editing a procedure involved dropping and recreating, check also for // CREATE ROUTINE privilege to avoid lost procedures. - $hasCreateRoutine = Util::currentUserHasPrivilege('CREATE ROUTINE', $db); + $hasCreateRoutine = Util::currentUserHasPrivilege('CREATE ROUTINE', $GLOBALS['db']); $hasEditPrivilege = ($hasCreateRoutine && $currentUserIsRoutineDefiner) || $this->dbi->isSuperUser(); $hasExportPrivilege = ($hasCreateRoutine && $currentUserIsRoutineDefiner) || $this->dbi->isSuperUser(); - $hasExecutePrivilege = Util::currentUserHasPrivilege('EXECUTE', $db) + $hasExecutePrivilege = Util::currentUserHasPrivilege('EXECUTE', $GLOBALS['db']) || $currentUserIsRoutineDefiner; // There is a problem with Util::currentUserHasPrivilege(): @@ -1482,7 +1478,12 @@ class Routines // we will show a dialog to get values for these parameters, // otherwise we can execute it directly. - $definition = $this->dbi->getDefinition($db, $routine['type'], $routine['name']); + if ($routine['type'] === 'FUNCTION') { + $definition = self::getFunctionDefinition($this->dbi, $GLOBALS['db'], $routine['name']); + } else { + $definition = self::getProcedureDefinition($this->dbi, $GLOBALS['db'], $routine['name']); + } + $executeAction = ''; if ($definition !== null) { @@ -1509,8 +1510,8 @@ class Routines } return $this->template->render('database/routines/row', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'sql_drop' => $sqlDrop, 'routine' => $routine, 'row_class' => $rowClass, @@ -1544,17 +1545,18 @@ class Routines public function export(): void { - global $db; - if (empty($_GET['export_item']) || empty($_GET['item_name']) || empty($_GET['item_type'])) { return; } - if ($_GET['item_type'] !== 'FUNCTION' && $_GET['item_type'] !== 'PROCEDURE') { + if ($_GET['item_type'] === 'FUNCTION') { + $routineDefinition = self::getFunctionDefinition($this->dbi, $GLOBALS['db'], $_GET['item_name']); + } elseif ($_GET['item_type'] === 'PROCEDURE') { + $routineDefinition = self::getProcedureDefinition($this->dbi, $GLOBALS['db'], $_GET['item_name']); + } else { return; } - $routineDefinition = $this->dbi->getDefinition($db, $_GET['item_type'], $_GET['item_name']); $exportData = false; if ($routineDefinition !== null) { @@ -1590,7 +1592,7 @@ class Routines . ' You might be lacking the necessary privileges to view/export this routine.' ), $itemName, - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); @@ -1603,4 +1605,131 @@ class Routines $this->response->addHTML($message->getDisplay()); } + + /** + * returns details about the PROCEDUREs or FUNCTIONs for a specific database + * or details about a specific routine + * + * @param string $db db name + * @param string|null $which PROCEDURE | FUNCTION or null for both + * @param string $name name of the routine (to fetch a specific routine) + * + * @return array information about PROCEDUREs or FUNCTIONs + */ + public static function getDetails( + DatabaseInterface $dbi, + string $db, + ?string $which = null, + string $name = '' + ): array { + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = QueryGenerator::getInformationSchemaRoutinesRequest( + $dbi->escapeString($db), + isset($which) && in_array($which, ['FUNCTION', 'PROCEDURE']) ? $which : null, + empty($name) ? null : $dbi->escapeString($name) + ); + $routines = $dbi->fetchResult($query); + } else { + $routines = []; + + if ($which === 'FUNCTION' || $which == null) { + $query = 'SHOW FUNCTION STATUS' + . " WHERE `Db` = '" . $dbi->escapeString($db) . "'"; + if ($name) { + $query .= " AND `Name` = '" + . $dbi->escapeString($name) . "'"; + } + + $routines = $dbi->fetchResult($query); + } + + if ($which === 'PROCEDURE' || $which == null) { + $query = 'SHOW PROCEDURE STATUS' + . " WHERE `Db` = '" . $dbi->escapeString($db) . "'"; + if ($name) { + $query .= " AND `Name` = '" + . $dbi->escapeString($name) . "'"; + } + + $routines = array_merge($routines, $dbi->fetchResult($query)); + } + } + + $ret = []; + foreach ($routines as $routine) { + $ret[] = [ + 'db' => $routine['Db'], + 'name' => $routine['Name'], + 'type' => $routine['Type'], + 'definer' => $routine['Definer'], + 'returns' => $routine['DTD_IDENTIFIER'] ?? '', + ]; + } + + // Sort results by name + $name = array_column($ret, 'name'); + array_multisort($name, SORT_ASC, $ret); + + return $ret; + } + + public static function getFunctionDefinition(DatabaseInterface $dbi, string $db, string $name): ?string + { + $result = $dbi->fetchValue( + 'SHOW CREATE FUNCTION ' . Util::backquote($db) . '.' . Util::backquote($name), + 'Create Function' + ); + + return is_string($result) ? $result : null; + } + + public static function getProcedureDefinition(DatabaseInterface $dbi, string $db, string $name): ?string + { + $result = $dbi->fetchValue( + 'SHOW CREATE PROCEDURE ' . Util::backquote($db) . '.' . Util::backquote($name), + 'Create Procedure' + ); + + return is_string($result) ? $result : null; + } + + /** + * @return array<int, string> + * @psalm-return list<non-empty-string> + */ + public static function getFunctionNames(DatabaseInterface $dbi, string $db): array + { + /** @psalm-var list<array{Db: string, Name: string, Type: string}> $functions */ + $functions = $dbi->fetchResult('SHOW FUNCTION STATUS;'); + $names = []; + foreach ($functions as $function) { + if ($function['Db'] !== $db || $function['Type'] !== 'FUNCTION' || $function['Name'] === '') { + continue; + } + + $names[] = $function['Name']; + } + + return $names; + } + + /** + * @return array<int, string> + * @psalm-return list<non-empty-string> + */ + public static function getProcedureNames(DatabaseInterface $dbi, string $db): array + { + /** @psalm-var list<array{Db: string, Name: string, Type: string}> $procedures */ + $procedures = $dbi->fetchResult('SHOW PROCEDURE STATUS;'); + $names = []; + foreach ($procedures as $procedure) { + if ($procedure['Db'] !== $db || $procedure['Type'] !== 'PROCEDURE' || $procedure['Name'] === '') { + continue; + } + + $names[] = $procedure['Name']; + } + + return $names; + } } diff --git a/libraries/classes/Database/Triggers.php b/libraries/classes/Database/Triggers.php index ca30e7eee1..8e556dccd1 100644 --- a/libraries/classes/Database/Triggers.php +++ b/libraries/classes/Database/Triggers.php @@ -7,11 +7,14 @@ namespace PhpMyAdmin\Database; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Message; +use PhpMyAdmin\Query\Generator as QueryGenerator; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Util; use function __; +use function array_column; +use function array_multisort; use function count; use function explode; use function htmlspecialchars; @@ -21,6 +24,8 @@ use function sprintf; use function str_contains; use function trim; +use const SORT_ASC; + /** * Functions for trigger management. */ @@ -58,23 +63,21 @@ class Triggers */ public function main(): void { - global $db, $table; - /** * Process all requests */ $this->handleEditor(); $this->export(); - $items = $this->dbi->getTriggers($db, $table); - $hasTriggerPrivilege = Util::currentUserHasPrivilege('TRIGGER', $db, $table); + $items = self::getDetails($this->dbi, $GLOBALS['db'], $GLOBALS['table']); + $hasTriggerPrivilege = Util::currentUserHasPrivilege('TRIGGER', $GLOBALS['db'], $GLOBALS['table']); $isAjax = $this->response->isAjax() && empty($_REQUEST['ajax_page_request']); $rows = ''; foreach ($items as $item) { $rows .= $this->template->render('database/triggers/row', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'trigger' => $item, 'has_drop_privilege' => $hasTriggerPrivilege, 'has_edit_privilege' => $hasTriggerPrivilege, @@ -83,8 +86,8 @@ class Triggers } echo $this->template->render('database/triggers/list', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'items' => $items, 'rows' => $rows, 'has_privilege' => $hasTriggerPrivilege, @@ -96,7 +99,8 @@ class Triggers */ public function handleEditor(): void { - global $db, $errors, $message, $table; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; if (! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit'])) { $sql_query = ''; @@ -104,7 +108,7 @@ class Triggers $item_query = $this->getQueryFromRequest(); // set by getQueryFromRequest() - if (! count($errors)) { + if (! count($GLOBALS['errors'])) { // Execute the created query if (! empty($_POST['editor_process_edit'])) { // Backup the old trigger, in case something goes wrong @@ -113,7 +117,7 @@ class Triggers $drop_item = $trigger['drop'] . ';'; $result = $this->dbi->tryQuery($drop_item); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($drop_item) ) @@ -122,7 +126,7 @@ class Triggers } else { $result = $this->dbi->tryQuery($item_query); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) @@ -133,13 +137,13 @@ class Triggers $result = $this->dbi->tryQuery($create_item); if (! $result) { - $errors = $this->checkResult($create_item, $errors); + $GLOBALS['errors'] = $this->checkResult($create_item, $GLOBALS['errors']); } } else { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Trigger %1$s has been modified.') ); - $message->addParam( + $GLOBALS['message']->addParam( Util::backquote($_POST['item_name']) ); $sql_query = $drop_item . $item_query; @@ -149,17 +153,17 @@ class Triggers // 'Add a new item' mode $result = $this->dbi->tryQuery($item_query); if (! $result) { - $errors[] = sprintf( + $GLOBALS['errors'][] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '<br><br>' . __('MySQL said: ') . $this->dbi->getError(); } else { - $message = Message::success( + $GLOBALS['message'] = Message::success( __('Trigger %1$s has been created.') ); - $message->addParam( + $GLOBALS['message']->addParam( Util::backquote($_POST['item_name']) ); $sql_query = $item_query; @@ -167,27 +171,27 @@ class Triggers } } - if (count($errors)) { - $message = Message::error( + if (count($GLOBALS['errors'])) { + $GLOBALS['message'] = Message::error( '<b>' . __( 'One or more errors have occurred while processing your request:' ) . '</b>' ); - $message->addHtml('<ul>'); - foreach ($errors as $string) { - $message->addHtml('<li>' . $string . '</li>'); + $GLOBALS['message']->addHtml('<ul>'); + foreach ($GLOBALS['errors'] as $string) { + $GLOBALS['message']->addHtml('<li>' . $string . '</li>'); } - $message->addHtml('</ul>'); + $GLOBALS['message']->addHtml('</ul>'); } - $output = Generator::getMessage($message, $sql_query); + $output = Generator::getMessage($GLOBALS['message'], $sql_query); if ($this->response->isAjax()) { - if ($message->isSuccess()) { - $items = $this->dbi->getTriggers($db, $table, ''); + if ($GLOBALS['message']->isSuccess()) { + $items = self::getDetails($this->dbi, $GLOBALS['db'], $GLOBALS['table'], ''); $trigger = false; foreach ($items as $value) { if ($value['name'] != $_POST['item_name']) { @@ -198,14 +202,18 @@ class Triggers } $insert = false; - if (empty($table) || ($trigger !== false && $table == $trigger['table'])) { + if (empty($GLOBALS['table']) || ($trigger !== false && $GLOBALS['table'] == $trigger['table'])) { $insert = true; - $hasTriggerPrivilege = Util::currentUserHasPrivilege('TRIGGER', $db, $table); + $hasTriggerPrivilege = Util::currentUserHasPrivilege( + 'TRIGGER', + $GLOBALS['db'], + $GLOBALS['table'] + ); $this->response->addJSON( 'new_row', $this->template->render('database/triggers/row', [ - 'db' => $db, - 'table' => $table, + 'db' => $GLOBALS['db'], + 'table' => $GLOBALS['table'], 'trigger' => $trigger, 'has_drop_privilege' => $hasTriggerPrivilege, 'has_edit_privilege' => $hasTriggerPrivilege, @@ -225,7 +233,7 @@ class Triggers $this->response->addJSON('insert', $insert); $this->response->addJSON('message', $output); } else { - $this->response->addJSON('message', $message); + $this->response->addJSON('message', $GLOBALS['message']); $this->response->setRequestStatus(false); } @@ -238,7 +246,7 @@ class Triggers * Display a form used to add/edit a trigger, if necessary */ if ( - ! count($errors) + ! count($GLOBALS['errors']) && (! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit']) || (empty($_REQUEST['add_item']) @@ -269,7 +277,7 @@ class Triggers $mode = 'edit'; } - $this->sendEditor($mode, $item, $title, $db, $table); + $this->sendEditor($mode, $item, $title, $GLOBALS['db'], $GLOBALS['table']); } /** @@ -306,10 +314,8 @@ class Triggers */ public function getDataFromName($name): ?array { - global $db, $table; - $temp = []; - $items = $this->dbi->getTriggers($db, $table, ''); + $items = self::getDetails($this->dbi, $GLOBALS['db'], $GLOBALS['table'], ''); foreach ($items as $value) { if ($value['name'] != $name) { continue; @@ -369,7 +375,7 @@ class Triggers */ public function getQueryFromRequest() { - global $db, $errors; + $GLOBALS['errors'] = $GLOBALS['errors'] ?? null; $query = 'CREATE '; if (! empty($_POST['item_definer'])) { @@ -378,7 +384,7 @@ class Triggers $query .= 'DEFINER=' . Util::backquote($arr[0]); $query .= '@' . Util::backquote($arr[1]) . ' '; } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); + $GLOBALS['errors'][] = __('The definer must be in the "username@hostname" format!'); } } @@ -386,33 +392,33 @@ class Triggers if (! empty($_POST['item_name'])) { $query .= Util::backquote($_POST['item_name']) . ' '; } else { - $errors[] = __('You must provide a trigger name!'); + $GLOBALS['errors'][] = __('You must provide a trigger name!'); } if (! empty($_POST['item_timing']) && in_array($_POST['item_timing'], $this->time)) { $query .= $_POST['item_timing'] . ' '; } else { - $errors[] = __('You must provide a valid timing for the trigger!'); + $GLOBALS['errors'][] = __('You must provide a valid timing for the trigger!'); } if (! empty($_POST['item_event']) && in_array($_POST['item_event'], $this->event)) { $query .= $_POST['item_event'] . ' '; } else { - $errors[] = __('You must provide a valid event for the trigger!'); + $GLOBALS['errors'][] = __('You must provide a valid event for the trigger!'); } $query .= 'ON '; - if (! empty($_POST['item_table']) && in_array($_POST['item_table'], $this->dbi->getTables($db))) { + if (! empty($_POST['item_table']) && in_array($_POST['item_table'], $this->dbi->getTables($GLOBALS['db']))) { $query .= Util::backquote($_POST['item_table']); } else { - $errors[] = __('You must provide a valid table name!'); + $GLOBALS['errors'][] = __('You must provide a valid table name!'); } $query .= ' FOR EACH ROW '; if (! empty($_POST['item_definition'])) { $query .= $_POST['item_definition']; } else { - $errors[] = __('You must provide a trigger definition.'); + $GLOBALS['errors'][] = __('You must provide a trigger definition.'); } return $query; @@ -481,14 +487,12 @@ class Triggers private function export(): void { - global $db, $table; - if (empty($_GET['export_item']) || empty($_GET['item_name'])) { return; } $itemName = $_GET['item_name']; - $triggers = $this->dbi->getTriggers($db, $table, ''); + $triggers = self::getDetails($this->dbi, $GLOBALS['db'], $GLOBALS['table'], ''); $exportData = false; foreach ($triggers as $trigger) { @@ -519,7 +523,7 @@ class Triggers $message = sprintf( __('Error in processing request: No trigger with name %1$s found in database %2$s.'), htmlspecialchars(Util::backquote($itemName)), - htmlspecialchars(Util::backquote($db)) + htmlspecialchars(Util::backquote($GLOBALS['db'])) ); $message = Message::error($message); @@ -532,4 +536,75 @@ class Triggers $this->response->addHTML($message->getDisplay()); } + + /** + * Returns details about the TRIGGERs for a specific table or database. + * + * @param string $db db name + * @param string $table table name + * @param string $delimiter the delimiter to use (may be empty) + * + * @return array information about triggers (may be empty) + */ + public static function getDetails( + DatabaseInterface $dbi, + string $db, + string $table = '', + string $delimiter = '//' + ): array { + $result = []; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = QueryGenerator::getInformationSchemaTriggersRequest( + $dbi->escapeString($db), + empty($table) ? null : $dbi->escapeString($table) + ); + } else { + $query = 'SHOW TRIGGERS FROM ' . Util::backquote($db); + if ($table) { + $query .= " LIKE '" . $dbi->escapeString($table) . "';"; + } + } + + $triggers = $dbi->fetchResult($query); + + foreach ($triggers as $trigger) { + if ($GLOBALS['cfg']['Server']['DisableIS']) { + $trigger['TRIGGER_NAME'] = $trigger['Trigger']; + $trigger['ACTION_TIMING'] = $trigger['Timing']; + $trigger['EVENT_MANIPULATION'] = $trigger['Event']; + $trigger['EVENT_OBJECT_TABLE'] = $trigger['Table']; + $trigger['ACTION_STATEMENT'] = $trigger['Statement']; + $trigger['DEFINER'] = $trigger['Definer']; + } + + $oneResult = []; + $oneResult['name'] = $trigger['TRIGGER_NAME']; + $oneResult['table'] = $trigger['EVENT_OBJECT_TABLE']; + $oneResult['action_timing'] = $trigger['ACTION_TIMING']; + $oneResult['event_manipulation'] = $trigger['EVENT_MANIPULATION']; + $oneResult['definition'] = $trigger['ACTION_STATEMENT']; + $oneResult['definer'] = $trigger['DEFINER']; + + // do not prepend the schema name; this way, importing the + // definition into another schema will work + $oneResult['full_trigger_name'] = Util::backquote($trigger['TRIGGER_NAME']); + $oneResult['drop'] = 'DROP TRIGGER IF EXISTS ' + . $oneResult['full_trigger_name']; + $oneResult['create'] = 'CREATE TRIGGER ' + . $oneResult['full_trigger_name'] . ' ' + . $trigger['ACTION_TIMING'] . ' ' + . $trigger['EVENT_MANIPULATION'] + . ' ON ' . Util::backquote($trigger['EVENT_OBJECT_TABLE']) + . "\n" . ' FOR EACH ROW ' + . $trigger['ACTION_STATEMENT'] . "\n" . $delimiter . "\n"; + + $result[] = $oneResult; + } + + // Sort results by name + $name = array_column($result, 'name'); + array_multisort($name, SORT_ASC, $result); + + return $result; + } } diff --git a/libraries/classes/DatabaseInterface.php b/libraries/classes/DatabaseInterface.php index eb7e56501b..9fcc247508 100644 --- a/libraries/classes/DatabaseInterface.php +++ b/libraries/classes/DatabaseInterface.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace PhpMyAdmin; +use PhpMyAdmin\Config\Settings\Server; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Database\DatabaseList; use PhpMyAdmin\Dbal\DatabaseName; @@ -22,13 +23,12 @@ use PhpMyAdmin\Query\Generator as QueryGenerator; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\Utils\SessionCache; +use RuntimeException; use function __; -use function array_column; use function array_diff; use function array_keys; use function array_map; -use function array_merge; use function array_multisort; use function array_reverse; use function array_shift; @@ -39,7 +39,6 @@ use function count; use function defined; use function explode; use function implode; -use function in_array; use function is_array; use function is_int; use function is_string; @@ -163,18 +162,18 @@ class DatabaseInterface implements DbalInterface /** * runs a query * - * @param string $query SQL query to execute - * @param mixed $link optional database link to use - * @param int $options optional query options - * @param bool $cache_affected_rows whether to cache affected rows + * @param string $query SQL query to execute + * @param mixed $link optional database link to use + * @param int $options optional query options + * @param bool $cacheAffectedRows whether to cache affected rows */ public function query( string $query, $link = self::CONNECT_USER, int $options = self::QUERY_BUFFERED, - bool $cache_affected_rows = true + bool $cacheAffectedRows = true ): ResultInterface { - $result = $this->tryQuery($query, $link, $options, $cache_affected_rows); + $result = $this->tryQuery($query, $link, $options, $cacheAffectedRows); if (! $result) { // The following statement will exit @@ -194,12 +193,12 @@ class DatabaseInterface implements DbalInterface /** * runs a query and returns the result * - * @param string $query query to run - * @param mixed $link link type - * @param int $options if DatabaseInterface::QUERY_UNBUFFERED - * is provided, it will instruct the extension - * to use unbuffered mode - * @param bool $cache_affected_rows whether to cache affected row + * @param string $query query to run + * @param mixed $link link type + * @param int $options if DatabaseInterface::QUERY_UNBUFFERED + * is provided, it will instruct the extension + * to use unbuffered mode + * @param bool $cacheAffectedRows whether to cache affected row * * @return ResultInterface|false */ @@ -207,7 +206,7 @@ class DatabaseInterface implements DbalInterface string $query, $link = self::CONNECT_USER, int $options = self::QUERY_BUFFERED, - bool $cache_affected_rows = true + bool $cacheAffectedRows = true ) { $debug = isset($GLOBALS['cfg']['DBG']) && $GLOBALS['cfg']['DBG']['sql']; if (! isset($this->links[$link])) { @@ -218,7 +217,7 @@ class DatabaseInterface implements DbalInterface $result = $this->extension->realQuery($query, $this->links[$link], $options); - if ($cache_affected_rows) { + if ($cacheAffectedRows) { $GLOBALS['cached_affected_rows'] = $this->affectedRows($link, false); } @@ -244,10 +243,10 @@ class DatabaseInterface implements DbalInterface sprintf( 'SQL[%s?route=%s]: %0.3f(W:%d,C:%s,L:0x%02X) > %s', basename($_SERVER['SCRIPT_NAME']), - Routing::getCurrentRoute(), + Common::getRequest()->getRoute(), $this->lastQueryExecutionTime, $warningsCount, - $cache_affected_rows ? 'y' : 'n', + $cacheAffectedRows ? 'y' : 'n', $link, $query ) @@ -357,12 +356,12 @@ class DatabaseInterface implements DbalInterface * * @param string $database database * @param string|array $table table name(s) - * @param bool $tbl_is_group $table is a table group - * @param int $limit_offset zero-based offset for the count - * @param bool|int $limit_count number of tables to return - * @param string $sort_by table attribute to sort by - * @param string $sort_order direction to sort (ASC or DESC) - * @param string|null $table_type whether table or view + * @param bool $tableIsGroup $table is a table group + * @param int $limitOffset zero-based offset for the count + * @param bool|int $limitCount number of tables to return + * @param string $sortBy table attribute to sort by + * @param string $sortOrder direction to sort (ASC or DESC) + * @param string|null $tableType whether table or view * @param mixed $link link type * * @return array list of tables in given db(s) @@ -372,22 +371,22 @@ class DatabaseInterface implements DbalInterface public function getTablesFull( string $database, $table = '', - bool $tbl_is_group = false, - int $limit_offset = 0, - $limit_count = false, - string $sort_by = 'Name', - string $sort_order = 'ASC', - ?string $table_type = null, + bool $tableIsGroup = false, + int $limitOffset = 0, + $limitCount = false, + string $sortBy = 'Name', + string $sortOrder = 'ASC', + ?string $tableType = null, $link = self::CONNECT_USER ): array { - if ($limit_count === true) { - $limit_count = $GLOBALS['cfg']['MaxTableList']; + if ($limitCount === true) { + $limitCount = $GLOBALS['cfg']['MaxTableList']; } $tables = []; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $sql_where_table = QueryGenerator::getTableCondition( + $sqlWhereTable = QueryGenerator::getTableCondition( is_array($table) ? array_map( [ $this, @@ -395,8 +394,8 @@ class DatabaseInterface implements DbalInterface ], $table ) : $this->escapeString($table), - $tbl_is_group, - $table_type + $tableIsGroup, + $tableType ); // for PMA bc: @@ -407,15 +406,16 @@ class DatabaseInterface implements DbalInterface // comparison (if we are looking for the db Aa we don't want // to find the db aa) - $sql = QueryGenerator::getSqlForTablesFull([$this->escapeString($database)], $sql_where_table); + $sql = QueryGenerator::getSqlForTablesFull([$this->escapeString($database)], $sqlWhereTable); // Sort the tables - $sql .= ' ORDER BY ' . $sort_by . ' ' . $sort_order; + $sql .= ' ORDER BY ' . $sortBy . ' ' . $sortOrder; - if ($limit_count) { - $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; + if ($limitCount) { + $sql .= ' LIMIT ' . $limitCount . ' OFFSET ' . $limitOffset; } + /** @var array<string, array<string, array<string, mixed>>> $tables */ $tables = $this->fetchResult( $sql, [ @@ -428,9 +428,9 @@ class DatabaseInterface implements DbalInterface // here, we check for Mroonga engine and compute the good data_length and index_length // in the StructureController only we need to sum the two values as the other engines - foreach ($tables as $one_database_name => $one_database_tables) { - foreach ($one_database_tables as $one_table_name => $one_table_data) { - if ($one_table_data['Engine'] !== 'Mroonga') { + foreach ($tables as $oneDatabaseName => $oneDatabaseTables) { + foreach ($oneDatabaseTables as $oneTableName => $oneTableData) { + if ($oneTableData['Engine'] !== 'Mroonga') { continue; } @@ -439,28 +439,28 @@ class DatabaseInterface implements DbalInterface } [ - $tables[$one_database_name][$one_table_name]['Data_length'], - $tables[$one_database_name][$one_table_name]['Index_length'], - ] = StorageEngine::getMroongaLengths($one_database_name, $one_table_name); + $tables[$oneDatabaseName][$oneTableName]['Data_length'], + $tables[$oneDatabaseName][$oneTableName]['Index_length'], + ] = StorageEngine::getMroongaLengths($oneDatabaseName, $oneTableName); } } - if ($sort_by === 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + if ($sortBy === 'Name' && $GLOBALS['cfg']['NaturalOrder']) { // here, the array's first key is by schema name - foreach ($tables as $one_database_name => $one_database_tables) { - uksort($one_database_tables, 'strnatcasecmp'); + foreach ($tables as $oneDatabaseName => $oneDatabaseTables) { + uksort($oneDatabaseTables, 'strnatcasecmp'); - if ($sort_order === 'DESC') { - $one_database_tables = array_reverse($one_database_tables); + if ($sortOrder === 'DESC') { + $oneDatabaseTables = array_reverse($oneDatabaseTables); } - $tables[$one_database_name] = $one_database_tables; + $tables[$oneDatabaseName] = $oneDatabaseTables; } - } elseif ($sort_by === 'Data_length') { + } elseif ($sortBy === 'Data_length') { // Size = Data_length + Index_length - foreach ($tables as $one_database_name => $one_database_tables) { + foreach ($tables as $oneDatabaseName => $oneDatabaseTables) { uasort( - $one_database_tables, + $oneDatabaseTables, /** * @param array $a * @param array $b @@ -473,11 +473,11 @@ class DatabaseInterface implements DbalInterface } ); - if ($sort_order === 'DESC') { - $one_database_tables = array_reverse($one_database_tables); + if ($sortOrder === 'DESC') { + $oneDatabaseTables = array_reverse($oneDatabaseTables); } - $tables[$one_database_name] = $one_database_tables; + $tables[$oneDatabaseName] = $oneDatabaseTables; } } } @@ -487,10 +487,10 @@ class DatabaseInterface implements DbalInterface // this is why we fall back to SHOW TABLE STATUS even for MySQL >= 50002 if ($tables === []) { $sql = 'SHOW TABLE STATUS FROM ' . Util::backquote($database); - if ($table || ($tbl_is_group === true) || $table_type) { + if ($table || ($tableIsGroup === true) || $tableType) { $sql .= ' WHERE'; $needAnd = false; - if ($table || ($tbl_is_group === true)) { + if ($table || ($tableIsGroup === true)) { if (is_array($table)) { $sql .= ' `Name` IN (\'' . implode( @@ -513,25 +513,25 @@ class DatabaseInterface implements DbalInterface $needAnd = true; } - if ($table_type) { + if ($tableType) { if ($needAnd) { $sql .= ' AND'; } - if ($table_type === 'view') { + if ($tableType === 'view') { $sql .= " `Comment` = 'VIEW'"; - } elseif ($table_type === 'table') { + } elseif ($tableType === 'table') { $sql .= " `Comment` != 'VIEW'"; } } } - $each_tables = $this->fetchResult($sql, 'Name', null, $link); + $eachTables = $this->fetchResult($sql, 'Name', null, $link); // here, we check for Mroonga engine and compute the good data_length and index_length // in the StructureController only we need to sum the two values as the other engines - foreach ($each_tables as $table_name => $table_data) { - if ($table_data['Engine'] !== 'Mroonga') { + foreach ($eachTables as $tableName => $tableData) { + if ($tableData['Engine'] !== 'Mroonga') { continue; } @@ -540,18 +540,18 @@ class DatabaseInterface implements DbalInterface } [ - $each_tables[$table_name]['Data_length'], - $each_tables[$table_name]['Index_length'], - ] = StorageEngine::getMroongaLengths($database, $table_name); + $eachTables[$tableName]['Data_length'], + $eachTables[$tableName]['Index_length'], + ] = StorageEngine::getMroongaLengths($database, $tableName); } // Sort naturally if the config allows it and we're sorting // the Name column. - if ($sort_by === 'Name' && $GLOBALS['cfg']['NaturalOrder']) { - uksort($each_tables, 'strnatcasecmp'); + if ($sortBy === 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + uksort($eachTables, 'strnatcasecmp'); - if ($sort_order === 'DESC') { - $each_tables = array_reverse($each_tables); + if ($sortOrder === 'DESC') { + $eachTables = array_reverse($eachTables); } } else { // Prepare to sort by creating array of the selected sort @@ -559,24 +559,24 @@ class DatabaseInterface implements DbalInterface // Size = Data_length + Index_length $sortValues = []; - if ($sort_by === 'Data_length') { - foreach ($each_tables as $table_name => $table_data) { - $sortValues[$table_name] = strtolower( - (string) ($table_data['Data_length'] - + $table_data['Index_length']) + if ($sortBy === 'Data_length') { + foreach ($eachTables as $tableName => $tableData) { + $sortValues[$tableName] = strtolower( + (string) ($tableData['Data_length'] + + $tableData['Index_length']) ); } } else { - foreach ($each_tables as $table_name => $table_data) { - $sortValues[$table_name] = strtolower($table_data[$sort_by] ?? ''); + foreach ($eachTables as $tableName => $tableData) { + $sortValues[$tableName] = strtolower($tableData[$sortBy] ?? ''); } } if ($sortValues) { - if ($sort_order === 'DESC') { - array_multisort($sortValues, SORT_DESC, $each_tables); + if ($sortOrder === 'DESC') { + array_multisort($sortValues, SORT_DESC, $eachTables); } else { - array_multisort($sortValues, SORT_ASC, $each_tables); + array_multisort($sortValues, SORT_ASC, $eachTables); } } @@ -584,11 +584,11 @@ class DatabaseInterface implements DbalInterface unset($sortValues); } - if ($limit_count) { - $each_tables = array_slice($each_tables, $limit_offset, $limit_count); + if ($limitCount) { + $eachTables = array_slice($eachTables, $limitOffset, $limitCount); } - $tables[$database] = Compatibility::getISCompatForGetTablesFull($each_tables, $database); + $tables[$database] = Compatibility::getISCompatForGetTablesFull($eachTables, $database); } // cache table data @@ -620,10 +620,10 @@ class DatabaseInterface implements DbalInterface */ public function getVirtualTables(string $db): array { - $tables_full = array_keys($this->getTablesFull($db)); + $tablesFull = array_keys($this->getTablesFull($db)); $views = []; - foreach ($tables_full as $table) { + foreach ($tablesFull as $table) { $table = $this->getTable($db, (string) $table); if (! $table->isView()) { continue; @@ -638,14 +638,13 @@ class DatabaseInterface implements DbalInterface /** * returns array with databases containing extended infos about them * - * @param string|null $database database - * @param bool $force_stats retrieve stats also for MySQL < 5 - * @param int $link link type - * @param string $sort_by column to order by - * @param string $sort_order ASC or DESC - * @param int $limit_offset starting offset for LIMIT - * @param bool|int $limit_count row count for LIMIT or true - * for $GLOBALS['cfg']['MaxDbList'] + * @param string|null $database database + * @param bool $forceStats retrieve stats also for MySQL < 5 + * @param int $link link type + * @param string $sortBy column to order by + * @param string $sortOrder ASC or DESC + * @param int $limitOffset starting offset for LIMIT + * @param bool|int $limitCount row count for LIMIT or true for $GLOBALS['cfg']['MaxDbList'] * * @return array * @@ -653,20 +652,20 @@ class DatabaseInterface implements DbalInterface */ public function getDatabasesFull( ?string $database = null, - bool $force_stats = false, + bool $forceStats = false, $link = self::CONNECT_USER, - string $sort_by = 'SCHEMA_NAME', - string $sort_order = 'ASC', - int $limit_offset = 0, - $limit_count = false + string $sortBy = 'SCHEMA_NAME', + string $sortOrder = 'ASC', + int $limitOffset = 0, + $limitCount = false ): array { - $sort_order = strtoupper($sort_order); + $sortOrder = strtoupper($sortOrder); - if ($limit_count === true) { - $limit_count = $GLOBALS['cfg']['MaxDbList']; + if ($limitCount === true) { + $limitCount = $GLOBALS['cfg']['MaxDbList']; } - $apply_limit_and_order_manual = true; + $applyLimitAndOrderManual = true; if (! $GLOBALS['cfg']['Server']['DisableIS']) { /** @@ -676,11 +675,11 @@ class DatabaseInterface implements DbalInterface */ $limit = ''; if (! $GLOBALS['cfg']['NaturalOrder']) { - if ($limit_count) { - $limit = ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; + if ($limitCount) { + $limit = ' LIMIT ' . $limitCount . ' OFFSET ' . $limitOffset; } - $apply_limit_and_order_manual = false; + $applyLimitAndOrderManual = false; } // get table information from information_schema @@ -691,18 +690,18 @@ class DatabaseInterface implements DbalInterface } $sql = QueryGenerator::getInformationSchemaDatabasesFullRequest( - $force_stats, + $forceStats, $sqlWhereSchema, - $sort_by, - $sort_order, + $sortBy, + $sortOrder, $limit ); $databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $link); - $mysql_error = $this->getError($link); + $mysqlError = $this->getError($link); if (! count($databases) && isset($GLOBALS['errno'])) { - Generator::mysqlDie($mysql_error, $sql); + Generator::mysqlDie($mysqlError, $sql); } // display only databases also in official database list @@ -716,44 +715,44 @@ class DatabaseInterface implements DbalInterface } } else { $databases = []; - foreach ($GLOBALS['dblist']->databases as $database_name) { + foreach ($GLOBALS['dblist']->databases as $databaseName) { // Compatibility with INFORMATION_SCHEMA output - $databases[$database_name]['SCHEMA_NAME'] = $database_name; + $databases[$databaseName]['SCHEMA_NAME'] = $databaseName; - $databases[$database_name]['DEFAULT_COLLATION_NAME'] = $this->getDbCollation($database_name); + $databases[$databaseName]['DEFAULT_COLLATION_NAME'] = $this->getDbCollation($databaseName); - if (! $force_stats) { + if (! $forceStats) { continue; } // get additional info about tables - $databases[$database_name]['SCHEMA_TABLES'] = 0; - $databases[$database_name]['SCHEMA_TABLE_ROWS'] = 0; - $databases[$database_name]['SCHEMA_DATA_LENGTH'] = 0; - $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] = 0; - $databases[$database_name]['SCHEMA_INDEX_LENGTH'] = 0; - $databases[$database_name]['SCHEMA_LENGTH'] = 0; - $databases[$database_name]['SCHEMA_DATA_FREE'] = 0; + $databases[$databaseName]['SCHEMA_TABLES'] = 0; + $databases[$databaseName]['SCHEMA_TABLE_ROWS'] = 0; + $databases[$databaseName]['SCHEMA_DATA_LENGTH'] = 0; + $databases[$databaseName]['SCHEMA_MAX_DATA_LENGTH'] = 0; + $databases[$databaseName]['SCHEMA_INDEX_LENGTH'] = 0; + $databases[$databaseName]['SCHEMA_LENGTH'] = 0; + $databases[$databaseName]['SCHEMA_DATA_FREE'] = 0; $res = $this->query( 'SHOW TABLE STATUS FROM ' - . Util::backquote($database_name) . ';' + . Util::backquote($databaseName) . ';' ); while ($row = $res->fetchAssoc()) { - $databases[$database_name]['SCHEMA_TABLES']++; - $databases[$database_name]['SCHEMA_TABLE_ROWS'] += $row['Rows']; - $databases[$database_name]['SCHEMA_DATA_LENGTH'] += $row['Data_length']; - $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] += $row['Max_data_length']; - $databases[$database_name]['SCHEMA_INDEX_LENGTH'] += $row['Index_length']; + $databases[$databaseName]['SCHEMA_TABLES']++; + $databases[$databaseName]['SCHEMA_TABLE_ROWS'] += $row['Rows']; + $databases[$databaseName]['SCHEMA_DATA_LENGTH'] += $row['Data_length']; + $databases[$databaseName]['SCHEMA_MAX_DATA_LENGTH'] += $row['Max_data_length']; + $databases[$databaseName]['SCHEMA_INDEX_LENGTH'] += $row['Index_length']; // for InnoDB, this does not contain the number of // overhead bytes but the total free space if ($row['Engine'] !== 'InnoDB') { - $databases[$database_name]['SCHEMA_DATA_FREE'] += $row['Data_free']; + $databases[$databaseName]['SCHEMA_DATA_FREE'] += $row['Data_free']; } - $databases[$database_name]['SCHEMA_LENGTH'] += $row['Data_length'] + $row['Index_length']; + $databases[$databaseName]['SCHEMA_LENGTH'] += $row['Data_length'] + $row['Index_length']; } unset($res); @@ -764,19 +763,19 @@ class DatabaseInterface implements DbalInterface * apply limit and order manually now * (caused by older MySQL < 5 or $GLOBALS['cfg']['NaturalOrder']) */ - if ($apply_limit_and_order_manual) { + if ($applyLimitAndOrderManual) { usort( $databases, - static function ($a, $b) use ($sort_by, $sort_order) { - return Utilities::usortComparisonCallback($a, $b, $sort_by, $sort_order); + static function ($a, $b) use ($sortBy, $sortOrder) { + return Utilities::usortComparisonCallback($a, $b, $sortBy, $sortOrder); } ); /** * now apply limit */ - if ($limit_count) { - $databases = array_slice($databases, $limit_offset, $limit_count); + if ($limitCount) { + $databases = array_slice($databases, $limitOffset, $limitCount); } } @@ -786,15 +785,15 @@ class DatabaseInterface implements DbalInterface /** * returns detailed array with all columns for sql * - * @param string $sql_query target SQL query to get columns - * @param array $view_columns alias for columns + * @param string $sqlQuery target SQL query to get columns + * @param array $viewColumns alias for columns * * @return array * @psalm-return list<array<string, mixed>> */ - public function getColumnMapFromSql(string $sql_query, array $view_columns = []): array + public function getColumnMapFromSql(string $sqlQuery, array $viewColumns = []): array { - $result = $this->tryQuery($sql_query); + $result = $this->tryQuery($sqlQuery); if ($result === false) { return []; @@ -802,8 +801,8 @@ class DatabaseInterface implements DbalInterface $meta = $this->getFieldsMeta($result); - $column_map = []; - $nbColumns = count($view_columns); + $columnMap = []; + $nbColumns = count($viewColumns); foreach ($meta as $i => $field) { $map = [ @@ -812,13 +811,13 @@ class DatabaseInterface implements DbalInterface ]; if ($nbColumns >= $i) { - $map['real_column'] = $view_columns[$i]; + $map['real_column'] = $viewColumns[$i]; } - $column_map[] = $map; + $columnMap[] = $map; } - return $column_map; + return $columnMap; } /** @@ -962,9 +961,9 @@ class DatabaseInterface implements DbalInterface } // Check if column is a part of multiple-column index and set its 'Key'. - $indexes = Index::getFromTable($table, $database); - foreach ($fields as $field => $field_data) { - if (! empty($field_data['Key'])) { + $indexes = Index::getFromTable($this, $table, $database); + foreach ($fields as $field => $fieldData) { + if (! empty($fieldData['Key'])) { continue; } @@ -973,8 +972,8 @@ class DatabaseInterface implements DbalInterface continue; } - $index_columns = $index->getColumns(); - if ($index_columns[$field]->getSeqInIndex() <= 1) { + $indexColumns = $index->getColumns(); + if ($indexColumns[$field]->getSeqInIndex() <= 1) { continue; } @@ -1016,7 +1015,25 @@ class DatabaseInterface implements DbalInterface * @param string $table name of the table whose indexes are to be retrieved * @param mixed $link mysql link resource * - * @return array + * @return array<int, array<string, string|null>> + * @psalm-return array<int, array{ + * Table: string, + * Non_unique: '0'|'1', + * Key_name: string, + * Seq_in_index: string, + * Column_name: string|null, + * Collation: 'A'|'D'|null, + * Cardinality: string, + * Sub_part: string|null, + * Packed: string|null, + * Null: string|null, + * Index_type: 'BTREE'|'FULLTEXT'|'HASH'|'RTREE', + * Comment: string, + * Index_comment: string, + * Ignored?: string, + * Visible?: string, + * Expression?: string|null + * }> */ public function getTableIndexes( string $database, @@ -1069,8 +1086,8 @@ class DatabaseInterface implements DbalInterface string $value, $link = self::CONNECT_USER ): bool { - $current_value = $this->getVariable($var, self::GETVAR_SESSION, $link); - if ($current_value == $value) { + $currentValue = $this->getVariable($var, self::GETVAR_SESSION, $link); + if ($currentValue == $value) { return true; } @@ -1100,16 +1117,16 @@ class DatabaseInterface implements DbalInterface } if ($this->versionInt > 50503) { - $default_charset = 'utf8mb4'; - $default_collation = 'utf8mb4_general_ci'; + $defaultCharset = 'utf8mb4'; + $defaultCollation = 'utf8mb4_general_ci'; } else { - $default_charset = 'utf8'; - $default_collation = 'utf8_general_ci'; + $defaultCharset = 'utf8'; + $defaultCollation = 'utf8_general_ci'; } - $GLOBALS['collation_connection'] = $default_collation; - $GLOBALS['charset_connection'] = $default_charset; - $this->query(sprintf('SET NAMES \'%s\' COLLATE \'%s\';', $default_charset, $default_collation)); + $GLOBALS['collation_connection'] = $defaultCollation; + $GLOBALS['charset_connection'] = $defaultCharset; + $this->query(sprintf('SET NAMES \'%s\' COLLATE \'%s\';', $defaultCharset, $defaultCollation)); /* Locale for messages */ $locale = LanguageManager::getInstance()->getCurrentLanguage()->getMySQLLocale(); @@ -1119,13 +1136,13 @@ class DatabaseInterface implements DbalInterface // Set timezone for the session, if required. if ($GLOBALS['cfg']['Server']['SessionTimeZone'] != '') { - $sql_query_tz = 'SET ' . Util::backquote('time_zone') . ' = ' + $sqlQueryTz = 'SET ' . Util::backquote('time_zone') . ' = ' . '\'' . $this->escapeString($GLOBALS['cfg']['Server']['SessionTimeZone']) . '\''; - if (! $this->tryQuery($sql_query_tz)) { - $error_message_tz = sprintf( + if (! $this->tryQuery($sqlQueryTz)) { + $errorMessageTz = sprintf( __( 'Unable to use timezone "%1$s" for server %2$d. ' . 'Please check your configuration setting for ' @@ -1138,7 +1155,7 @@ class DatabaseInterface implements DbalInterface $GLOBALS['server'] ); - trigger_error($error_message_tz, E_USER_WARNING); + trigger_error($errorMessageTz, E_USER_WARNING); } } @@ -1350,57 +1367,57 @@ class DatabaseInterface implements DbalInterface $value = null, $link = self::CONNECT_USER ): array { - $resultrows = []; + $resultRows = []; $result = $this->tryQuery($query, $link, self::QUERY_BUFFERED, false); // return empty array if result is empty or false if ($result === false) { - return $resultrows; + return $resultRows; } - $fetch_function = self::FETCH_ASSOC; + $fetchFunction = self::FETCH_ASSOC; if ($key === null) { // no nested array if only one field is in result if ($result->numFields() === 1) { $value = 0; - $fetch_function = self::FETCH_NUM; + $fetchFunction = self::FETCH_NUM; } - while ($row = $this->fetchByMode($result, $fetch_function)) { - $resultrows[] = $this->fetchValueOrValueByIndex($row, $value); + while ($row = $this->fetchByMode($result, $fetchFunction)) { + $resultRows[] = $this->fetchValueOrValueByIndex($row, $value); } } elseif (is_array($key)) { - while ($row = $this->fetchByMode($result, $fetch_function)) { - $result_target =& $resultrows; - foreach ($key as $key_index) { - if ($key_index === null) { - $result_target =& $result_target[]; + while ($row = $this->fetchByMode($result, $fetchFunction)) { + $resultTarget =& $resultRows; + foreach ($key as $keyIndex) { + if ($keyIndex === null) { + $resultTarget =& $resultTarget[]; continue; } - if (! isset($result_target[$row[$key_index]])) { - $result_target[$row[$key_index]] = []; + if (! isset($resultTarget[$row[$keyIndex]])) { + $resultTarget[$row[$keyIndex]] = []; } - $result_target =& $result_target[$row[$key_index]]; + $resultTarget =& $resultTarget[$row[$keyIndex]]; } - $result_target = $this->fetchValueOrValueByIndex($row, $value); + $resultTarget = $this->fetchValueOrValueByIndex($row, $value); } } else { // if $key is an integer use non associative mysql fetch function if (is_int($key)) { - $fetch_function = self::FETCH_NUM; + $fetchFunction = self::FETCH_NUM; } - while ($row = $this->fetchByMode($result, $fetch_function)) { - $resultrows[$row[$key]] = $this->fetchValueOrValueByIndex($row, $value); + while ($row = $this->fetchByMode($result, $fetchFunction)) { + $resultRows[$row[$key]] = $this->fetchValueOrValueByIndex($row, $value); } } - return $resultrows; + return $resultRows; } /** @@ -1449,237 +1466,6 @@ class DatabaseInterface implements DbalInterface } /** - * returns an array of PROCEDURE or FUNCTION names for a db - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION - * @param int $link link type - * - * @return array the procedure names or function names - */ - public function getProceduresOrFunctions( - string $db, - string $which, - $link = self::CONNECT_USER - ): array { - $shows = $this->fetchResult('SHOW ' . $which . ' STATUS;', null, null, $link); - $result = []; - foreach ($shows as $one_show) { - if ($one_show['Db'] != $db || $one_show['Type'] != $which) { - continue; - } - - $result[] = $one_show['Name']; - } - - return $result; - } - - /** - * returns the definition of a specific PROCEDURE, FUNCTION, EVENT or VIEW - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION | EVENT | VIEW - * @param string $name the procedure|function|event|view name - * @param int $link link type - * - * @return string|null the definition - */ - public function getDefinition( - string $db, - string $which, - string $name, - $link = self::CONNECT_USER - ): ?string { - $returned_field = [ - 'PROCEDURE' => 'Create Procedure', - 'FUNCTION' => 'Create Function', - 'EVENT' => 'Create Event', - 'VIEW' => 'Create View', - ]; - $query = 'SHOW CREATE ' . $which . ' ' - . Util::backquote($db) . '.' - . Util::backquote($name); - $result = $this->fetchValue($query, $returned_field[$which], $link); - - return is_string($result) ? $result : null; - } - - /** - * returns details about the PROCEDUREs or FUNCTIONs for a specific database - * or details about a specific routine - * - * @param string $db db name - * @param string|null $which PROCEDURE | FUNCTION or null for both - * @param string $name name of the routine (to fetch a specific routine) - * - * @return array information about PROCEDUREs or FUNCTIONs - */ - public function getRoutines( - string $db, - ?string $which = null, - string $name = '' - ): array { - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = QueryGenerator::getInformationSchemaRoutinesRequest( - $this->escapeString($db), - isset($which) && in_array($which, ['FUNCTION', 'PROCEDURE']) ? $which : null, - empty($name) ? null : $this->escapeString($name) - ); - $routines = $this->fetchResult($query); - } else { - $routines = []; - - if ($which === 'FUNCTION' || $which == null) { - $query = 'SHOW FUNCTION STATUS' - . " WHERE `Db` = '" . $this->escapeString($db) . "'"; - if ($name) { - $query .= " AND `Name` = '" - . $this->escapeString($name) . "'"; - } - - $routines = $this->fetchResult($query); - } - - if ($which === 'PROCEDURE' || $which == null) { - $query = 'SHOW PROCEDURE STATUS' - . " WHERE `Db` = '" . $this->escapeString($db) . "'"; - if ($name) { - $query .= " AND `Name` = '" - . $this->escapeString($name) . "'"; - } - - $routines = array_merge($routines, $this->fetchResult($query)); - } - } - - $ret = []; - foreach ($routines as $routine) { - $ret[] = [ - 'db' => $routine['Db'], - 'name' => $routine['Name'], - 'type' => $routine['Type'], - 'definer' => $routine['Definer'], - 'returns' => $routine['DTD_IDENTIFIER'] ?? '', - ]; - } - - // Sort results by name - $name = array_column($ret, 'name'); - array_multisort($name, SORT_ASC, $ret); - - return $ret; - } - - /** - * returns details about the EVENTs for a specific database - * - * @param string $db db name - * @param string $name event name - * - * @return array information about EVENTs - */ - public function getEvents(string $db, string $name = ''): array - { - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = QueryGenerator::getInformationSchemaEventsRequest( - $this->escapeString($db), - empty($name) ? null : $this->escapeString($name) - ); - } else { - $query = 'SHOW EVENTS FROM ' . Util::backquote($db); - if ($name) { - $query .= " WHERE `Name` = '" - . $this->escapeString($name) . "'"; - } - } - - $result = []; - $events = $this->fetchResult($query); - - foreach ($events as $event) { - $result[] = [ - 'name' => $event['Name'], - 'type' => $event['Type'], - 'status' => $event['Status'], - ]; - } - - // Sort results by name - $name = array_column($result, 'name'); - array_multisort($name, SORT_ASC, $result); - - return $result; - } - - /** - * returns details about the TRIGGERs for a specific table or database - * - * @param string $db db name - * @param string $table table name - * @param string $delimiter the delimiter to use (may be empty) - * - * @return array information about triggers (may be empty) - */ - public function getTriggers(string $db, string $table = '', string $delimiter = '//'): array - { - $result = []; - if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $query = QueryGenerator::getInformationSchemaTriggersRequest( - $this->escapeString($db), - empty($table) ? null : $this->escapeString($table) - ); - } else { - $query = 'SHOW TRIGGERS FROM ' . Util::backquote($db); - if ($table) { - $query .= " LIKE '" . $this->escapeString($table) . "';"; - } - } - - $triggers = $this->fetchResult($query); - - foreach ($triggers as $trigger) { - if ($GLOBALS['cfg']['Server']['DisableIS']) { - $trigger['TRIGGER_NAME'] = $trigger['Trigger']; - $trigger['ACTION_TIMING'] = $trigger['Timing']; - $trigger['EVENT_MANIPULATION'] = $trigger['Event']; - $trigger['EVENT_OBJECT_TABLE'] = $trigger['Table']; - $trigger['ACTION_STATEMENT'] = $trigger['Statement']; - $trigger['DEFINER'] = $trigger['Definer']; - } - - $one_result = []; - $one_result['name'] = $trigger['TRIGGER_NAME']; - $one_result['table'] = $trigger['EVENT_OBJECT_TABLE']; - $one_result['action_timing'] = $trigger['ACTION_TIMING']; - $one_result['event_manipulation'] = $trigger['EVENT_MANIPULATION']; - $one_result['definition'] = $trigger['ACTION_STATEMENT']; - $one_result['definer'] = $trigger['DEFINER']; - - // do not prepend the schema name; this way, importing the - // definition into another schema will work - $one_result['full_trigger_name'] = Util::backquote($trigger['TRIGGER_NAME']); - $one_result['drop'] = 'DROP TRIGGER IF EXISTS ' - . $one_result['full_trigger_name']; - $one_result['create'] = 'CREATE TRIGGER ' - . $one_result['full_trigger_name'] . ' ' - . $trigger['ACTION_TIMING'] . ' ' - . $trigger['EVENT_MANIPULATION'] - . ' ON ' . Util::backquote($trigger['EVENT_OBJECT_TABLE']) - . "\n" . ' FOR EACH ROW ' - . $trigger['ACTION_STATEMENT'] . "\n" . $delimiter . "\n"; - - $result[] = $one_result; - } - - // Sort results by name - $name = array_column($result, 'name'); - array_multisort($name, SORT_ASC, $result); - - return $result; - } - - /** * gets the current user with host * * @return string the current user i.e. user@host @@ -1724,8 +1510,6 @@ class DatabaseInterface implements DbalInterface public function isGrantUser(): bool { - global $cfg; - if (SessionCache::has('is_grantuser')) { return (bool) SessionCache::get('is_grantuser'); } @@ -1736,7 +1520,7 @@ class DatabaseInterface implements DbalInterface $hasGrantPrivilege = false; - if ($cfg['Server']['DisableIS']) { + if ($GLOBALS['cfg']['Server']['DisableIS']) { $grants = $this->getCurrentUserGrants(); foreach ($grants as $grant) { @@ -1766,8 +1550,6 @@ class DatabaseInterface implements DbalInterface public function isCreateUser(): bool { - global $cfg; - if (SessionCache::has('is_createuser')) { return (bool) SessionCache::get('is_createuser'); } @@ -1778,7 +1560,7 @@ class DatabaseInterface implements DbalInterface $hasCreatePrivilege = false; - if ($cfg['Server']['DisableIS']) { + if ($GLOBALS['cfg']['Server']['DisableIS']) { $grants = $this->getCurrentUserGrants(); foreach ($grants as $grant) { @@ -1863,7 +1645,7 @@ class DatabaseInterface implements DbalInterface $target = $mode; } - if ($user === null || $password === null) { + if ($user === null || $password === null || ! is_array($server)) { trigger_error( __('Missing connection parameters!'), E_USER_WARNING @@ -1872,9 +1654,11 @@ class DatabaseInterface implements DbalInterface return false; } + $server['host'] = ! is_string($server['host']) || $server['host'] === '' ? 'localhost' : $server['host']; + // Do not show location and backtrace for connection errors $GLOBALS['errorHandler']->setHideLocation(true); - $result = $this->extension->connect($user, $password, $server); + $result = $this->extension->connect($user, $password, new Server($server)); $GLOBALS['errorHandler']->setHideLocation(false); if ($result) { @@ -2064,21 +1848,21 @@ class DatabaseInterface implements DbalInterface /** * returns the number of rows affected by last query * - * @param int $link link type - * @param bool $get_from_cache whether to retrieve from cache + * @param int $link link type + * @param bool $getFromCache whether to retrieve from cache * * @return int|string * @psalm-return int|numeric-string */ public function affectedRows( $link = self::CONNECT_USER, - bool $get_from_cache = true + bool $getFromCache = true ) { if (! isset($this->links[$link])) { return -1; } - if ($get_from_cache) { + if ($getFromCache) { return $GLOBALS['cached_affected_rows']; } @@ -2127,13 +1911,13 @@ class DatabaseInterface implements DbalInterface * * @return string a MySQL escaped string */ - public function escapeString(string $str, $link = self::CONNECT_USER) + public function escapeString(string $str, $link = self::CONNECT_USER): string { - if ($this->extension === null || ! isset($this->links[$link])) { - return $str; + if (isset($this->links[$link])) { + return $this->extension->escapeString($this->links[$link], $str); } - return $this->extension->escapeString($this->links[$link], $str); + return $str; } /** @@ -2191,12 +1975,12 @@ class DatabaseInterface implements DbalInterface /** * Get a table with database name and table name * - * @param string $db_name DB name - * @param string $table_name Table name + * @param string $dbName DB name + * @param string $tableName Table name */ - public function getTable(string $db_name, string $table_name): Table + public function getTable(string $dbName, string $tableName): Table { - return new Table($table_name, $db_name, $this); + return new Table($tableName, $dbName, $this); } /** @@ -2250,6 +2034,15 @@ class DatabaseInterface implements DbalInterface return $this->versionInt; } + public function setVersion(int $version): void + { + if (! defined('TESTSUITE')) { + throw new RuntimeException('This method should only be executed in a testing environment.'); + } + + $this->versionInt = $version; + } + /** * Server version */ diff --git a/libraries/classes/DbTableExists.php b/libraries/classes/DbTableExists.php index 9de04f01a2..a13398b270 100644 --- a/libraries/classes/DbTableExists.php +++ b/libraries/classes/DbTableExists.php @@ -8,34 +8,33 @@ use PhpMyAdmin\Controllers\Database\SqlController; use function __; use function defined; -use function strlen; final class DbTableExists { /** - * Ensure the database and the table exist (else move to the "parent" script) - * and display headers + * Ensure the database and the table exist (else move to the "parent" script) and display headers. */ - public static function check(): void + public static function check(string $db, string $table, bool $isTransformationWrapper = false): void { - self::checkDatabase(); - self::checkTable(); + self::checkDatabase($db, $isTransformationWrapper); + self::checkTable($db, $table, $isTransformationWrapper); } - private static function checkDatabase(): void + private static function checkDatabase(string $db, bool $isTransformationWrapper): void { - global $db, $dbi, $is_db, $message, $show_as_php, $sql_query; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['show_as_php'] = $GLOBALS['show_as_php'] ?? null; - if (! empty($is_db)) { + if (! empty($GLOBALS['is_db'])) { return; } - $is_db = false; - if (strlen($db) > 0) { - $is_db = @$dbi->selectDb($db); + $GLOBALS['is_db'] = false; + if ($db !== '') { + $GLOBALS['is_db'] = @$GLOBALS['dbi']->selectDb($db); } - if ($is_db || defined('IS_TRANSFORMATION_WRAPPER')) { + if ($GLOBALS['is_db'] || $isTransformationWrapper) { return; } @@ -52,16 +51,16 @@ final class DbTableExists $urlParams = ['reload' => 1]; - if (isset($message)) { - $urlParams['message'] = $message; + if (isset($GLOBALS['message'])) { + $urlParams['message'] = $GLOBALS['message']; } - if (! empty($sql_query)) { - $urlParams['sql_query'] = $sql_query; + if (! empty($GLOBALS['sql_query'])) { + $urlParams['sql_query'] = $GLOBALS['sql_query']; } - if (isset($show_as_php)) { - $urlParams['show_as_php'] = $show_as_php; + if (isset($GLOBALS['show_as_php'])) { + $urlParams['show_as_php'] = $GLOBALS['show_as_php']; } Core::sendHeaderLocation('./index.php?route=/' . Url::getCommonRaw($urlParams, '&')); @@ -69,49 +68,49 @@ final class DbTableExists exit; } - private static function checkTable(): void + private static function checkTable(string $db, string $table, bool $isTransformationWrapper): void { - global $containerBuilder, $db, $table, $dbi, $is_table; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; - if (! empty($is_table) || defined('PMA_SUBMIT_MULT') || defined('TABLE_MAY_BE_ABSENT')) { + if (! empty($GLOBALS['is_table']) || defined('PMA_SUBMIT_MULT') || defined('TABLE_MAY_BE_ABSENT')) { return; } - $is_table = false; - if (strlen($table) > 0) { - $is_table = $dbi->getCache()->getCachedTableContent([$db, $table], false); - if ($is_table) { + $GLOBALS['is_table'] = false; + if ($table !== '') { + $GLOBALS['is_table'] = $GLOBALS['dbi']->getCache()->getCachedTableContent([$db, $table], false); + if ($GLOBALS['is_table']) { return; } - $result = $dbi->tryQuery('SHOW TABLES LIKE \'' . $dbi->escapeString($table) . '\';'); - $is_table = $result && $result->numRows(); + $result = $GLOBALS['dbi']->tryQuery('SHOW TABLES LIKE \'' . $GLOBALS['dbi']->escapeString($table) . '\';'); + $GLOBALS['is_table'] = $result && $result->numRows(); } - if ($is_table) { + if ($GLOBALS['is_table']) { return; } - if (defined('IS_TRANSFORMATION_WRAPPER')) { + if ($isTransformationWrapper) { exit; } - if (strlen($table) > 0) { + if ($table !== '') { /** * SHOW TABLES doesn't show temporary tables, so try select * (as it can happen just in case temporary table, it should be fast): */ - $result = $dbi->tryQuery('SELECT COUNT(*) FROM ' . Util::backquote($table) . ';'); - $is_table = $result && $result->numRows(); + $result = $GLOBALS['dbi']->tryQuery('SELECT COUNT(*) FROM ' . Util::backquote($table) . ';'); + $GLOBALS['is_table'] = $result && $result->numRows(); } - if ($is_table) { + if ($GLOBALS['is_table']) { return; } /** @var SqlController $controller */ - $controller = $containerBuilder->get(SqlController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(SqlController::class); + $controller(Common::getRequest()); exit; } diff --git a/libraries/classes/Dbal/DatabaseName.php b/libraries/classes/Dbal/DatabaseName.php index 773dca909b..854fe168af 100644 --- a/libraries/classes/Dbal/DatabaseName.php +++ b/libraries/classes/Dbal/DatabaseName.php @@ -28,20 +28,35 @@ final class DatabaseName implements Stringable /** * @param mixed $name * - * @throws InvalidArgumentException + * @throws InvalidDatabaseName */ private function __construct($name) { - Assert::stringNotEmpty($name); - Assert::maxLength($name, self::MAX_LENGTH); - Assert::notEndsWith($name, ' '); + try { + Assert::stringNotEmpty($name); + } catch (InvalidArgumentException $exception) { + throw InvalidDatabaseName::fromEmptyName(); + } + + try { + Assert::maxLength($name, self::MAX_LENGTH); + } catch (InvalidArgumentException $exception) { + throw InvalidDatabaseName::fromLongName(self::MAX_LENGTH); + } + + try { + Assert::notEndsWith($name, ' '); + } catch (InvalidArgumentException $exception) { + throw InvalidDatabaseName::fromNameWithTrailingSpace(); + } + $this->name = $name; } /** * @param mixed $name * - * @throws InvalidArgumentException + * @throws InvalidDatabaseName */ public static function fromValue($name): self { @@ -49,6 +64,18 @@ final class DatabaseName implements Stringable } /** + * @param mixed $name + */ + public static function tryFromValue($name): ?self + { + try { + return new self($name); + } catch (InvalidDatabaseName $exception) { + return null; + } + } + + /** * @psalm-return non-empty-string */ public function getName(): string diff --git a/libraries/classes/Dbal/DbalInterface.php b/libraries/classes/Dbal/DbalInterface.php index 97e0468125..e51a504c53 100644 --- a/libraries/classes/Dbal/DbalInterface.php +++ b/libraries/classes/Dbal/DbalInterface.php @@ -21,25 +21,25 @@ interface DbalInterface /** * runs a query * - * @param string $query SQL query to execute - * @param mixed $link optional database link to use - * @param int $options optional query options - * @param bool $cache_affected_rows whether to cache affected rows + * @param string $query SQL query to execute + * @param mixed $link optional database link to use + * @param int $options optional query options + * @param bool $cacheAffectedRows whether to cache affected rows */ public function query( string $query, $link = DatabaseInterface::CONNECT_USER, int $options = 0, - bool $cache_affected_rows = true + bool $cacheAffectedRows = true ): ResultInterface; /** * runs a query and returns the result * - * @param string $query query to run - * @param mixed $link link type - * @param int $options query options - * @param bool $cache_affected_rows whether to cache affected row + * @param string $query query to run + * @param mixed $link link type + * @param int $options query options + * @param bool $cacheAffectedRows whether to cache affected row * * @return mixed */ @@ -47,7 +47,7 @@ interface DbalInterface string $query, $link = DatabaseInterface::CONNECT_USER, int $options = 0, - bool $cache_affected_rows = true + bool $cacheAffectedRows = true ); /** @@ -87,12 +87,12 @@ interface DbalInterface * * @param string $database database * @param string|array $table table name(s) - * @param bool $tbl_is_group $table is a table group - * @param int $limit_offset zero-based offset for the count - * @param bool|int $limit_count number of tables to return - * @param string $sort_by table attribute to sort by - * @param string $sort_order direction to sort (ASC or DESC) - * @param string|null $table_type whether table or view + * @param bool $tableIsGroup $table is a table group + * @param int $limitOffset zero-based offset for the count + * @param bool|int $limitCount number of tables to return + * @param string $sortBy table attribute to sort by + * @param string $sortOrder direction to sort (ASC or DESC) + * @param string|null $tableType whether table or view * @param mixed $link link type * * @return array list of tables in given db(s) @@ -102,12 +102,12 @@ interface DbalInterface public function getTablesFull( string $database, $table = '', - bool $tbl_is_group = false, - int $limit_offset = 0, - $limit_count = false, - string $sort_by = 'Name', - string $sort_order = 'ASC', - ?string $table_type = null, + bool $tableIsGroup = false, + int $limitOffset = 0, + $limitCount = false, + string $sortBy = 'Name', + string $sortOrder = 'ASC', + ?string $tableType = null, $link = DatabaseInterface::CONNECT_USER ): array; @@ -123,14 +123,13 @@ interface DbalInterface /** * returns array with databases containing extended infos about them * - * @param string|null $database database - * @param bool $force_stats retrieve stats also for MySQL < 5 - * @param int $link link type - * @param string $sort_by column to order by - * @param string $sort_order ASC or DESC - * @param int $limit_offset starting offset for LIMIT - * @param bool|int $limit_count row count for LIMIT or true - * for $GLOBALS['cfg']['MaxDbList'] + * @param string|null $database database + * @param bool $forceStats retrieve stats also for MySQL < 5 + * @param int $link link type + * @param string $sortBy column to order by + * @param string $sortOrder ASC or DESC + * @param int $limitOffset starting offset for LIMIT + * @param bool|int $limitCount row count for LIMIT or true for $GLOBALS['cfg']['MaxDbList'] * * @return array * @@ -138,23 +137,23 @@ interface DbalInterface */ public function getDatabasesFull( ?string $database = null, - bool $force_stats = false, + bool $forceStats = false, $link = DatabaseInterface::CONNECT_USER, - string $sort_by = 'SCHEMA_NAME', - string $sort_order = 'ASC', - int $limit_offset = 0, - $limit_count = false + string $sortBy = 'SCHEMA_NAME', + string $sortOrder = 'ASC', + int $limitOffset = 0, + $limitCount = false ): array; /** * returns detailed array with all columns for sql * - * @param string $sql_query target SQL query to get columns - * @param array $view_columns alias for columns + * @param string $sqlQuery target SQL query to get columns + * @param array $viewColumns alias for columns * * @return array */ - public function getColumnMapFromSql(string $sql_query, array $view_columns = []): array; + public function getColumnMapFromSql(string $sqlQuery, array $viewColumns = []): array; /** * returns detailed array with all columns for given table in database, @@ -232,7 +231,25 @@ interface DbalInterface * @param string $table name of the table whose indexes are to be retrieved * @param mixed $link mysql link resource * - * @return array + * @return array<int, array<string, string|null>> + * @psalm-return array<int, array{ + * Table: string, + * Non_unique: '0'|'1', + * Key_name: string, + * Seq_in_index: string, + * Column_name: string|null, + * Collation: 'A'|'D'|null, + * Cardinality: string, + * Sub_part: string|null, + * Packed: string|null, + * Null: string|null, + * Index_type: 'BTREE'|'FULLTEXT'|'HASH'|'RTREE', + * Comment: string, + * Index_comment: string, + * Ignored?: string, + * Visible?: string, + * Expression?: string|null + * }> */ public function getTableIndexes( string $database, @@ -413,71 +430,6 @@ interface DbalInterface public function getWarnings($link = DatabaseInterface::CONNECT_USER): array; /** - * returns an array of PROCEDURE or FUNCTION names for a db - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION - * @param int $link link type - * - * @return array the procedure names or function names - */ - public function getProceduresOrFunctions( - string $db, - string $which, - $link = DatabaseInterface::CONNECT_USER - ): array; - - /** - * returns the definition of a specific PROCEDURE, FUNCTION, EVENT or VIEW - * - * @param string $db db name - * @param string $which PROCEDURE | FUNCTION | EVENT | VIEW - * @param string $name the procedure|function|event|view name - * @param int $link link type - * - * @return string|null the definition - */ - public function getDefinition( - string $db, - string $which, - string $name, - $link = DatabaseInterface::CONNECT_USER - ): ?string; - - /** - * returns details about the PROCEDUREs or FUNCTIONs for a specific database - * or details about a specific routine - * - * @param string $db db name - * @param string|null $which PROCEDURE | FUNCTION or null for both - * @param string $name name of the routine (to fetch a specific routine) - * - * @return array information about ROCEDUREs or FUNCTIONs - */ - public function getRoutines(string $db, ?string $which = null, string $name = ''): array; - - /** - * returns details about the EVENTs for a specific database - * - * @param string $db db name - * @param string $name event name - * - * @return array information about EVENTs - */ - public function getEvents(string $db, string $name = ''): array; - - /** - * returns details about the TRIGGERs for a specific table or database - * - * @param string $db db name - * @param string $table table name - * @param string $delimiter the delimiter to use (may be empty) - * - * @return array information about triggers (may be empty) - */ - public function getTriggers(string $db, string $table = '', string $delimiter = '//'): array; - - /** * gets the current user with host * * @return string the current user i.e. user@host @@ -608,13 +560,13 @@ interface DbalInterface /** * returns the number of rows affected by last query * - * @param int $link link type - * @param bool $get_from_cache whether to retrieve from cache + * @param int $link link type + * @param bool $getFromCache whether to retrieve from cache * * @return int|string * @psalm-return int|numeric-string */ - public function affectedRows($link = DatabaseInterface::CONNECT_USER, bool $get_from_cache = true); + public function affectedRows($link = DatabaseInterface::CONNECT_USER, bool $getFromCache = true); /** * returns metainfo for fields in $result @@ -633,7 +585,7 @@ interface DbalInterface * * @return string a MySQL escaped string */ - public function escapeString(string $str, $link = DatabaseInterface::CONNECT_USER); + public function escapeString(string $str, $link = DatabaseInterface::CONNECT_USER): string; /** * returns properly escaped string for use in MySQL LIKE clauses @@ -665,10 +617,10 @@ interface DbalInterface /** * Get a table with database name and table name * - * @param string $db_name DB name - * @param string $table_name Table name + * @param string $dbName DB name + * @param string $tableName Table name */ - public function getTable(string $db_name, string $table_name): Table; + public function getTable(string $dbName, string $tableName): Table; /** * returns collation of given db diff --git a/libraries/classes/Dbal/DbiExtension.php b/libraries/classes/Dbal/DbiExtension.php index 1061d026ce..ebe8dd95fc 100644 --- a/libraries/classes/Dbal/DbiExtension.php +++ b/libraries/classes/Dbal/DbiExtension.php @@ -7,25 +7,19 @@ declare(strict_types=1); namespace PhpMyAdmin\Dbal; +use PhpMyAdmin\Config\Settings\Server; + /** * Contract for every database extension supported by phpMyAdmin */ interface DbiExtension { /** - * connects to the database server - * - * @param string $user user name - * @param string $password user password - * @param array $server host/port/socket/persistent + * Connects to the database server. * - * @return mixed false on error or a connection object on success + * @return object|bool A connection object on success or false on failure. */ - public function connect( - $user, - $password, - array $server - ); + public function connect(string $user, string $password, Server $server); /** * selects given database diff --git a/libraries/classes/Dbal/DbiMysqli.php b/libraries/classes/Dbal/DbiMysqli.php index 6247cedf16..9a2769dc6c 100644 --- a/libraries/classes/Dbal/DbiMysqli.php +++ b/libraries/classes/Dbal/DbiMysqli.php @@ -8,7 +8,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Dbal; use mysqli; +use mysqli_sql_exception; use mysqli_stmt; +use PhpMyAdmin\Config\Settings\Server; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Query\Utilities; @@ -30,7 +32,9 @@ use const MYSQLI_CLIENT_SSL; use const MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; use const MYSQLI_OPT_LOCAL_INFILE; use const MYSQLI_OPT_SSL_VERIFY_SERVER_CERT; +use const MYSQLI_REPORT_ERROR; use const MYSQLI_REPORT_OFF; +use const MYSQLI_REPORT_STRICT; use const MYSQLI_STORE_RESULT; use const MYSQLI_USE_RESULT; @@ -40,23 +44,13 @@ use const MYSQLI_USE_RESULT; class DbiMysqli implements DbiExtension { /** - * connects to the database server + * Connects to the database server. * - * @param string $user mysql user name - * @param string $password mysql user password - * @param array $server host/port/socket/persistent - * - * @return mysqli|bool false on error or a mysqli object on success + * @return object|bool A connection object on success or false on failure. */ - public function connect($user, $password, array $server) + public function connect(string $user, string $password, Server $server) { - if ($server) { - $server['host'] = empty($server['host']) - ? 'localhost' - : $server['host']; - } - - mysqli_report(MYSQLI_REPORT_OFF); + mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $mysqli = mysqli_init(); @@ -67,69 +61,59 @@ class DbiMysqli implements DbiExtension $client_flags = 0; /* Optionally compress connection */ - if ($server['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) { + if ($server->compress && defined('MYSQLI_CLIENT_COMPRESS')) { $client_flags |= MYSQLI_CLIENT_COMPRESS; } + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps /* Optionally enable SSL */ - if ($server['ssl']) { + if ($server->ssl) { $client_flags |= MYSQLI_CLIENT_SSL; if ( - ! empty($server['ssl_key']) || - ! empty($server['ssl_cert']) || - ! empty($server['ssl_ca']) || - ! empty($server['ssl_ca_path']) || - ! empty($server['ssl_ciphers']) + $server->ssl_key !== null && $server->ssl_key !== '' || + $server->ssl_cert !== null && $server->ssl_cert !== '' || + $server->ssl_ca !== null && $server->ssl_ca !== '' || + $server->ssl_ca_path !== null && $server->ssl_ca_path !== '' || + $server->ssl_ciphers !== null && $server->ssl_ciphers !== '' ) { $mysqli->ssl_set( - $server['ssl_key'] ?? '', - $server['ssl_cert'] ?? '', - $server['ssl_ca'] ?? '', - $server['ssl_ca_path'] ?? '', - $server['ssl_ciphers'] ?? '' + $server->ssl_key ?? '', + $server->ssl_cert ?? '', + $server->ssl_ca ?? '', + $server->ssl_ca_path ?? '', + $server->ssl_ciphers ?? '' ); } - /* + /** * disables SSL certificate validation on mysqlnd for MySQL 5.6 or later + * * @link https://bugs.php.net/bug.php?id=68344 * @link https://github.com/phpmyadmin/phpmyadmin/pull/11838 */ - if (! $server['ssl_verify']) { - $mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, (int) $server['ssl_verify']); + if (! $server->ssl_verify) { + $mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, (int) $server->ssl_verify); $client_flags |= MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; } } if ($GLOBALS['cfg']['PersistentConnections']) { - $host = 'p:' . $server['host']; + $host = 'p:' . $server->host; } else { - $host = $server['host']; + $host = $server->host; } - if ($server['hide_connection_errors']) { - $return_value = @$mysqli->real_connect( + try { + $mysqli->real_connect( $host, $user, $password, '', - $server['port'], - (string) $server['socket'], + (int) $server->port, + $server->socket, $client_flags ); - } else { - $return_value = $mysqli->real_connect( - $host, - $user, - $password, - '', - $server['port'], - (string) $server['socket'], - $client_flags - ); - } - - if ($return_value === false) { + } catch (mysqli_sql_exception $exception) { /* * Switch to SSL if server asked us to do so, unfortunately * there are more ways MySQL server can tell this: @@ -138,12 +122,10 @@ class DbiMysqli implements DbiExtension * - #2001 - SSL Connection is required. Please specify SSL options and retry. * - #9002 - SSL connection is required. Please specify SSL options and retry. */ - // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $error_number = $mysqli->connect_errno; $error_message = $mysqli->connect_error; - // phpcs:enable if ( - ! $server['ssl'] + ! $server->ssl && ($error_number == 3159 || (($error_number == 2001 || $error_number == 9002) && stripos($error_message, 'SSL Connection is required') !== false)) @@ -152,12 +134,11 @@ class DbiMysqli implements DbiExtension __('SSL connection enforced by server, automatically enabling it.'), E_USER_WARNING ); - $server['ssl'] = true; - return self::connect($user, $password, $server); + return self::connect($user, $password, $server->withSSL(true)); } - if ($error_number === 1045 && $server['hide_connection_errors']) { + if ($error_number === 1045 && $server->hide_connection_errors) { trigger_error( sprintf( __( @@ -169,13 +150,21 @@ class DbiMysqli implements DbiExtension ), E_USER_ERROR ); + } else { + trigger_error($error_number . ': ' . $error_message, E_USER_WARNING); } + mysqli_report(MYSQLI_REPORT_OFF); + return false; } + // phpcs:enable + $mysqli->options(MYSQLI_OPT_LOCAL_INFILE, (int) defined('PMA_ENABLE_LDI')); + mysqli_report(MYSQLI_REPORT_OFF); + return $mysqli; } diff --git a/libraries/classes/Dbal/InvalidDatabaseName.php b/libraries/classes/Dbal/InvalidDatabaseName.php new file mode 100644 index 0000000000..339acca92d --- /dev/null +++ b/libraries/classes/Dbal/InvalidDatabaseName.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Dbal; + +use function __; +use function sprintf; + +class InvalidDatabaseName extends InvalidIdentifierName +{ + public static function fromEmptyName(): self + { + return new self(__('The database name must be a non-empty string.')); + } + + /** + * @psalm-param positive-int $length + */ + public static function fromLongName(int $length): self + { + return new self(sprintf(__('The database name cannot be longer than %d characters.'), $length)); + } + + public static function fromNameWithTrailingSpace(): self + { + return new self(__('The database name cannot end with a space character.')); + } +} diff --git a/libraries/classes/Dbal/InvalidIdentifierName.php b/libraries/classes/Dbal/InvalidIdentifierName.php new file mode 100644 index 0000000000..9b5a683476 --- /dev/null +++ b/libraries/classes/Dbal/InvalidIdentifierName.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Dbal; + +use InvalidArgumentException; + +class InvalidIdentifierName extends InvalidArgumentException +{ +} diff --git a/libraries/classes/Dbal/InvalidTableName.php b/libraries/classes/Dbal/InvalidTableName.php new file mode 100644 index 0000000000..20758bc261 --- /dev/null +++ b/libraries/classes/Dbal/InvalidTableName.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Dbal; + +use function __; +use function sprintf; + +class InvalidTableName extends InvalidIdentifierName +{ + public static function fromEmptyName(): self + { + return new self(__('The table name must be a non-empty string.')); + } + + /** + * @psalm-param positive-int $length + */ + public static function fromLongName(int $length): self + { + return new self(sprintf(__('The table name cannot be longer than %d characters.'), $length)); + } + + public static function fromNameWithTrailingSpace(): self + { + return new self(__('The table name cannot end with a space character.')); + } +} diff --git a/libraries/classes/Dbal/TableName.php b/libraries/classes/Dbal/TableName.php index 994fcf6dff..470a4087a5 100644 --- a/libraries/classes/Dbal/TableName.php +++ b/libraries/classes/Dbal/TableName.php @@ -28,20 +28,35 @@ final class TableName implements Stringable /** * @param mixed $name * - * @throws InvalidArgumentException + * @throws InvalidTableName */ private function __construct($name) { - Assert::stringNotEmpty($name); - Assert::maxLength($name, self::MAX_LENGTH); - Assert::notEndsWith($name, ' '); + try { + Assert::stringNotEmpty($name); + } catch (InvalidArgumentException $exception) { + throw InvalidTableName::fromEmptyName(); + } + + try { + Assert::maxLength($name, self::MAX_LENGTH); + } catch (InvalidArgumentException $exception) { + throw InvalidTableName::fromLongName(self::MAX_LENGTH); + } + + try { + Assert::notEndsWith($name, ' '); + } catch (InvalidArgumentException $exception) { + throw InvalidTableName::fromNameWithTrailingSpace(); + } + $this->name = $name; } /** * @param mixed $name * - * @throws InvalidArgumentException + * @throws InvalidTableName */ public static function fromValue($name): self { @@ -49,6 +64,18 @@ final class TableName implements Stringable } /** + * @param mixed $name + */ + public static function tryFromValue($name): ?self + { + try { + return new self($name); + } catch (InvalidTableName $exception) { + return null; + } + } + + /** * @psalm-return non-empty-string */ public function getName(): string diff --git a/libraries/classes/Display/DisplayParts.php b/libraries/classes/Display/DisplayParts.php new file mode 100644 index 0000000000..6d13343da3 --- /dev/null +++ b/libraries/classes/Display/DisplayParts.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin\Display; + +/** + * @psalm-immutable + */ +final class DisplayParts +{ + public const NO_DELETE = 0; + public const DELETE_ROW = 1; + public const KILL_PROCESS = 2; + + /** @var bool */ + public $hasEditLink; + + /** + * @var int + * @psalm-var self::NO_DELETE|self::DELETE_ROW|self::KILL_PROCESS + */ + public $deleteLink; + + /** @var bool */ + public $hasSortLink; + + /** @var bool */ + public $hasNavigationBar; + + /** @var bool */ + public $hasBookmarkForm; + + /** @var bool */ + public $hasTextButton; + + /** @var bool */ + public $hasPrintLink; + + /** + * @psalm-param self::NO_DELETE|self::DELETE_ROW|self::KILL_PROCESS $deleteLink + */ + private function __construct( + bool $hasEditLink, + int $deleteLink, + bool $hasSortLink, + bool $hasNavigationBar, + bool $hasBookmarkForm, + bool $hasTextButton, + bool $hasPrintLink + ) { + $this->hasEditLink = $hasEditLink; + $this->deleteLink = $deleteLink; + $this->hasSortLink = $hasSortLink; + $this->hasNavigationBar = $hasNavigationBar; + $this->hasBookmarkForm = $hasBookmarkForm; + $this->hasTextButton = $hasTextButton; + $this->hasPrintLink = $hasPrintLink; + } + + /** + * @param array<string, bool|int> $parts + * @psalm-param array{ + * hasEditLink?: bool, + * deleteLink?: self::NO_DELETE|self::DELETE_ROW|self::KILL_PROCESS, + * hasSortLink?: bool, + * hasNavigationBar?: bool, + * hasBookmarkForm?: bool, + * hasTextButton?: bool, + * hasPrintLink?: bool + * } $parts + */ + public static function fromArray(array $parts): self + { + return new self( + $parts['hasEditLink'] ?? false, + $parts['deleteLink'] ?? self::NO_DELETE, + $parts['hasSortLink'] ?? false, + $parts['hasNavigationBar'] ?? false, + $parts['hasBookmarkForm'] ?? false, + $parts['hasTextButton'] ?? false, + $parts['hasPrintLink'] ?? false + ); + } + + /** + * @param array<string, bool|int> $parts + * @psalm-param array{ + * hasEditLink?: bool, + * deleteLink?: self::NO_DELETE|self::DELETE_ROW|self::KILL_PROCESS, + * hasSortLink?: bool, + * hasNavigationBar?: bool, + * hasBookmarkForm?: bool, + * hasTextButton?: bool, + * hasPrintLink?: bool + * } $parts + */ + public function with(array $parts): self + { + return new self( + $parts['hasEditLink'] ?? $this->hasEditLink, + $parts['deleteLink'] ?? $this->deleteLink, + $parts['hasSortLink'] ?? $this->hasSortLink, + $parts['hasNavigationBar'] ?? $this->hasNavigationBar, + $parts['hasBookmarkForm'] ?? $this->hasBookmarkForm, + $parts['hasTextButton'] ?? $this->hasTextButton, + $parts['hasPrintLink'] ?? $this->hasPrintLink + ); + } +} diff --git a/libraries/classes/Display/Results.php b/libraries/classes/Display/Results.php index ddf2574952..158f861875 100644 --- a/libraries/classes/Display/Results.php +++ b/libraries/classes/Display/Results.php @@ -24,6 +24,7 @@ use PhpMyAdmin\Sql; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\SelectStatement; use PhpMyAdmin\SqlParser\Utils\Query; +use PhpMyAdmin\StatementInfo; use PhpMyAdmin\Table; use PhpMyAdmin\Template; use PhpMyAdmin\Theme; @@ -33,7 +34,6 @@ use PhpMyAdmin\Util; use PhpMyAdmin\Utils\Gis; use function __; -use function _pgettext; use function array_filter; use function array_keys; use function array_merge; @@ -84,12 +84,6 @@ use function trim; */ class Results { - // Define constants - public const NO_EDIT_OR_DELETE = 'nn'; - public const UPDATE_ROW = 'ur'; - public const DELETE_ROW = 'dr'; - public const KILL_PROCESS = 'kp'; - public const POSITION_LEFT = 'left'; public const POSITION_RIGHT = 'right'; public const POSITION_BOTH = 'both'; @@ -451,33 +445,24 @@ class Results /** * Defines the parts to display for a print view - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts */ - private function setDisplayPartsForPrintView(array $displayParts) + private function setDisplayPartsForPrintView(DisplayParts $displayParts): DisplayParts { - // set all elements to false! - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link - $displayParts['sort_lnk'] = '0'; - $displayParts['nav_bar'] = '0'; - $displayParts['bkm_form'] = '0'; - $displayParts['text_btn'] = '0'; - $displayParts['pview_lnk'] = '0'; - - return $displayParts; + return $displayParts->with([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => false, + 'hasNavigationBar' => false, + 'hasBookmarkForm' => false, + 'hasTextButton' => false, + 'hasPrintLink' => false, + ]); } /** * Defines the parts to display for a SHOW statement - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts */ - private function setDisplayPartsForShow(array $displayParts) + private function setDisplayPartsForShow(DisplayParts $displayParts): DisplayParts { preg_match( '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?' @@ -493,78 +478,51 @@ class Results $bIsProcessList = strpos($str, 'PROCESSLIST') > 0; } - // no edit link - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - if ($bIsProcessList) { - // "kill process" type edit link - $displayParts['del_lnk'] = self::KILL_PROCESS; - } else { - // Default case -> no links - // no delete link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; - } - - // Other settings - $displayParts['sort_lnk'] = '0'; - $displayParts['nav_bar'] = '0'; - $displayParts['bkm_form'] = '1'; - $displayParts['text_btn'] = '1'; - $displayParts['pview_lnk'] = '1'; - - return $displayParts; + return $displayParts->with([ + 'hasEditLink' => false, + 'deleteLink' => $bIsProcessList ? DisplayParts::KILL_PROCESS : DisplayParts::NO_DELETE, + 'hasSortLink' => false, + 'hasNavigationBar' => false, + 'hasBookmarkForm' => true, + 'hasTextButton' => true, + 'hasPrintLink' => true, + ]); } /** * Defines the parts to display for statements not related to data - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts */ - private function setDisplayPartsForNonData(array $displayParts) + private function setDisplayPartsForNonData(DisplayParts $displayParts): DisplayParts { // Statement is a "SELECT COUNT", a // "CHECK/ANALYZE/REPAIR/OPTIMIZE/CHECKSUM", an "EXPLAIN" one or // contains a "PROC ANALYSE" part - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link - $displayParts['sort_lnk'] = '0'; - $displayParts['nav_bar'] = '0'; - $displayParts['bkm_form'] = '1'; - - if ($this->properties['is_maint']) { - $displayParts['text_btn'] = '1'; - } else { - $displayParts['text_btn'] = '0'; - } - - $displayParts['pview_lnk'] = '1'; - - return $displayParts; + return $displayParts->with([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => false, + 'hasNavigationBar' => false, + 'hasBookmarkForm' => true, + 'hasTextButton' => (bool) $this->properties['is_maint'], + 'hasPrintLink' => true, + ]); } /** - * Defines the parts to display for other statements (probably SELECT) - * - * @param array $displayParts the parts to display - * - * @return array the modified display parts + * Defines the parts to display for other statements (probably SELECT). */ - private function setDisplayPartsForSelect(array $displayParts) + private function setDisplayPartsForSelect(DisplayParts $displayParts): DisplayParts { - // Other statements (ie "SELECT" ones) -> updates - // $displayParts['edit_lnk'], $displayParts['del_lnk'] and - // $displayParts['text_btn'] (keeps other default values) - $fieldsMeta = $this->properties['fields_meta']; $previousTable = ''; - $displayParts['text_btn'] = '1'; $numberOfColumns = $this->properties['fields_cnt']; + $hasTextButton = true; + $hasEditLink = $displayParts->hasEditLink; + $deleteLink = $displayParts->deleteLink; + $hasPrintLink = $displayParts->hasPrintLink; for ($i = 0; $i < $numberOfColumns; $i++) { - $isLink = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['sort_lnk'] != '0'); + $isLink = $hasEditLink || $deleteLink !== DisplayParts::NO_DELETE || $displayParts->hasSortLink; // Displays edit/delete/sort/insert links? if ( @@ -574,19 +532,13 @@ class Results && $fieldsMeta[$i]->table != $previousTable ) { // don't display links - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; - /** - * @todo May be problematic with same field names - * in two joined table. - */ - if ($displayParts['text_btn'] == '1') { - break; - } + $hasEditLink = false; + $deleteLink = DisplayParts::NO_DELETE; + break; } // Always display print view link - $displayParts['pview_lnk'] = '1'; + $hasPrintLink = true; if ($fieldsMeta[$i]->table == '') { continue; } @@ -596,11 +548,16 @@ class Results if ($previousTable == '') { // no table for any of the columns // don't display links - $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; - $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; + $hasEditLink = false; + $deleteLink = DisplayParts::NO_DELETE; } - return $displayParts; + return $displayParts->with([ + 'hasEditLink' => $hasEditLink, + 'deleteLink' => $deleteLink, + 'hasTextButton' => $hasTextButton, + 'hasPrintLink' => $hasPrintLink, + ]); } /** @@ -609,17 +566,14 @@ class Results * * @see getTable() * - * @param array $displayParts the parts to display (see a few - * lines above for explanations) - * - * @return array the first element is an array with explicit indexes - * for all the display elements + * @return array<int, DisplayParts|int|mixed> the first element is a {@see DisplayParts} object * the second element is the total number of rows returned * by the SQL query without any programmatically appended * LIMIT clause (just a copy of $unlim_num_rows if it exists, * else computed inside this function) + * @psalm-return array{DisplayParts, int|mixed} */ - private function setDisplayPartsAndTotal(array $displayParts) + private function setDisplayPartsAndTotal(DisplayParts $displayParts): array { $theTotal = 0; @@ -649,8 +603,8 @@ class Results if ($unlimNumRows > 0) { $theTotal = $unlimNumRows; } elseif ( - ($displayParts['nav_bar'] == '1') - || ($displayParts['sort_lnk'] == '1') + $displayParts->hasNavigationBar + || $displayParts->hasSortLink && $db !== '' && $table !== '' ) { $theTotal = $this->dbi->getTable($db, $table)->countRecords(); @@ -659,21 +613,23 @@ class Results // if for COUNT query, number of rows returned more than 1 // (may be being used GROUP BY) if ($this->properties['is_count'] && $numRows > 1) { - $displayParts['nav_bar'] = '1'; - $displayParts['sort_lnk'] = '1'; + $displayParts = $displayParts->with([ + 'hasNavigationBar' => true, + 'hasSortLink' => true, + ]); } // 4. If navigation bar or sorting fields names URLs should be // displayed but there is only one row, change these settings to // false - if ($displayParts['nav_bar'] == '1' || $displayParts['sort_lnk'] == '1') { + if ($displayParts->hasNavigationBar || $displayParts->hasSortLink) { // - Do not display sort links if less than 2 rows. // - For a VIEW we (probably) did not count the number of rows // so don't test this number here, it would remove the possibility // of sorting VIEW results. $tableObject = new Table($table, $db); if ($unlimNumRows < 2 && ! $tableObject->isView()) { - $displayParts['sort_lnk'] = '0'; + $displayParts = $displayParts->with(['hasSortLink' => false]); } } @@ -688,77 +644,17 @@ class Results * "SELECT * FROM <a table> ..." * * @see getTableHeaders(), getColumnParams() - * - * @param array $analyzedSqlResults analyzed sql results */ - private function isSelect(array $analyzedSqlResults): bool + private function isSelect(StatementInfo $statementInfo): bool { return ! ($this->properties['is_count'] || $this->properties['is_export'] || $this->properties['is_func'] || $this->properties['is_analyse']) - && ! empty($analyzedSqlResults['select_from']) - && ! empty($analyzedSqlResults['statement']->from) - && (count($analyzedSqlResults['statement']->from) === 1) - && ! empty($analyzedSqlResults['statement']->from[0]->table); - } - - /** - * Get a navigation button - * - * @see getMoveBackwardButtonsForTableNavigation(), - * getMoveForwardButtonsForTableNavigation() - * - * @param string $caption iconic caption for button - * @param string $title text for button - * @param int $pos position for next query - * @param string $htmlSqlQuery query ready for display - * @param bool $back whether 'begin' or 'previous' - * @param string $onsubmit optional onsubmit clause - * @param string $inputForRealEnd optional hidden field for special treatment - * - * @return string html content - */ - private function getTableNavigationButton( - $caption, - $title, - $pos, - $htmlSqlQuery, - $back, - $onsubmit = '', - $inputForRealEnd = '' - ): string { - $captionOutput = ''; - if ($back) { - if (Util::showIcons('TableNavigationLinksMode')) { - $captionOutput .= $caption; - } - - if (Util::showText('TableNavigationLinksMode')) { - $captionOutput .= ' ' . $title; - } - } else { - if (Util::showText('TableNavigationLinksMode')) { - $captionOutput .= $title; - } - - if (Util::showIcons('TableNavigationLinksMode')) { - $captionOutput .= ' ' . $caption; - } - } - - return $this->template->render('display/results/table_navigation_button', [ - 'db' => $this->properties['db'], - 'table' => $this->properties['table'], - 'sql_query' => $htmlSqlQuery, - 'pos' => $pos, - 'is_browse_distinct' => $this->properties['is_browse_distinct'], - 'goto' => $this->properties['goto'], - 'input_for_real_end' => $inputForRealEnd, - 'caption_output' => $captionOutput, - 'title' => $title, - 'onsubmit' => $onsubmit, - ]); + && ! empty($statementInfo->selectFrom) + && ! empty($statementInfo->statement->from) + && (count($statementInfo->statement->from) === 1) + && ! empty($statementInfo->statement->from[0]->table); } /** @@ -819,15 +715,6 @@ class Results ): array { $isShowingAll = $_SESSION['tmpval']['max_rows'] === self::ALL_ROWS; - // Move to the beginning or to the previous page - $moveBackwardButtons = ''; - if ($_SESSION['tmpval']['pos'] && ! $isShowingAll) { - $moveBackwardButtons = $this->getMoveBackwardButtonsForTableNavigation( - htmlspecialchars($this->properties['sql_query']), - $posPrevious - ); - } - $pageSelector = ''; $numberTotalPage = 1; if (! $isShowingAll) { @@ -837,22 +724,24 @@ class Results ] = $this->getHtmlPageSelector(); } - // Move to the next page or to the last one - $moveForwardButtons = ''; - if ( - // view with unknown number of rows - ($this->properties['unlim_num_rows'] === -1 || $this->properties['unlim_num_rows'] === false) - || (! $isShowingAll - && intval($_SESSION['tmpval']['pos']) + intval($_SESSION['tmpval']['max_rows']) - < $this->properties['unlim_num_rows'] - && $this->properties['num_rows'] >= $_SESSION['tmpval']['max_rows']) - ) { - $moveForwardButtons = $this->getMoveForwardButtonsForTableNavigation( - htmlspecialchars($this->properties['sql_query']), - $posNext, - $isInnodb - ); - } + $isLastPage = $this->properties['unlim_num_rows'] !== -1 && $this->properties['unlim_num_rows'] !== false + && ($isShowingAll + || intval($_SESSION['tmpval']['pos']) + intval($_SESSION['tmpval']['max_rows']) + >= $this->properties['unlim_num_rows'] + || $this->properties['num_rows'] < $_SESSION['tmpval']['max_rows']); + + $onsubmit = ' onsubmit="return ' + . (intval($_SESSION['tmpval']['pos']) + + intval($_SESSION['tmpval']['max_rows']) + < $this->properties['unlim_num_rows'] + && $this->properties['num_rows'] >= intval($_SESSION['tmpval']['max_rows']) + ? 'true' + : 'false') . ';"'; + + $hasRealEndInput = $isInnodb && $this->properties['unlim_num_rows'] > $GLOBALS['cfg']['MaxExactCount']; + $posLast = @((int) ceil( + (int) $this->properties['unlim_num_rows'] / $_SESSION['tmpval']['max_rows'] + ) - 1) * intval($_SESSION['tmpval']['max_rows']); $hiddenFields = [ 'db' => $this->properties['db'], @@ -864,9 +753,7 @@ class Results ]; return [ - 'move_backward_buttons' => $moveBackwardButtons, 'page_selector' => $pageSelector, - 'move_forward_buttons' => $moveForwardButtons, 'number_total_page' => $numberTotalPage, 'has_show_all' => $GLOBALS['cfg']['ShowAll'] || ($this->properties['unlim_num_rows'] <= 500), 'hidden_fields' => $hiddenFields, @@ -875,107 +762,21 @@ class Results 'max_rows' => $_SESSION['tmpval']['max_rows'], 'pos' => $_SESSION['tmpval']['pos'], 'sort_by_key' => $sortByKeyData, + 'pos_previous' => $posPrevious, + 'pos_next' => $posNext, + 'pos_last' => $posLast, + 'is_last_page' => $isLastPage, + 'is_last_page_known' => $this->properties['unlim_num_rows'] !== false, + 'has_real_end_input' => $hasRealEndInput, + 'onsubmit' => $onsubmit, ]; } /** - * Prepare move backward buttons - previous and first - * - * @see getTableNavigation() - * - * @param string $htmlSqlQuery the sql encoded by html special characters - * @param int $posPrev the offset for the "previous" page - * - * @return string html content - */ - private function getMoveBackwardButtonsForTableNavigation( - string $htmlSqlQuery, - int $posPrev - ): string { - return $this->getTableNavigationButton( - '<<', - _pgettext('First page', 'Begin'), - 0, - $htmlSqlQuery, - true - ) - . $this->getTableNavigationButton( - '<', - _pgettext('Previous page', 'Previous'), - $posPrev, - $htmlSqlQuery, - true - ); - } - - /** - * Prepare move forward buttons - next and last - * - * @see getTableNavigation() - * - * @param string $htmlSqlQuery the sql encoded by htmlspecialchars() - * @param int $posNext the offset for the "next" page - * @param bool $isInnodb whether it's InnoDB or not - * - * @return string html content - */ - private function getMoveForwardButtonsForTableNavigation( - string $htmlSqlQuery, - int $posNext, - bool $isInnodb - ): string { - // display the Next button - $buttonsHtml = $this->getTableNavigationButton( - '>', - _pgettext('Next page', 'Next'), - $posNext, - $htmlSqlQuery, - false - ); - - // If the number of rows is unknown, stop here (don't add the End button) - if ($this->properties['unlim_num_rows'] === false) { - return $buttonsHtml; - } - - $inputForRealEnd = ''; - // prepare some options for the End button - if ($isInnodb && $this->properties['unlim_num_rows'] > $GLOBALS['cfg']['MaxExactCount']) { - $inputForRealEnd = '<input id="real_end_input" type="hidden" name="find_real_end" value="1">'; - // no backquote around this message - } - - $maxRows = (int) $_SESSION['tmpval']['max_rows']; - $onsubmit = 'onsubmit="return ' - . (intval($_SESSION['tmpval']['pos']) - + $maxRows - < $this->properties['unlim_num_rows'] - && $this->properties['num_rows'] >= $maxRows - ? 'true' - : 'false') . '"'; - - // display the End button - return $buttonsHtml . $this->getTableNavigationButton( - '>>', - _pgettext('Last page', 'End'), - @((int) ceil( - (int) $this->properties['unlim_num_rows'] - / $_SESSION['tmpval']['max_rows'] - ) - 1) * $maxRows, - $htmlSqlQuery, - false, - $onsubmit, - $inputForRealEnd - ); - } - - /** * Get the headers of the results table, for all of the columns * * @see getTableHeaders() * - * @param array $displayParts which elements to display - * @param array $analyzedSqlResults analyzed sql results * @param array $sortExpression sort expression * @param array<int, string> $sortExpressionNoDirection sort expression * without direction @@ -987,8 +788,8 @@ class Results * @return string html content */ private function getTableHeadersForColumns( - array $displayParts, - array $analyzedSqlResults, + bool $hasSortLink, + StatementInfo $statementInfo, array $sortExpression, array $sortExpressionNoDirection, array $sortDirection, @@ -1009,9 +810,9 @@ class Results // Prepare Display column comments if enabled // ($GLOBALS['cfg']['ShowBrowseComments']). - $commentsMap = $this->getTableCommentsArray($analyzedSqlResults); + $commentsMap = $this->getTableCommentsArray($statementInfo); - [$colOrder, $colVisib] = $this->getColumnParams($analyzedSqlResults); + [$colOrder, $colVisib] = $this->getColumnParams($statementInfo); // optimize: avoid calling a method on each iteration $numberOfColumns = $this->properties['fields_cnt']; @@ -1035,7 +836,7 @@ class Results $comments = $this->getCommentForRow($commentsMap, $fieldsMeta[$i]); $displayParams = $this->properties['display_params'] ?? []; - if (($displayParts['sort_lnk'] == '1') && ! $isLimitedDisplay) { + if ($hasSortLink && ! $isLimitedDisplay) { $sortedHeaderData = $this->getOrderLinkAndSortedHeaderHtml( $fieldsMeta[$i], $sortExpression, @@ -1080,7 +881,7 @@ class Results } return $this->template->render('display/results/table_headers_for_columns', [ - 'is_sortable' => $displayParts['sort_lnk'] == '1' && ! $isLimitedDisplay, + 'is_sortable' => $hasSortLink && ! $isLimitedDisplay, 'columns' => $columns, ]); } @@ -1090,8 +891,6 @@ class Results * * @see getTable() * - * @param array $displayParts which elements to display - * @param array $analyzedSqlResults analyzed sql results * @param string $unsortedSqlQuery the unsorted sql query * @param array $sortExpression sort expression * @param array<int, string> $sortExpressionNoDirection sort expression without direction @@ -1108,8 +907,8 @@ class Results * } */ private function getTableHeaders( - array $displayParts, - array $analyzedSqlResults, + DisplayParts $displayParts, + StatementInfo $statementInfo, $unsortedSqlQuery, array $sortExpression = [], array $sortExpressionNoDirection = [], @@ -1122,7 +921,7 @@ class Results $displayParams = $this->properties['display_params']; // Output data needed for column reordering and show/hide column - $columnOrder = $this->getDataForResettingColumnOrder($analyzedSqlResults); + $columnOrder = $this->getDataForResettingColumnOrder($statementInfo); $displayParams['emptypre'] = 0; $displayParams['emptyafter'] = 0; @@ -1142,8 +941,8 @@ class Results // 1. Set $colspan and generate html with full/partial // text button or link - $colspan = $displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE - && $displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE ? ' colspan="4"' : ''; + $colspan = $displayParts->hasEditLink + && $displayParts->deleteLink !== DisplayParts::NO_DELETE ? ' colspan="4"' : ''; $buttonHtml = $this->getFieldVisibilityParams($displayParts, $fullOrPartialTextLink, $colspan); // 2. Displays the fields' name @@ -1152,12 +951,12 @@ class Results // See if we have to highlight any header fields of a WHERE query. // Uses SQL-Parser results. - $this->setHighlightedColumnGlobalField($analyzedSqlResults); + $this->setHighlightedColumnGlobalField($statementInfo); // Get the headers for all of the columns $tableHeadersForColumns = $this->getTableHeadersForColumns( - $displayParts, - $analyzedSqlResults, + $displayParts->hasSortLink, + $statementInfo, $sortExpression, $sortExpressionNoDirection, $sortDirection, @@ -1174,8 +973,8 @@ class Results return [ 'column_order' => $columnOrder, 'options' => $optionsBlock, - 'has_bulk_actions_form' => $displayParts['del_lnk'] === self::DELETE_ROW - || $displayParts['del_lnk'] === self::KILL_PROCESS, + 'has_bulk_actions_form' => $displayParts->deleteLink === DisplayParts::DELETE_ROW + || $displayParts->deleteLink === DisplayParts::KILL_PROCESS, 'button' => $buttonHtml, 'table_headers_for_columns' => $tableHeadersForColumns, 'column_at_right_side' => $columnAtRightSide, @@ -1198,7 +997,7 @@ class Results string $unsortedSqlQuery ): array { // grab indexes data: - $indexes = Index::getFromTable($this->properties['table'], $this->properties['db']); + $indexes = Index::getFromTable($this->dbi, $this->properties['table'], $this->properties['db']); // do we have any index? if ($indexes === []) { @@ -1276,14 +1075,13 @@ class Results * * @see getTableHeaders() * - * @param array $displayParts which elements to display * @param string $fullOrPartialTextLink full/partial link or text button * @param string $colspan column span of table header * * @return string html with full/partial text button or link */ private function getFieldVisibilityParams( - array $displayParts, + DisplayParts $displayParts, string $fullOrPartialTextLink, string $colspan ) { @@ -1292,20 +1090,19 @@ class Results // 1. Displays the full/partial text button (part 1)... $buttonHtml = '<thead><tr>' . "\n"; - $emptyPreCondition = $displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE - && $displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE; + $emptyPreCondition = $displayParts->hasEditLink && $displayParts->deleteLink !== DisplayParts::NO_DELETE; $leftOrBoth = $GLOBALS['cfg']['RowActionLinks'] === self::POSITION_LEFT || $GLOBALS['cfg']['RowActionLinks'] === self::POSITION_BOTH; // ... before the result table if ( - ($displayParts['edit_lnk'] === self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] === self::NO_EDIT_OR_DELETE) - && ($displayParts['text_btn'] == '1') + ! $displayParts->hasEditLink + && $displayParts->deleteLink === DisplayParts::NO_DELETE + && $displayParts->hasTextButton ) { - $displayParams['emptypre'] = $emptyPreCondition ? 4 : 0; - } elseif ($leftOrBoth && ($displayParts['text_btn'] == '1')) { + $displayParams['emptypre'] = 0; + } elseif ($leftOrBoth && $displayParts->hasTextButton) { // ... at the left column of the result table header if possible // and required @@ -1315,8 +1112,7 @@ class Results . '>' . $fullOrPartialTextLink . '</th>'; } elseif ( $leftOrBoth - && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) + && ($displayParts->hasEditLink || $displayParts->deleteLink !== DisplayParts::NO_DELETE) ) { // ... elseif no button, displays empty(ies) col(s) if required @@ -1339,18 +1135,16 @@ class Results * * @see getTableHeaders() * - * @param array $analyzedSqlResults analyzed sql results - * * @return array table comments */ - private function getTableCommentsArray(array $analyzedSqlResults) + private function getTableCommentsArray(StatementInfo $statementInfo) { - if (! $GLOBALS['cfg']['ShowBrowseComments'] || empty($analyzedSqlResults['statement']->from)) { + if (! $GLOBALS['cfg']['ShowBrowseComments'] || empty($statementInfo->statement->from)) { return []; } $ret = []; - foreach ($analyzedSqlResults['statement']->from as $field) { + foreach ($statementInfo->statement->from as $field) { if (empty($field->table)) { continue; } @@ -1368,15 +1162,13 @@ class Results * Set global array for store highlighted header fields * * @see getTableHeaders() - * - * @param array $analyzedSqlResults analyzed sql results */ - private function setHighlightedColumnGlobalField(array $analyzedSqlResults): void + private function setHighlightedColumnGlobalField(StatementInfo $statementInfo): void { $highlightColumns = []; - if (! empty($analyzedSqlResults['statement']->where)) { - foreach ($analyzedSqlResults['statement']->where as $expr) { + if (! empty($statementInfo->statement->where)) { + foreach ($statementInfo->statement->where as $expr) { foreach ($expr->identifiers as $identifier) { $highlightColumns[$identifier] = 'true'; } @@ -1391,17 +1183,15 @@ class Results * * @see getTableHeaders() * - * @param array $analyzedSqlResults analyzed sql results - * * @return array */ - private function getDataForResettingColumnOrder(array $analyzedSqlResults): array + private function getDataForResettingColumnOrder(StatementInfo $statementInfo): array { - if (! $this->isSelect($analyzedSqlResults)) { + if (! $this->isSelect($statementInfo)) { return []; } - [$columnOrder, $columnVisibility] = $this->getColumnParams($analyzedSqlResults); + [$columnOrder, $columnVisibility] = $this->getColumnParams($statementInfo); $tableCreateTime = ''; $table = new Table($this->properties['table'], $this->properties['db']); @@ -1457,7 +1247,7 @@ class Results */ private function getFullOrPartialTextButtonOrLink(): string { - global $theme; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; $urlParamsFullText = [ 'db' => $this->properties['db'], @@ -1479,7 +1269,7 @@ class Results } $tmpImage = '<img class="fulltext" src="' - . ($theme instanceof Theme ? $theme->getImgPath($tmpImageFile) : '') + . ($GLOBALS['theme'] instanceof Theme ? $GLOBALS['theme']->getImgPath($tmpImageFile) : '') . '" alt="' . $tmpTxt . '" title="' . $tmpTxt . '">'; return Generator::linkOrButton(Url::getFromRoute('/sql'), $urlParamsFullText, $tmpImage); @@ -1951,14 +1741,13 @@ class Results * * @see getTableHeaders() * - * @param array $displayParts which elements to display * @param string $fullOrPartialTextLink full/partial link or text button * @param string $colspan column span of table header * * @return string html content */ private function getColumnAtRightSide( - array $displayParts, + DisplayParts $displayParts, string $fullOrPartialTextLink, string $colspan ) { @@ -1970,12 +1759,11 @@ class Results if ( ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_RIGHT) || ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_BOTH) - && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) - && ($displayParts['text_btn'] == '1') + && ($displayParts->hasEditLink || $displayParts->deleteLink !== DisplayParts::NO_DELETE) + && $displayParts->hasTextButton ) { - $displayParams['emptyafter'] = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) ? 4 : 1; + $displayParams['emptyafter'] = $displayParts->hasEditLink + && $displayParts->deleteLink !== DisplayParts::NO_DELETE ? 4 : 1; $rightColumnHtml .= "\n" . '<th class="column_action d-print-none"' . $colspan . '>' @@ -1984,15 +1772,15 @@ class Results } elseif ( ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_LEFT) || ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_BOTH) - && (($displayParts['edit_lnk'] === self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] === self::NO_EDIT_OR_DELETE)) + && (! $displayParts->hasEditLink + && $displayParts->deleteLink === DisplayParts::NO_DELETE) && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent']) ) { // ... elseif no button, displays empty columns if required // (unless coming from Browse mode print view) - $displayParams['emptyafter'] = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) ? 4 : 1; + $displayParams['emptyafter'] = $displayParts->hasEditLink + && $displayParts->deleteLink !== DisplayParts::NO_DELETE ? 4 : 1; $rightColumnHtml .= "\n" . '<td class="d-print-none"' . $colspan . '></td>'; @@ -2139,12 +1927,10 @@ class Results * * @see getTable() * - * @param ResultInterface $dtResult the link id associated to the query - * which results have to be displayed - * @param array $displayParts which elements to display - * @param array<string, string[]> $map the list of relations - * @param array $analyzedSqlResults analyzed sql results - * @param bool $isLimitedDisplay with limited operations or not + * @param ResultInterface $dtResult the link id associated to the query + * which results have to be displayed + * @param array<string, string[]> $map the list of relations + * @param bool $isLimitedDisplay with limited operations or not * * @return string html content * @@ -2152,19 +1938,20 @@ class Results */ private function getTableBody( ResultInterface $dtResult, - array $displayParts, + DisplayParts $displayParts, array $map, - array $analyzedSqlResults, + StatementInfo $statementInfo, $isLimitedDisplay = false ) { // Mostly because of browser transformations, to make the row-data accessible in a plugin. - global $row; + + $GLOBALS['row'] = $GLOBALS['row'] ?? null; $tableBodyHtml = ''; // query without conditions to shorten URLs when needed, 200 is just // guess, it should depend on remaining URL length - $urlSqlQuery = $this->getUrlSqlQuery($analyzedSqlResults); + $urlSqlQuery = $this->getUrlSqlQuery($statementInfo); $displayParams = $this->properties['display_params']; @@ -2176,29 +1963,16 @@ class Results $displayParams['row_delete'] = []; $this->properties['display_params'] = $displayParams; - // name of the class added to all grid editable elements; - // if we don't have all the columns of a unique key in the result set, - // do not permit grid editing - if ($isLimitedDisplay || ! $this->properties['editable']) { - $gridEditClass = ''; - } else { - switch ($GLOBALS['cfg']['GridEditing']) { - case 'double-click': - // trying to reduce generated HTML by using shorter - // classes like click1 and click2 - $gridEditClass = 'grid_edit click2'; - break; - case 'click': - $gridEditClass = 'grid_edit click1'; - break; - default: // 'disabled' - $gridEditClass = ''; - break; - } + $gridEditConfig = 'double-click'; + // If we don't have all the columns of a unique key in the result set, do not permit grid editing. + if ($isLimitedDisplay || ! $this->properties['editable'] || $GLOBALS['cfg']['GridEditing'] === 'disabled') { + $gridEditConfig = 'disabled'; + } elseif ($GLOBALS['cfg']['GridEditing'] === 'click') { + $gridEditConfig = 'click'; } // prepare to get the column order, if available - [$colOrder, $colVisib] = $this->getColumnParams($analyzedSqlResults); + [$colOrder, $colVisib] = $this->getColumnParams($statementInfo); // Correction University of Virginia 19991216 in the while below // Previous code assumed that all tables have keys, specifically that @@ -2213,7 +1987,7 @@ class Results // delete/edit options correctly for tables without keys. $whereClauseMap = $this->properties['whereClauseMap']; - while ($row = $dtResult->fetchRow()) { + while ($GLOBALS['row'] = $dtResult->fetchRow()) { // add repeating headers if ( ($rowNumber !== 0) && ($_SESSION['tmpval']['repeat_cells'] > 0) @@ -2254,16 +2028,16 @@ class Results // 1.2 Defines the URLs for the modify/delete link(s) if ( - ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) - || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) + $displayParts->hasEditLink + || ($displayParts->deleteLink !== DisplayParts::NO_DELETE) ) { $expressions = []; if ( - isset($analyzedSqlResults['statement']) - && $analyzedSqlResults['statement'] instanceof SelectStatement + isset($statementInfo->statement) + && $statementInfo->statement instanceof SelectStatement ) { - $expressions = $analyzedSqlResults['statement']->expr; + $expressions = $statementInfo->statement->expr; } // Results from a "SELECT" statement -> builds the @@ -2276,7 +2050,7 @@ class Results [$whereClause, $clauseIsUnique, $conditionArray] = Util::getUniqueCondition( $this->properties['fields_cnt'], $this->properties['fields_meta'], - $row, + $GLOBALS['row'], false, $this->properties['table'], $expressions @@ -2285,7 +2059,7 @@ class Results $this->properties['whereClauseMap'] = $whereClauseMap; // 1.2.1 Modify link(s) - update row case - if ($displayParts['edit_lnk'] === self::UPDATE_ROW) { + if ($displayParts->hasEditLink) { [ $editUrl, $copyUrl, @@ -2300,8 +2074,8 @@ class Results $whereClause, $clauseIsUnique, $urlSqlQuery, - $displayParts['del_lnk'], - (int) $row[0] + $displayParts->deleteLink, + (int) $GLOBALS['row'][0] ); // 1.3 Displays the links at left if required @@ -2311,7 +2085,7 @@ class Results ) { $tableBodyHtml .= $this->template->render('display/results/checkbox_and_links', [ 'position' => self::POSITION_LEFT, - 'has_checkbox' => $deleteUrl && $displayParts['del_lnk'] !== self::KILL_PROCESS, + 'has_checkbox' => $deleteUrl && $displayParts->deleteLink !== DisplayParts::KILL_PROCESS, 'edit' => [ 'url' => $editUrl, 'params' => $editCopyUrlParams + ['default_action' => 'update'], @@ -2329,11 +2103,12 @@ class Results 'condition' => json_encode($conditionArray), 'is_ajax' => ResponseRenderer::getInstance()->isAjax(), 'js_conf' => $jsConf ?? '', + 'grid_edit_config' => $gridEditConfig, ]); } elseif ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_NONE) { $tableBodyHtml .= $this->template->render('display/results/checkbox_and_links', [ 'position' => self::POSITION_NONE, - 'has_checkbox' => $deleteUrl && $displayParts['del_lnk'] !== self::KILL_PROCESS, + 'has_checkbox' => $deleteUrl && $displayParts->deleteLink !== DisplayParts::KILL_PROCESS, 'edit' => [ 'url' => $editUrl, 'params' => $editCopyUrlParams + ['default_action' => 'update'], @@ -2351,6 +2126,7 @@ class Results 'condition' => json_encode($conditionArray), 'is_ajax' => ResponseRenderer::getInstance()->isAjax(), 'js_conf' => $jsConf ?? '', + 'grid_edit_config' => $gridEditConfig, ]); } } @@ -2361,26 +2137,26 @@ class Results } $tableBodyHtml .= $this->getRowValues( - $row, + $GLOBALS['row'], $rowNumber, $colOrder, $map, - $gridEditClass, + $gridEditConfig, $colVisib, $urlSqlQuery, - $analyzedSqlResults + $statementInfo ); // 3. Displays the modify/delete links on the right if required if ( - ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE - || $displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) + ($displayParts->hasEditLink + || $displayParts->deleteLink !== DisplayParts::NO_DELETE) && ($GLOBALS['cfg']['RowActionLinks'] === self::POSITION_RIGHT || $GLOBALS['cfg']['RowActionLinks'] === self::POSITION_BOTH) ) { $tableBodyHtml .= $this->template->render('display/results/checkbox_and_links', [ 'position' => self::POSITION_RIGHT, - 'has_checkbox' => $deleteUrl && $displayParts['del_lnk'] !== self::KILL_PROCESS, + 'has_checkbox' => $deleteUrl && $displayParts->deleteLink !== DisplayParts::KILL_PROCESS, 'edit' => [ 'url' => $editUrl, 'params' => $editCopyUrlParams + ['default_action' => 'update'], @@ -2398,6 +2174,7 @@ class Results 'condition' => json_encode($conditionArray ?? []), 'is_ajax' => ResponseRenderer::getInstance()->isAjax(), 'js_conf' => $jsConf ?? '', + 'grid_edit_config' => $gridEditConfig, ]); } @@ -2478,19 +2255,17 @@ class Results * * @see getTableBody() * - * @param array $row current row data - * @param int $rowNumber the index of current row - * @param array|false $colOrder the column order false when - * a property not found false - * when a property not found - * @param array<string, string[]> $map the list of relations - * @param string $gridEditClass the class for all editable - * columns - * @param bool|array|string $colVisib column is visible(false); - * column isn't visible(string - * array) - * @param string $urlSqlQuery the analyzed sql query - * @param array $analyzedSqlResults analyzed sql results + * @param array $row current row data + * @param int $rowNumber the index of current row + * @param array|false $colOrder the column order false when + * a property not found false + * when a property not found + * @param array<string, string[]> $map the list of relations + * @param bool|array|string $colVisib column is visible(false); + * column isn't visible(string + * array) + * @param string $urlSqlQuery the analyzed sql query + * @psalm-param 'double-click'|'click'|'disabled' $gridEditConfig * * @return string html content */ @@ -2499,10 +2274,10 @@ class Results $rowNumber, $colOrder, array $map, - $gridEditClass, + string $gridEditConfig, $colVisib, $urlSqlQuery, - array $analyzedSqlResults + StatementInfo $statementInfo ) { $rowValuesHtml = ''; @@ -2535,7 +2310,11 @@ class Results $hideClass = is_array($colVisib) && isset($colVisib[$currentColumn]) && ! $colVisib[$currentColumn] ? 'hide' : ''; - $gridEdit = $meta->orgtable != '' ? $gridEditClass : ''; + + $gridEdit = ''; + if ($meta->orgtable != '' && $gridEditConfig !== 'disabled') { + $gridEdit = $gridEditConfig === 'click' ? 'grid_edit click1' : 'grid_edit click2'; + } // handle datetime-related class, for grid editing $fieldTypeClass = $this->getClassForDateTimeRelatedFields($meta); @@ -2640,10 +2419,10 @@ class Results $expressions = []; if ( - isset($analyzedSqlResults['statement']) - && $analyzedSqlResults['statement'] instanceof SelectStatement + isset($statementInfo->statement) + && $statementInfo->statement instanceof SelectStatement ) { - $expressions = $analyzedSqlResults['statement']->expr; + $expressions = $statementInfo->statement->expr; } /** @@ -2700,7 +2479,7 @@ class Results $conditionField, $meta, $map, - $analyzedSqlResults, + $statementInfo, $transformationPlugin, $transformOptions ); @@ -2720,7 +2499,7 @@ class Results $conditionField, $transformationPlugin, $transformOptions, - $analyzedSqlResults + $statementInfo ); } else { // n o t n u m e r i c @@ -2734,7 +2513,7 @@ class Results $conditionField, $transformationPlugin, $transformOptions, - $analyzedSqlResults + $statementInfo ); } @@ -2830,23 +2609,26 @@ class Results * * @see getTableBody() * - * @param array $analyzedSqlResults analyzed sql results - * * @return string analyzed sql query */ - private function getUrlSqlQuery(array $analyzedSqlResults) + private function getUrlSqlQuery(StatementInfo $statementInfo) { - if (($analyzedSqlResults['querytype'] !== 'SELECT') || (mb_strlen($this->properties['sql_query']) < 200)) { + if ( + $statementInfo->queryType !== 'SELECT' + || mb_strlen($this->properties['sql_query']) < 200 + || $statementInfo->statement === null + || $statementInfo->parser === null + ) { return $this->properties['sql_query']; } $query = 'SELECT ' . Query::getClause( - $analyzedSqlResults['statement'], - $analyzedSqlResults['parser']->list, + $statementInfo->statement, + $statementInfo->parser->list, 'SELECT' ); - $fromClause = Query::getClause($analyzedSqlResults['statement'], $analyzedSqlResults['parser']->list, 'FROM'); + $fromClause = Query::getClause($statementInfo->statement, $statementInfo->parser->list, 'FROM'); if ($fromClause !== '') { $query .= ' FROM ' . $fromClause; @@ -2860,13 +2642,11 @@ class Results * * @see getTableBody() * - * @param array $analyzedSqlResults analyzed sql results - * * @return mixed[] 2 element array - $col_order, $col_visib */ - private function getColumnParams(array $analyzedSqlResults): array + private function getColumnParams(StatementInfo $statementInfo): array { - if ($this->isSelect($analyzedSqlResults)) { + if ($this->isSelect($statementInfo)) { $pmatable = new Table($this->properties['table'], $this->properties['db']); $colOrder = $pmatable->getUiProp(Table::PROP_COLUMN_ORDER); $fieldsCount = $this->properties['fields_cnt']; @@ -2997,8 +2777,8 @@ class Results * @param string $whereClause the where clause of the sql * @param bool $clauseIsUnique the unique condition of clause * @param string $urlSqlQuery the analyzed sql query - * @param string $deleteLink the delete link of current row * @param int $processId Process ID + * @psalm-param DisplayParts::NO_DELETE|DisplayParts::DELETE_ROW|DisplayParts::KILL_PROCESS $deleteLink * * @return array $del_url, $del_str, $js_conf * @psalm-return array{?string, ?string, ?string} @@ -3007,12 +2787,12 @@ class Results $whereClause, $clauseIsUnique, $urlSqlQuery, - $deleteLink, + int $deleteLink, int $processId ) { $goto = $this->properties['goto']; - if ($deleteLink === self::DELETE_ROW) { // delete row case + if ($deleteLink === DisplayParts::DELETE_ROW) { // delete row case $urlParams = [ 'db' => $this->properties['db'], 'table' => $this->properties['table'], @@ -3042,7 +2822,7 @@ class Results . ($clauseIsUnique ? '' : ' LIMIT 1'); $deleteString = $this->getActionLinkContent('b_drop', __('Delete')); - } elseif ($deleteLink === self::KILL_PROCESS) { // kill process case + } elseif ($deleteLink === DisplayParts::KILL_PROCESS) { // kill process case $urlParams = [ 'db' => $this->properties['db'], 'table' => $this->properties['table'], @@ -3140,13 +2920,12 @@ class Results * * @see getTableBody() * - * @param string|null $column the column's value - * @param string $class the html class for column - * @param bool $conditionField the column should highlighted or not - * @param FieldMetadata $meta the meta-information about this field - * @param array<string, string[]> $map the list of relations - * @param array $analyzedSqlResults the analyzed query - * @param array $transformOptions the transformation parameters + * @param string|null $column the column's value + * @param string $class the html class for column + * @param bool $conditionField the column should highlighted or not + * @param FieldMetadata $meta the meta-information about this field + * @param array<string, string[]> $map the list of relations + * @param array $transformOptions the transformation parameters * * @return string the prepared cell, html content */ @@ -3156,7 +2935,7 @@ class Results bool $conditionField, FieldMetadata $meta, array $map, - array $analyzedSqlResults, + StatementInfo $statementInfo, ?TransformationsPlugin $transformationPlugin, array $transformOptions ) { @@ -3173,7 +2952,7 @@ class Results return $this->getRowData( $class, $conditionField, - $analyzedSqlResults, + $statementInfo, $meta, $map, $column, @@ -3190,14 +2969,13 @@ class Results * * @see getTableBody() * - * @param string|null $column the relevant column in data row - * @param string $class the html class for column - * @param FieldMetadata $meta the meta-information about this field - * @param array<string, string[]> $map the list of relations - * @param array $urlParams the parameters for generate url - * @param bool $conditionField the column should highlighted or not - * @param array $transformOptions the transformation parameters - * @param array $analyzedSqlResults the analyzed query + * @param string|null $column the relevant column in data row + * @param string $class the html class for column + * @param FieldMetadata $meta the meta-information about this field + * @param array<string, string[]> $map the list of relations + * @param array $urlParams the parameters for generate url + * @param bool $conditionField the column should highlighted or not + * @param array $transformOptions the transformation parameters * * @return string the prepared data cell, html content */ @@ -3210,7 +2988,7 @@ class Results bool $conditionField, ?TransformationsPlugin $transformationPlugin, $transformOptions, - array $analyzedSqlResults + StatementInfo $statementInfo ) { if ($column === null) { return $this->buildNullDisplay($class, $conditionField, $meta); @@ -3249,7 +3027,7 @@ class Results return $this->getRowData( $class, $conditionField, - $analyzedSqlResults, + $statementInfo, $meta, $map, $wktval, @@ -3277,7 +3055,7 @@ class Results return $this->getRowData( $class, $conditionField, - $analyzedSqlResults, + $statementInfo, $meta, $map, $wkbval, @@ -3307,14 +3085,13 @@ class Results * * @see getTableBody() * - * @param string|null $column the relevant column in data row - * @param string $class the html class for column - * @param FieldMetadata $meta the meta-information about the field - * @param array<string, string[]> $map the list of relations - * @param array $urlParams the parameters for generate url - * @param bool $conditionField the column should highlighted or not - * @param array $transformOptions the transformation parameters - * @param array $analyzedSqlResults the analyzed query + * @param string|null $column the relevant column in data row + * @param string $class the html class for column + * @param FieldMetadata $meta the meta-information about the field + * @param array<string, string[]> $map the list of relations + * @param array $urlParams the parameters for generate url + * @param bool $conditionField the column should highlighted or not + * @param array $transformOptions the transformation parameters * * @return string the prepared data cell, html content */ @@ -3327,7 +3104,7 @@ class Results bool $conditionField, ?TransformationsPlugin $transformationPlugin, $transformOptions, - array $analyzedSqlResults + StatementInfo $statementInfo ) { $originalLength = 0; @@ -3434,7 +3211,7 @@ class Results return $this->getRowData( $class, $conditionField, - $analyzedSqlResults, + $statementInfo, $meta, $map, $column, @@ -3586,24 +3363,22 @@ class Results /** * Prepare a table of results returned by a SQL query. * - * @param ResultInterface $dtResult the link id associated to the query - * which results have to be displayed - * @param array $displayParts the parts to display - * @param array $analyzedSqlResults analyzed sql results - * @param bool $isLimitedDisplay With limited operations or not + * @param ResultInterface $dtResult the link id associated to the query + * which results have to be displayed + * @param bool $isLimitedDisplay With limited operations or not * * @return string Generated HTML content for resulted table */ public function getTable( ResultInterface $dtResult, - array &$displayParts, - array $analyzedSqlResults, + DisplayParts $displayParts, + StatementInfo $statementInfo, $isLimitedDisplay = false ) { // The statement this table is built for. - if (isset($analyzedSqlResults['statement'])) { + if (isset($statementInfo->statement)) { /** @var SelectStatement $statement */ - $statement = $analyzedSqlResults['statement']; + $statement = $statementInfo->statement; } else { $statement = null; } @@ -3621,7 +3396,7 @@ class Results $isInnodb = (isset($showTable['Type']) && $showTable['Type'] === self::TABLE_TYPE_INNO_DB); - if ($isInnodb && Sql::isJustBrowsing($analyzedSqlResults, true)) { + if ($isInnodb && Sql::isJustBrowsing($statementInfo, true)) { $preCount = '~'; $afterCount = Generator::showHint( Sanitize::sanitizeMessage( @@ -3646,7 +3421,7 @@ class Results // 1.2 Defines offsets for the next and previous pages $posNext = 0; $posPrev = 0; - if ($displayParts['nav_bar'] == '1') { + if ($displayParts->hasNavigationBar) { [$posNext, $posPrev] = $this->getOffsets(); } @@ -3679,10 +3454,10 @@ class Results // 2.1 Prepares a messages with position information $sqlQueryMessage = ''; - if ($displayParts['nav_bar'] == '1') { + if ($displayParts->hasNavigationBar) { $message = $this->setMessageInformation( $sortedColumnMessage, - $analyzedSqlResults, + $statementInfo, $total, $posNext, $preCount, @@ -3699,7 +3474,7 @@ class Results } // 2.3 Prepare the navigation bars - if ($this->properties['table'] === '' && $analyzedSqlResults['querytype'] === 'SELECT') { + if ($this->properties['table'] === '' && $statementInfo->queryType === 'SELECT') { // table does not always contain a real table name, // for example in MySQL 5.0.x, the query SHOW STATUS // returns STATUS as a table name @@ -3709,16 +3484,20 @@ class Results $unsortedSqlQuery = ''; $sortByKeyData = []; // can the result be sorted? - if ($displayParts['sort_lnk'] == '1' && isset($analyzedSqlResults['statement'])) { + if ( + $displayParts->hasSortLink + && $statementInfo->statement !== null + && $statementInfo->parser !== null + ) { $unsortedSqlQuery = Query::replaceClause( - $analyzedSqlResults['statement'], - $analyzedSqlResults['parser']->list, + $statementInfo->statement, + $statementInfo->parser->list, 'ORDER BY', '' ); // Data is sorted by indexes only if there is only one table. - if ($this->isSelect($analyzedSqlResults)) { + if ($this->isSelect($statementInfo)) { $sortByKeyData = $this->getSortByKeyDropDown( $sortExpression, $unsortedSqlQuery @@ -3727,7 +3506,7 @@ class Results } $navigation = []; - if ($displayParts['nav_bar'] == '1' && $statement !== null && empty($statement->limit)) { + if ($displayParts->hasNavigationBar && $statement !== null && empty($statement->limit)) { $navigation = $this->getTableNavigation($posNext, $posPrev, $isInnodb, $sortByKeyData); } @@ -3758,7 +3537,7 @@ class Results // 3. ----- Prepare the results table ----- $headers = $this->getTableHeaders( $displayParts, - $analyzedSqlResults, + $statementInfo, $unsortedSqlQuery, $sortExpression, $sortExpressionNoDirection, @@ -3766,17 +3545,17 @@ class Results $isLimitedDisplay ); - $body = $this->getTableBody($dtResult, $displayParts, $map, $analyzedSqlResults, $isLimitedDisplay); + $body = $this->getTableBody($dtResult, $displayParts, $map, $statementInfo, $isLimitedDisplay); $this->properties['display_params'] = null; // 4. ----- Prepares the link for multi-fields edit and delete - $bulkLinks = $this->getBulkLinks($dtResult, $analyzedSqlResults, $displayParts['del_lnk']); + $bulkLinks = $this->getBulkLinks($dtResult, $statementInfo, $displayParts->deleteLink); // 5. ----- Prepare "Query results operations" $operations = []; if (($printView === null || $printView != '1') && ! $isLimitedDisplay) { - $operations = $this->getResultsOperations($displayParts['pview_lnk'], $analyzedSqlResults); + $operations = $this->getResultsOperations($displayParts->hasPrintLink, $statementInfo); } $relationParameters = $this->relation->getRelationParameters(); @@ -3799,6 +3578,7 @@ class Results 'save_cells_at_once' => $GLOBALS['cfg']['SaveCellsAtOnce'], 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], 'text_dir' => $this->properties['text_dir'], + 'is_browse_distinct' => $this->properties['is_browse_distinct'], ]); } @@ -3937,7 +3717,6 @@ class Results * @see getTable() * * @param string $sortedColumnMessage the message for sorted column - * @param array $analyzedSqlResults the analyzed query * @param int $total the total number of rows returned by * the SQL query without any * programmatically appended LIMIT clause @@ -3949,7 +3728,7 @@ class Results */ private function setMessageInformation( string $sortedColumnMessage, - array $analyzedSqlResults, + StatementInfo $statementInfo, $total, $posNext, string $preCount, @@ -3957,9 +3736,9 @@ class Results ) { $unlimNumRows = $this->properties['unlim_num_rows']; // To use in isset() - if (! empty($analyzedSqlResults['statement']->limit)) { - $firstShownRec = $analyzedSqlResults['statement']->limit->offset; - $rowCount = $analyzedSqlResults['statement']->limit->rowCount; + if (! empty($statementInfo->statement->limit)) { + $firstShownRec = $statementInfo->statement->limit->offset; + $rowCount = $statementInfo->statement->limit->rowCount; if ($rowCount < $total) { $lastShownRec = $firstShownRec + $rowCount - 1; @@ -4093,19 +3872,18 @@ class Results * * @see getTable() * - * @param ResultInterface $dtResult the link id associated to the query which - * results have to be displayed - * @param array $analyzedSqlResults analyzed sql results - * @param string $deleteLink the display element - 'del_link' + * @param ResultInterface $dtResult the link id associated to the query which + * results have to be displayed + * @psalm-param DisplayParts::NO_DELETE|DisplayParts::DELETE_ROW|DisplayParts::KILL_PROCESS $deleteLink * * @psalm-return array{has_export_button:bool, clause_is_unique:mixed}|array<empty, empty> */ private function getBulkLinks( ResultInterface $dtResult, - array $analyzedSqlResults, - $deleteLink + StatementInfo $statementInfo, + int $deleteLink ): array { - if ($deleteLink !== self::DELETE_ROW) { + if ($deleteLink !== DisplayParts::DELETE_ROW) { return []; } @@ -4115,8 +3893,8 @@ class Results $expressions = []; - if (isset($analyzedSqlResults['statement']) && $analyzedSqlResults['statement'] instanceof SelectStatement) { - $expressions = $analyzedSqlResults['statement']->expr; + if (isset($statementInfo->statement) && $statementInfo->statement instanceof SelectStatement) { + $expressions = $statementInfo->statement->expr; } /** @@ -4136,7 +3914,7 @@ class Results $dtResult->seek(0); return [ - 'has_export_button' => $analyzedSqlResults['querytype'] === 'SELECT', + 'has_export_button' => $statementInfo->queryType === 'SELECT', 'clause_is_unique' => $clauseIsUnique, ]; } @@ -4146,9 +3924,6 @@ class Results * * @see getTable() * - * @param string $printLink the parts to display - * @param array $analyzedSqlResults analyzed sql results - * * @psalm-return array{ * has_export_link: bool, * has_geometry: bool, @@ -4166,8 +3941,8 @@ class Results * } */ private function getResultsOperations( - string $printLink, - array $analyzedSqlResults + bool $hasPrintLink, + StatementInfo $statementInfo ): array { $urlParams = [ 'db' => $this->properties['db'], @@ -4185,16 +3960,16 @@ class Results // (most probably PROCEDURE ANALYSE()) it makes no sense to // display the Export link). if ( - ($analyzedSqlResults['querytype'] === self::QUERY_TYPE_SELECT) - && empty($analyzedSqlResults['procedure']) + ($statementInfo->queryType === self::QUERY_TYPE_SELECT) + && empty($statementInfo->isProcedure) ) { - if (count($analyzedSqlResults['select_tables']) === 1) { + if (count($statementInfo->selectTables) === 1) { $urlParams['single_table'] = 'true'; } // In case this query doesn't involve any tables, // implies only raw query is to be exported - if (! $analyzedSqlResults['select_tables']) { + if (! $statementInfo->selectTables) { $urlParams['raw_query'] = 'true'; } @@ -4222,10 +3997,10 @@ class Results } return [ - 'has_procedure' => ! empty($analyzedSqlResults['procedure']), + 'has_procedure' => ! empty($statementInfo->isProcedure), 'has_geometry' => $geometryFound, - 'has_print_link' => $printLink == '1', - 'has_export_link' => $analyzedSqlResults['querytype'] === self::QUERY_TYPE_SELECT, + 'has_print_link' => $hasPrintLink, + 'has_export_link' => $statementInfo->queryType === self::QUERY_TYPE_SELECT, 'url_params' => $urlParams, ]; } @@ -4364,25 +4139,24 @@ class Results * @see getDataCellForNumericColumns(), getDataCellForGeometryColumns(), * getDataCellForNonNumericColumns(), * - * @param string $class css classes for the td element - * @param bool $conditionField whether the column is a part of the where clause - * @param array $analyzedSqlResults the analyzed query - * @param FieldMetadata $meta the meta-information about the field - * @param array<string, string[]> $map the list of relations - * @param string $data data - * @param string $displayedData data that will be displayed (maybe be chunked) - * @param string $nowrap 'nowrap' if the content should not be wrapped - * @param string $whereComparison data for the where clause - * @param array $transformOptions options for transformation - * @param bool $isFieldTruncated whether the field is truncated - * @param string $originalLength of a truncated column, or '' + * @param string $class css classes for the td element + * @param bool $conditionField whether the column is a part of the where clause + * @param FieldMetadata $meta the meta-information about the field + * @param array<string, string[]> $map the list of relations + * @param string $data data + * @param string $displayedData data that will be displayed (maybe be chunked) + * @param string $nowrap 'nowrap' if the content should not be wrapped + * @param string $whereComparison data for the where clause + * @param array $transformOptions options for transformation + * @param bool $isFieldTruncated whether the field is truncated + * @param string $originalLength of a truncated column, or '' * * @return string formatted data */ private function getRowData( string $class, bool $conditionField, - array $analyzedSqlResults, + StatementInfo $statementInfo, FieldMetadata $meta, array $map, $data, @@ -4406,8 +4180,8 @@ class Results $transformationPlugin !== null ); - if (! empty($analyzedSqlResults['statement']->expr)) { - foreach ($analyzedSqlResults['statement']->expr as $expr) { + if (! empty($statementInfo->statement->expr)) { + foreach ($statementInfo->statement->expr as $expr) { if (empty($expr->alias) || empty($expr->column)) { continue; } diff --git a/libraries/classes/EditField.php b/libraries/classes/EditField.php new file mode 100644 index 0000000000..26ded0dd5a --- /dev/null +++ b/libraries/classes/EditField.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin; + +/** + * @psalm-immutable + */ +final class EditField +{ + /** @var string $columnName */ + public $columnName; + /** @var string $value */ + public $value; + /** @var string $type */ + public $type; + /** @var bool $autoIncrement */ + public $autoIncrement; + /** @var bool $isNull */ + public $isNull; + /** @var bool $wasPreviouslyNull */ + public $wasPreviouslyNull; + /** @var string $function */ + public $function; + /** @var string|null $salt */ + public $salt; + /** @var string|null $previousValue */ + public $previousValue; + /** @var bool $isUploaded */ + public $isUploaded; + + public function __construct( + string $columnName, + string $value, + string $type, + bool $autoIncrement, + bool $isNull, + bool $wasPreviouslyNull, + string $function, + ?string $salt, + ?string $previousValue, + bool $isUploaded + ) { + $this->columnName = $columnName; + $this->value = $value; + $this->type = $type; + $this->autoIncrement = $autoIncrement; + $this->isNull = $isNull; + $this->wasPreviouslyNull = $wasPreviouslyNull; + $this->function = $function; + $this->salt = $salt; + $this->previousValue = $previousValue; + $this->isUploaded = $isUploaded; + } +} diff --git a/libraries/classes/Engines/Innodb.php b/libraries/classes/Engines/Innodb.php index 5b32fb5f39..15b5307779 100644 --- a/libraries/classes/Engines/Innodb.php +++ b/libraries/classes/Engines/Innodb.php @@ -117,15 +117,13 @@ class Innodb extends StorageEngine */ public function getPageBufferpool() { - global $dbi; - // The following query is only possible because we know // that we are on MySQL 5 here (checked above)! // side note: I love MySQL 5 for this. :-) $sql = 'SHOW STATUS' . ' WHERE Variable_name LIKE \'Innodb\\_buffer\\_pool\\_%\'' . ' OR Variable_name = \'Innodb_page_size\';'; - $status = $dbi->fetchResult($sql, 0, 1); + $status = $GLOBALS['dbi']->fetchResult($sql, 0, 1); /** @var string[] $bytes */ $bytes = Util::formatByteDown($status['Innodb_buffer_pool_pages_total'] * $status['Innodb_page_size']); @@ -261,10 +259,8 @@ class Innodb extends StorageEngine */ public function getPageStatus() { - global $dbi; - return '<pre id="pre_innodb_status">' . "\n" - . htmlspecialchars((string) $dbi->fetchValue( + . htmlspecialchars((string) $GLOBALS['dbi']->fetchValue( 'SHOW ENGINE INNODB STATUS;', 'Status' )) . "\n" . '</pre>' . "\n"; @@ -288,9 +284,7 @@ class Innodb extends StorageEngine */ public function getInnodbPluginVersion() { - global $dbi; - - return $dbi->fetchValue('SELECT @@innodb_version;') ?: ''; + return $GLOBALS['dbi']->fetchValue('SELECT @@innodb_version;') ?: ''; } /** @@ -302,9 +296,7 @@ class Innodb extends StorageEngine */ public function getInnodbFileFormat(): ?string { - global $dbi; - - $value = $dbi->fetchValue("SHOW GLOBAL VARIABLES LIKE 'innodb_file_format';", 1); + $value = $GLOBALS['dbi']->fetchValue("SHOW GLOBAL VARIABLES LIKE 'innodb_file_format';", 1); if ($value === false) { // This variable does not exist anymore on MariaDB >= 10.6.0 @@ -322,8 +314,6 @@ class Innodb extends StorageEngine */ public function supportsFilePerTable(): bool { - global $dbi; - - return $dbi->fetchValue("SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';", 1) === 'ON'; + return $GLOBALS['dbi']->fetchValue("SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';", 1) === 'ON'; } } diff --git a/libraries/classes/Error.php b/libraries/classes/Error.php index 7b71615bc8..b06b35a3ef 100644 --- a/libraries/classes/Error.php +++ b/libraries/classes/Error.php @@ -354,62 +354,52 @@ class Error extends Message */ public function getBacktraceDisplay(): string { - return self::formatBacktrace( - $this->getBacktrace(), - "<br>\n", - "<br>\n" - ); + return self::formatBacktrace($this->getBacktrace()); } /** * return formatted backtrace field * - * @param array $backtrace Backtrace data - * @param string $separator Arguments separator to use - * @param string $lines Lines separator to use + * @param array $backtrace Backtrace data * * @return string formatted backtrace */ - public static function formatBacktrace( - array $backtrace, - string $separator, - string $lines - ): string { - $retval = ''; + public static function formatBacktrace(array $backtrace): string + { + $retval = '<ol class="list-group">'; foreach ($backtrace as $step) { + $retval .= '<li class="list-group-item">'; if (isset($step['file'], $step['line'])) { - $retval .= self::relPath($step['file']) - . '#' . $step['line'] . ': '; + $retval .= self::relPath($step['file']) . '#' . $step['line'] . ': '; } if (isset($step['class'])) { $retval .= $step['class'] . $step['type']; } - $retval .= self::getFunctionCall($step, $separator); - $retval .= $lines; + $retval .= self::getFunctionCall($step); + $retval .= '</li>'; } - return $retval; + return $retval . '</ol>'; } /** * Formats function call in a backtrace * - * @param array $step backtrace step - * @param string $separator Arguments separator to use + * @param array $step backtrace step */ - public static function getFunctionCall(array $step, string $separator): string + public static function getFunctionCall(array $step): string { $retval = $step['function'] . '('; if (isset($step['args'])) { if (count($step['args']) > 1) { - $retval .= $separator; + $retval .= '<br>'; foreach ($step['args'] as $arg) { $retval .= "\t"; $retval .= $arg; - $retval .= ',' . $separator; + $retval .= ',<br>'; } } elseif (count($step['args']) > 0) { foreach ($step['args'] as $arg) { @@ -477,25 +467,17 @@ class Error extends Message $context = 'danger'; } - $retval = '<div class="alert alert-' . $context . '" role="alert">'; - if (! $this->isUserError()) { - $retval .= '<strong>' . $this->getType() . '</strong>'; - $retval .= ' in ' . $this->getFile() . '#' . $this->getLine(); - $retval .= "<br>\n"; - } - - $retval .= $this->getMessage(); - if (! $this->isUserError()) { - $retval .= "<br>\n"; - $retval .= "<br>\n"; - $retval .= "<strong>Backtrace</strong><br>\n"; - $retval .= "<br>\n"; - $retval .= $this->getBacktraceDisplay(); - } - - $retval .= '</div>'; - - return $retval; + $template = new Template(); + + return $template->render('error/get_display', [ + 'context' => $context, + 'is_user_error' => $this->isUserError(), + 'type' => $this->getType(), + 'file' => $this->getFile(), + 'line' => $this->getLine(), + 'message' => $this->getMessage(), + 'formatted_backtrace' => $this->getBacktraceDisplay(), + ]); } /** diff --git a/libraries/classes/ErrorHandler.php b/libraries/classes/ErrorHandler.php index 1e114ccc2f..8151281bc9 100644 --- a/libraries/classes/ErrorHandler.php +++ b/libraries/classes/ErrorHandler.php @@ -195,8 +195,6 @@ class ErrorHandler string $errfile, int $errline ): void { - global $cfg; - if (Util::isErrorReportingAvailable()) { /** * Check if Error Control Operator (@) was used, but still show @@ -208,7 +206,11 @@ class ErrorHandler $isSilenced = error_reporting() == 0; } - if (isset($cfg['environment']) && $cfg['environment'] === 'development' && ! $isSilenced) { + if ( + isset($GLOBALS['cfg']['environment']) + && $GLOBALS['cfg']['environment'] === 'development' + && ! $isSilenced + ) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } @@ -599,7 +601,7 @@ class ErrorHandler // send the error reports asynchronously & without asking user $jsCode .= '$("#pma_report_errors_form").submit();' . 'Functions.ajaxShowMessage( - Messages.phpErrorsBeingSubmitted, false + window.Messages.phpErrorsBeingSubmitted, false );'; // js code to appropriate focusing, $jsCode .= '$("html, body").animate({ @@ -610,7 +612,7 @@ class ErrorHandler //ask user whether to submit errors or not. if (! $response->isAjax()) { // js code to show appropriate msgs, event binding & focusing. - $jsCode = 'Functions.ajaxShowMessage(Messages.phpErrorsFound);' + $jsCode = 'Functions.ajaxShowMessage(window.Messages.phpErrorsFound);' . '$("#pma_ignore_errors_popup").on("click", function() { Functions.ignorePhpErrors() });' @@ -635,6 +637,6 @@ class ErrorHandler // The errors are already sent from the response. // Just focus on errors division upon load event. - $response->getFooter()->getScripts()->addCode($jsCode); + $response->getFooterScripts()->addCode($jsCode); } } diff --git a/libraries/classes/Export.php b/libraries/classes/Export.php index 30804905b1..6982ad58b7 100644 --- a/libraries/classes/Export.php +++ b/libraries/classes/Export.php @@ -14,6 +14,7 @@ use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Plugins\SchemaPlugin; use function __; +use function array_filter; use function array_merge_recursive; use function error_get_last; use function fclose; @@ -25,6 +26,7 @@ use function gzencode; use function header; use function htmlentities; use function htmlspecialchars; +use function http_build_query; use function implode; use function in_array; use function ini_get; @@ -45,7 +47,6 @@ use function strtolower; use function substr; use function time; use function trim; -use function urlencode; /** * PhpMyAdmin\Export class @@ -125,7 +126,8 @@ class Export */ public function outputHandler(?string $line): bool { - global $time_start, $save_filename; + $GLOBALS['time_start'] = $GLOBALS['time_start'] ?? null; + $GLOBALS['save_filename'] = $GLOBALS['save_filename'] ?? null; // Kanji encoding convert feature if ($GLOBALS['output_kanji_conversion']) { @@ -157,7 +159,7 @@ class Export $GLOBALS['message'] = Message::error( __('Insufficient space to save the file %s.') ); - $GLOBALS['message']->addParam($save_filename); + $GLOBALS['message']->addParam($GLOBALS['save_filename']); return false; } @@ -170,8 +172,8 @@ class Export } } else { $timeNow = time(); - if ($time_start >= $timeNow + 30) { - $time_start = $timeNow; + if ($GLOBALS['time_start'] >= $timeNow + 30) { + $GLOBALS['time_start'] = $timeNow; header('X-pmaPing: Pong'); } } @@ -193,14 +195,14 @@ class Export $GLOBALS['message'] = Message::error( __('Insufficient space to save the file %s.') ); - $GLOBALS['message']->addParam($save_filename); + $GLOBALS['message']->addParam($GLOBALS['save_filename']); return false; } $timeNow = time(); - if ($time_start >= $timeNow + 30) { - $time_start = $timeNow; + if ($GLOBALS['time_start'] >= $timeNow + 30) { + $GLOBALS['time_start'] = $timeNow; header('X-pmaPing: Pong'); } } else { @@ -218,14 +220,16 @@ class Export /** * Returns HTML containing the footer for a displayed export * - * @param string $backButton the link for going Back - * @param string $refreshButton the link for refreshing page + * @param string $exportType the export type + * @param string $db the database name + * @param string $table the table name * * @return string the HTML output */ public function getHtmlForDisplayedExportFooter( - string $backButton, - string $refreshButton + string $exportType, + string $db, + string $table ): string { /** * Close the html tags and add the footers for on-screen export @@ -234,8 +238,8 @@ class Export . ' </form>' . '<br>' // bottom back button - . $backButton - . $refreshButton + . $this->getHTMLForBackButton($exportType, $db, $table) + . $this->getHTMLForRefreshButton($exportType) . '</div>' . '<script type="text/javascript">' . "\n" . '//<![CDATA[' . "\n" @@ -532,88 +536,24 @@ class Export * @param string $db the database name * @param string $table the table name * - * @return string[] the generated HTML and back button + * @return string the generated HTML and back button */ public function getHtmlForDisplayedExportHeader( string $exportType, string $db, string $table - ): array { - $html = '<div>'; - + ): string { /** * Displays a back button with all the $_POST data in the URL - * (store in a variable to also display after the textarea) */ - $backButton = '<p>[ <a href="'; - if ($exportType === 'server') { - $backButton .= Url::getFromRoute('/server/export') . '" data-post="' . Url::getCommon([], '', false); - } elseif ($exportType === 'database') { - $backButton .= Url::getFromRoute('/database/export') . '" data-post="' . Url::getCommon( - ['db' => $db], - '', - false - ); - } else { - $backButton .= Url::getFromRoute('/table/export') . '" data-post="' . Url::getCommon( - ['db' => $db, 'table' => $table], - '', - false - ); - } - - $postParams = $_POST; - - // Convert the multiple select elements from an array to a string - if ($exportType === 'database') { - $structOrDataForced = empty($postParams['structure_or_data_forced']); - if ($structOrDataForced && ! isset($postParams['table_structure'])) { - $postParams['table_structure'] = []; - } - - if ($structOrDataForced && ! isset($postParams['table_data'])) { - $postParams['table_data'] = []; - } - } - - foreach ($postParams as $name => $value) { - if (is_array($value)) { - continue; - } - - $backButton .= '&' . urlencode((string) $name) . '=' . urlencode((string) $value); - } - - $backButton .= '&repopulate=1">' . __('Back') . '</a> ]</p>'; - $html .= '<br>'; - $html .= $backButton; - $refreshButton = '<form id="export_refresh_form" method="POST" action="' - . Url::getFromRoute('/export') . '" class="disableAjax">'; - $refreshButton .= '[ <a class="disableAjax export_refresh_btn">' . __('Refresh') . '</a> ]'; - foreach ($postParams as $name => $value) { - if (is_array($value)) { - foreach ($value as $val) { - $refreshButton .= '<input type="hidden" name="' . htmlentities((string) $name) - . '[]" value="' . htmlentities((string) $val) . '">'; - } - } else { - $refreshButton .= '<input type="hidden" name="' . htmlentities((string) $name) - . '" value="' . htmlentities((string) $value) . '">'; - } - } - - $refreshButton .= '</form>'; - $html .= $refreshButton + return '<div>' + . '<br>' + . $this->getHTMLForBackButton($exportType, $db, $table) + . $this->getHTMLForRefreshButton($exportType) . '<br>' . '<form name="nofunction">' . '<textarea name="sqldump" cols="50" rows="30" ' . 'id="textSQLDUMP" wrap="OFF">'; - - return [ - $html, - $backButton, - $refreshButton, - ]; } /** @@ -622,7 +562,6 @@ class Export * @param string|array $dbSelect the selected databases to export * @param string $whatStrucOrData structure or data or both * @param ExportPlugin $exportPlugin the selected export plugin - * @param string $crlf end of line character(s) * @param string $errorUrl the URL in case of error * @param string $exportType the export type * @param bool $doRelation whether to export relation info @@ -636,7 +575,6 @@ class Export $dbSelect, string $whatStrucOrData, ExportPlugin $exportPlugin, - string $crlf, string $errorUrl, string $exportType, bool $doRelation, @@ -665,7 +603,6 @@ class Export $tables, $tables, $exportPlugin, - $crlf, $errorUrl, $exportType, $doRelation, @@ -692,7 +629,6 @@ class Export * @param array $tableStructure whether to export structure for each table * @param array $tableData whether to export data for each table * @param ExportPlugin $exportPlugin the selected export plugin - * @param string $crlf end of line character(s) * @param string $errorUrl the URL in case of error * @param string $exportType the export type * @param bool $doRelation whether to export relation info @@ -709,7 +645,6 @@ class Export array $tableStructure, array $tableData, ExportPlugin $exportPlugin, - string $crlf, string $errorUrl, string $exportType, bool $doRelation, @@ -771,7 +706,6 @@ class Export && ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'stand_in', $exportType, @@ -807,7 +741,6 @@ class Export ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'create_table', $exportType, @@ -836,7 +769,7 @@ class Export . ' FROM ' . Util::backquote($db) . '.' . Util::backquote($table); - if (! $exportPlugin->exportData($db, $table, $crlf, $errorUrl, $localQuery, $aliases)) { + if (! $exportPlugin->exportData($db, $table, $errorUrl, $localQuery, $aliases)) { break; } } @@ -860,7 +793,6 @@ class Export ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'triggers', $exportType, @@ -892,7 +824,6 @@ class Export ! $exportPlugin->exportStructure( $db, $view, - $crlf, $errorUrl, 'create_view', $exportType, @@ -956,7 +887,6 @@ class Export * * @param string $whatStrucOrData whether to export structure for each table or raw * @param ExportPlugin $exportPlugin the selected export plugin - * @param string $crlf end of line character(s) * @param string $errorUrl the URL in case of error * @param string $sqlQuery the query to be executed * @param string $exportType the export type @@ -964,7 +894,6 @@ class Export public static function exportRaw( string $whatStrucOrData, ExportPlugin $exportPlugin, - string $crlf, string $errorUrl, string $sqlQuery, string $exportType @@ -974,7 +903,7 @@ class Export return; } - if (! $exportPlugin->exportRawQuery($errorUrl, $sqlQuery, $crlf)) { + if (! $exportPlugin->exportRawQuery($errorUrl, $sqlQuery)) { $GLOBALS['message'] = Message::error( // phpcs:disable Generic.Files.LineLength.TooLong /* l10n: A query written by the user is a "raw query" that could be using no tables or databases in particular */ @@ -992,7 +921,6 @@ class Export * @param string $table the table to export * @param string $whatStrucOrData structure or data or both * @param ExportPlugin $exportPlugin the selected export plugin - * @param string $crlf end of line character(s) * @param string $errorUrl the URL in case of error * @param string $exportType the export type * @param bool $doRelation whether to export relation info @@ -1010,7 +938,6 @@ class Export string $table, string $whatStrucOrData, ExportPlugin $exportPlugin, - string $crlf, string $errorUrl, string $exportType, bool $doRelation, @@ -1046,7 +973,6 @@ class Export ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'create_view', $exportType, @@ -1065,7 +991,6 @@ class Export ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'create_table', $exportType, @@ -1104,7 +1029,7 @@ class Export . '.' . Util::backquote($table) . $addQuery; } - if (! $exportPlugin->exportData($db, $table, $crlf, $errorUrl, $localQuery, $aliases)) { + if (! $exportPlugin->exportData($db, $table, $errorUrl, $localQuery, $aliases)) { return; } } @@ -1119,7 +1044,6 @@ class Export ! $exportPlugin->exportStructure( $db, $table, - $crlf, $errorUrl, 'triggers', $exportType, @@ -1153,30 +1077,32 @@ class Export */ public function showPage(string $exportType): void { - global $active_page, $containerBuilder; + $GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; + $request = Common::getRequest(); if ($exportType === 'server') { - $active_page = Url::getFromRoute('/server/export'); + $GLOBALS['active_page'] = Url::getFromRoute('/server/export'); /** @var ServerExportController $controller */ - $controller = $containerBuilder->get(ServerExportController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(ServerExportController::class); + $controller($request); return; } if ($exportType === 'database') { - $active_page = Url::getFromRoute('/database/export'); + $GLOBALS['active_page'] = Url::getFromRoute('/database/export'); /** @var DatabaseExportController $controller */ - $controller = $containerBuilder->get(DatabaseExportController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(DatabaseExportController::class); + $controller($request); return; } - $active_page = Url::getFromRoute('/table/export'); + $GLOBALS['active_page'] = Url::getFromRoute('/table/export'); /** @var TableExportController $controller */ - $controller = $containerBuilder->get(TableExportController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(TableExportController::class); + $controller($request); } /** @@ -1337,4 +1263,74 @@ class Export $this->dbi->selectDb($_POST['db']); $exportPlugin->exportSchema($_POST['db']); } + + private function getHTMLForRefreshButton(string $exportType): string + { + $postParams = $this->getPostParams($exportType); + + $refreshButton = '<form id="export_refresh_form" method="POST" action="' + . Url::getFromRoute('/export') . '" class="disableAjax">'; + $refreshButton .= '[ <a class="disableAjax export_refresh_btn">' . __('Refresh') . '</a> ]'; + foreach ($postParams as $name => $value) { + if (is_array($value)) { + foreach ($value as $val) { + $refreshButton .= '<input type="hidden" name="' . htmlentities((string) $name) + . '[]" value="' . htmlentities((string) $val) . '">'; + } + } else { + $refreshButton .= '<input type="hidden" name="' . htmlentities((string) $name) + . '" value="' . htmlentities((string) $value) . '">'; + } + } + + return $refreshButton . '</form>'; + } + + private function getHTMLForBackButton(string $exportType, string $db, string $table): string + { + $backButton = '<p>[ <a href="'; + if ($exportType === 'server') { + $backButton .= Url::getFromRoute('/server/export') . '" data-post="' . Url::getCommon([], '', false); + } elseif ($exportType === 'database') { + $backButton .= Url::getFromRoute('/database/export') . '" data-post="' . Url::getCommon( + ['db' => $db], + '', + false + ); + } else { + $backButton .= Url::getFromRoute('/table/export') . '" data-post="' . Url::getCommon( + ['db' => $db, 'table' => $table], + '', + false + ); + } + + $postParams = array_filter($this->getPostParams($exportType), static function ($value) { + return ! is_array($value); + }); + $backButton .= '&' . http_build_query($postParams); + + $backButton .= '&repopulate=1">' . __('Back') . '</a> ]</p>'; + + return $backButton; + } + + private function getPostParams(string $exportType): array + { + $postParams = $_POST; + + // Convert the multiple select elements from an array to a string + if ($exportType === 'database') { + $structOrDataForced = empty($postParams['structure_or_data_forced']); + if ($structOrDataForced && ! isset($postParams['table_structure'])) { + $postParams['table_structure'] = []; + } + + if ($structOrDataForced && ! isset($postParams['table_data'])) { + $postParams['table_data'] = []; + } + } + + return $postParams; + } } diff --git a/libraries/classes/Export/Options.php b/libraries/classes/Export/Options.php index 028a1e16e9..d776c329f2 100644 --- a/libraries/classes/Export/Options.php +++ b/libraries/classes/Export/Options.php @@ -114,8 +114,6 @@ final class Options $unlimNumRows, array $exportList ) { - global $cfg; - $exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature; $templates = []; @@ -151,9 +149,9 @@ final class Options unset($_SESSION['tmpval']['aliases']); $filenameTemplate = $this->getFileNameTemplate($exportType, $_POST['filename_template'] ?? null); $isEncodingSupported = Encoding::isSupported(); - $selectedCompression = $_POST['compression'] ?? $cfg['Export']['compression'] ?? 'none'; + $selectedCompression = $_POST['compression'] ?? $GLOBALS['cfg']['Export']['compression'] ?? 'none'; - if (isset($cfg['Export']['as_separate_files']) && $cfg['Export']['as_separate_files']) { + if (isset($GLOBALS['cfg']['Export']['as_separate_files']) && $GLOBALS['cfg']['Export']['as_separate_files']) { $selectedCompression = 'zip'; } @@ -161,7 +159,7 @@ final class Options 'db' => $db, 'table' => $table, 'export_type' => $exportType, - 'export_method' => $_POST['export_method'] ?? $cfg['Export']['method'] ?? 'quick', + 'export_method' => $_POST['export_method'] ?? $GLOBALS['cfg']['Export']['method'] ?? 'quick', 'template_id' => $_POST['template_id'] ?? '', ]; @@ -184,14 +182,14 @@ final class Options ], 'sql_query' => $sqlQuery, 'hidden_inputs' => $hiddenInputs, - 'export_method' => $_POST['quick_or_custom'] ?? $cfg['Export']['method'] ?? '', + 'export_method' => $_POST['quick_or_custom'] ?? $GLOBALS['cfg']['Export']['method'] ?? '', 'plugins_choice' => $dropdown, 'options' => Plugins::getOptions('Export', $exportList), 'can_convert_kanji' => Encoding::canConvertKanji(), - 'exec_time_limit' => $cfg['ExecTimeLimit'], + 'exec_time_limit' => $GLOBALS['cfg']['ExecTimeLimit'], 'rows' => $rows, - 'has_save_dir' => isset($cfg['SaveDir']) && ! empty($cfg['SaveDir']), - 'save_dir' => Util::userDir((string) ($cfg['SaveDir'] ?? '')), + 'has_save_dir' => isset($GLOBALS['cfg']['SaveDir']) && ! empty($GLOBALS['cfg']['SaveDir']), + 'save_dir' => Util::userDir((string) ($GLOBALS['cfg']['SaveDir'] ?? '')), 'export_is_checked' => $this->checkboxCheck('quick_export_onserver'), 'export_overwrite_is_checked' => $this->checkboxCheck('quick_export_onserver_overwrite'), 'has_aliases' => $hasAliases, @@ -206,10 +204,10 @@ final class Options 'lock_tables' => isset($_POST['lock_tables']), 'is_encoding_supported' => $isEncodingSupported, 'encodings' => $isEncodingSupported ? Encoding::listEncodings() : [], - 'export_charset' => $cfg['Export']['charset'], - 'export_asfile' => $cfg['Export']['asfile'], - 'has_zip' => $cfg['ZipDump'] && function_exists('gzcompress'), - 'has_gzip' => $cfg['GZipDump'] && function_exists('gzencode'), + 'export_charset' => $GLOBALS['cfg']['Export']['charset'], + 'export_asfile' => $GLOBALS['cfg']['Export']['asfile'], + 'has_zip' => $GLOBALS['cfg']['ZipDump'] && function_exists('gzcompress'), + 'has_gzip' => $GLOBALS['cfg']['GZipDump'] && function_exists('gzencode'), 'selected_compression' => $selectedCompression, 'filename_template' => $filenameTemplate, ]; @@ -217,20 +215,29 @@ final class Options private function getFileNameTemplate(string $exportType, ?string $filename = null): string { - global $cfg, $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; if ($filename !== null) { return $filename; } if ($exportType === 'database') { - return (string) $config->getUserValue('pma_db_filename_template', $cfg['Export']['file_template_database']); + return (string) $GLOBALS['config']->getUserValue( + 'pma_db_filename_template', + $GLOBALS['cfg']['Export']['file_template_database'] + ); } if ($exportType === 'table') { - return (string) $config->getUserValue('pma_table_filename_template', $cfg['Export']['file_template_table']); + return (string) $GLOBALS['config']->getUserValue( + 'pma_table_filename_template', + $GLOBALS['cfg']['Export']['file_template_table'] + ); } - return (string) $config->getUserValue('pma_server_filename_template', $cfg['Export']['file_template_server']); + return (string) $GLOBALS['config']->getUserValue( + 'pma_server_filename_template', + $GLOBALS['cfg']['Export']['file_template_server'] + ); } } diff --git a/libraries/classes/FileListing.php b/libraries/classes/FileListing.php index 83b9cbc59d..b2eccb5dd2 100644 --- a/libraries/classes/FileListing.php +++ b/libraries/classes/FileListing.php @@ -97,15 +97,13 @@ class FileListing */ public function supportedDecompressions(): string { - global $cfg; - $compressions = ''; - if ($cfg['GZipDump'] && function_exists('gzopen')) { + if ($GLOBALS['cfg']['GZipDump'] && function_exists('gzopen')) { $compressions = 'gz'; } - if ($cfg['BZipDump'] && function_exists('bzopen')) { + if ($GLOBALS['cfg']['BZipDump'] && function_exists('bzopen')) { if (! empty($compressions)) { $compressions .= '|'; } @@ -113,7 +111,7 @@ class FileListing $compressions .= 'bz2'; } - if ($cfg['ZipDump'] && function_exists('gzinflate')) { + if ($GLOBALS['cfg']['ZipDump'] && function_exists('gzinflate')) { if (! empty($compressions)) { $compressions .= '|'; } diff --git a/libraries/classes/Footer.php b/libraries/classes/Footer.php index 29c5d981f4..162995c817 100644 --- a/libraries/classes/Footer.php +++ b/libraries/classes/Footer.php @@ -62,13 +62,11 @@ class Footer */ public function __construct() { - global $dbi; - $this->template = new Template(); $this->isEnabled = true; $this->scripts = new Scripts(); $this->isMinimal = false; - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); } /** @@ -119,7 +117,7 @@ class Footer */ public function getDebugMessage(): string { - $retval = '\'null\''; + $retval = '\'false\''; if ($GLOBALS['cfg']['DBG']['sql'] && empty($_REQUEST['no_debug']) && ! empty($_SESSION['debug'])) { // Remove recursions and iterators from $_SESSION['debug'] self::removeRecursion($_SESSION['debug']); @@ -140,45 +138,20 @@ class Footer */ public function getSelfUrl(): string { - global $route, $db, $table, $server; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; $params = []; - if (isset($route)) { - $params['route'] = $route; - } + $params['route'] = Common::getRequest()->getRoute(); - if (isset($db) && strlen($db) > 0) { - $params['db'] = $db; + if (isset($GLOBALS['db']) && strlen($GLOBALS['db']) > 0) { + $params['db'] = $GLOBALS['db']; } - if (isset($table) && strlen($table) > 0) { - $params['table'] = $table; + if (isset($GLOBALS['table']) && strlen($GLOBALS['table']) > 0) { + $params['table'] = $GLOBALS['table']; } - $params['server'] = $server; - - // needed for server privileges tabs - if (isset($_GET['viewing_mode']) && in_array($_GET['viewing_mode'], ['server', 'db', 'table'])) { - $params['viewing_mode'] = $_GET['viewing_mode']; - } - - /** - * @todo coming from /server/privileges, here $db is not set, - * add the following condition below when that is fixed - * && $_GET['checkprivsdb'] == $db - */ - if (isset($_GET['checkprivsdb'])) { - $params['checkprivsdb'] = $_GET['checkprivsdb']; - } - - /** - * @todo coming from /server/privileges, here $table is not set, - * add the following condition below when that is fixed - * && $_REQUEST['checkprivstable'] == $table - */ - if (isset($_GET['checkprivstable'])) { - $params['checkprivstable'] = $_GET['checkprivstable']; - } + $params['server'] = $GLOBALS['server']; if (isset($_REQUEST['single_table']) && in_array($_REQUEST['single_table'], [true, false])) { $params['single_table'] = $_REQUEST['single_table']; @@ -210,8 +183,6 @@ class Footer */ private function setHistory(): void { - global $dbi; - if ( ( isset($_REQUEST['no_history']) @@ -220,8 +191,8 @@ class Footer ) || ! empty($GLOBALS['error_message']) || empty($GLOBALS['sql_query']) - || ! isset($dbi) - || ! $dbi->isConnected() + || ! isset($GLOBALS['dbi']) + || ! $GLOBALS['dbi']->isConnected() ) { return; } @@ -283,7 +254,7 @@ class Footer $url = $this->getSelfUrl(); } - $this->scripts->addCode('var debugSQLInfo = ' . $this->getDebugMessage() . ';'); + $this->scripts->addCode('window.Console.debugSqlInfo = ' . $this->getDebugMessage() . ';'); $errorMessages = $this->getErrorMessages(); $scripts = $this->scripts->getDisplay(); diff --git a/libraries/classes/Gis/GisGeometry.php b/libraries/classes/Gis/GisGeometry.php index deef0cfb22..be5c1f32d1 100644 --- a/libraries/classes/Gis/GisGeometry.php +++ b/libraries/classes/Gis/GisGeometry.php @@ -10,6 +10,7 @@ namespace PhpMyAdmin\Gis; use PhpMyAdmin\Image\ImageWrapper; use TCPDF; +use function defined; use function explode; use function floatval; use function mb_strripos; @@ -377,6 +378,6 @@ abstract class GisGeometry protected function getRandomId(): int { - return random_int(0, mt_getrandmax()); + return ! defined('TESTSUITE') ? random_int(0, mt_getrandmax()) : 1234567890; } } diff --git a/libraries/classes/Gis/GisVisualization.php b/libraries/classes/Gis/GisVisualization.php index b9abe2708b..a0e4d50836 100644 --- a/libraries/classes/Gis/GisVisualization.php +++ b/libraries/classes/Gis/GisVisualization.php @@ -244,9 +244,7 @@ class GisVisualization */ private function fetchRawData(): array { - global $dbi; - - $modified_result = $dbi->tryQuery($this->modifiedSql); + $modified_result = $GLOBALS['dbi']->tryQuery($this->modifiedSql); if ($modified_result === false) { return []; diff --git a/libraries/classes/Header.php b/libraries/classes/Header.php index f625473494..e23146b458 100644 --- a/libraries/classes/Header.php +++ b/libraries/classes/Header.php @@ -97,21 +97,22 @@ class Header /** @var Template */ private $template; + /** @var bool */ + private $isTransformationWrapper = false; + /** * Creates a new class instance */ public function __construct() { - global $db, $table, $dbi; - $this->template = new Template(); $this->isEnabled = true; $this->isAjax = false; $this->bodyId = ''; $this->title = ''; - $this->console = new Console(); - $this->menu = new Menu($dbi, $db ?? '', $table ?? ''); + $this->console = new Console(new Relation($GLOBALS['dbi']), $this->template); + $this->menu = new Menu($GLOBALS['dbi'], $GLOBALS['db'] ?? '', $GLOBALS['table'] ?? ''); $this->menuEnabled = true; $this->warningsEnabled = true; $this->scripts = new Scripts(); @@ -126,7 +127,7 @@ class Header */ private function addDefaultScripts(): void { - // Localised strings + $this->scripts->addFile('runtime.js'); $this->scripts->addFile('vendor/jquery/jquery.min.js'); $this->scripts->addFile('vendor/jquery/jquery-migrate.js'); $this->scripts->addFile('vendor/sprintf.js'); @@ -138,27 +139,16 @@ class Header $this->scripts->addFile('vendor/js.cookie.js'); $this->scripts->addFile('vendor/jquery/jquery.validate.js'); $this->scripts->addFile('vendor/jquery/jquery-ui-timepicker-addon.js'); - $this->scripts->addFile('vendor/jquery/jquery.debounce-1.0.6.js'); $this->scripts->addFile('menu_resizer.js'); - - // Cross-framing protection - // At this point browser settings are not merged - // this is good that we only use file configuration for this protection - if ($GLOBALS['cfg']['AllowThirdPartyFraming'] === false) { - $this->scripts->addFile('cross_framing_protection.js'); - } - - // Here would not be a good place to add CodeMirror because - // the user preferences have not been merged at this point - - $this->scripts->addFile('messages.php', ['l' => $GLOBALS['lang']]); + $this->scripts->addFile('cross_framing_protection.js'); + $this->scripts->addFile('index.php', ['route' => '/messages', 'l' => $GLOBALS['lang']]); $this->scripts->addFile('config.js'); - $this->scripts->addFile('doclinks.js'); $this->scripts->addFile('functions.js'); $this->scripts->addFile('navigation.js'); $this->scripts->addFile('indexes.js'); $this->scripts->addFile('common.js'); $this->scripts->addFile('page_settings.js'); + $this->scripts->addFile('main.js'); $this->scripts->addCode($this->getJsParamsCode()); } @@ -171,8 +161,6 @@ class Header */ public function getJsParams(): array { - global $db, $table, $dbi; - $pftext = $_SESSION['tmpval']['pftext'] ?? ''; $params = [ @@ -181,8 +169,8 @@ class Header 'opendb_url' => Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'), 'lang' => $GLOBALS['lang'], 'server' => $GLOBALS['server'], - 'table' => $table ?? '', - 'db' => $db ?? '', + 'table' => $GLOBALS['table'] ?? '', + 'db' => $GLOBALS['db'] ?? '', 'token' => $_SESSION[' PMA_token '], 'text_dir' => $GLOBALS['text_dir'], 'LimitChars' => $GLOBALS['cfg']['LimitChars'], @@ -190,7 +178,7 @@ class Header 'confirm' => $GLOBALS['cfg']['Confirm'], 'LoginCookieValidity' => $GLOBALS['cfg']['LoginCookieValidity'], 'session_gc_maxlifetime' => (int) ini_get('session.gc_maxlifetime'), - 'logged_in' => isset($dbi) ? $dbi->isConnected() : false, + 'logged_in' => isset($GLOBALS['dbi']) ? $GLOBALS['dbi']->isConnected() : false, 'is_https' => $GLOBALS['config']->isHttps(), 'rootPath' => $GLOBALS['config']->getRootPath(), 'arg_separator' => Url::getArgSeparator(), @@ -221,7 +209,7 @@ class Header } } - return 'CommonParams.setAll({' . implode(',', $params) . '});'; + return 'window.CommonParams.setAll({' . implode(',', $params) . '});'; } /** @@ -308,7 +296,7 @@ class Header */ public function getDisplay(): string { - global $db, $table, $theme, $dbi; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; if ($this->headerIsSent || ! $this->isEnabled) { return ''; @@ -316,7 +304,7 @@ class Header $recentTable = ''; if (empty($_REQUEST['recent_table'])) { - $recentTable = $this->addRecentTable($db, $table); + $recentTable = $this->addRecentTable($GLOBALS['db'], $GLOBALS['table']); } if ($this->isAjax) { @@ -326,7 +314,7 @@ class Header $this->sendHttpHeaders(); $baseDir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : ''; - $themePath = $theme instanceof Theme ? $theme->getPath() : ''; + $themePath = $GLOBALS['theme'] instanceof Theme ? $GLOBALS['theme']->getPath() : ''; $version = self::getVersionParameter(); // The user preferences have been merged at this point @@ -379,8 +367,8 @@ class Header if ($this->menuEnabled && $GLOBALS['server'] > 0) { $nav = new Navigation( $this->template, - new Relation($dbi), - $dbi + new Relation($GLOBALS['dbi']), + $GLOBALS['dbi'] ); $navigation = $nav->getDisplay(); } @@ -399,6 +387,9 @@ class Header $console = $this->console->getDisplay(); $messages = $this->getMessage(); + $this->scripts->addFile('datetimepicker.js'); + $this->scripts->addFile('validator-messages.js'); + return $this->template->render('header', [ 'lang' => $GLOBALS['lang'], 'allow_third_party_framing' => $GLOBALS['cfg']['AllowThirdPartyFraming'], @@ -524,7 +515,10 @@ class Header $headers = array_merge($headers, Core::getNoCacheHeaders()); - if (! defined('IS_TRANSFORMATION_WRAPPER')) { + /** + * A different Content-Type is set in {@see \PhpMyAdmin\Controllers\Transformation\WrapperController}. + */ + if (! $this->isTransformationWrapper) { // Define the charset to be used $headers['Content-Type'] = 'text/html; charset=utf-8'; } @@ -568,20 +562,18 @@ class Header */ private function getCspHeaders(): array { - global $cfg; - $mapTileUrls = ' *.tile.openstreetmap.org'; $captchaUrl = ''; - $cspAllow = $cfg['CSPAllow']; + $cspAllow = $GLOBALS['cfg']['CSPAllow']; if ( - ! empty($cfg['CaptchaLoginPrivateKey']) - && ! empty($cfg['CaptchaLoginPublicKey']) - && ! empty($cfg['CaptchaApi']) - && ! empty($cfg['CaptchaRequestParam']) - && ! empty($cfg['CaptchaResponseParam']) + ! empty($GLOBALS['cfg']['CaptchaLoginPrivateKey']) + && ! empty($GLOBALS['cfg']['CaptchaLoginPublicKey']) + && ! empty($GLOBALS['cfg']['CaptchaApi']) + && ! empty($GLOBALS['cfg']['CaptchaRequestParam']) + && ! empty($GLOBALS['cfg']['CaptchaResponseParam']) ) { - $captchaUrl = ' ' . $cfg['CaptchaCsp'] . ' '; + $captchaUrl = ' ' . $GLOBALS['cfg']['CaptchaCsp'] . ' '; } $headers = []; @@ -662,14 +654,17 @@ class Header private function getVariablesForJavaScript(): string { - global $cfg; - $maxInputVars = ini_get('max_input_vars'); $maxInputVarsValue = $maxInputVars === false || $maxInputVars === '' ? 'false' : (int) $maxInputVars; return $this->template->render('javascript/variables', [ - 'first_day_of_calendar' => $cfg['FirstDayOfCalendar'] ?? 0, + 'first_day_of_calendar' => $GLOBALS['cfg']['FirstDayOfCalendar'] ?? 0, 'max_input_vars' => $maxInputVarsValue, ]); } + + public function setIsTransformationWrapper(bool $isTransformationWrapper): void + { + $this->isTransformationWrapper = $isTransformationWrapper; + } } diff --git a/libraries/classes/Html/Generator.php b/libraries/classes/Html/Generator.php index 37d7661790..da73100420 100644 --- a/libraries/classes/Html/Generator.php +++ b/libraries/classes/Html/Generator.php @@ -165,10 +165,8 @@ class Generator $minimumVersion, $bugReference ): string { - global $dbi; - $return = ''; - if (($component === 'mysql') && ($dbi->getVersion() < $minimumVersion)) { + if (($component === 'mysql') && ($GLOBALS['dbi']->getVersion() < $minimumVersion)) { $return .= self::showHint( sprintf( __('The %s functionality is affected by a known bug, see %s'), @@ -274,19 +272,19 @@ class Generator */ public static function getDefaultFunctionForField(array $field, $insertMode): string { - global $cfg, $data, $dbi; + $GLOBALS['data'] = $GLOBALS['data'] ?? null; $defaultFunction = ''; // Can we get field class based values? - $currentClass = $dbi->types->getTypeClass($field['True_Type']); - if (! empty($currentClass) && isset($cfg['DefaultFunctions']['FUNC_' . $currentClass])) { - $defaultFunction = $cfg['DefaultFunctions']['FUNC_' . $currentClass]; + $currentClass = $GLOBALS['dbi']->types->getTypeClass($field['True_Type']); + if (! empty($currentClass) && isset($GLOBALS['cfg']['DefaultFunctions']['FUNC_' . $currentClass])) { + $defaultFunction = $GLOBALS['cfg']['DefaultFunctions']['FUNC_' . $currentClass]; // Change the configured default function to include the ST_ prefix with MySQL 5.6 and later. // It needs to match the function listed in the select html element. if ( $currentClass === 'SPATIAL' && - $dbi->getVersion() >= 50600 && + $GLOBALS['dbi']->getVersion() >= 50600 && strtoupper(substr($defaultFunction, 0, 3)) !== 'ST_' ) { $defaultFunction = 'ST_' . $defaultFunction; @@ -303,11 +301,11 @@ class Generator ($field['True_Type'] === 'timestamp') && $field['first_timestamp'] && empty($field['Default']) - && empty($data) + && empty($GLOBALS['data']) && $field['Extra'] !== 'on update CURRENT_TIMESTAMP' && $field['Null'] === 'NO' ) { - $defaultFunction = $cfg['DefaultFunctions']['first_timestamp']; + $defaultFunction = $GLOBALS['cfg']['DefaultFunctions']['first_timestamp']; } // For primary keys of type char(36) or varchar(36) UUID if the default @@ -318,7 +316,7 @@ class Generator && $field['Key'] === 'PRI' && ($field['Type'] === 'char(36)' || $field['Type'] === 'varchar(36)') ) { - $defaultFunction = $cfg['DefaultFunctions']['FUNC_UUID']; + $defaultFunction = $GLOBALS['cfg']['DefaultFunctions']['FUNC_UUID']; } return $defaultFunction; @@ -335,15 +333,13 @@ class Generator */ public static function getFunctionsForField(array $field, $insertMode, array $foreignData): string { - global $dbi; - $defaultFunction = self::getDefaultFunctionForField($field, $insertMode); // Create the output $retval = '<option></option>' . "\n"; // loop on the dropdown array and print all available options for that // field. - $functions = $dbi->types->getAllFunctions(); + $functions = $GLOBALS['dbi']->types->getAllFunctions(); foreach ($functions as $function) { $retval .= '<option'; if ($function === $defaultFunction && ! isset($foreignData['foreign_field'])) { @@ -459,13 +455,11 @@ class Generator */ private static function generateRowQueryOutput($sqlQuery): string { - global $dbi; - $ret = ''; - $result = $dbi->query($sqlQuery); + $result = $GLOBALS['dbi']->query($sqlQuery); $devider = '+'; $columnNames = '|'; - $fieldsMeta = $dbi->getFieldsMeta($result); + $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); foreach ($fieldsMeta as $meta) { $devider .= '---+'; $columnNames .= ' ' . $meta->name . ' |'; @@ -510,8 +504,6 @@ class Generator $sqlQuery = null, $type = 'notice' ): string { - global $cfg, $dbi; - $retval = ''; if ($sqlQuery === null) { @@ -526,7 +518,7 @@ class Generator } } - $renderSql = $cfg['ShowSQL'] == true && ! empty($sqlQuery) && $sqlQuery !== ';'; + $renderSql = $GLOBALS['cfg']['ShowSQL'] == true && ! empty($sqlQuery) && $sqlQuery !== ';'; if (isset($GLOBALS['using_bookmark_message'])) { $retval .= $GLOBALS['using_bookmark_message']->getDisplay(); @@ -566,11 +558,11 @@ class Generator $queryTooBig = false; $queryLength = mb_strlen($sqlQuery); - if ($queryLength > $cfg['MaxCharactersInDisplayedSQL']) { + if ($queryLength > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { // when the query is large (for example an INSERT of binary // data), the parser chokes; so avoid parsing the query $queryTooBig = true; - $queryBase = mb_substr($sqlQuery, 0, $cfg['MaxCharactersInDisplayedSQL']) . '[...]'; + $queryBase = mb_substr($sqlQuery, 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) . '[...]'; } else { $queryBase = $sqlQuery; } @@ -621,7 +613,7 @@ class Generator /* SQL-Parser-Analyzer */ $explainLink = ''; $isSelect = preg_match('@^SELECT[[:space:]]+@i', $sqlQuery); - if (! empty($cfg['SQLQuery']['Explain']) && ! $queryTooBig) { + if (! empty($GLOBALS['cfg']['SQLQuery']['Explain']) && ! $queryTooBig) { $explainParams = $urlParams; if ($isSelect) { $explainParams['sql_query'] = 'EXPLAIN ' . $sqlQuery; @@ -644,8 +636,8 @@ class Generator . urlencode(self::generateRowQueryOutput($sqlQuery)); $explainLink .= ' [' . self::linkOrButton( - htmlspecialchars('url.php?url=' . urlencode($url)), - null, + Url::getFromRoute('/url'), + ['url' => $url], sprintf(__('Analyze Explain at %s'), 'mariadb.org'), [], '_blank', @@ -659,7 +651,7 @@ class Generator // even if the query is big and was truncated, offer the chance // to edit it (unless it's enormous, see linkOrButton() ) - if (! empty($cfg['SQLQuery']['Edit']) && empty($GLOBALS['show_as_php'])) { + if (! empty($GLOBALS['cfg']['SQLQuery']['Edit']) && empty($GLOBALS['show_as_php'])) { $editLink = ' [ ' . self::linkOrButton($editLink, $urlParams, __('Edit')) . ' ]'; @@ -669,7 +661,7 @@ class Generator // Also we would like to get the SQL formed in some nice // php-code - if (! empty($cfg['SQLQuery']['ShowAsPHP']) && ! $queryTooBig) { + if (! empty($GLOBALS['cfg']['SQLQuery']['ShowAsPHP']) && ! $queryTooBig) { if (! empty($GLOBALS['show_as_php'])) { $phpLink = ' [ ' . self::linkOrButton( @@ -703,7 +695,7 @@ class Generator // Refresh query if ( - ! empty($cfg['SQLQuery']['Refresh']) + ! empty($GLOBALS['cfg']['SQLQuery']['Refresh']) && ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same && preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sqlQuery) ) { @@ -726,7 +718,7 @@ class Generator // avoid displaying a Profiling checkbox that could // be checked, which would re-execute an INSERT, for example - if (! empty($refreshLink) && Profiling::isSupported($dbi)) { + if (! empty($refreshLink) && Profiling::isSupported($GLOBALS['dbi'])) { $retval .= '<input type="hidden" name="profiling_form" value="1">'; $retval .= '<input type="checkbox" name="profiling" id="profilingCheckbox" class="autosubmit"'; $retval .= isset($_SESSION['profiling']) ? ' checked' : ''; @@ -738,7 +730,7 @@ class Generator /** * TODO: Should we have $cfg['SQLQuery']['InlineEdit']? */ - if (! empty($cfg['SQLQuery']['Edit']) && ! $queryTooBig && empty($GLOBALS['show_as_php'])) { + if (! empty($GLOBALS['cfg']['SQLQuery']['Edit']) && ! $queryTooBig && empty($GLOBALS['show_as_php'])) { $inlineEditLink = ' [ ' . self::linkOrButton( '#', @@ -813,8 +805,6 @@ class Generator $backUrl = '', $exit = true ): ?string { - global $table, $db, $dbi; - /** * Error message to be built. */ @@ -822,7 +812,7 @@ class Generator // Checking for any server errors. if (empty($serverMessage)) { - $serverMessage = $dbi->getError(); + $serverMessage = $GLOBALS['dbi']->getError(); } // Finding the query that failed, if not specified. @@ -900,12 +890,12 @@ class Generator 'sql_query' => $sqlQuery, 'show_query' => 1, ]; - if (strlen($table) > 0) { - $urlParams['db'] = $db; - $urlParams['table'] = $table; + if (strlen($GLOBALS['table']) > 0) { + $urlParams['db'] = $GLOBALS['db']; + $urlParams['table'] = $GLOBALS['table']; $doEditGoto = '<a href="' . Url::getFromRoute('/table/sql', $urlParams) . '">'; - } elseif (strlen($db) > 0) { - $urlParams['db'] = $db; + } elseif (strlen($GLOBALS['db']) > 0) { + $urlParams['db'] = $GLOBALS['db']; $doEditGoto = '<a href="' . Url::getFromRoute('/database/sql', $urlParams) . '">'; } else { $doEditGoto = '<a href="' . Url::getFromRoute('/server/sql', $urlParams) . '">'; @@ -1081,7 +1071,7 @@ class Generator if (! empty($target)) { $tagParams['target'] = $target; - if ($target === '_blank' && str_starts_with($url, 'url.php?')) { + if ($target === '_blank' && str_starts_with($url, 'index.php?route=/url&url=')) { $tagParams['rel'] = 'noopener noreferrer'; } } @@ -1215,10 +1205,8 @@ class Generator */ public static function formatSql($sqlQuery, $truncate = false): string { - global $cfg; - - if ($truncate && mb_strlen($sqlQuery) > $cfg['MaxCharactersInDisplayedSQL']) { - $sqlQuery = mb_substr($sqlQuery, 0, $cfg['MaxCharactersInDisplayedSQL']) . '[...]'; + if ($truncate && mb_strlen($sqlQuery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { + $sqlQuery = mb_substr($sqlQuery, 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) . '[...]'; } return '<code class="sql"><pre>' . "\n" @@ -1235,12 +1223,10 @@ class Generator */ public static function getSupportedDatatypes($selected): string { - global $dbi; - // NOTE: the SELECT tag is not included in this snippet. $retval = ''; - foreach ($dbi->types->getColumns() as $key => $value) { + foreach ($GLOBALS['dbi']->types->getColumns() as $key => $value) { if (is_array($value)) { $retval .= '<optgroup label="' . htmlspecialchars($key) . '">'; foreach ($value as $subvalue) { @@ -1251,12 +1237,12 @@ class Generator continue; } - $isLengthRestricted = Compatibility::isIntegersSupportLength($subvalue, '2', $dbi); + $isLengthRestricted = Compatibility::isIntegersSupportLength($subvalue, '2', $GLOBALS['dbi']); $retval .= sprintf( '<option data-length-restricted="%b" %s title="%s">%s</option>', $isLengthRestricted ? 0 : 1, $selected === $subvalue ? 'selected="selected"' : '', - $dbi->types->getTypeDescription($subvalue), + $GLOBALS['dbi']->types->getTypeDescription($subvalue), $subvalue ); } @@ -1265,12 +1251,12 @@ class Generator continue; } - $isLengthRestricted = Compatibility::isIntegersSupportLength($value, '2', $dbi); + $isLengthRestricted = Compatibility::isIntegersSupportLength($value, '2', $GLOBALS['dbi']); $retval .= sprintf( '<option data-length-restricted="%b" %s title="%s">%s</option>', $isLengthRestricted ? 0 : 1, $selected === $value ? 'selected="selected"' : '', - $dbi->types->getTypeDescription($value), + $GLOBALS['dbi']->types->getTypeDescription($value), $value ); } diff --git a/libraries/classes/Http/ServerRequest.php b/libraries/classes/Http/ServerRequest.php index 379371a73f..dc2f911deb 100644 --- a/libraries/classes/Http/ServerRequest.php +++ b/libraries/classes/Http/ServerRequest.php @@ -10,6 +10,7 @@ use Psr\Http\Message\UriInterface; use function is_array; use function is_object; +use function is_string; use function property_exists; class ServerRequest implements ServerRequestInterface @@ -339,4 +340,37 @@ class ServerRequest implements ServerRequestInterface { return $this->getMethod() === 'POST'; } + + /** + * @psalm-return non-empty-string + */ + public function getRoute(): string + { + $getParams = $this->getQueryParams(); + $postParams = $this->getParsedBody(); + $route = '/'; + if (isset($getParams['route']) && is_string($getParams['route']) && $getParams['route'] !== '') { + $route = $getParams['route']; + } elseif ( + is_array($postParams) + && isset($postParams['route']) + && is_string($postParams['route']) + && $postParams['route'] !== '' + ) { + $route = $postParams['route']; + } + + /** + * See FAQ 1.34. + * + * @see https://docs.phpmyadmin.net/en/latest/faq.html#faq1-34 + */ + $db = isset($getParams['db']) && is_string($getParams['db']) ? $getParams['db'] : ''; + if ($route === '/' && $db !== '') { + $table = isset($getParams['table']) && is_string($getParams['table']) ? $getParams['table'] : ''; + $route = $table === '' ? '/database/structure' : '/sql'; + } + + return $route; + } } diff --git a/libraries/classes/Import.php b/libraries/classes/Import.php index 48eccd25b0..b493b6f324 100644 --- a/libraries/classes/Import.php +++ b/libraries/classes/Import.php @@ -34,7 +34,6 @@ use function preg_replace; use function sprintf; use function str_contains; use function str_starts_with; -use function strcmp; use function strlen; use function strpos; use function substr; @@ -66,13 +65,14 @@ class Import public const SIZES = 1; public const FORMATTEDSQL = 2; + /** @var string|null importRunBuffer */ + private $importRunBuffer = null; + public function __construct() { - global $dbi; - $GLOBALS['cfg']['Server']['DisableIS'] = false; - $checkUserPrivileges = new CheckUserPrivileges($dbi); + $checkUserPrivileges = new CheckUserPrivileges($GLOBALS['dbi']); $checkUserPrivileges->getPrivileges(); } @@ -81,19 +81,22 @@ class Import */ public function checkTimeout(): bool { - global $timestamp, $maximum_time, $timeout_passed; - if ($maximum_time == 0) { + $GLOBALS['timestamp'] = $GLOBALS['timestamp'] ?? null; + $GLOBALS['maximum_time'] = $GLOBALS['maximum_time'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + + if ($GLOBALS['maximum_time'] == 0) { return false; } - if ($timeout_passed) { + if ($GLOBALS['timeout_passed']) { return true; /* 5 in next row might be too much */ } - if (time() - $timestamp > $maximum_time - 5) { - $timeout_passed = true; + if (time() - $GLOBALS['timestamp'] > $GLOBALS['maximum_time'] - 5) { + $GLOBALS['timeout_passed'] = true; return true; } @@ -105,220 +108,180 @@ class Import * Runs query inside import buffer. This is needed to allow displaying * of last SELECT, SHOW or HANDLER results and similar nice stuff. * - * @param string $sql query to run - * @param string $full query to display, this might be commented - * @param array $sqlData SQL parse data storage + * @param string $sql query to run + * @param string[] $sqlData SQL parse data storage */ - public function executeQuery(string $sql, string $full, array &$sqlData): void + public function executeQuery(string $sql, array &$sqlData): void { - global $sql_query, $my_die, $error, $reload, $result, $msg, $cfg, $sql_query_disabled, $db, $dbi; - - $result = $dbi->tryQuery($sql); + $GLOBALS['my_die'] = $GLOBALS['my_die'] ?? null; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['reload'] = $GLOBALS['reload'] ?? null; + $GLOBALS['msg'] = $GLOBALS['msg'] ?? null; + $GLOBALS['sql_query_disabled'] = $GLOBALS['sql_query_disabled'] ?? null; + $GLOBALS['result'] = $GLOBALS['dbi']->tryQuery($sql); // USE query changes the database, son need to track // while running multiple queries $isUseQuery = mb_stripos($sql, 'use ') !== false; - $msg = '# '; - if ($result === false) { // execution failed - if (! isset($my_die)) { - $my_die = []; + $GLOBALS['msg'] = '# '; + if ($GLOBALS['result'] === false) { // execution failed + if (! isset($GLOBALS['my_die'])) { + $GLOBALS['my_die'] = []; } - $my_die[] = [ - 'sql' => $full, - 'error' => $dbi->getError(), + $GLOBALS['my_die'][] = [ + 'sql' => $sql, + 'error' => $GLOBALS['dbi']->getError(), ]; - $msg .= __('Error'); + $GLOBALS['msg'] .= __('Error'); - if (! $cfg['IgnoreMultiSubmitErrors']) { - $error = true; + if (! $GLOBALS['cfg']['IgnoreMultiSubmitErrors']) { + $GLOBALS['error'] = true; return; } } else { - $aNumRows = (int) $result->numRows(); - $aAffectedRows = (int) @$dbi->affectedRows(); + $aNumRows = (int) $GLOBALS['result']->numRows(); + $aAffectedRows = (int) @$GLOBALS['dbi']->affectedRows(); if ($aNumRows > 0) { - $msg .= __('Rows') . ': ' . $aNumRows; + $GLOBALS['msg'] .= __('Rows') . ': ' . $aNumRows; } elseif ($aAffectedRows > 0) { $message = Message::getMessageForAffectedRows($aAffectedRows); - $msg .= $message->getMessage(); + $GLOBALS['msg'] .= $message->getMessage(); } else { - $msg .= __('MySQL returned an empty result set (i.e. zero rows).'); + $GLOBALS['msg'] .= __('MySQL returned an empty result set (i.e. zero rows).'); } if (($aNumRows > 0) || $isUseQuery) { - $sqlData['valid_sql'][] = $sql; - if (! isset($sqlData['valid_queries'])) { - $sqlData['valid_queries'] = 0; - } - - $sqlData['valid_queries']++; + $sqlData[] = $sql; } } - if (! $sql_query_disabled) { - $sql_query .= $msg . "\n"; + if (! $GLOBALS['sql_query_disabled']) { + $GLOBALS['sql_query'] .= $GLOBALS['msg'] . "\n"; } // If a 'USE <db>' SQL-clause was found and the query // succeeded, set our current $db to the new one - if ($result != false) { - [$db, $reload] = $this->lookForUse($sql, $db, $reload); + if ($GLOBALS['result'] != false) { + [$GLOBALS['db'], $GLOBALS['reload']] = $this->lookForUse($sql, $GLOBALS['db'], $GLOBALS['reload']); } $pattern = '@^[\s]*(DROP|CREATE)[\s]+(IF EXISTS[[:space:]]+)?(TABLE|DATABASE)[[:space:]]+(.+)@im'; - if ($result == false || ! preg_match($pattern, $sql)) { + if ($GLOBALS['result'] == false || ! preg_match($pattern, $sql)) { return; } - $reload = true; + $GLOBALS['reload'] = true; } /** * Runs query inside import buffer. This is needed to allow displaying * of last SELECT, SHOW or HANDLER results and similar nice stuff. * - * @param string $sql query to run - * @param string $full query to display, this might be commented - * @param array $sqlData SQL parse data storage + * @param string $sql query to run + * @param string[] $sqlData SQL parse data storage */ - public function runQuery( - string $sql = '', - string $full = '', - array &$sqlData = [] - ): void { - global $import_run_buffer, $go_sql, $complete_query, $display_query, $sql_query, $msg, - $skip_queries, $executed_queries, $max_sql_len, $read_multiply, $sql_query_disabled, $run_query; - $read_multiply = 1; - if (! isset($import_run_buffer)) { + public function runQuery(string $sql, array &$sqlData): void + { + $GLOBALS['go_sql'] = $GLOBALS['go_sql'] ?? null; + $GLOBALS['complete_query'] = $GLOBALS['complete_query'] ?? null; + $GLOBALS['display_query'] = $GLOBALS['display_query'] ?? null; + $GLOBALS['msg'] = $GLOBALS['msg'] ?? null; + $GLOBALS['skip_queries'] = $GLOBALS['skip_queries'] ?? null; + $GLOBALS['executed_queries'] = $GLOBALS['executed_queries'] ?? null; + $GLOBALS['max_sql_len'] = $GLOBALS['max_sql_len'] ?? null; + $GLOBALS['sql_query_disabled'] = $GLOBALS['sql_query_disabled'] ?? null; + $GLOBALS['run_query'] = $GLOBALS['run_query'] ?? null; + + $GLOBALS['read_multiply'] = 1; + if ($this->importRunBuffer === null) { // Do we have something to push into buffer? - $import_run_buffer = $this->runQueryPost($import_run_buffer, $sql, $full); + $this->importRunBuffer = $sql !== '' ? $sql . ';' : null; return; } // Should we skip something? - if ($skip_queries > 0) { - $skip_queries--; + if ($GLOBALS['skip_queries'] > 0) { + $GLOBALS['skip_queries']--; // Do we have something to push into buffer? - $import_run_buffer = $this->runQueryPost($import_run_buffer, $sql, $full); + $this->importRunBuffer = $sql !== '' ? $sql . ';' : null; return; } - if (! empty($import_run_buffer['sql']) && trim($import_run_buffer['sql']) != '') { - $max_sql_len = max( - $max_sql_len, - mb_strlen($import_run_buffer['sql']) - ); - if (! $sql_query_disabled) { - $sql_query .= $import_run_buffer['full']; - } - - $executed_queries++; + $GLOBALS['max_sql_len'] = max( + $GLOBALS['max_sql_len'], + mb_strlen($this->importRunBuffer) + ); + if (! $GLOBALS['sql_query_disabled']) { + $GLOBALS['sql_query'] .= $this->importRunBuffer; + } - if ($run_query && $executed_queries < 50) { - $go_sql = true; + $GLOBALS['executed_queries']++; - if (! $sql_query_disabled) { - $complete_query = $sql_query; - $display_query = $sql_query; - } else { - $complete_query = ''; - $display_query = ''; - } + if ($GLOBALS['run_query'] && $GLOBALS['executed_queries'] < 50) { + $GLOBALS['go_sql'] = true; - $sql_query = $import_run_buffer['sql']; - $sqlData['valid_sql'][] = $import_run_buffer['sql']; - $sqlData['valid_full'][] = $import_run_buffer['full']; - if (! isset($sqlData['valid_queries'])) { - $sqlData['valid_queries'] = 0; - } + if (! $GLOBALS['sql_query_disabled']) { + $GLOBALS['complete_query'] = $GLOBALS['sql_query']; + $GLOBALS['display_query'] = $GLOBALS['sql_query']; + } else { + $GLOBALS['complete_query'] = ''; + $GLOBALS['display_query'] = ''; + } - $sqlData['valid_queries']++; - } elseif ($run_query) { - /* Handle rollback from go_sql */ - if ($go_sql && isset($sqlData['valid_full'])) { - $queries = $sqlData['valid_sql']; - $fulls = $sqlData['valid_full']; - $count = $sqlData['valid_queries']; - $go_sql = false; - - $sqlData['valid_sql'] = []; - $sqlData['valid_queries'] = 0; - unset($sqlData['valid_full']); - for ($i = 0; $i < $count; $i++) { - $this->executeQuery($queries[$i], $fulls[$i], $sqlData); - } + $GLOBALS['sql_query'] = $this->importRunBuffer; + $sqlData[] = $this->importRunBuffer; + } elseif ($GLOBALS['run_query']) { + /* Handle rollback from go_sql */ + if ($GLOBALS['go_sql'] && $sqlData !== []) { + $queries = $sqlData; + $sqlData = []; + $GLOBALS['go_sql'] = false; + + foreach ($queries as $query) { + $this->executeQuery($query, $sqlData); } - - $this->executeQuery($import_run_buffer['sql'], $import_run_buffer['full'], $sqlData); - } - } elseif (! empty($import_run_buffer['full'])) { - if ($go_sql) { - $complete_query .= $import_run_buffer['full']; - $display_query .= $import_run_buffer['full']; - } elseif (! $sql_query_disabled) { - $sql_query .= $import_run_buffer['full']; } + + $this->executeQuery($this->importRunBuffer, $sqlData); } // check length of query unless we decided to pass it to /sql // (if $run_query is false, we are just displaying so show // the complete query in the textarea) - if (! $go_sql && $run_query && ! empty($sql_query)) { - if (mb_strlen($sql_query) > 50000 || $executed_queries > 50 || $max_sql_len > 1000) { - $sql_query = ''; - $sql_query_disabled = true; + if (! $GLOBALS['go_sql'] && $GLOBALS['run_query'] && ! empty($GLOBALS['sql_query'])) { + if ( + mb_strlen($GLOBALS['sql_query']) > 50000 + || $GLOBALS['executed_queries'] > 50 + || $GLOBALS['max_sql_len'] > 1000 + ) { + $GLOBALS['sql_query'] = ''; + $GLOBALS['sql_query_disabled'] = true; } } // Do we have something to push into buffer? - $import_run_buffer = $this->runQueryPost($import_run_buffer, $sql, $full); + $this->importRunBuffer = $sql !== '' ? $sql . ';' : null; // In case of ROLLBACK, notify the user. if (! isset($_POST['rollback_query'])) { return; } - $msg .= __('[ROLLBACK occurred.]'); - } - - /** - * Return import run buffer - * - * @param array $importRunBuffer Buffer of queries for import - * @param string $sql SQL query - * @param string $full Query to display - * - * @return array Buffer of queries for import - */ - public function runQueryPost( - ?array $importRunBuffer, - string $sql, - string $full - ): ?array { - if (! empty($sql) || ! empty($full)) { - return [ - 'sql' => $sql . ';', - 'full' => $full . ';', - ]; - } - - unset($GLOBALS['import_run_buffer']); - - return $importRunBuffer; + $GLOBALS['msg'] .= __('[ROLLBACK occurred.]'); } /** * Looks for the presence of USE to possibly change current db * - * @param string $buffer buffer to examine - * @param string $db current db - * @param bool $reload reload + * @param string|null $buffer buffer to examine + * @param string|null $db current db + * @param bool|null $reload reload * * @return array (current or new db, whether to reload) */ @@ -351,16 +314,18 @@ class Import */ public function getNextChunk(?File $importHandle = null, int $size = 32768) { - global $charset_conversion, $charset_of_file, $read_multiply; + $GLOBALS['charset_conversion'] = $GLOBALS['charset_conversion'] ?? null; + $GLOBALS['charset_of_file'] = $GLOBALS['charset_of_file'] ?? null; + $GLOBALS['read_multiply'] = $GLOBALS['read_multiply'] ?? null; // Add some progression while reading large amount of data - if ($read_multiply <= 8) { - $size *= $read_multiply; + if ($GLOBALS['read_multiply'] <= 8) { + $size *= $GLOBALS['read_multiply']; } else { $size *= 8; } - $read_multiply++; + $GLOBALS['read_multiply']++; // We can not read too much if ($size > $GLOBALS['read_limit']) { @@ -399,8 +364,8 @@ class Import $GLOBALS['finished'] = $importHandle->eof(); $GLOBALS['offset'] += $size; - if ($charset_conversion) { - return Encoding::convertString($charset_of_file, 'utf-8', $result); + if ($GLOBALS['charset_conversion']) { + return Encoding::convertString($GLOBALS['charset_of_file'], 'utf-8', $result); } /** @@ -622,7 +587,7 @@ class Import /** * If the cell is NULL, don't treat it as a varchar */ - if (! strcmp('NULL', $cell)) { + if ($cell === 'NULL') { return $lastCumulativeSize; } @@ -712,8 +677,8 @@ class Import /* New val if M or D is greater than current largest */ if ($size[self::M] > $oldM || $size[self::D] > $oldD) { /* Take the largest of both types */ - return (string) (($size[self::M] > $oldM ? $size[self::M] : $oldM) - . ',' . ($size[self::D] > $oldD ? $size[self::D] : $oldD)); + return ($size[self::M] > $oldM ? $size[self::M] : $oldM) + . ',' . ($size[self::D] > $oldD ? $size[self::D] : $oldD); } return $lastCumulativeSize; @@ -775,7 +740,7 @@ class Import $oldM = $this->getDecimalPrecision($lastCumulativeSize); $oldD = $this->getDecimalScale($lastCumulativeSize); $oldInt = $oldM - $oldD; - $newInt = mb_strlen((string) $cell); + $newInt = mb_strlen($cell); /* See which has the larger integer length */ if ($oldInt >= $newInt) { @@ -828,7 +793,7 @@ class Import /** * Determines what MySQL type a cell is * - * @param int $lastCumulativeType Last cumulative column type + * @param int|null $lastCumulativeType Last cumulative column type * (VARCHAR or INT or BIGINT or DECIMAL or NONE) * @param string|null $cell String representation of the cell for which * a best-fit type is to be determined @@ -843,7 +808,7 @@ class Import * Else, we call it varchar for simplicity */ - if (! strcmp('NULL', (string) $cell)) { + if ($cell === 'NULL') { if ($lastCumulativeType === null || $lastCumulativeType == self::NONE) { return self::NONE; } @@ -857,8 +822,8 @@ class Import if ( $cell == (string) (float) $cell - && str_contains((string) $cell, '.') - && mb_substr_count((string) $cell, '.') === 1 + && str_contains($cell, '.') + && mb_substr_count($cell, '.') === 1 ) { return self::DECIMAL; } @@ -885,7 +850,7 @@ class Import * * @todo Handle the error case more elegantly */ - public function analyzeTable(array &$table) + public function analyzeTable(array $table) { /* Get number of rows in table */ $numRows = count($table[self::ROWS]); @@ -957,7 +922,7 @@ class Import /* Check to ensure that all types are valid */ $len = count($types); for ($n = 0; $n < $len; ++$n) { - if (strcmp((string) self::NONE, (string) $types[$n])) { + if ((string) $types[$n] !== (string) self::NONE) { continue; } @@ -982,20 +947,20 @@ class Import * @param array|null $analyses Analyses of the tables * @param array|null $additionalSql Additional SQL statements to be executed * @param array|null $options Associative array of options - * @param array $sqlData 2-element array with sql data + * @param string[] $sqlData List of SQL statements to be executed */ public function buildSql( string $dbName, array &$tables, - ?array &$analyses = null, + ?array $analyses = null, ?array &$additionalSql = null, ?array $options = null, array &$sqlData = [] ): void { - global $import_notice, $dbi; + $GLOBALS['import_notice'] = $GLOBALS['import_notice'] ?? null; /* Needed to quell the beast that is Message */ - $import_notice = null; + $GLOBALS['import_notice'] = null; /* Take care of the options */ $collation = $options['db_collation'] ?? 'utf8_general_ci'; @@ -1025,7 +990,7 @@ class Import /* Execute the SQL statements create above */ $sqlLength = count($sql); for ($i = 0; $i < $sqlLength; ++$i) { - $this->runQuery($sql[$i], $sql[$i], $sqlData); + $this->runQuery($sql[$i], $sqlData); } /* No longer needed */ @@ -1056,7 +1021,7 @@ class Import for ($i = 0; $i < $additionalSqlLength; ++$i) { $additionalSql[$i] = preg_replace($pattern, $replacement, $additionalSql[$i]); /* Execute the resulting statements */ - $this->runQuery($additionalSql[$i], $additionalSql[$i], $sqlData); + $this->runQuery($additionalSql[$i], $sqlData); } } @@ -1109,7 +1074,7 @@ class Import * after it is formed so that we don't have * to store them in a (possibly large) buffer */ - $this->runQuery($tempSQLStr, $tempSQLStr, $sqlData); + $this->runQuery($tempSQLStr, $sqlData); } } @@ -1160,12 +1125,12 @@ class Import } /* Don't put quotes around NULL fields */ - if (! strcmp((string) $tables[$i][self::ROWS][$j][$k], 'NULL')) { + if ((string) $tables[$i][self::ROWS][$j][$k] === 'NULL') { $isVarchar = false; } $tempSQLStr .= $isVarchar ? "'" : ''; - $tempSQLStr .= $dbi->escapeString((string) $tables[$i][self::ROWS][$j][$k]); + $tempSQLStr .= $GLOBALS['dbi']->escapeString((string) $tables[$i][self::ROWS][$j][$k]); $tempSQLStr .= $isVarchar ? "'" : ''; } @@ -1201,7 +1166,7 @@ class Import * after it is formed so that we don't have * to store them in a (possibly large) buffer */ - $this->runQuery($tempSQLStr, $tempSQLStr, $sqlData); + $this->runQuery($tempSQLStr, $sqlData); } /* No longer needed */ @@ -1219,34 +1184,26 @@ class Import $tablePattern = '@CREATE TABLE IF NOT EXISTS `([^`]+)`@'; /* Check a third pattern to make sure its not a "USE `db_name`;" statement */ - $regs = []; - - $inTables = false; - - $additionalSqlLength = $additionalSql === null ? 0 : count($additionalSql); - for ($i = 0; $i < $additionalSqlLength; ++$i) { - preg_match($viewPattern, $additionalSql[$i], $regs); + /** @var string $sql */ + foreach ($additionalSql ?? [] as $sql) { + $regs = []; + preg_match($viewPattern, $sql, $regs); - if (count($regs) === 0) { - preg_match($tablePattern, $additionalSql[$i], $regs); + if ($regs === []) { + preg_match($tablePattern, $sql, $regs); } - if (count($regs)) { - for ($n = 0; $n < $numTables; ++$n) { - if (! strcmp($regs[1], $tables[$n][self::TBL_NAME])) { - $inTables = true; - break; - } - } + if ($regs === []) { + continue; + } - if (! $inTables) { - $tables[] = [self::TBL_NAME => $regs[1]]; + for ($n = 0; $n < $numTables; ++$n) { + if ($regs[1] === $tables[$n][self::TBL_NAME]) { + continue 2; } } - /* Reset the array */ - $regs = []; - $inTables = false; + $tables[] = [self::TBL_NAME => $regs[1]]; } $params = ['db' => $dbName]; @@ -1338,7 +1295,7 @@ class Import $message .= '</ul></ul>'; - $import_notice = $message; + $GLOBALS['import_notice'] = $message; } /** @@ -1348,8 +1305,6 @@ class Import */ public function handleRollbackRequest(string $sqlQuery): void { - global $dbi; - $sqlDelimiter = $_POST['sql_delimiter']; $queries = explode($sqlDelimiter, $sqlQuery); $error = false; @@ -1367,7 +1322,7 @@ class Import continue; } - $globalError = $dbi->getError(); + $globalError = $GLOBALS['dbi']->getError(); if ($globalError) { $error = $globalError; } else { @@ -1386,7 +1341,7 @@ class Import } // If everything fine, START a transaction. - $dbi->query('START TRANSACTION'); + $GLOBALS['dbi']->query('START TRANSACTION'); } /** @@ -1434,8 +1389,6 @@ class Import */ public function isTableTransactional(string $table): bool { - global $dbi; - $table = explode('.', $table); if (count($table) === 2) { $db = Util::unQuote($table[0]); @@ -1450,7 +1403,7 @@ class Import . '.' . Util::backquote($table) . ' ' . 'LIMIT 1'; - $result = $dbi->tryQuery($checkTableQuery); + $result = $GLOBALS['dbi']->tryQuery($checkTableQuery); if (! $result) { return false; @@ -1470,13 +1423,13 @@ class Import // Query to check if table is 'Transactional'. $checkQuery = 'SELECT `ENGINE` FROM `information_schema`.`tables` ' - . 'WHERE `table_name` = "' . $dbi->escapeString($table) . '" ' - . 'AND `table_schema` = "' . $dbi->escapeString($db) . '" ' + . 'WHERE `table_name` = "' . $GLOBALS['dbi']->escapeString($table) . '" ' + . 'AND `table_schema` = "' . $GLOBALS['dbi']->escapeString($db) . '" ' . 'AND UPPER(`engine`) IN ("' . implode('", "', $transactionalEngines) . '")'; - $result = $dbi->tryQuery($checkQuery); + $result = $GLOBALS['dbi']->tryQuery($checkQuery); return $result && $result->numRows() == 1; } @@ -1484,19 +1437,17 @@ class Import /** @return string[] */ public static function getCompressions(): array { - global $cfg; - $compressions = []; - if ($cfg['GZipDump'] && function_exists('gzopen')) { + if ($GLOBALS['cfg']['GZipDump'] && function_exists('gzopen')) { $compressions[] = 'gzip'; } - if ($cfg['BZipDump'] && function_exists('bzopen')) { + if ($GLOBALS['cfg']['BZipDump'] && function_exists('bzopen')) { $compressions[] = 'bzip2'; } - if ($cfg['ZipDump'] && function_exists('zip_open')) { + if ($GLOBALS['cfg']['ZipDump'] && function_exists('zip_open')) { $compressions[] = 'zip'; } diff --git a/libraries/classes/Import/Ajax.php b/libraries/classes/Import/Ajax.php index 25587cf497..0c56cd3563 100644 --- a/libraries/classes/Import/Ajax.php +++ b/libraries/classes/Import/Ajax.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Import; use PhpMyAdmin\Core; +use function defined; use function function_exists; use function ini_get; use function json_encode; @@ -35,7 +36,7 @@ final class Ajax /** * unique ID for each upload */ - $upload_id = uniqid(''); + $upload_id = ! defined('TESTSUITE') ? uniqid('') : 'abc1234567890'; /** * list of available plugins @@ -71,7 +72,7 @@ final class Ajax */ public static function progressCheck(): bool { - return function_exists('uploadprogress_get_info'); + return ! defined('TESTSUITE') && function_exists('uploadprogress_get_info'); } /** @@ -79,7 +80,7 @@ final class Ajax */ public static function sessionCheck(): bool { - return ini_get('session.upload_progress.enabled') === '1'; + return ! defined('TESTSUITE') && ini_get('session.upload_progress.enabled') === '1'; } /** diff --git a/libraries/classes/Index.php b/libraries/classes/Index.php index 79f9e3a239..94cb50b641 100644 --- a/libraries/classes/Index.php +++ b/libraries/classes/Index.php @@ -24,7 +24,7 @@ class Index /** * Class-wide storage container for indexes (caching, singleton) * - * @var array + * @var array<string, array<string, array<string, Index>>> */ private static $registry = []; @@ -40,7 +40,7 @@ class Index /** * Columns in index * - * @var array + * @var array<string, IndexColumn> */ private $columns = []; @@ -106,17 +106,17 @@ class Index } /** - * Creates(if not already created) and returns the corresponding Index object - * - * @param string $schema database name - * @param string $table table name - * @param string $index_name index name + * Creates (if not already created) and returns the corresponding Index object * * @return Index corresponding Index object */ - public static function singleton($schema, $table, $index_name = '') - { - self::loadIndexes($table, $schema); + public static function singleton( + DatabaseInterface $dbi, + string $schema, + string $table, + string $index_name = '' + ): Index { + self::loadIndexes($dbi, $table, $schema); if (! isset(self::$registry[$schema][$table][$index_name])) { $index = new Index(); if (strlen($index_name) > 0) { @@ -133,14 +133,11 @@ class Index /** * returns an array with all indexes from the given table * - * @param string $table table - * @param string $schema schema - * - * @return Index[] array of indexes + * @return Index[] */ - public static function getFromTable($table, $schema) + public static function getFromTable(DatabaseInterface $dbi, string $table, string $schema): array { - self::loadIndexes($table, $schema); + self::loadIndexes($dbi, $table, $schema); if (isset(self::$registry[$schema][$table])) { return self::$registry[$schema][$table]; @@ -161,7 +158,7 @@ class Index public static function getFromTableByChoice($table, $schema, $choices = 31) { $indexes = []; - foreach (self::getFromTable($table, $schema) as $index) { + foreach (self::getFromTable($GLOBALS['dbi'], $table, $schema) as $index) { if (($choices & self::PRIMARY) && $index->getChoice() === 'PRIMARY') { $indexes[] = $index; } @@ -188,35 +185,18 @@ class Index return $indexes; } - /** - * return primary if set, false otherwise - * - * @param string $table table - * @param string $schema schema - * - * @return Index|false primary index or false if no one exists - */ - public static function getPrimary($table, $schema) + public static function getPrimary(DatabaseInterface $dbi, string $table, string $schema): ?Index { - self::loadIndexes($table, $schema); - - if (isset(self::$registry[$schema][$table]['PRIMARY'])) { - return self::$registry[$schema][$table]['PRIMARY']; - } + self::loadIndexes($dbi, $table, $schema); - return false; + return self::$registry[$schema][$table]['PRIMARY'] ?? null; } /** * Load index data for table - * - * @param string $table table - * @param string $schema schema */ - private static function loadIndexes($table, $schema): bool + private static function loadIndexes(DatabaseInterface $dbi, string $table, string $schema): bool { - global $dbi; - if (isset(self::$registry[$schema][$table])) { return true; } @@ -241,7 +221,7 @@ class Index /** * Add column to index * - * @param array $params column params + * @param array<string, string|null> $params column params */ public function addColumn(array $params): void { @@ -473,7 +453,7 @@ class Index public function hasPrimary(): bool { - return (bool) self::getPrimary($this->table, $this->schema); + return self::getPrimary($GLOBALS['dbi'], $this->table, $this->schema) !== null; } /** @@ -558,7 +538,7 @@ class Index /** * Returns the columns of the index * - * @return IndexColumn[] the columns of the index + * @return array<string, IndexColumn> */ public function getColumns() { @@ -568,9 +548,20 @@ class Index /** * Gets the properties in an array for comparison purposes * - * @return array an array containing the properties of the index - */ - public function getCompareData() + * @return array<string, array<int, array<string, int|string|null>>|string|null> + * @psalm-return array{ + * Packed: string|null, + * Index_choice: string, + * columns?: list<array{ + * Column_name: string, + * Seq_in_index: int, + * Collation: string|null, + * Sub_part: int|null, + * Null: string + * }> + * } + */ + public function getCompareData(): array { $data = [ 'Packed' => $this->packed, @@ -594,7 +585,7 @@ class Index */ public static function findDuplicates($table, $schema) { - $indexes = self::getFromTable($table, $schema); + $indexes = self::getFromTable($GLOBALS['dbi'], $table, $schema); $output = ''; diff --git a/libraries/classes/IndexColumn.php b/libraries/classes/IndexColumn.php index 4921002f32..adfca050c8 100644 --- a/libraries/classes/IndexColumn.php +++ b/libraries/classes/IndexColumn.php @@ -191,9 +191,16 @@ class IndexColumn /** * Gets the properties in an array for comparison purposes * - * @return array an array containing the properties of the index column + * @return array<string, int|string|null> + * @psalm-return array{ + * Column_name: string, + * Seq_in_index: int, + * Collation: string|null, + * Sub_part: int|null, + * Null: string + * } */ - public function getCompareData() + public function getCompareData(): array { return [ 'Column_name' => $this->name, diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 3301c529c5..fc8107c023 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -1,7 +1,4 @@ <?php -/** - * set of functions with the insert/edit features in pma - */ declare(strict_types=1); @@ -53,16 +50,9 @@ use function trim; use const ENT_COMPAT; use const PASSWORD_DEFAULT; -/** - * PhpMyAdmin\InsertEdit class - */ class InsertEdit { - /** - * DatabaseInterface instance - * - * @var DatabaseInterface - */ + /** @var DatabaseInterface */ private $dbi; /** @var Relation */ @@ -75,18 +65,48 @@ class InsertEdit private $fileListing; /** @var Template */ - public $template; - - /** - * @param DatabaseInterface $dbi DatabaseInterface instance - */ - public function __construct(DatabaseInterface $dbi) - { + private $template; + + private const FUNC_OPTIONAL_PARAM = [ + 'RAND', + 'UNIX_TIMESTAMP', + ]; + + private const FUNC_NO_PARAM = [ + 'CONNECTION_ID', + 'CURRENT_USER', + 'CURDATE', + 'CURTIME', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'DATABASE', + 'LAST_INSERT_ID', + 'NOW', + 'PI', + 'RAND', + 'SYSDATE', + 'UNIX_TIMESTAMP', + 'USER', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'UUID', + 'UUID_SHORT', + 'VERSION', + ]; + + public function __construct( + DatabaseInterface $dbi, + Relation $relation, + Transformations $transformations, + FileListing $fileListing, + Template $template + ) { $this->dbi = $dbi; - $this->relation = new Relation($this->dbi); - $this->transformations = new Transformations(); - $this->fileListing = new FileListing(); - $this->template = new Template(); + $this->relation = $relation; + $this->transformations = $transformations; + $this->fileListing = $fileListing; + $this->template = $template; } /** @@ -98,7 +118,7 @@ class InsertEdit * @param array $whereClauseArray array of where clauses * @param string $errorUrl error url * - * @return array array of insert/edit form parameters + * @return array<string, string> array of insert/edit form parameters */ public function getFormParametersForInsertForm( $db, @@ -130,9 +150,9 @@ class InsertEdit /** * Creates array of where clauses * - * @param array|string|null $whereClause where clause + * @param string[]|string|null $whereClause where clause * - * @return array whereClauseArray array of where clauses + * @return string[] whereClauseArray array of where clauses */ private function getWhereClauseArray($whereClause): array { @@ -144,17 +164,18 @@ class InsertEdit return $whereClause; } - return [0 => $whereClause]; + return [$whereClause]; } /** * Analysing where clauses array * - * @param array $whereClauseArray array of where clauses - * @param string $table name of the table - * @param string $db name of the database + * @param string[] $whereClauseArray array of where clauses + * @param string $table name of the table + * @param string $db name of the database * - * @return array $where_clauses, $result, $rows, $found_unique_key + * @return array<int, string[]|ResultInterface[]|array<string, string|null>[]|bool> + * @phpstan-return array{string[], ResultInterface[], array<string, string|null>[], bool} */ private function analyzeWhereClauses( array $whereClauseArray, @@ -247,9 +268,10 @@ class InsertEdit * @param string $table name of the table * @param string $db name of the database * - * @return array containing $result and $rows arrays + * @return array<int, ResultInterface|false[]> + * @phpstan-return array{ResultInterface, false[]} */ - private function loadFirstRow($table, $db) + private function loadFirstRow($table, $db): array { $result = $this->dbi->query( 'SELECT * FROM ' . Util::backquote($db) @@ -815,11 +837,12 @@ class InsertEdit // HTML5 data-* attribute data-type $dataType = $this->dbi->types->getTypeClass($column['True_Type']); $fieldsize = $this->getColumnSize($column, $extractedColumnspec['spec_in_brackets']); - $htmlOutput = $backupField . "\n"; - if ($column['is_char'] && ($GLOBALS['cfg']['CharEditing'] === 'textarea' || str_contains($data, "\n"))) { - $htmlOutput .= "\n"; + + $isTextareaRequired = $column['is_char'] + && ($GLOBALS['cfg']['CharEditing'] === 'textarea' || str_contains($data, "\n")); + if ($isTextareaRequired) { $GLOBALS['cfg']['CharEditing'] = $defaultCharEditing; - $htmlOutput .= $this->getTextarea( + $htmlField = $this->getTextarea( $column, $backupField, $columnNameAppendix, @@ -833,7 +856,7 @@ class InsertEdit $readOnly ); } else { - $htmlOutput .= $this->getHtmlInput( + $htmlField = $this->getHtmlInput( $column, $columnNameAppendix, $specialChars, @@ -845,38 +868,15 @@ class InsertEdit $dataType, $readOnly ); - - if ( - preg_match('/(VIRTUAL|PERSISTENT|GENERATED)/', $column['Extra']) - && ! str_contains($column['Extra'], 'DEFAULT_GENERATED') - ) { - $htmlOutput .= '<input type="hidden" name="virtual' - . $columnNameAppendix . '" value="1">'; - } - - if ($column['Extra'] === 'auto_increment') { - $htmlOutput .= '<input type="hidden" name="auto_increment' - . $columnNameAppendix . '" value="1">'; - } - - if (substr($column['pma_type'], 0, 9) === 'timestamp') { - $htmlOutput .= '<input type="hidden" name="fields_type' - . $columnNameAppendix . '" value="timestamp">'; - } - - if (substr($column['pma_type'], 0, 4) === 'date') { - $type = substr($column['pma_type'], 0, 8) === 'datetime' ? 'datetime' : 'date'; - $htmlOutput .= '<input type="hidden" name="fields_type' - . $columnNameAppendix . '" value="' . $type . '">'; - } - - if ($column['True_Type'] === 'bit') { - $htmlOutput .= '<input type="hidden" name="fields_type' - . $columnNameAppendix . '" value="bit">'; - } } - return $htmlOutput; + return $this->template->render('table/insert/value_column_for_other_datatype', [ + 'html_field' => $htmlField, + 'backup_field' => $backupField, + 'is_textarea' => $isTextareaRequired, + 'columnNameAppendix' => $columnNameAppendix, + 'column' => $column, + ]); } /** @@ -1550,39 +1550,23 @@ class InsertEdit } /** - * Get current value in multi edit mode - * - * @param array $multiEditFuncs multiple edit functions array - * @param array $multiEditSalt multiple edit array with encryption salt - * @param array $gisFromTextFunctions array that contains gis from text functions - * @param string $currentValue current value in the column - * @param array $gisFromWkbFunctions initially $val is $multi_edit_columns[$key] - * @param array $funcOptionalParam array('RAND','UNIX_TIMESTAMP') - * @param array $funcNoParam array of set of string - * @param string $key an md5 of the column name + * Get value part if a function was specified */ - public function getCurrentValueAsAnArrayForMultipleEdit( - $multiEditFuncs, - $multiEditSalt, - $gisFromTextFunctions, - $currentValue, - $gisFromWkbFunctions, - $funcOptionalParam, - $funcNoParam, - $key + private function formatAsSqlFunction( + EditField $editField ): string { - if ($multiEditFuncs[$key] === 'PHP_PASSWORD_HASH') { + if ($editField->function === 'PHP_PASSWORD_HASH') { /** * @see https://github.com/vimeo/psalm/issues/3350 * * @psalm-suppress InvalidArgument */ - $hash = password_hash($currentValue, PASSWORD_DEFAULT); + $hash = password_hash($editField->value, PASSWORD_DEFAULT); return "'" . $this->dbi->escapeString($hash) . "'"; } - if ($multiEditFuncs[$key] === 'UUID') { + if ($editField->function === 'UUID') { /* This way user will know what UUID new row has */ $uuid = (string) $this->dbi->fetchValue('SELECT UUID()'); @@ -1590,179 +1574,123 @@ class InsertEdit } if ( - in_array($multiEditFuncs[$key], $gisFromTextFunctions) - || in_array($multiEditFuncs[$key], $gisFromWkbFunctions) + in_array($editField->function, $this->getGisFromTextFunctions()) + || in_array($editField->function, $this->getGisFromWKBFunctions()) ) { - return $multiEditFuncs[$key] . "('" . $this->dbi->escapeString($currentValue) . "')"; + return $editField->function . "('" . $this->dbi->escapeString($editField->value) . "')"; } if ( - ! in_array($multiEditFuncs[$key], $funcNoParam) - || ($currentValue != "''" - && in_array($multiEditFuncs[$key], $funcOptionalParam)) + ! in_array($editField->function, self::FUNC_NO_PARAM) + || ($editField->value !== '' && in_array($editField->function, self::FUNC_OPTIONAL_PARAM)) ) { if ( - (isset($multiEditSalt[$key]) - && ($multiEditFuncs[$key] === 'AES_ENCRYPT' - || $multiEditFuncs[$key] === 'AES_DECRYPT')) - || (! empty($multiEditSalt[$key]) - && ($multiEditFuncs[$key] === 'DES_ENCRYPT' - || $multiEditFuncs[$key] === 'DES_DECRYPT' - || $multiEditFuncs[$key] === 'ENCRYPT')) + ($editField->salt !== null + && ($editField->function === 'AES_ENCRYPT' + || $editField->function === 'AES_DECRYPT')) + || ($editField->salt + && ($editField->function === 'DES_ENCRYPT' + || $editField->function === 'DES_DECRYPT' + || $editField->function === 'ENCRYPT')) ) { - return $multiEditFuncs[$key] . "('" . $this->dbi->escapeString($currentValue) . "','" - . $this->dbi->escapeString($multiEditSalt[$key]) . "')"; + return $editField->function . "('" . $this->dbi->escapeString($editField->value) . "','" + . $this->dbi->escapeString($editField->salt) . "')"; } - return $multiEditFuncs[$key] . "('" . $this->dbi->escapeString($currentValue) . "')"; + return $editField->function . "('" . $this->dbi->escapeString($editField->value) . "')"; } - return $multiEditFuncs[$key] . '()'; + return $editField->function . '()'; } /** - * Get query values array and query fields array for insert and update in multi edit - * - * @param array $multiEditColumnsName multiple edit columns name array - * @param array $multiEditColumnsNull multiple edit columns null array - * @param string $currentValue current value in the column in loop - * @param array $multiEditColumnsPrev multiple edit previous columns array - * @param array $multiEditFuncs multiple edit functions array - * @param bool $isInsert boolean value whether insert or not - * @param array $queryValues SET part of the sql query - * @param array $queryFields array of query fields - * @param string $currentValueAsAnArray current value in the column - * as an array - * @param array $valueSets array of valu sets - * @param string $key an md5 of the column name - * @param array $multiEditColumnsNullPrev array of multiple edit columns - * null previous - * - * @return array[] ($query_values, $query_fields) + * Get the field value formatted for use in a SQL statement. + * Used in both INSERT and UPDATE statements. */ - public function getQueryValuesForInsertAndUpdateInMultipleEdit( - $multiEditColumnsName, - $multiEditColumnsNull, - $currentValue, - $multiEditColumnsPrev, - $multiEditFuncs, - $isInsert, - $queryValues, - $queryFields, - $currentValueAsAnArray, - $valueSets, - $key, - $multiEditColumnsNullPrev - ) { - // i n s e r t - if ($isInsert) { - // no need to add column into the valuelist - if (strlen($currentValueAsAnArray) > 0) { - $queryValues[] = $currentValueAsAnArray; - // first inserted row so prepare the list of fields - if (empty($valueSets)) { - $queryFields[] = Util::backquote($multiEditColumnsName[$key]); - } - } - } elseif (! empty($multiEditColumnsNullPrev[$key]) && ! isset($multiEditColumnsNull[$key])) { - // u p d a t e + private function getValueFormattedAsSql( + EditField $editField, + string $protectedValue = '' + ): string { + if ($editField->isUploaded) { + return $editField->value; + } - // field had the null checkbox before the update - // field no longer has the null checkbox - $queryValues[] = Util::backquote($multiEditColumnsName[$key]) - . ' = ' . $currentValueAsAnArray; - } elseif ( - ! (empty($multiEditFuncs[$key]) - && empty($multiEditColumnsNull[$key]) - && isset($multiEditColumnsPrev[$key]) - && $currentValue === $multiEditColumnsPrev[$key]) - && $currentValueAsAnArray !== '' - ) { - // avoid setting a field to NULL when it's already NULL - // (field had the null checkbox before the update - // field still has the null checkbox) - if (empty($multiEditColumnsNullPrev[$key]) || empty($multiEditColumnsNull[$key])) { - $queryValues[] = Util::backquote($multiEditColumnsName[$key]) - . ' = ' . $currentValueAsAnArray; - } + if ($editField->function !== '') { + return $this->formatAsSqlFunction($editField); } - return [ - $queryValues, - $queryFields, - ]; + return $this->formatAsSqlValueBasedOnType( + $editField, + $protectedValue + ); } /** - * Get the current column value in the form for different data types + * Get query values array and query fields array for insert and update in multi edit * - * @param string|false $possiblyUploadedVal uploaded file content - * @param string $key an md5 of the column name - * @param array|null $multiEditColumnsType array of multi edit column types - * @param string $currentValue current column value in the form - * @param array|null $multiEditAutoIncrement multi edit auto increment - * @param int $rownumber index of where clause array - * @param array $multiEditColumnsName multi edit column names array - * @param array $multiEditColumnsNull multi edit columns null array - * @param array $multiEditColumnsNullPrev multi edit columns previous null - * @param bool $isInsert whether insert or not - * @param bool $usingKey whether editing or new row - * @param string $whereClause where clause - * @param string $table table name - * @param array $multiEditFuncs multiple edit functions array - * - * @return string current column value in the form + * @param string|int $whereClause Either a positional index or string representing selected row */ - public function getCurrentValueForDifferentTypes( - $possiblyUploadedVal, - $key, - ?array $multiEditColumnsType, - $currentValue, - ?array $multiEditAutoIncrement, - $rownumber, - $multiEditColumnsName, - $multiEditColumnsNull, - $multiEditColumnsNullPrev, - $isInsert, - $usingKey, - $whereClause, - $table, - $multiEditFuncs + public function getQueryValueForInsert( + EditField $editField, + bool $usingKey, + $whereClause ): string { - if ($possiblyUploadedVal !== false) { - return $possiblyUploadedVal; + $protectedValue = ''; + if ($editField->type === 'protected' && $usingKey && $whereClause !== '') { + // Fetch the current values of a row to use in case we have a protected field + $protectedValue = $this->dbi->fetchValue( + 'SELECT ' . Util::backquote($editField->columnName) + . ' FROM ' . Util::backquote($GLOBALS['table']) + . ' WHERE ' . $whereClause + ) ?: ''; } - // c o l u m n v a l u e i n t h e f o r m - $type = $multiEditColumnsType[$key] ?? ''; + return $this->getValueFormattedAsSql($editField, $protectedValue); + } - if ($type !== 'protected' && $type !== 'set' && strlen($currentValue) === 0) { - // best way to avoid problems in strict mode - // (works also in non-strict mode) - $currentValue = "''"; - if (isset($multiEditAutoIncrement, $multiEditAutoIncrement[$key])) { - $currentValue = 'NULL'; - } - } elseif ($type === 'set') { - $currentValue = "''"; - if (! empty($_POST['fields']['multi_edit'][$rownumber][$key])) { - $currentValue = implode(',', $_POST['fields']['multi_edit'][$rownumber][$key]); - $currentValue = "'" - . $this->dbi->escapeString($currentValue) . "'"; - } - } elseif ($type === 'protected') { - // Fetch the current values of a row to use in case we have a protected field - if ( - $isInsert - && $usingKey - && is_array($multiEditColumnsType) && $whereClause - ) { - $protectedRow = $this->dbi->fetchSingleRow( - 'SELECT * FROM ' . Util::backquote($table) - . ' WHERE ' . $whereClause . ';' - ); - } + /** + * Get field-value pairs for update SQL. + * During update, we build the SQL only with the fields that should be updated. + */ + public function getQueryValueForUpdate(EditField $editField): string + { + $currentValueFormattedAsSql = $this->getValueFormattedAsSql($editField); + // avoid setting a field to NULL when it's already NULL + // (field had the null checkbox before the update; field still has the null checkbox) + if ($editField->wasPreviouslyNull && $editField->isNull) { + return ''; + } + + // A blob field that hasn't been changed will have no value + if ($currentValueFormattedAsSql === '') { + return ''; + } + + if ( + // Field had the null checkbox before the update; field no longer has the null checkbox + $editField->wasPreviouslyNull || + // Field was marked as NULL (the value will be unchanged if it was an empty string) + $editField->isNull || + // A function was applied to the field + $editField->function !== '' || + // The value was changed + $editField->value !== $editField->previousValue + ) { + return Util::backquote($editField->columnName) . ' = ' . $currentValueFormattedAsSql; + } + + return ''; + } + + /** + * Get the current column value in the form for different data types + */ + private function formatAsSqlValueBasedOnType( + EditField $editField, + string $protectedValue + ): string { + if ($editField->type === 'protected') { // here we are in protected mode (asked in the config) // so tbl_change has put this special value in the // columns array, so we do not change the column value @@ -1771,44 +1699,54 @@ class InsertEdit // when in UPDATE mode, do not alter field's contents. When in INSERT // mode, insert empty field because no values were submitted. // If protected blobs where set, insert original fields content. - $currentValue = ''; - if (! empty($protectedRow[$multiEditColumnsName[$key]])) { - $currentValue = '0x' - . bin2hex($protectedRow[$multiEditColumnsName[$key]]); + if ($protectedValue !== '') { + return '0x' . bin2hex($protectedValue); } - } elseif ($type === 'hex') { - if (substr($currentValue, 0, 2) != '0x') { - $currentValue = '0x' . $currentValue; + + if ($editField->isNull) { + return 'NULL'; } - } elseif ($type === 'bit') { - $currentValue = (string) preg_replace('/[^01]/', '0', $currentValue); - $currentValue = "b'" . $this->dbi->escapeString($currentValue) . "'"; - } elseif ( - ! ($type === 'datetime' || $type === 'timestamp' || $type === 'date') - || ($currentValue !== 'CURRENT_TIMESTAMP' - && $currentValue !== 'current_timestamp()') - ) { - $currentValue = "'" . $this->dbi->escapeString($currentValue) - . "'"; + + // The Null checkbox was unchecked for this field + if ($editField->wasPreviouslyNull) { + return "''"; + } + + return ''; } - // Was the Null checkbox checked for this field? - // (if there is a value, we ignore the Null checkbox: this could - // be possible if Javascript is disabled in the browser) - if (! empty($multiEditColumnsNull[$key]) && ($currentValue == "''" || $currentValue == '')) { - $currentValue = 'NULL'; + if ($editField->value === '') { + // When the field is autoIncrement, the best way to avoid problems + // in strict mode is to set the value to null (works also in non-strict mode) + + // If the value is empty and the null checkbox is checked, set it to null + return $editField->autoIncrement || $editField->isNull ? 'NULL' : "''"; + } + + if ($editField->type === 'hex') { + if (substr($editField->value, 0, 2) != '0x') { + return '0x' . $editField->value; + } + + return $editField->value; + } + + if ($editField->type === 'bit') { + $currentValue = (string) preg_replace('/[^01]/', '0', $editField->value); + + return "b'" . $this->dbi->escapeString($currentValue) . "'"; } - // The Null checkbox was unchecked for this field if ( - empty($currentValue) - && ! empty($multiEditColumnsNullPrev[$key]) - && ! isset($multiEditColumnsNull[$key]) + ($editField->type !== 'datetime' && $editField->type !== 'timestamp' && $editField->type !== 'date') + || ($editField->value !== 'CURRENT_TIMESTAMP' && $editField->value !== 'current_timestamp()') ) { - $currentValue = "''"; + return "'" . $this->dbi->escapeString($editField->value) . "'"; } - return $currentValue; + // If there is a value, we ignore the Null checkbox; + // this could be possible if Javascript is disabled in the browser + return $editField->value; } /** @@ -1876,11 +1814,21 @@ class InsertEdit /** * Function to determine Insert/Edit rows * - * @param string|null $whereClause where clause - * @param string $db current database - * @param string $table current table - * - * @return array + * @param string[]|string|null $whereClause where clause + * @param string $db current database + * @param string $table current table + * + * @return array<int, bool|string[]|string|ResultInterface|ResultInterface[]|null> + * @phpstan-return array{ + * bool, + * string[]|string|null, + * string[], + * string[]|null, + * ResultInterface[]|ResultInterface, + * array<string, string|null>[]|false[], + * bool, + * string|null + * } */ public function determineInsertOrEdit($whereClause, $db, $table): array { @@ -2373,15 +2321,13 @@ class InsertEdit private function isColumnBinary(array $column, bool $isUpload): bool { - global $cfg; - - if (! $cfg['ShowFunctionFields']) { + if (! $GLOBALS['cfg']['ShowFunctionFields']) { return false; } - return ($cfg['ProtectBinary'] === 'blob' && $column['is_blob'] && ! $isUpload) - || ($cfg['ProtectBinary'] === 'all' && $column['is_binary']) - || ($cfg['ProtectBinary'] === 'noblob' && $column['is_binary']); + return ($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob'] && ! $isUpload) + || ($GLOBALS['cfg']['ProtectBinary'] === 'all' && $column['is_binary']) + || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && $column['is_binary']); } /** @@ -2501,4 +2447,64 @@ class InsertEdit . '</table></div><br>' . '<div class="clearfloat"></div>'; } + + /** + * Returns list of function names that accept WKB as text + * + * @return string[] + */ + private function getGisFromTextFunctions(): array + { + return $this->dbi->getVersion() >= 50600 ? + [ + 'ST_GeomFromText', + 'ST_GeomCollFromText', + 'ST_LineFromText', + 'ST_MLineFromText', + 'ST_PointFromText', + 'ST_MPointFromText', + 'ST_PolyFromText', + 'ST_MPolyFromText', + ] : + [ + 'GeomFromText', + 'GeomCollFromText', + 'LineFromText', + 'MLineFromText', + 'PointFromText', + 'MPointFromText', + 'PolyFromText', + 'MPolyFromText', + ]; + } + + /** + * Returns list of function names that accept WKB as binary + * + * @return string[] + */ + private function getGisFromWKBFunctions(): array + { + return $this->dbi->getVersion() >= 50600 ? + [ + 'ST_GeomFromWKB', + 'ST_GeomCollFromWKB', + 'ST_LineFromWKB', + 'ST_MLineFromWKB', + 'ST_PointFromWKB', + 'ST_MPointFromWKB', + 'ST_PolyFromWKB', + 'ST_MPolyFromWKB', + ] : + [ + 'GeomFromWKB', + 'GeomCollFromWKB', + 'LineFromWKB', + 'MLineFromWKB', + 'PointFromWKB', + 'MPointFromWKB', + 'PolyFromWKB', + 'MPolyFromWKB', + ]; + } } diff --git a/libraries/classes/IpAllowDeny.php b/libraries/classes/IpAllowDeny.php index 17b84dd557..ca93dfff85 100644 --- a/libraries/classes/IpAllowDeny.php +++ b/libraries/classes/IpAllowDeny.php @@ -238,8 +238,6 @@ class IpAllowDeny */ private function allowDeny($type): bool { - global $cfg; - // Grabs true IP of the user and returns if it can't be found $remote_ip = Core::getIp(); if (empty($remote_ip)) { @@ -247,11 +245,11 @@ class IpAllowDeny } // copy username - $username = $cfg['Server']['user']; + $username = $GLOBALS['cfg']['Server']['user']; // copy rule database - if (isset($cfg['Server']['AllowDeny']['rules'])) { - $rules = $cfg['Server']['AllowDeny']['rules']; + if (isset($GLOBALS['cfg']['Server']['AllowDeny']['rules'])) { + $rules = $GLOBALS['cfg']['Server']['AllowDeny']['rules']; if (! is_array($rules)) { $rules = []; } diff --git a/libraries/classes/ListDatabase.php b/libraries/classes/ListDatabase.php index db97349e31..dc8c0f568b 100644 --- a/libraries/classes/ListDatabase.php +++ b/libraries/classes/ListDatabase.php @@ -25,11 +25,9 @@ class ListDatabase extends ListAbstract { public function __construct() { - global $dbi; - parent::__construct(); - $checkUserPrivileges = new CheckUserPrivileges($dbi); + $checkUserPrivileges = new CheckUserPrivileges($GLOBALS['dbi']); $checkUserPrivileges->getPrivileges(); $this->build(); @@ -62,8 +60,6 @@ class ListDatabase extends ListAbstract */ protected function retrieve($like_db_name = null) { - global $dbi; - $database_list = []; $command = ''; if (! $GLOBALS['cfg']['Server']['DisableIS']) { @@ -88,7 +84,7 @@ class ListDatabase extends ListAbstract } if ($command) { - $database_list = $dbi->fetchResult($command, null, null); + $database_list = $GLOBALS['dbi']->fetchResult($command, null, null); } if ($GLOBALS['cfg']['NaturalOrder']) { diff --git a/libraries/classes/Menu.php b/libraries/classes/Menu.php index 17d89b05ce..4d9bf22d81 100644 --- a/libraries/classes/Menu.php +++ b/libraries/classes/Menu.php @@ -162,28 +162,26 @@ class Menu */ private function getBreadcrumbs(): string { - global $cfg; - $server = []; $database = []; $table = []; - if (empty($cfg['Server']['host'])) { - $cfg['Server']['host'] = ''; + if (empty($GLOBALS['cfg']['Server']['host'])) { + $GLOBALS['cfg']['Server']['host'] = ''; } - $server['name'] = ! empty($cfg['Server']['verbose']) - ? $cfg['Server']['verbose'] : $cfg['Server']['host']; - $server['name'] .= empty($cfg['Server']['port']) - ? '' : ':' . $cfg['Server']['port']; - $server['url'] = Util::getUrlForOption($cfg['DefaultTabServer'], 'server'); + $server['name'] = ! empty($GLOBALS['cfg']['Server']['verbose']) + ? $GLOBALS['cfg']['Server']['verbose'] : $GLOBALS['cfg']['Server']['host']; + $server['name'] .= empty($GLOBALS['cfg']['Server']['port']) + ? '' : ':' . $GLOBALS['cfg']['Server']['port']; + $server['url'] = Util::getUrlForOption($GLOBALS['cfg']['DefaultTabServer'], 'server'); if ($this->db !== '') { $database['name'] = $this->db; - $database['url'] = Util::getUrlForOption($cfg['DefaultTabDatabase'], 'database'); + $database['url'] = Util::getUrlForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); if ($this->table !== '') { $table['name'] = $this->table; - $table['url'] = Util::getUrlForOption($cfg['DefaultTabTable'], 'table'); + $table['url'] = Util::getUrlForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $tableObj = $this->dbi->getTable($this->db, $this->table); $table['is_view'] = $tableObj->isView(); $table['comment'] = ''; @@ -220,7 +218,7 @@ class Menu */ private function getTableTabs(): array { - global $route; + $route = Common::getRequest()->getRoute(); $isSystemSchema = Utilities::isSystemSchema($this->db); $tableIsView = $this->dbi->getTable($this->db, $this->table) @@ -288,14 +286,11 @@ class Menu } if (($isSuperUser || $isCreateOrGrantUser) && ! $isSystemSchema) { - $tabs['privileges']['route'] = '/server/privileges'; - $tabs['privileges']['args']['checkprivsdb'] = $this->db; - $tabs['privileges']['args']['checkprivstable'] = $this->table; + $tabs['privileges']['route'] = '/table/privileges'; // stay on table view - $tabs['privileges']['args']['viewing_mode'] = 'table'; $tabs['privileges']['text'] = __('Privileges'); $tabs['privileges']['icon'] = 's_rights'; - $tabs['privileges']['active'] = $route === '/server/privileges'; + $tabs['privileges']['active'] = $route === '/table/privileges'; } /** @@ -342,7 +337,7 @@ class Menu */ private function getDbTabs(): array { - global $route; + $route = Common::getRequest()->getRoute(); $isSystemSchema = Utilities::isSystemSchema($this->db); $numTables = count($this->dbi->getTables($this->db)); @@ -399,13 +394,11 @@ class Menu $tabs['operation']['active'] = $route === '/database/operations'; if ($isSuperUser || $isCreateOrGrantUser) { - $tabs['privileges']['route'] = '/server/privileges'; - $tabs['privileges']['args']['checkprivsdb'] = $this->db; + $tabs['privileges']['route'] = '/database/privileges'; // stay on database view - $tabs['privileges']['args']['viewing_mode'] = 'db'; $tabs['privileges']['text'] = __('Privileges'); $tabs['privileges']['icon'] = 's_rights'; - $tabs['privileges']['active'] = $route === '/server/privileges'; + $tabs['privileges']['active'] = $route === '/database/privileges'; } $tabs['routines']['route'] = '/database/routines'; @@ -459,7 +452,7 @@ class Menu */ private function getServerTabs(): array { - global $route; + $route = Common::getRequest()->getRoute(); $isSuperUser = $this->dbi->isSuperUser(); $isCreateOrGrantUser = $this->dbi->isGrantUser() || $this->dbi->isCreateUser(); @@ -505,7 +498,6 @@ class Menu '/server/privileges', '/server/user-groups', ]); - $tabs['rights']['args']['viewing_mode'] = 'server'; } $tabs['export']['icon'] = 'b_export'; diff --git a/libraries/classes/Navigation/Navigation.php b/libraries/classes/Navigation/Navigation.php index f7bacef25c..a7b700ed47 100644 --- a/libraries/classes/Navigation/Navigation.php +++ b/libraries/classes/Navigation/Navigation.php @@ -67,10 +67,8 @@ class Navigation */ public function getDisplay(): string { - global $cfg; - $logo = [ - 'is_displayed' => $cfg['NavigationDisplayLogo'], + 'is_displayed' => $GLOBALS['cfg']['NavigationDisplayLogo'], 'has_link' => false, 'link' => '#', 'attributes' => ' target="_blank" rel="noopener noreferrer"', @@ -80,13 +78,13 @@ class Navigation $response = ResponseRenderer::getInstance(); if (! $response->isAjax()) { $logo['source'] = $this->getLogoSource(); - $logo['has_link'] = (string) $cfg['NavigationLogoLink'] !== ''; - $logo['link'] = trim((string) $cfg['NavigationLogoLink']); + $logo['has_link'] = (string) $GLOBALS['cfg']['NavigationLogoLink'] !== ''; + $logo['link'] = trim((string) $GLOBALS['cfg']['NavigationLogoLink']); if (! Sanitize::checkLink($logo['link'], true)) { $logo['link'] = 'index.php'; } - if ($cfg['NavigationLogoLinkWindow'] === 'main') { + if ($GLOBALS['cfg']['NavigationLogoLinkWindow'] === 'main') { if (empty(parse_url($logo['link'], PHP_URL_HOST))) { $hasStartChar = strpos($logo['link'], '?'); $logo['link'] .= Url::getCommon( @@ -102,7 +100,7 @@ class Navigation } } - if ($cfg['NavigationDisplayServers'] && count($cfg['Servers']) > 1) { + if ($GLOBALS['cfg']['NavigationDisplayServers'] && count($GLOBALS['cfg']['Servers']) > 1) { $serverSelect = Select::render(true, true); } @@ -114,7 +112,7 @@ class Navigation } if (! $response->isAjax() || ! empty($_POST['full']) || ! empty($_POST['reload'])) { - if ($cfg['ShowDatabasesNavigationAsTree']) { + if ($GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { // provide database tree in navigation $navRender = $this->tree->renderState(); } else { @@ -128,19 +126,19 @@ class Navigation return $this->template->render('navigation/main', [ 'is_ajax' => $response->isAjax(), 'logo' => $logo, - 'config_navigation_width' => $cfg['NavigationWidth'], - 'is_synced' => $cfg['NavigationLinkWithMainPanel'], - 'is_highlighted' => $cfg['NavigationTreePointerEnable'], - 'is_autoexpanded' => $cfg['NavigationTreeAutoexpandSingleDb'], + 'config_navigation_width' => $GLOBALS['cfg']['NavigationWidth'], + 'is_synced' => $GLOBALS['cfg']['NavigationLinkWithMainPanel'], + 'is_highlighted' => $GLOBALS['cfg']['NavigationTreePointerEnable'], + 'is_autoexpanded' => $GLOBALS['cfg']['NavigationTreeAutoexpandSingleDb'], 'server' => $GLOBALS['server'], - 'auth_type' => $cfg['Server']['auth_type'], - 'is_servers_displayed' => $cfg['NavigationDisplayServers'], - 'servers' => $cfg['Servers'], + 'auth_type' => $GLOBALS['cfg']['Server']['auth_type'], + 'is_servers_displayed' => $GLOBALS['cfg']['NavigationDisplayServers'], + 'servers' => $GLOBALS['cfg']['Servers'], 'server_select' => $serverSelect ?? '', 'navigation_tree' => $navRender, 'is_navigation_settings_enabled' => ! defined('PMA_DISABLE_NAVI_SETTINGS'), 'navigation_settings' => $navigationSettings ?? '', - 'is_drag_drop_import_enabled' => $cfg['enable_drag_drop_import'] === true, + 'is_drag_drop_import_enabled' => $GLOBALS['cfg']['enable_drag_drop_import'] === true, 'is_mariadb' => $this->dbi->isMariaDB(), ]); } @@ -288,15 +286,15 @@ class Navigation */ private function getLogoSource(): string { - global $theme; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; - if ($theme instanceof Theme) { - if (@file_exists($theme->getFsPath() . 'img/logo_left.png')) { - return $theme->getPath() . '/img/logo_left.png'; + if ($GLOBALS['theme'] instanceof Theme) { + if (@file_exists($GLOBALS['theme']->getFsPath() . 'img/logo_left.png')) { + return $GLOBALS['theme']->getPath() . '/img/logo_left.png'; } - if (@file_exists($theme->getFsPath() . 'img/pma_logo2.png')) { - return $theme->getPath() . '/img/pma_logo2.png'; + if (@file_exists($GLOBALS['theme']->getFsPath() . 'img/pma_logo2.png')) { + return $GLOBALS['theme']->getPath() . '/img/pma_logo2.png'; } } diff --git a/libraries/classes/Navigation/Nodes/Node.php b/libraries/classes/Navigation/Nodes/Node.php index e20d7f25a1..5fb0a5c73e 100644 --- a/libraries/classes/Navigation/Nodes/Node.php +++ b/libraries/classes/Navigation/Nodes/Node.php @@ -138,8 +138,6 @@ class Node */ public function __construct($name, $type = self::OBJECT, $isGroup = false) { - global $dbi; - if (strlen((string) $name)) { $this->name = $name; $this->realName = $name; @@ -150,7 +148,7 @@ class Node } $this->isGroup = (bool) $isGroup; - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); } /** @@ -397,28 +395,26 @@ class Node */ public function getPresence($type = '', $searchClause = '') { - global $dbi; - if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { if (isset($GLOBALS['cfg']['Server']['DisableIS']) && ! $GLOBALS['cfg']['Server']['DisableIS']) { $query = 'SELECT COUNT(*) '; $query .= 'FROM INFORMATION_SCHEMA.SCHEMATA '; $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); - return (int) $dbi->fetchValue($query); + return (int) $GLOBALS['dbi']->fetchValue($query); } if ($GLOBALS['dbs_to_test'] === false) { $query = 'SHOW DATABASES '; $query .= $this->getWhereClause('Database', $searchClause); - return (int) $dbi->queryAndGetNumRows($query); + return (int) $GLOBALS['dbi']->queryAndGetNumRows($query); } $retval = 0; foreach ($this->getDatabasesToSearch($searchClause) as $db) { $query = "SHOW DATABASES LIKE '" . $db . "'"; - $retval += (int) $dbi->queryAndGetNumRows($query); + $retval += (int) $GLOBALS['dbi']->queryAndGetNumRows($query); } return $retval; @@ -435,14 +431,14 @@ class Node $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); $query .= ') t '; - return (int) $dbi->fetchValue($query); + return (int) $GLOBALS['dbi']->fetchValue($query); } if ($GLOBALS['dbs_to_test'] !== false) { $prefixMap = []; foreach ($this->getDatabasesToSearch($searchClause) as $db) { $query = "SHOW DATABASES LIKE '" . $db . "'"; - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle === false) { continue; } @@ -467,7 +463,7 @@ class Node $prefixMap = []; $query = 'SHOW DATABASES '; $query .= $this->getWhereClause('Database', $searchClause); - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle !== false) { while ($arr = $handle->fetchRow()) { $prefix = strstr($arr[0], $dbSeparator, true); @@ -505,12 +501,10 @@ class Node */ private function getDatabasesToSearch($searchClause) { - global $dbi; - $databases = []; if (! empty($searchClause)) { $databases = [ - '%' . $dbi->escapeString($searchClause) . '%', + '%' . $GLOBALS['dbi']->escapeString($searchClause) . '%', ]; } elseif (! empty($GLOBALS['cfg']['Server']['only_db'])) { $databases = $GLOBALS['cfg']['Server']['only_db']; @@ -534,20 +528,18 @@ class Node */ private function getWhereClause($columnName, $searchClause = '') { - global $dbi; - $whereClause = 'WHERE TRUE '; if (! empty($searchClause)) { $whereClause .= 'AND ' . Util::backquote($columnName) . " LIKE '%"; - $whereClause .= $dbi->escapeString($searchClause); + $whereClause .= $GLOBALS['dbi']->escapeString($searchClause); $whereClause .= "%' "; } if (! empty($GLOBALS['cfg']['Server']['hide_db'])) { $whereClause .= 'AND ' . Util::backquote($columnName) . " NOT REGEXP '" - . $dbi->escapeString($GLOBALS['cfg']['Server']['hide_db']) + . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['hide_db']) . "' "; } @@ -563,7 +555,7 @@ class Node foreach ($GLOBALS['cfg']['Server']['only_db'] as $eachOnlyDb) { $subClauses[] = ' ' . Util::backquote($columnName) . " LIKE '" - . $dbi->escapeString($eachOnlyDb) . "' "; + . $GLOBALS['dbi']->escapeString($eachOnlyDb) . "' "; } $whereClause .= implode('OR', $subClauses) . ') '; @@ -637,18 +629,16 @@ class Node */ public function getNavigationHidingData() { - global $dbi; - $navigationItemsHidingFeature = $this->relation->getRelationParameters()->navigationItemsHidingFeature; if ($navigationItemsHidingFeature !== null) { $navTable = Util::backquote($navigationItemsHidingFeature->database) . '.' . Util::backquote($navigationItemsHidingFeature->navigationHiding); $sqlQuery = 'SELECT `db_name`, COUNT(*) AS `count` FROM ' . $navTable . " WHERE `username`='" - . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'" + . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) . "'" . ' GROUP BY `db_name`'; - return $dbi->fetchResult($sqlQuery, 'db_name', 'count', DatabaseInterface::CONNECT_CONTROL); + return $GLOBALS['dbi']->fetchResult($sqlQuery, 'db_name', 'count', DatabaseInterface::CONNECT_CONTROL); } return null; @@ -662,10 +652,8 @@ class Node */ private function getDataFromInfoSchema($pos, $searchClause) { - global $dbi, $cfg; - - $maxItems = $cfg['FirstLevelNavigationItems']; - if (! $cfg['NavigationTreeEnableGrouping'] || ! $cfg['ShowDatabasesNavigationAsTree']) { + $maxItems = $GLOBALS['cfg']['FirstLevelNavigationItems']; + if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { $query = sprintf( 'SELECT `SCHEMA_NAME` FROM `INFORMATION_SCHEMA`.`SCHEMATA` %sORDER BY `SCHEMA_NAME` LIMIT %d, %d', $this->getWhereClause('SCHEMA_NAME', $searchClause), @@ -673,10 +661,10 @@ class Node $maxItems ); - return $dbi->fetchResult($query); + return $GLOBALS['dbi']->fetchResult($query); } - $dbSeparator = $cfg['NavigationTreeDbSeparator']; + $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; $query = sprintf( 'SELECT `SCHEMA_NAME` FROM `INFORMATION_SCHEMA`.`SCHEMATA`, (SELECT DB_first_level' . ' FROM ( SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, \'%1$s\', 1) DB_first_level' @@ -684,13 +672,13 @@ class Node . ' ORDER BY DB_first_level ASC LIMIT %3$d, %4$d) t2' . ' %2$sAND 1 = LOCATE(CONCAT(DB_first_level, \'%1$s\'),' . ' CONCAT(SCHEMA_NAME, \'%1$s\')) ORDER BY SCHEMA_NAME ASC', - $dbi->escapeString($dbSeparator), + $GLOBALS['dbi']->escapeString($dbSeparator), $this->getWhereClause('SCHEMA_NAME', $searchClause), $pos, $maxItems ); - return $dbi->fetchResult($query); + return $GLOBALS['dbi']->fetchResult($query); } /** @@ -701,11 +689,9 @@ class Node */ private function getDataFromShowDatabases($pos, $searchClause) { - global $dbi, $cfg; - - $maxItems = $cfg['FirstLevelNavigationItems']; - if (! $cfg['NavigationTreeEnableGrouping'] || ! $cfg['ShowDatabasesNavigationAsTree']) { - $handle = $dbi->tryQuery(sprintf( + $maxItems = $GLOBALS['cfg']['FirstLevelNavigationItems']; + if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { + $handle = $GLOBALS['dbi']->tryQuery(sprintf( 'SHOW DATABASES %s', $this->getWhereClause('Database', $searchClause) )); @@ -731,8 +717,8 @@ class Node return $retval; } - $dbSeparator = $cfg['NavigationTreeDbSeparator']; - $handle = $dbi->tryQuery(sprintf( + $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; + $handle = $GLOBALS['dbi']->tryQuery(sprintf( 'SHOW DATABASES %s', $this->getWhereClause('Database', $searchClause) )); @@ -759,7 +745,7 @@ class Node foreach ($prefixes as $prefix) { $subClauses[] = sprintf( ' LOCATE(\'%1$s%2$s\', CONCAT(`Database`, \'%2$s\')) = 1 ', - $dbi->escapeString((string) $prefix), + $GLOBALS['dbi']->escapeString((string) $prefix), $dbSeparator ); } @@ -770,7 +756,7 @@ class Node implode('OR', $subClauses) ); - return $dbi->fetchResult($query); + return $GLOBALS['dbi']->fetchResult($query); } /** @@ -781,14 +767,12 @@ class Node */ private function getDataFromShowDatabasesLike($pos, $searchClause) { - global $dbi, $cfg; - - $maxItems = $cfg['FirstLevelNavigationItems']; - if (! $cfg['NavigationTreeEnableGrouping'] || ! $cfg['ShowDatabasesNavigationAsTree']) { + $maxItems = $GLOBALS['cfg']['FirstLevelNavigationItems']; + if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree']) { $retval = []; $count = 0; foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $handle = $dbi->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); + $handle = $GLOBALS['dbi']->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); if ($handle === false) { continue; } @@ -816,12 +800,12 @@ class Node return $retval; } - $dbSeparator = $cfg['NavigationTreeDbSeparator']; + $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; $retval = []; $prefixMap = []; $total = $pos + $maxItems; foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $handle = $dbi->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); + $handle = $GLOBALS['dbi']->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); if ($handle === false) { continue; } @@ -846,7 +830,7 @@ class Node $prefixes = array_slice(array_keys($prefixMap), $pos); foreach ($this->getDatabasesToSearch($searchClause) as $db) { - $handle = $dbi->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); + $handle = $GLOBALS['dbi']->tryQuery(sprintf('SHOW DATABASES LIKE \'%s\'', $db)); if ($handle === false) { continue; } diff --git a/libraries/classes/Navigation/Nodes/NodeDatabase.php b/libraries/classes/Navigation/Nodes/NodeDatabase.php index ed31ee008a..e7ca4f1f57 100644 --- a/libraries/classes/Navigation/Nodes/NodeDatabase.php +++ b/libraries/classes/Navigation/Nodes/NodeDatabase.php @@ -107,8 +107,6 @@ class NodeDatabase extends Node */ private function getTableOrViewCount($which, $searchClause, $singleItem) { - global $dbi; - $db = $this->realName; if ($which === 'tables') { $condition = 'IN'; @@ -117,7 +115,7 @@ class NodeDatabase extends Node } if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`TABLES` '; $query .= "WHERE `TABLE_SCHEMA`='" . $db . "' "; @@ -126,7 +124,7 @@ class NodeDatabase extends Node $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'TABLE_NAME'); } - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { $query = 'SHOW FULL TABLES FROM '; $query .= Util::backquote($db); @@ -135,7 +133,7 @@ class NodeDatabase extends Node $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'Tables_in_' . $db); } - $retval = $dbi->queryAndGetNumRows($query); + $retval = $GLOBALS['dbi']->queryAndGetNumRows($query); } return $retval; @@ -183,11 +181,9 @@ class NodeDatabase extends Node */ private function getProcedureCount($searchClause, $singleItem) { - global $dbi; - $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`ROUTINES` '; $query .= 'WHERE `ROUTINE_SCHEMA` ' @@ -197,15 +193,15 @@ class NodeDatabase extends Node $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'ROUTINE_NAME'); } - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = "SHOW PROCEDURE STATUS WHERE `Db`='" . $db . "' "; if (! empty($searchClause)) { $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'Name'); } - $retval = $dbi->queryAndGetNumRows($query); + $retval = $GLOBALS['dbi']->queryAndGetNumRows($query); } return $retval; @@ -223,11 +219,9 @@ class NodeDatabase extends Node */ private function getFunctionCount($searchClause, $singleItem) { - global $dbi; - $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`ROUTINES` '; $query .= 'WHERE `ROUTINE_SCHEMA` ' @@ -237,15 +231,15 @@ class NodeDatabase extends Node $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'ROUTINE_NAME'); } - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = "SHOW FUNCTION STATUS WHERE `Db`='" . $db . "' "; if (! empty($searchClause)) { $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'Name'); } - $retval = $dbi->queryAndGetNumRows($query); + $retval = $GLOBALS['dbi']->queryAndGetNumRows($query); } return $retval; @@ -263,11 +257,9 @@ class NodeDatabase extends Node */ private function getEventCount($searchClause, $singleItem) { - global $dbi; - $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); + $db = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`EVENTS` '; $query .= 'WHERE `EVENT_SCHEMA` ' @@ -276,7 +268,7 @@ class NodeDatabase extends Node $query .= 'AND ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'EVENT_NAME'); } - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { $db = Util::backquote($db); $query = 'SHOW EVENTS FROM ' . $db . ' '; @@ -284,7 +276,7 @@ class NodeDatabase extends Node $query .= 'WHERE ' . $this->getWhereClauseForSearch($searchClause, $singleItem, 'Name'); } - $retval = $dbi->queryAndGetNumRows($query); + $retval = $GLOBALS['dbi']->queryAndGetNumRows($query); } return $retval; @@ -304,15 +296,13 @@ class NodeDatabase extends Node $singleItem, $columnName ) { - global $dbi; - $query = ''; if ($singleItem) { $query .= Util::backquote($columnName) . ' = '; - $query .= "'" . $dbi->escapeString($searchClause) . "'"; + $query .= "'" . $GLOBALS['dbi']->escapeString($searchClause) . "'"; } else { $query .= Util::backquote($columnName) . ' LIKE '; - $query .= "'%" . $dbi->escapeString($searchClause) + $query .= "'%" . $GLOBALS['dbi']->escapeString($searchClause) . "%'"; } @@ -381,8 +371,6 @@ class NodeDatabase extends Node */ public function getHiddenItems($type) { - global $dbi; - $db = $this->realName; $relationParameters = $this->relation->getRelationParameters(); if ($relationParameters->navigationItemsHidingFeature === null || $relationParameters->user === null) { @@ -394,9 +382,9 @@ class NodeDatabase extends Node $sqlQuery = 'SELECT `item_name` FROM ' . $navTable . " WHERE `username`='" . $relationParameters->user . "'" . " AND `item_type`='" . $type - . "' AND `db_name`='" . $dbi->escapeString($db) + . "' AND `db_name`='" . $GLOBALS['dbi']->escapeString($db) . "'"; - $result = $dbi->tryQueryAsControlUser($sqlQuery); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sqlQuery); if ($result) { return $result->fetchAllColumn(); } @@ -415,8 +403,6 @@ class NodeDatabase extends Node */ private function getTablesOrViews($which, int $pos, $searchClause) { - global $dbi; - if ($which === 'tables') { $condition = 'IN'; } else { @@ -427,31 +413,31 @@ class NodeDatabase extends Node $retval = []; $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $dbi->escapeString($db); + $escdDb = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT `TABLE_NAME` AS `name` '; $query .= 'FROM `INFORMATION_SCHEMA`.`TABLES` '; $query .= "WHERE `TABLE_SCHEMA`='" . $escdDb . "' "; $query .= 'AND `TABLE_TYPE` ' . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; if (! empty($searchClause)) { $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= $dbi->escapeString($searchClause); + $query .= $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } $query .= 'ORDER BY `TABLE_NAME` ASC '; $query .= 'LIMIT ' . $pos . ', ' . $maxItems; - $retval = $dbi->fetchResult($query); + $retval = $GLOBALS['dbi']->fetchResult($query); } else { $query = ' SHOW FULL TABLES FROM '; $query .= Util::backquote($db); $query .= ' WHERE `Table_type` ' . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; if (! empty($searchClause)) { $query .= 'AND ' . Util::backquote('Tables_in_' . $db); - $query .= " LIKE '%" . $dbi->escapeString($searchClause); + $query .= " LIKE '%" . $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle !== false) { $count = 0; if ($handle->seek($pos)) { @@ -507,13 +493,11 @@ class NodeDatabase extends Node */ private function getRoutines($routineType, $pos, $searchClause) { - global $dbi; - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; $retval = []; $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $dbi->escapeString($db); + $escdDb = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT `ROUTINE_NAME` AS `name` '; $query .= 'FROM `INFORMATION_SCHEMA`.`ROUTINES` '; $query .= 'WHERE `ROUTINE_SCHEMA` ' @@ -521,23 +505,23 @@ class NodeDatabase extends Node $query .= "AND `ROUTINE_TYPE`='" . $routineType . "' "; if (! empty($searchClause)) { $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= $dbi->escapeString($searchClause); + $query .= $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } $query .= 'ORDER BY `ROUTINE_NAME` ASC '; $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems; - $retval = $dbi->fetchResult($query); + $retval = $GLOBALS['dbi']->fetchResult($query); } else { - $escdDb = $dbi->escapeString($db); + $escdDb = $GLOBALS['dbi']->escapeString($db); $query = 'SHOW ' . $routineType . " STATUS WHERE `Db`='" . $escdDb . "' "; if (! empty($searchClause)) { $query .= "AND `Name` LIKE '%"; - $query .= $dbi->escapeString($searchClause); + $query .= $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle !== false) { $count = 0; if ($handle->seek($pos)) { @@ -592,36 +576,34 @@ class NodeDatabase extends Node */ private function getEvents($pos, $searchClause) { - global $dbi; - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; $retval = []; $db = $this->realName; if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $escdDb = $dbi->escapeString($db); + $escdDb = $GLOBALS['dbi']->escapeString($db); $query = 'SELECT `EVENT_NAME` AS `name` '; $query .= 'FROM `INFORMATION_SCHEMA`.`EVENTS` '; $query .= 'WHERE `EVENT_SCHEMA` ' . Util::getCollateForIS() . "='" . $escdDb . "' "; if (! empty($searchClause)) { $query .= "AND `EVENT_NAME` LIKE '%"; - $query .= $dbi->escapeString($searchClause); + $query .= $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } $query .= 'ORDER BY `EVENT_NAME` ASC '; $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems; - $retval = $dbi->fetchResult($query); + $retval = $GLOBALS['dbi']->fetchResult($query); } else { $escdDb = Util::backquote($db); $query = 'SHOW EVENTS FROM ' . $escdDb . ' '; if (! empty($searchClause)) { $query .= "WHERE `Name` LIKE '%"; - $query .= $dbi->escapeString($searchClause); + $query .= $GLOBALS['dbi']->escapeString($searchClause); $query .= "%'"; } - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle !== false) { $count = 0; if ($handle->seek($pos)) { diff --git a/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php b/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php index 8d2b9e5a9e..f68bcc2109 100644 --- a/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php +++ b/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php @@ -24,9 +24,7 @@ class NodeDatabaseContainer extends Node */ public function __construct($name) { - global $dbi; - - $checkUserPrivileges = new CheckUserPrivileges($dbi); + $checkUserPrivileges = new CheckUserPrivileges($GLOBALS['dbi']); $checkUserPrivileges->getPrivileges(); parent::__construct($name, Node::CONTAINER); diff --git a/libraries/classes/Navigation/Nodes/NodeTable.php b/libraries/classes/Navigation/Nodes/NodeTable.php index a80cc58994..9856ac2c27 100644 --- a/libraries/classes/Navigation/Nodes/NodeTable.php +++ b/libraries/classes/Navigation/Nodes/NodeTable.php @@ -83,26 +83,24 @@ class NodeTable extends NodeDatabaseChild */ public function getPresence($type = '', $searchClause = '') { - global $dbi; - $retval = 0; $db = $this->realParent()->realName; $table = $this->realName; switch ($type) { case 'columns': if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); - $table = $dbi->escapeString($table); + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`COLUMNS` '; $query .= "WHERE `TABLE_NAME`='" . $table . "' "; $query .= "AND `TABLE_SCHEMA`='" . $db . "'"; - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { $db = Util::backquote($db); $table = Util::backquote($table); $query = 'SHOW COLUMNS FROM ' . $table . ' FROM ' . $db . ''; - $retval = (int) $dbi->queryAndGetNumRows($query); + $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query); } break; @@ -110,24 +108,24 @@ class NodeTable extends NodeDatabaseChild $db = Util::backquote($db); $table = Util::backquote($table); $query = 'SHOW INDEXES FROM ' . $table . ' FROM ' . $db; - $retval = (int) $dbi->queryAndGetNumRows($query); + $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query); break; case 'triggers': if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); - $table = $dbi->escapeString($table); + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SELECT COUNT(*) '; $query .= 'FROM `INFORMATION_SCHEMA`.`TRIGGERS` '; $query .= 'WHERE `EVENT_OBJECT_SCHEMA` ' . Util::getCollateForIS() . "='" . $db . "' "; $query .= 'AND `EVENT_OBJECT_TABLE` ' . Util::getCollateForIS() . "='" . $table . "'"; - $retval = (int) $dbi->fetchValue($query); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); } else { $db = Util::backquote($db); - $table = $dbi->escapeString($table); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SHOW TRIGGERS FROM ' . $db . " WHERE `Table` = '" . $table . "'"; - $retval = (int) $dbi->queryAndGetNumRows($query); + $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query); } break; @@ -152,8 +150,6 @@ class NodeTable extends NodeDatabaseChild */ public function getData($type, $pos, $searchClause = '') { - global $dbi; - $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; $retval = []; $db = $this->realParent()->realName; @@ -161,8 +157,8 @@ class NodeTable extends NodeDatabaseChild switch ($type) { case 'columns': if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); - $table = $dbi->escapeString($table); + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SELECT `COLUMN_NAME` AS `name` '; $query .= ',`COLUMN_KEY` AS `key` '; $query .= ',`DATA_TYPE` AS `type` '; @@ -173,14 +169,14 @@ class NodeTable extends NodeDatabaseChild $query .= "AND `TABLE_SCHEMA`='" . $db . "' "; $query .= 'ORDER BY `COLUMN_NAME` ASC '; $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems; - $retval = $dbi->fetchResult($query); + $retval = $GLOBALS['dbi']->fetchResult($query); break; } $db = Util::backquote($db); $table = Util::backquote($table); $query = 'SHOW COLUMNS FROM ' . $table . ' FROM ' . $db; - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle === false) { break; } @@ -208,7 +204,7 @@ class NodeTable extends NodeDatabaseChild $db = Util::backquote($db); $table = Util::backquote($table); $query = 'SHOW INDEXES FROM ' . $table . ' FROM ' . $db; - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle === false) { break; } @@ -230,8 +226,8 @@ class NodeTable extends NodeDatabaseChild break; case 'triggers': if (! $GLOBALS['cfg']['Server']['DisableIS']) { - $db = $dbi->escapeString($db); - $table = $dbi->escapeString($table); + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SELECT `TRIGGER_NAME` AS `name` '; $query .= 'FROM `INFORMATION_SCHEMA`.`TRIGGERS` '; $query .= 'WHERE `EVENT_OBJECT_SCHEMA` ' @@ -240,14 +236,14 @@ class NodeTable extends NodeDatabaseChild . Util::getCollateForIS() . "='" . $table . "' "; $query .= 'ORDER BY `TRIGGER_NAME` ASC '; $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems; - $retval = $dbi->fetchResult($query); + $retval = $GLOBALS['dbi']->fetchResult($query); break; } $db = Util::backquote($db); - $table = $dbi->escapeString($table); + $table = $GLOBALS['dbi']->escapeString($table); $query = 'SHOW TRIGGERS FROM ' . $db . " WHERE `Table` = '" . $table . "'"; - $handle = $dbi->tryQuery($query); + $handle = $GLOBALS['dbi']->tryQuery($query); if ($handle === false) { break; } diff --git a/libraries/classes/Normalization.php b/libraries/classes/Normalization.php index c95c94fbc8..319177c0b3 100644 --- a/libraries/classes/Normalization.php +++ b/libraries/classes/Normalization.php @@ -273,11 +273,11 @@ class Normalization { $step = 2; $stepTxt = __('Have a primary key'); - $primary = Index::getPrimary($table, $db); + $primary = Index::getPrimary($this->dbi, $table, $db); $hasPrimaryKey = '0'; $legendText = __('Step 1.') . $step . ' ' . $stepTxt; $extra = ''; - if ($primary !== false) { + if ($primary !== null) { $headText = __('Primary key already exists.'); $subText = __('Taking you to next step…'); $hasPrimaryKey = '1'; @@ -375,8 +375,8 @@ class Normalization . __('Done') . '">' . '<input class="btn btn-secondary" type="submit" value="' . __('No repeating group') . '" onclick="goToStep4();">'; - $primary = Index::getPrimary($table, $db); - $primarycols = $primary === false ? [] : $primary->getColumns(); + $primary = Index::getPrimary($this->dbi, $table, $db); + $primarycols = $primary === null ? [] : $primary->getColumns(); $pk = []; foreach ($primarycols as $col) { $pk[] = $col->getName(); @@ -402,8 +402,8 @@ class Normalization public function getHtmlFor2NFstep1($db, $table) { $legendText = __('Step 2.') . '1 ' . __('Find partial dependencies'); - $primary = Index::getPrimary($table, $db); - $primarycols = $primary === false ? [] : $primary->getColumns(); + $primary = Index::getPrimary($this->dbi, $table, $db); + $primarycols = $primary === null ? [] : $primary->getColumns(); $pk = []; $subText = ''; $selectPkForm = ''; @@ -626,8 +626,8 @@ class Normalization continue; } - $primary = Index::getPrimary($table, $db); - $primarycols = $primary === false ? [] : $primary->getColumns(); + $primary = Index::getPrimary($this->dbi, $table, $db); + $primarycols = $primary === null ? [] : $primary->getColumns(); $pk = []; foreach ($primarycols as $col) { $pk[] = $col->getName(); @@ -878,8 +878,8 @@ class Normalization ); $cnt = 0; foreach ($tables as $table) { - $primary = Index::getPrimary($table, $db); - $primarycols = $primary === false ? [] : $primary->getColumns(); + $primary = Index::getPrimary($this->dbi, $table, $db); + $primarycols = $primary === null ? [] : $primary->getColumns(); $selectTdForm = ''; $pk = []; foreach ($primarycols as $col) { @@ -938,52 +938,6 @@ class Normalization } /** - * get html for options to normalize table - * - * @return string HTML - */ - public function getHtmlForNormalizeTable() - { - $htmlOutput = '<form method="post" action="' . Url::getFromRoute('/normalization') - . '" name="normalize" ' - . 'id="normalizeTable" ' - . '>' - . Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) - . '<input type="hidden" name="step1" value="1">'; - $htmlOutput .= '<fieldset class="pma-fieldset">'; - $htmlOutput .= '<legend>' - . __('Improve table structure (Normalization):') . '</legend>'; - $htmlOutput .= '<h3>' . __('Select up to what step you want to normalize') - . '</h3>'; - - $htmlOutput .= '<div><input type="radio" name="normalizeTo" id="normalizeToRadio1" value="1nf" checked>'; - $htmlOutput .= ' <label for="normalizeToRadio1">'; - $htmlOutput .= __('First step of normalization (1NF)'); - $htmlOutput .= '</label></div>'; - - $htmlOutput .= '<div><input type="radio" name="normalizeTo" id="normalizeToRadio2" value="2nf">'; - $htmlOutput .= ' <label for="normalizeToRadio2">'; - $htmlOutput .= __('Second step of normalization (1NF+2NF)'); - $htmlOutput .= '</label></div>'; - - $htmlOutput .= '<div><input type="radio" name="normalizeTo" id="normalizeToRadio3" value="3nf">'; - $htmlOutput .= ' <label for="normalizeToRadio3">'; - $htmlOutput .= __('Third step of normalization (1NF+2NF+3NF)'); - $htmlOutput .= '</label></div>'; - - $htmlOutput .= '</fieldset><fieldset class="pma-fieldset tblFooters">' - . "<span class='float-start'>" . __( - 'Hint: Please follow the procedure carefully in order to obtain correct normalization' - ) . '</span>' - . '<input class="btn btn-primary" type="submit" name="submit_normalize" value="' . __('Go') . '">' - . '</fieldset>' - . '</form>' - . '</div>'; - - return $htmlOutput; - } - - /** * find all the possible partial dependencies based on data in the table. * * @param string $table current table @@ -1006,8 +960,8 @@ class Normalization . Util::backquote($table) . ' LIMIT 500) as dt;' ); $totalRows = $totalRowsRes[0]; - $primary = Index::getPrimary($table, $db); - $primarycols = $primary === false ? [] : $primary->getColumns(); + $primary = Index::getPrimary($this->dbi, $table, $db); + $primarycols = $primary === null ? [] : $primary->getColumns(); $pk = []; foreach ($primarycols as $col) { $pk[] = Util::backquote($col->getName()); diff --git a/libraries/classes/Operations.php b/libraries/classes/Operations.php index 164a1f702f..4c86cf7866 100644 --- a/libraries/classes/Operations.php +++ b/libraries/classes/Operations.php @@ -5,6 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Database\Events; +use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\Triggers; +use PhpMyAdmin\Dbal\DatabaseName; use PhpMyAdmin\Engines\Innodb; use PhpMyAdmin\Partitioning\Partition; use PhpMyAdmin\Plugins\Export\ExportSql; @@ -52,39 +56,39 @@ class Operations * * @param string $db database name */ - public function runProcedureAndFunctionDefinitions($db): void + public function runProcedureAndFunctionDefinitions($db, DatabaseName $newDatabaseName): void { - $procedure_names = $this->dbi->getProceduresOrFunctions($db, 'PROCEDURE'); + $procedure_names = Routines::getProcedureNames($this->dbi, $db); if ($procedure_names) { foreach ($procedure_names as $procedure_name) { $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition($db, 'PROCEDURE', $procedure_name); + $tmp_query = Routines::getProcedureDefinition($this->dbi, $db, $procedure_name); if ($tmp_query === null) { continue; } // collect for later display $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); + $this->dbi->selectDb($newDatabaseName); $this->dbi->query($tmp_query); } } - $function_names = $this->dbi->getProceduresOrFunctions($db, 'FUNCTION'); + $function_names = Routines::getFunctionNames($this->dbi, $db); if (! $function_names) { return; } foreach ($function_names as $function_name) { $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition($db, 'FUNCTION', $function_name); + $tmp_query = Routines::getFunctionDefinition($this->dbi, $db, $function_name); if ($tmp_query === null) { continue; } // collect for later display $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); + $this->dbi->selectDb($newDatabaseName); $this->dbi->query($tmp_query); } } @@ -92,10 +96,10 @@ class Operations /** * Create database before copy */ - public function createDbBeforeCopy(): void + public function createDbBeforeCopy(DatabaseName $newDatabaseName): void { $local_query = 'CREATE DATABASE IF NOT EXISTS ' - . Util::backquote($_POST['newname']); + . Util::backquote($newDatabaseName); if (isset($_POST['db_collation'])) { $local_query .= ' DEFAULT' . Util::getCharsetQueryPart($_POST['db_collation'] ?? ''); @@ -133,7 +137,8 @@ class Operations public function getViewsAndCreateSqlViewStandIn( array $tables_full, $export_sql_plugin, - $db + $db, + DatabaseName $newDatabaseName ) { $views = []; foreach (array_keys($tables_full) as $each_table) { @@ -147,7 +152,7 @@ class Operations // If view exists, and 'add drop view' is selected: Drop it! if ($_POST['what'] !== 'nocopy' && isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true') { $drop_query = 'DROP VIEW IF EXISTS ' - . Util::backquote($_POST['newname']) . '.' + . Util::backquote($newDatabaseName) . '.' . Util::backquote($each_table); $this->dbi->query($drop_query); @@ -156,8 +161,8 @@ class Operations $views[] = $each_table; // Create stand-in definition to resolve view dependencies - $sql_view_standin = $export_sql_plugin->getTableDefStandIn($db, $each_table, "\n"); - $this->dbi->selectDb($_POST['newname']); + $sql_view_standin = $export_sql_plugin->getTableDefStandIn($db, $each_table); + $this->dbi->selectDb($newDatabaseName); $this->dbi->query($sql_view_standin); $GLOBALS['sql_query'] .= "\n" . $sql_view_standin; } @@ -174,7 +179,7 @@ class Operations * * @return array SQL queries for the constraints */ - public function copyTables(array $tables_full, $move, $db) + public function copyTables(array $tables_full, $move, $db, DatabaseName $newDatabaseName) { $sqlContraints = []; foreach (array_keys($tables_full) as $each_table) { @@ -205,13 +210,13 @@ class Operations // keep the triggers from the original db+table // (third param is empty because delimiters are only intended // for importing via the mysql client or our Import feature) - $triggers = $this->dbi->getTriggers($db, (string) $each_table, ''); + $triggers = Triggers::getDetails($this->dbi, $db, (string) $each_table, ''); if ( ! Table::moveCopy( $db, $each_table, - $_POST['newname'], + $newDatabaseName->getName(), $each_table, ($this_what ?? 'data'), $move, @@ -225,7 +230,7 @@ class Operations // apply the triggers to the destination db+table if ($triggers) { - $this->dbi->selectDb($_POST['newname']); + $this->dbi->selectDb($newDatabaseName); foreach ($triggers as $trigger) { $this->dbi->query($trigger['create']); $GLOBALS['sql_query'] .= "\n" . $trigger['create'] . ';'; @@ -253,7 +258,7 @@ class Operations * * @param string $db database name */ - public function runEventDefinitionsForDb($db): void + public function runEventDefinitionsForDb($db, DatabaseName $newDatabaseName): void { $event_names = $this->dbi->fetchResult( 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' @@ -265,10 +270,10 @@ class Operations foreach ($event_names as $event_name) { $this->dbi->selectDb($db); - $tmp_query = $this->dbi->getDefinition($db, 'EVENT', $event_name); + $tmp_query = Events::getDefinition($this->dbi, $db, $event_name); // collect for later display $GLOBALS['sql_query'] .= "\n" . $tmp_query; - $this->dbi->selectDb($_POST['newname']); + $this->dbi->selectDb($newDatabaseName); $this->dbi->query($tmp_query); } } @@ -280,14 +285,14 @@ class Operations * @param bool $move whether database name is empty or not * @param string $db database name */ - public function handleTheViews(array $views, $move, $db): void + public function handleTheViews(array $views, $move, $db, DatabaseName $newDatabaseName): void { // Add DROP IF EXIST to CREATE VIEW query, to remove stand-in VIEW that was created earlier. foreach ($views as $view) { $copying_succeeded = Table::moveCopy( $db, $view, - $_POST['newname'], + $newDatabaseName->getName(), $view, 'structure', $move, @@ -304,10 +309,9 @@ class Operations /** * Adjust the privileges after Renaming the db * - * @param string $oldDb Database name before renaming - * @param string $newname New Database name requested + * @param string $oldDb Database name before renaming */ - public function adjustPrivilegesMoveDb($oldDb, $newname): void + public function adjustPrivilegesMoveDb($oldDb, DatabaseName $newDatabaseName): void { if ( ! $GLOBALS['db_priv'] || ! $GLOBALS['table_priv'] @@ -318,30 +322,30 @@ class Operations } $this->dbi->selectDb('mysql'); - $newname = str_replace('_', '\_', $newname); + $newName = str_replace('_', '\_', $newDatabaseName->getName()); $oldDb = str_replace('_', '\_', $oldDb); // For Db specific privileges $query_db_specific = 'UPDATE ' . Util::backquote('db') - . 'SET Db = \'' . $this->dbi->escapeString($newname) + . 'SET Db = \'' . $this->dbi->escapeString($newName) . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; $this->dbi->query($query_db_specific); // For table specific privileges $query_table_specific = 'UPDATE ' . Util::backquote('tables_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) + . 'SET Db = \'' . $this->dbi->escapeString($newName) . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; $this->dbi->query($query_table_specific); // For column specific privileges $query_col_specific = 'UPDATE ' . Util::backquote('columns_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) + . 'SET Db = \'' . $this->dbi->escapeString($newName) . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; $this->dbi->query($query_col_specific); // For procedures specific privileges $query_proc_specific = 'UPDATE ' . Util::backquote('procs_priv') - . 'SET Db = \'' . $this->dbi->escapeString($newname) + . 'SET Db = \'' . $this->dbi->escapeString($newName) . '\' where Db = \'' . $this->dbi->escapeString($oldDb) . '\';'; $this->dbi->query($query_proc_specific); @@ -353,10 +357,9 @@ class Operations /** * Adjust the privileges after Copying the db * - * @param string $oldDb Database name before copying - * @param string $newname New Database name requested + * @param string $oldDb Database name before copying */ - public function adjustPrivilegesCopyDb($oldDb, $newname): void + public function adjustPrivilegesCopyDb($oldDb, DatabaseName $newDatabaseName): void { if ( ! $GLOBALS['db_priv'] || ! $GLOBALS['table_priv'] @@ -367,7 +370,7 @@ class Operations } $this->dbi->selectDb('mysql'); - $newname = str_replace('_', '\_', $newname); + $newName = str_replace('_', '\_', $newDatabaseName->getName()); $oldDb = str_replace('_', '\_', $oldDb); $query_db_specific_old = 'SELECT * FROM ' @@ -378,7 +381,7 @@ class Operations foreach ($old_privs_db as $old_priv) { $newDb_db_privs_query = 'INSERT INTO ' . Util::backquote('db') - . ' VALUES("' . $old_priv[0] . '", "' . $newname . '"'; + . ' VALUES("' . $old_priv[0] . '", "' . $newName . '"'; $privCount = count($old_priv); for ($i = 2; $i < $privCount; $i++) { $newDb_db_privs_query .= ', "' . $old_priv[$i] . '"'; @@ -399,7 +402,7 @@ class Operations foreach ($old_privs_table as $old_priv) { $newDb_table_privs_query = 'INSERT INTO ' . Util::backquote( 'tables_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' + ) . ' VALUES("' . $old_priv[0] . '", "' . $newName . '", "' . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "' . $old_priv[7] . '");'; @@ -417,7 +420,7 @@ class Operations foreach ($old_privs_col as $old_priv) { $newDb_col_privs_query = 'INSERT INTO ' . Util::backquote( 'columns_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' + ) . ' VALUES("' . $old_priv[0] . '", "' . $newName . '", "' . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '");'; @@ -434,7 +437,7 @@ class Operations foreach ($old_privs_proc as $old_priv) { $newDb_proc_privs_query = 'INSERT INTO ' . Util::backquote( 'procs_priv' - ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "' + ) . ' VALUES("' . $old_priv[0] . '", "' . $newName . '", "' . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4] . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "' . $old_priv[7] . '");'; @@ -452,9 +455,9 @@ class Operations * * @param array $sqlConstratints array of sql constraints for the database */ - public function createAllAccumulatedConstraints(array $sqlConstratints): void + public function createAllAccumulatedConstraints(array $sqlConstratints, DatabaseName $newDatabaseName): void { - $this->dbi->selectDb($_POST['newname']); + $this->dbi->selectDb($newDatabaseName); foreach ($sqlConstratints as $one_query) { $this->dbi->query($one_query); // and prepare to display them @@ -468,9 +471,9 @@ class Operations * @param bool $_error whether table rename/copy or not * @param string $db database name */ - public function duplicateBookmarks($_error, $db): void + public function duplicateBookmarks($_error, $db, DatabaseName $newDatabaseName): void { - if ($_error || $db == $_POST['newname']) { + if ($_error || $db === $newDatabaseName->getName()) { return; } @@ -480,7 +483,7 @@ class Operations 'query', ]; $where_fields = ['dbase' => $db]; - $new_fields = ['dbase' => $_POST['newname']]; + $new_fields = ['dbase' => $newDatabaseName->getName()]; Table::duplicateInfo('bookmarkwork', 'bookmark', $get_fields, $where_fields, $new_fields); } @@ -549,8 +552,6 @@ class Operations */ public function getPartitionMaintenanceChoices(): array { - global $db, $table; - $choices = [ 'ANALYZE' => __('Analyze'), 'CHECK' => __('Check'), @@ -560,7 +561,7 @@ class Operations 'TRUNCATE' => __('Truncate'), ]; - $partitionMethod = Partition::getPartitionMethod($db, $table); + $partitionMethod = Partition::getPartitionMethod($GLOBALS['db'], $GLOBALS['table']); // add COALESCE or DROP option to choices array depending on Partition method if ( @@ -587,34 +588,32 @@ class Operations array $urlParams, $hasRelationFeature ): array { - global $db, $table; - if (! $hasRelationFeature) { return []; } $foreigners = []; - $this->dbi->selectDb($db); - $foreign = $this->relation->getForeigners($db, $table, '', 'internal'); + $this->dbi->selectDb($GLOBALS['db']); + $foreign = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'internal'); foreach ($foreign as $master => $arr) { $joinQuery = 'SELECT ' - . Util::backquote($table) . '.*' - . ' FROM ' . Util::backquote($table) + . Util::backquote($GLOBALS['table']) . '.*' + . ' FROM ' . Util::backquote($GLOBALS['table']) . ' LEFT JOIN ' . Util::backquote($arr['foreign_db']) . '.' . Util::backquote($arr['foreign_table']); - if ($arr['foreign_table'] == $table) { - $foreignTable = $table . '1'; + if ($arr['foreign_table'] == $GLOBALS['table']) { + $foreignTable = $GLOBALS['table'] . '1'; $joinQuery .= ' AS ' . Util::backquote($foreignTable); } else { $foreignTable = $arr['foreign_table']; } $joinQuery .= ' ON ' - . Util::backquote($table) . '.' + . Util::backquote($GLOBALS['table']) . '.' . Util::backquote($master) . ' = ' . Util::backquote($arr['foreign_db']) @@ -627,7 +626,7 @@ class Operations . Util::backquote($foreignTable) . '.' . Util::backquote($arr['foreign_field']) . ' IS NULL AND ' - . Util::backquote($table) . '.' + . Util::backquote($GLOBALS['table']) . '.' . Util::backquote($master) . ' IS NOT NULL'; $thisUrlParams = array_merge( @@ -676,7 +675,7 @@ class Operations $transactional, $tbl_collation ) { - global $auto_increment; + $GLOBALS['auto_increment'] = $GLOBALS['auto_increment'] ?? null; $table_alters = []; @@ -728,8 +727,8 @@ class Operations if ( $pma_table->isEngine(['MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB']) && ! empty($_POST['new_auto_increment']) - && (! isset($auto_increment) - || $_POST['new_auto_increment'] !== $auto_increment) + && (! isset($GLOBALS['auto_increment']) + || $_POST['new_auto_increment'] !== $GLOBALS['auto_increment']) && $_POST['new_auto_increment'] !== $_POST['hidden_auto_increment'] ) { $table_alters[] = 'auto_increment = ' diff --git a/libraries/classes/ParseAnalyze.php b/libraries/classes/ParseAnalyze.php index 1a01f885ac..083ceae893 100644 --- a/libraries/classes/ParseAnalyze.php +++ b/libraries/classes/ParseAnalyze.php @@ -23,26 +23,26 @@ class ParseAnalyze * @param string $sqlQuery the query to parse * @param string $db the current database * - * @return array + * @return array<int, StatementInfo|string> + * @psalm-return array{StatementInfo, string, string} */ - public static function sqlQuery($sqlQuery, $db) + public static function sqlQuery(string $sqlQuery, string $db): array { // @todo: move to returned results (also in all the calling chain) $GLOBALS['unparsed_sql'] = $sqlQuery; - // Get details about the SQL query. - $analyzedSqlResults = Query::getAll($sqlQuery); + $info = Query::getAll($sqlQuery); $table = ''; // If the targeted table (and database) are different than the ones that is // currently browsed, edit `$db` and `$table` to match them so other elements // (page headers, links, navigation panel) can be updated properly. - if (! empty($analyzedSqlResults['select_tables'])) { + if (! empty($info['select_tables'])) { // Previous table and database name is stored to check if it changed. $previousDb = $db; - if (count($analyzedSqlResults['select_tables']) > 1) { + if (count($info['select_tables']) > 1) { /** * @todo if there are more than one table name in the Select: @@ -52,25 +52,21 @@ class ParseAnalyze */ $table = ''; } else { - $table = $analyzedSqlResults['select_tables'][0][0]; - if (! empty($analyzedSqlResults['select_tables'][0][1])) { - $db = $analyzedSqlResults['select_tables'][0][1]; + $table = $info['select_tables'][0][0] ?? ''; + if (isset($info['select_tables'][0][1])) { + $db = $info['select_tables'][0][1]; } } - // There is no point checking if a reload is required if we already decided + // There is no point checking if a reloading is required if we already decided // to reload. Also, no reload is required for AJAX requests. $response = ResponseRenderer::getInstance(); - if (empty($analyzedSqlResults['reload']) && ! $response->isAjax()) { + if (empty($info['reload']) && ! $response->isAjax()) { // NOTE: Database names are case-insensitive. - $analyzedSqlResults['reload'] = strcasecmp($db, $previousDb) != 0; + $info['reload'] = strcasecmp($db, $previousDb) !== 0; } } - return [ - $analyzedSqlResults, - $db, - $table, - ]; + return [StatementInfo::fromArray($info), $db, $table]; } } diff --git a/libraries/classes/Partitioning/Partition.php b/libraries/classes/Partitioning/Partition.php index 21c0bf1c91..4caee2cb4b 100644 --- a/libraries/classes/Partitioning/Partition.php +++ b/libraries/classes/Partitioning/Partition.php @@ -144,13 +144,11 @@ class Partition extends SubPartition */ public static function getPartitions($db, $table) { - global $dbi; - if (self::havePartitioning()) { - $result = $dbi->fetchResult( + $result = $GLOBALS['dbi']->fetchResult( 'SELECT * FROM `information_schema`.`PARTITIONS`' - . " WHERE `TABLE_SCHEMA` = '" . $dbi->escapeString($db) - . "' AND `TABLE_NAME` = '" . $dbi->escapeString($table) . "'" + . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) + . "' AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" ); if ($result) { $partitionMap = []; @@ -191,13 +189,11 @@ class Partition extends SubPartition */ public static function getPartitionNames($db, $table) { - global $dbi; - if (self::havePartitioning()) { - return $dbi->fetchResult( + return $GLOBALS['dbi']->fetchResult( 'SELECT DISTINCT `PARTITION_NAME` FROM `information_schema`.`PARTITIONS`' - . " WHERE `TABLE_SCHEMA` = '" . $dbi->escapeString($db) - . "' AND `TABLE_NAME` = '" . $dbi->escapeString($table) . "'" + . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) + . "' AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" ); } @@ -214,13 +210,11 @@ class Partition extends SubPartition */ public static function getPartitionMethod($db, $table) { - global $dbi; - if (self::havePartitioning()) { - $partition_method = $dbi->fetchResult( + $partition_method = $GLOBALS['dbi']->fetchResult( 'SELECT `PARTITION_METHOD` FROM `information_schema`.`PARTITIONS`' - . " WHERE `TABLE_SCHEMA` = '" . $dbi->escapeString($db) . "'" - . " AND `TABLE_NAME` = '" . $dbi->escapeString($table) . "'" + . " WHERE `TABLE_SCHEMA` = '" . $GLOBALS['dbi']->escapeString($db) . "'" + . " AND `TABLE_NAME` = '" . $GLOBALS['dbi']->escapeString($table) . "'" . ' LIMIT 1' ); if (! empty($partition_method)) { @@ -240,21 +234,19 @@ class Partition extends SubPartition */ public static function havePartitioning(): bool { - global $dbi; - static $have_partitioning = false; static $already_checked = false; if (! $already_checked) { - if ($dbi->getVersion() < 50600) { - if ($dbi->fetchValue('SELECT @@have_partitioning;')) { + if ($GLOBALS['dbi']->getVersion() < 50600) { + if ($GLOBALS['dbi']->fetchValue('SELECT @@have_partitioning;')) { $have_partitioning = true; } - } elseif ($dbi->getVersion() >= 80000) { + } elseif ($GLOBALS['dbi']->getVersion() >= 80000) { $have_partitioning = true; } else { // see https://dev.mysql.com/doc/refman/5.6/en/partitioning.html - $plugins = $dbi->fetchResult('SHOW PLUGINS'); + $plugins = $GLOBALS['dbi']->fetchResult('SHOW PLUGINS'); foreach ($plugins as $value) { if ($value['Name'] === 'partition') { $have_partitioning = true; diff --git a/libraries/classes/Plugins.php b/libraries/classes/Plugins.php index 3fc83de55b..6b5077ac1f 100644 --- a/libraries/classes/Plugins.php +++ b/libraries/classes/Plugins.php @@ -59,9 +59,7 @@ class Plugins */ public static function getPlugin(string $type, string $format, $param = null): ?object { - global $plugin_param; - - $plugin_param = $param; + $GLOBALS['plugin_param'] = $param; $pluginType = mb_strtoupper($type[0]) . mb_strtolower(mb_substr($type, 1)); $pluginFormat = mb_strtoupper($format[0]) . mb_strtolower(mb_substr($format, 1)); $class = sprintf('PhpMyAdmin\\Plugins\\%s\\%s%s', $pluginType, $pluginType, $pluginFormat); @@ -69,39 +67,51 @@ class Plugins return null; } + if ($type === 'export') { + /** + * @psalm-suppress InvalidArrayOffset, MixedAssignment, MixedMethodCall + */ + return new $class( + $GLOBALS['containerBuilder']->get('relation'), + $GLOBALS['containerBuilder']->get('export'), + $GLOBALS['containerBuilder']->get('transformations') + ); + } + return new $class(); } /** * @param string $type server|database|table|raw + * @psalm-param 'server'|'database'|'table'|'raw' $type * * @return ExportPlugin[] + * @psalm-return list<ExportPlugin> */ public static function getExport(string $type, bool $singleTable): array { - global $plugin_param; - - $plugin_param = ['export_type' => $type, 'single_table' => $singleTable]; + $GLOBALS['plugin_param'] = ['export_type' => $type, 'single_table' => $singleTable]; return self::getPlugins('Export'); } /** * @param string $type server|database|table + * @psalm-param 'server'|'database'|'table' $type * * @return ImportPlugin[] + * @psalm-return list<ImportPlugin> */ public static function getImport(string $type): array { - global $plugin_param; - - $plugin_param = $type; + $GLOBALS['plugin_param'] = $type; return self::getPlugins('Import'); } /** * @return SchemaPlugin[] + * @psalm-return list<SchemaPlugin> */ public static function getSchema(): array { @@ -115,6 +125,11 @@ class Plugins * @psalm-param 'Export'|'Import'|'Schema' $type * * @return Plugin[] list of plugin instances + * @psalm-return ( + * $type is 'Export' + * ? list<ExportPlugin> + * : ($type is 'Import' ? list<ImportPlugin> : list<SchemaPlugin>) + * ) */ private static function getPlugins(string $type): array { @@ -141,7 +156,17 @@ class Plugins continue; } - $plugins[] = new $class(); + if ($type === 'Export' && is_subclass_of($class, ExportPlugin::class)) { + $plugins[] = new $class( + $GLOBALS['containerBuilder']->get('relation'), + $GLOBALS['containerBuilder']->get('export'), + $GLOBALS['containerBuilder']->get('transformations') + ); + } elseif ($type === 'Import' && is_subclass_of($class, ImportPlugin::class)) { + $plugins[] = new $class(); + } elseif ($type === 'Schema' && is_subclass_of($class, SchemaPlugin::class)) { + $plugins[] = new $class(); + } } usort($plugins, static function (Plugin $plugin1, Plugin $plugin2): int { @@ -181,7 +206,7 @@ class Plugins isset($_GET[$opt]) || ! isset($_GET['repopulate']) && ((! empty($GLOBALS['timeout_passed']) && isset($_REQUEST[$opt])) - || ! empty($GLOBALS['cfg'][$section][$opt])) + || ! empty($GLOBALS['cfg'][$section][$opt])) ) { return ' checked="checked"'; } @@ -375,7 +400,7 @@ class Plugins * Get HTML for properties items * * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin + * $GLOBALS['cfg'][$section] for plugin * @param string $plugin_name unique plugin name * @param OptionsPropertyItem $propertyItem Property item * @psalm-param 'Export'|'Import'|'Schema' $section @@ -394,14 +419,14 @@ class Plugins $ret .= '<li class="list-group-item">' . "\n"; $ret .= '<div class="form-check form-switch">' . "\n"; $ret .= '<input class="form-check-input" type="checkbox" role="switch" name="' . $plugin_name . '_' - . $propertyItem->getName() . '"' - . ' value="something" id="checkbox_' . $plugin_name . '_' - . $propertyItem->getName() . '"' - . ' ' - . self::checkboxCheck( - $section, - $plugin_name . '_' . $propertyItem->getName() - ); + . $propertyItem->getName() . '"' + . ' value="something" id="checkbox_' . $plugin_name . '_' + . $propertyItem->getName() . '"' + . ' ' + . self::checkboxCheck( + $section, + $plugin_name . '_' . $propertyItem->getName() + ); if ($propertyItem->getForce() != null) { // Same code is also few lines lower, update both if needed @@ -416,19 +441,19 @@ class Plugins $ret .= '>'; $ret .= '<label class="form-check-label" for="checkbox_' . $plugin_name . '_' - . $propertyItem->getName() . '">' - . self::getString($propertyItem->getText()) . '</label></div>'; + . $propertyItem->getName() . '">' + . self::getString($propertyItem->getText()) . '</label></div>'; break; case DocPropertyItem::class: echo DocPropertyItem::class; break; case HiddenPropertyItem::class: $ret .= '<li class="list-group-item"><input type="hidden" name="' . $plugin_name . '_' - . $propertyItem->getName() . '"' - . ' value="' . self::getDefault( - $section, - $plugin_name . '_' . $propertyItem->getName() - ) + . $propertyItem->getName() . '"' + . ' value="' . self::getDefault( + $section, + $plugin_name . '_' . $propertyItem->getName() + ) . '"></li>'; break; case MessageOnlyPropertyItem::class: @@ -458,8 +483,8 @@ class Plugins } $ret .= '><label class="form-check-label" for="radio_' . $plugin_name . '_' - . $pitem->getName() . '_' . $key . '">' - . self::getString($val) . '</label></div>'; + . $pitem->getName() . '_' . $key . '">' + . self::getString($val) . '</label></div>'; } $ret .= '</li>'; @@ -472,12 +497,12 @@ class Plugins $pitem = $propertyItem; $ret .= '<li class="list-group-item">' . "\n"; $ret .= '<label for="select_' . $plugin_name . '_' - . $pitem->getName() . '" class="form-label">' - . self::getString($pitem->getText()) . '</label>'; + . $pitem->getName() . '" class="form-label">' + . self::getString($pitem->getText()) . '</label>'; $ret .= '<select class="form-select" name="' . $plugin_name . '_' - . $pitem->getName() . '"' - . ' id="select_' . $plugin_name . '_' - . $pitem->getName() . '">'; + . $pitem->getName() . '"' + . ' id="select_' . $plugin_name . '_' + . $pitem->getName() . '">'; $default = self::getDefault( $section, $plugin_name . '_' . $pitem->getName() @@ -500,22 +525,22 @@ class Plugins $pitem = $propertyItem; $ret .= '<li class="list-group-item">' . "\n"; $ret .= '<label for="text_' . $plugin_name . '_' - . $pitem->getName() . '" class="form-label">' - . self::getString($pitem->getText()) . '</label>'; + . $pitem->getName() . '" class="form-label">' + . self::getString($pitem->getText()) . '</label>'; $ret .= '<input class="form-control" type="text" name="' . $plugin_name . '_' - . $pitem->getName() . '"' - . ' value="' . self::getDefault( - $section, - $plugin_name . '_' . $pitem->getName() - ) . '"' + . $pitem->getName() . '"' + . ' value="' . self::getDefault( + $section, + $plugin_name . '_' . $pitem->getName() + ) . '"' . ' id="text_' . $plugin_name . '_' . $pitem->getName() . '"' . ($pitem->getSize() != null - ? ' size="' . $pitem->getSize() . '"' - : '') + ? ' size="' . $pitem->getSize() . '"' + : '') . ($pitem->getLen() != null - ? ' maxlength="' . $pitem->getLen() . '"' - : '') + ? ' maxlength="' . $pitem->getLen() . '"' + : '') . '>'; break; case NumberPropertyItem::class: @@ -597,15 +622,14 @@ class Plugins public static function getAuthPlugin(): AuthenticationPlugin { - global $cfg; - /** @psalm-var class-string $class */ - $class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($cfg['Server']['auth_type'])); + $class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' + . ucfirst(strtolower($GLOBALS['cfg']['Server']['auth_type'])); if (! class_exists($class)) { Core::fatalError( __('Invalid authentication method set in configuration:') - . ' ' . $cfg['Server']['auth_type'] + . ' ' . $GLOBALS['cfg']['Server']['auth_type'] ); } diff --git a/libraries/classes/Plugins/Auth/AuthenticationConfig.php b/libraries/classes/Plugins/Auth/AuthenticationConfig.php index 6f814a7d70..96bb762989 100644 --- a/libraries/classes/Plugins/Auth/AuthenticationConfig.php +++ b/libraries/classes/Plugins/Auth/AuthenticationConfig.php @@ -73,18 +73,15 @@ class AuthenticationConfig extends AuthenticationPlugin */ public function showFailure($failure): void { - global $dbi; - parent::showFailure($failure); - $conn_error = $dbi->getError(); + $conn_error = $GLOBALS['dbi']->getError(); if (! $conn_error) { $conn_error = __('Cannot connect: invalid settings.'); } /* HTML header */ $response = ResponseRenderer::getInstance(); - $response->getFooter() - ->setMinimal(); + $response->setMinimalFooter(); $header = $response->getHeader(); $header->setBodyId('loginform'); $header->setTitle(__('Access denied!')); diff --git a/libraries/classes/Plugins/Auth/AuthenticationCookie.php b/libraries/classes/Plugins/Auth/AuthenticationCookie.php index e083ddf19a..c468223232 100644 --- a/libraries/classes/Plugins/Auth/AuthenticationCookie.php +++ b/libraries/classes/Plugins/Auth/AuthenticationCookie.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Auth; +use PhpMyAdmin\Common; use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\LanguageManager; @@ -63,7 +64,7 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function showLoginForm(): bool { - global $conn_error, $route; + $GLOBALS['conn_error'] = $GLOBALS['conn_error'] ?? null; $response = ResponseRenderer::getInstance(); @@ -126,8 +127,8 @@ class AuthenticationCookie extends AuthenticationPlugin $errorMessages = ''; // Show error message - if (! empty($conn_error)) { - $errorMessages = Message::rawError((string) $conn_error)->getDisplay(); + if (! empty($GLOBALS['conn_error'])) { + $errorMessages = Message::rawError((string) $GLOBALS['conn_error'])->getDisplay(); } elseif (isset($_GET['session_expired']) && intval($_GET['session_expired']) == 1) { $errorMessages = Message::rawError( __('Your session has expired. Please log in again.') @@ -147,9 +148,7 @@ class AuthenticationCookie extends AuthenticationPlugin } $_form_params = []; - if (isset($route)) { - $_form_params['route'] = $route; - } + $_form_params['route'] = Common::getRequest()->getRoute(); if (strlen($GLOBALS['db'])) { $_form_params['db'] = $GLOBALS['db']; @@ -227,7 +226,7 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function readCredentials(): bool { - global $conn_error; + $GLOBALS['conn_error'] = $GLOBALS['conn_error'] ?? null; // Initialization /** @@ -249,7 +248,9 @@ class AuthenticationCookie extends AuthenticationPlugin && ! empty($GLOBALS['cfg']['CaptchaLoginPublicKey']) ) { if (empty($_POST[$GLOBALS['cfg']['CaptchaResponseParam']])) { - $conn_error = __('Missing reCAPTCHA verification, maybe it has been blocked by adblock?'); + $GLOBALS['conn_error'] = __( + 'Missing reCAPTCHA verification, maybe it has been blocked by adblock?' + ); return false; } @@ -284,9 +285,9 @@ class AuthenticationCookie extends AuthenticationPlugin $codes = $resp->getErrorCodes(); if (in_array('invalid-json', $codes)) { - $conn_error = __('Failed to connect to the reCAPTCHA service!'); + $GLOBALS['conn_error'] = __('Failed to connect to the reCAPTCHA service!'); } else { - $conn_error = __('Entered captcha is wrong, try again!'); + $GLOBALS['conn_error'] = __('Entered captcha is wrong, try again!'); } return false; @@ -298,7 +299,7 @@ class AuthenticationCookie extends AuthenticationPlugin $password = $_POST['pma_password'] ?? ''; if (strlen($password) >= 1000) { - $conn_error = __('Your password is too long. To prevent denial-of-service attacks, ' . + $GLOBALS['conn_error'] = __('Your password is too long. To prevent denial-of-service attacks, ' . 'phpMyAdmin restricts passwords to less than 1000 characters.'); return false; @@ -317,7 +318,7 @@ class AuthenticationCookie extends AuthenticationPlugin $match = preg_match($GLOBALS['cfg']['ArbitraryServerRegexp'], $tmp_host); if (! $match) { - $conn_error = __('You are not allowed to log in to this MySQL server!'); + $GLOBALS['conn_error'] = __('You are not allowed to log in to this MySQL server!'); return false; } @@ -424,8 +425,6 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function storeCredentials(): bool { - global $cfg; - if ($GLOBALS['cfg']['AllowArbitraryServer'] && ! empty($GLOBALS['pma_auth_server'])) { /* Allow to specify 'host port' */ $parts = explode(' ', $GLOBALS['pma_auth_server']); @@ -437,10 +436,10 @@ class AuthenticationCookie extends AuthenticationPlugin $tmp_port = ''; } - if ($cfg['Server']['host'] != $GLOBALS['pma_auth_server']) { - $cfg['Server']['host'] = $tmp_host; + if ($GLOBALS['cfg']['Server']['host'] != $GLOBALS['pma_auth_server']) { + $GLOBALS['cfg']['Server']['host'] = $tmp_host; if (! empty($tmp_port)) { - $cfg['Server']['port'] = $tmp_port; + $GLOBALS['cfg']['Server']['port'] = $tmp_port; } } @@ -455,8 +454,6 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function rememberCredentials(): void { - global $route; - // Name and password cookies need to be refreshed each time // Duration = one month for username $this->storeUsernameCookie($this->user); @@ -470,9 +467,7 @@ class AuthenticationCookie extends AuthenticationPlugin // any parameters to pass? $url_params = []; - if (isset($route)) { - $url_params['route'] = $route; - } + $url_params['route'] = Common::getRequest()->getRoute(); if (strlen($GLOBALS['db']) > 0) { $url_params['db'] = $GLOBALS['db']; @@ -574,14 +569,14 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function showFailure($failure): void { - global $conn_error; + $GLOBALS['conn_error'] = $GLOBALS['conn_error'] ?? null; parent::showFailure($failure); // Deletes password cookie and displays the login form $GLOBALS['config']->removeCookie('pmaAuth-' . $GLOBALS['server']); - $conn_error = $this->getErrorMessage($failure); + $GLOBALS['conn_error'] = $this->getErrorMessage($failure); $response = ResponseRenderer::getInstance(); @@ -677,23 +672,23 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function logOut(): void { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; // -> delete password cookie(s) if ($GLOBALS['cfg']['LoginCookieDeleteAll']) { foreach (array_keys($GLOBALS['cfg']['Servers']) as $key) { - $config->removeCookie('pmaAuth-' . $key); - if (! $config->issetCookie('pmaAuth-' . $key)) { + $GLOBALS['config']->removeCookie('pmaAuth-' . $key); + if (! $GLOBALS['config']->issetCookie('pmaAuth-' . $key)) { continue; } - $config->removeCookie('pmaAuth-' . $key); + $GLOBALS['config']->removeCookie('pmaAuth-' . $key); } } else { $cookieName = 'pmaAuth-' . $GLOBALS['server']; - $config->removeCookie($cookieName); - if ($config->issetCookie($cookieName)) { - $config->removeCookie($cookieName); + $GLOBALS['config']->removeCookie($cookieName); + if ($GLOBALS['config']->issetCookie($cookieName)) { + $GLOBALS['config']->removeCookie($cookieName); } } diff --git a/libraries/classes/Plugins/Auth/AuthenticationHttp.php b/libraries/classes/Plugins/Auth/AuthenticationHttp.php index 4ed280fb3e..200d68209a 100644 --- a/libraries/classes/Plugins/Auth/AuthenticationHttp.php +++ b/libraries/classes/Plugins/Auth/AuthenticationHttp.php @@ -76,8 +76,7 @@ class AuthenticationHttp extends AuthenticationPlugin $response->setHttpResponseCode(401); /* HTML header */ - $footer = $response->getFooter(); - $footer->setMinimal(); + $response->setMinimalFooter(); $header = $response->getHeader(); $header->setTitle(__('Access denied!')); $header->disableMenuAndConsole(); @@ -196,10 +195,8 @@ class AuthenticationHttp extends AuthenticationPlugin */ public function showFailure($failure): void { - global $dbi; - parent::showFailure($failure); - $error = $dbi->getError(); + $error = $GLOBALS['dbi']->getError(); if ($error && $GLOBALS['errno'] != 1045) { Core::fatalError($error); } else { diff --git a/libraries/classes/Plugins/AuthenticationPlugin.php b/libraries/classes/Plugins/AuthenticationPlugin.php index 927bba518a..df2869140b 100644 --- a/libraries/classes/Plugins/AuthenticationPlugin.php +++ b/libraries/classes/Plugins/AuthenticationPlugin.php @@ -78,12 +78,10 @@ abstract class AuthenticationPlugin */ public function storeCredentials(): bool { - global $cfg; - $this->setSessionAccessTime(); - $cfg['Server']['user'] = $this->user; - $cfg['Server']['password'] = $this->password; + $GLOBALS['cfg']['Server']['user'] = $this->user; + $GLOBALS['cfg']['Server']['password'] = $this->password; return true; } @@ -110,7 +108,7 @@ abstract class AuthenticationPlugin */ public function logOut(): void { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; /* Obtain redirect URL (before doing logout) */ if (! empty($GLOBALS['cfg']['Server']['LogoutURL'])) { @@ -129,7 +127,7 @@ abstract class AuthenticationPlugin $server = 0; if ($GLOBALS['cfg']['LoginCookieDeleteAll'] === false && $GLOBALS['cfg']['Server']['auth_type'] === 'cookie') { foreach (array_keys($GLOBALS['cfg']['Servers']) as $key) { - if (! $config->issetCookie('pmaAuth-' . $key)) { + if (! $GLOBALS['config']->issetCookie('pmaAuth-' . $key)) { continue; } @@ -174,8 +172,6 @@ abstract class AuthenticationPlugin */ public function getErrorMessage($failure) { - global $dbi; - if ($failure === 'empty-denied') { return __('Login without a password is forbidden by configuration (see AllowNoPassword)'); } @@ -192,7 +188,7 @@ abstract class AuthenticationPlugin ); } - $dbi_error = $dbi->getError(); + $dbi_error = $GLOBALS['dbi']->getError(); if (! empty($dbi_error)) { return htmlspecialchars($dbi_error); } @@ -271,13 +267,11 @@ abstract class AuthenticationPlugin */ public function checkRules(): void { - global $cfg; - // Check IP-based Allow/Deny rules as soon as possible to reject the // user based on mod_access in Apache - if (isset($cfg['Server']['AllowDeny']['order'])) { + if (isset($GLOBALS['cfg']['Server']['AllowDeny']['order'])) { $allowDeny_forbidden = false; // default - if ($cfg['Server']['AllowDeny']['order'] === 'allow,deny') { + if ($GLOBALS['cfg']['Server']['AllowDeny']['order'] === 'allow,deny') { $allowDeny_forbidden = true; if ($this->ipAllowDeny->allow()) { $allowDeny_forbidden = false; @@ -286,7 +280,7 @@ abstract class AuthenticationPlugin if ($this->ipAllowDeny->deny()) { $allowDeny_forbidden = true; } - } elseif ($cfg['Server']['AllowDeny']['order'] === 'deny,allow') { + } elseif ($GLOBALS['cfg']['Server']['AllowDeny']['order'] === 'deny,allow') { if ($this->ipAllowDeny->deny()) { $allowDeny_forbidden = true; } @@ -294,7 +288,7 @@ abstract class AuthenticationPlugin if ($this->ipAllowDeny->allow()) { $allowDeny_forbidden = false; } - } elseif ($cfg['Server']['AllowDeny']['order'] === 'explicit') { + } elseif ($GLOBALS['cfg']['Server']['AllowDeny']['order'] === 'explicit') { if ($this->ipAllowDeny->allow() && ! $this->ipAllowDeny->deny()) { $allowDeny_forbidden = false; } else { @@ -309,12 +303,12 @@ abstract class AuthenticationPlugin } // is root allowed? - if (! $cfg['Server']['AllowRoot'] && $cfg['Server']['user'] === 'root') { + if (! $GLOBALS['cfg']['Server']['AllowRoot'] && $GLOBALS['cfg']['Server']['user'] === 'root') { $this->showFailure('root-denied'); } // is a login without password allowed? - if ($cfg['Server']['AllowNoPassword'] || $cfg['Server']['password'] !== '') { + if ($GLOBALS['cfg']['Server']['AllowNoPassword'] || $GLOBALS['cfg']['Server']['password'] !== '') { return; } diff --git a/libraries/classes/Plugins/Export/ExportCodegen.php b/libraries/classes/Plugins/Export/ExportCodegen.php index c4be71107d..6bfc53ba24 100644 --- a/libraries/classes/Plugins/Export/ExportCodegen.php +++ b/libraries/classes/Plugins/Export/ExportCodegen.php @@ -23,6 +23,8 @@ use function preg_replace; use function sprintf; use function ucfirst; +use const PHP_EOL; + /** * Handles the export for the CodeGen class */ @@ -144,7 +146,6 @@ class ExportCodegen extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -152,7 +153,6 @@ class ExportCodegen extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] @@ -160,11 +160,11 @@ class ExportCodegen extends ExportPlugin $format = (int) $GLOBALS['codegen_format']; if ($format === self::HANDLER_NHIBERNATE_CS) { - return $this->export->outputHandler($this->handleNHibernateCSBody($db, $table, $crlf, $aliases)); + return $this->export->outputHandler($this->handleNHibernateCSBody($db, $table, $aliases)); } if ($format === self::HANDLER_NHIBERNATE_XML) { - return $this->export->outputHandler($this->handleNHibernateXMLBody($db, $table, $crlf, $aliases)); + return $this->export->outputHandler($this->handleNHibernateXMLBody($db, $table, $aliases)); } return $this->export->outputHandler(sprintf('%s is not supported.', $format)); @@ -199,20 +199,17 @@ class ExportCodegen extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf line separator * @param array $aliases Aliases of db/table/columns * * @return string containing C# code lines, separated by "\n" */ - private function handleNHibernateCSBody($db, $table, $crlf, array $aliases = []) + private function handleNHibernateCSBody($db, $table, array $aliases = []) { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); - $result = $dbi->query( + $result = $GLOBALS['dbi']->query( sprintf( 'DESC %s.%s', Util::backquote($db), @@ -296,7 +293,7 @@ class ExportCodegen extends ExportPlugin $lines[] = ' #endregion'; $lines[] = '}'; - return implode($crlf, $lines); + return implode(PHP_EOL, $lines); } /** @@ -304,7 +301,6 @@ class ExportCodegen extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf line separator * @param array $aliases Aliases of db/table/columns * * @return string containing XML code lines, separated by "\n" @@ -312,11 +308,8 @@ class ExportCodegen extends ExportPlugin private function handleNHibernateXMLBody( $db, $table, - $crlf, array $aliases = [] ) { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -328,7 +321,7 @@ class ExportCodegen extends ExportPlugin $lines[] = ' <class ' . 'name="' . self::cgMakeIdentifier($table_alias) . '" ' . 'table="' . self::cgMakeIdentifier($table_alias) . '">'; - $result = $dbi->query( + $result = $GLOBALS['dbi']->query( sprintf( 'DESC %s.%s', Util::backquote($db), @@ -367,7 +360,7 @@ class ExportCodegen extends ExportPlugin $lines[] = ' </class>'; $lines[] = '</hibernate-mapping>'; - return implode($crlf, $lines); + return implode(PHP_EOL, $lines); } /** diff --git a/libraries/classes/Plugins/Export/ExportCsv.php b/libraries/classes/Plugins/Export/ExportCsv.php index f5821cc026..4b836452fa 100644 --- a/libraries/classes/Plugins/Export/ExportCsv.php +++ b/libraries/classes/Plugins/Export/ExportCsv.php @@ -21,9 +21,10 @@ use function mb_strtolower; use function mb_substr; use function preg_replace; use function str_replace; -use function stripslashes; use function trim; +use const PHP_EOL; + /** * Handles the export for the CSV format */ @@ -104,38 +105,43 @@ class ExportCsv extends ExportPlugin */ public function exportHeader(): bool { - global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; + $GLOBALS['csv_terminated'] = $GLOBALS['csv_terminated'] ?? null; + $GLOBALS['csv_separator'] = $GLOBALS['csv_separator'] ?? null; + $GLOBALS['csv_enclosed'] = $GLOBALS['csv_enclosed'] ?? null; + $GLOBALS['csv_escaped'] = $GLOBALS['csv_escaped'] ?? null; + //Enable columns names by default for CSV - if ($what === 'csv') { + if ($GLOBALS['what'] === 'csv') { $GLOBALS['csv_columns'] = 'yes'; } // Here we just prepare some values for export - if ($what === 'excel') { - $csv_terminated = "\015\012"; + if ($GLOBALS['what'] === 'excel') { + $GLOBALS['csv_terminated'] = "\015\012"; switch ($GLOBALS['excel_edition']) { case 'win': // as tested on Windows with Excel 2002 and Excel 2007 - $csv_separator = ';'; + $GLOBALS['csv_separator'] = ';'; break; case 'mac_excel2003': - $csv_separator = ';'; + $GLOBALS['csv_separator'] = ';'; break; case 'mac_excel2008': - $csv_separator = ','; + $GLOBALS['csv_separator'] = ','; break; } - $csv_enclosed = '"'; - $csv_escaped = '"'; + $GLOBALS['csv_enclosed'] = '"'; + $GLOBALS['csv_escaped'] = '"'; if (isset($GLOBALS['excel_columns'])) { $GLOBALS['csv_columns'] = 'yes'; } } else { - if (empty($csv_terminated) || mb_strtolower($csv_terminated) === 'auto') { - $csv_terminated = $GLOBALS['crlf']; + if (empty($GLOBALS['csv_terminated']) || mb_strtolower($GLOBALS['csv_terminated']) === 'auto') { + $GLOBALS['csv_terminated'] = PHP_EOL; } else { - $csv_terminated = str_replace( + $GLOBALS['csv_terminated'] = str_replace( [ '\\r', '\\n', @@ -146,11 +152,11 @@ class ExportCsv extends ExportPlugin "\012", "\011", ], - $csv_terminated + $GLOBALS['csv_terminated'] ); } - $csv_separator = str_replace('\\t', "\011", $csv_separator); + $GLOBALS['csv_separator'] = str_replace('\\t', "\011", $GLOBALS['csv_separator']); } return true; @@ -202,7 +208,6 @@ class ExportCsv extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -210,19 +215,26 @@ class ExportCsv extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped, $dbi; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; + $GLOBALS['csv_terminated'] = $GLOBALS['csv_terminated'] ?? null; + $GLOBALS['csv_separator'] = $GLOBALS['csv_separator'] ?? null; + $GLOBALS['csv_enclosed'] = $GLOBALS['csv_enclosed'] ?? null; + $GLOBALS['csv_escaped'] = $GLOBALS['csv_escaped'] ?? null; $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); // Gets the data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); // If required, get fields name at the first line @@ -233,20 +245,23 @@ class ExportCsv extends ExportPlugin $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $col_as = stripslashes($col_as); - if ($csv_enclosed == '') { + if ($GLOBALS['csv_enclosed'] == '') { $schema_insert .= $col_as; } else { - $schema_insert .= $csv_enclosed - . str_replace($csv_enclosed, $csv_escaped . $csv_enclosed, $col_as) - . $csv_enclosed; + $schema_insert .= $GLOBALS['csv_enclosed'] + . str_replace( + $GLOBALS['csv_enclosed'], + $GLOBALS['csv_escaped'] . $GLOBALS['csv_enclosed'], + $col_as + ) + . $GLOBALS['csv_enclosed']; } - $schema_insert .= $csv_separator; + $schema_insert .= $GLOBALS['csv_separator']; } $schema_insert = trim(mb_substr($schema_insert, 0, -1)); - if (! $this->export->outputHandler($schema_insert . $csv_terminated)) { + if (! $this->export->outputHandler($schema_insert . $GLOBALS['csv_terminated'])) { return false; } } @@ -256,15 +271,17 @@ class ExportCsv extends ExportPlugin $schema_insert = ''; for ($j = 0; $j < $fields_cnt; $j++) { if (! isset($row[$j])) { - $schema_insert .= $GLOBALS[$what . '_null']; + $schema_insert .= $GLOBALS[$GLOBALS['what'] . '_null']; } elseif ($row[$j] == '0' || $row[$j] != '') { // always enclose fields - if ($what === 'excel') { + if ($GLOBALS['what'] === 'excel') { $row[$j] = preg_replace("/\015(\012)?/", "\012", $row[$j]); } // remove CRLF characters within field - if (isset($GLOBALS[$what . '_removeCRLF']) && $GLOBALS[$what . '_removeCRLF']) { + if ( + isset($GLOBALS[$GLOBALS['what'] . '_removeCRLF']) && $GLOBALS[$GLOBALS['what'] . '_removeCRLF'] + ) { $row[$j] = str_replace( [ "\r", @@ -275,27 +292,31 @@ class ExportCsv extends ExportPlugin ); } - if ($csv_enclosed == '') { + if ($GLOBALS['csv_enclosed'] == '') { $schema_insert .= $row[$j]; } else { // also double the escape string if found in the data - if ($csv_escaped != $csv_enclosed) { - $schema_insert .= $csv_enclosed + if ($GLOBALS['csv_escaped'] != $GLOBALS['csv_enclosed']) { + $schema_insert .= $GLOBALS['csv_enclosed'] . str_replace( - $csv_enclosed, - $csv_escaped . $csv_enclosed, + $GLOBALS['csv_enclosed'], + $GLOBALS['csv_escaped'] . $GLOBALS['csv_enclosed'], str_replace( - $csv_escaped, - $csv_escaped . $csv_escaped, + $GLOBALS['csv_escaped'], + $GLOBALS['csv_escaped'] . $GLOBALS['csv_escaped'], $row[$j] ) ) - . $csv_enclosed; + . $GLOBALS['csv_enclosed']; } else { // avoid a problem when escape string equals enclose - $schema_insert .= $csv_enclosed - . str_replace($csv_enclosed, $csv_escaped . $csv_enclosed, $row[$j]) - . $csv_enclosed; + $schema_insert .= $GLOBALS['csv_enclosed'] + . str_replace( + $GLOBALS['csv_enclosed'], + $GLOBALS['csv_escaped'] . $GLOBALS['csv_enclosed'], + $row[$j] + ) + . $GLOBALS['csv_enclosed']; } } } else { @@ -306,10 +327,10 @@ class ExportCsv extends ExportPlugin continue; } - $schema_insert .= $csv_separator; + $schema_insert .= $GLOBALS['csv_separator']; } - if (! $this->export->outputHandler($schema_insert . $csv_terminated)) { + if (! $this->export->outputHandler($schema_insert . $GLOBALS['csv_terminated'])) { return false; } } @@ -322,10 +343,9 @@ class ExportCsv extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } } diff --git a/libraries/classes/Plugins/Export/ExportHtmlword.php b/libraries/classes/Plugins/Export/ExportHtmlword.php index f86739e38e..daf1593650 100644 --- a/libraries/classes/Plugins/Export/ExportHtmlword.php +++ b/libraries/classes/Plugins/Export/ExportHtmlword.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -21,7 +22,6 @@ use function __; use function htmlspecialchars; use function in_array; use function str_replace; -use function stripslashes; /** * Handles the export for the HTML-Word format @@ -99,7 +99,7 @@ class ExportHtmlword extends ExportPlugin */ public function exportHeader(): bool { - global $charset; + $GLOBALS['charset'] = $GLOBALS['charset'] ?? null; return $this->export->outputHandler( '<html xmlns:o="urn:schemas-microsoft-com:office:office" @@ -111,7 +111,7 @@ class ExportHtmlword extends ExportPlugin <html> <head> <meta http-equiv="Content-type" content="text/html;charset=' - . ($charset ?? 'utf-8') . '" /> + . ($GLOBALS['charset'] ?? 'utf-8') . '" /> </head> <body>' ); @@ -169,7 +169,6 @@ class ExportHtmlword extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -177,12 +176,11 @@ class ExportHtmlword extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $what, $dbi; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; $db_alias = $db; $table_alias = $table; @@ -203,7 +201,11 @@ class ExportHtmlword extends ExportPlugin } // Gets the data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); // If required, get fields name at the first line @@ -214,7 +216,6 @@ class ExportHtmlword extends ExportPlugin $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $col_as = stripslashes($col_as); $schema_insert .= '<td class="print"><strong>' . htmlspecialchars($col_as) . '</strong></td>'; @@ -231,7 +232,7 @@ class ExportHtmlword extends ExportPlugin $schema_insert = '<tr class="print-category">'; for ($j = 0; $j < $fields_cnt; $j++) { if (! isset($row[$j])) { - $value = $GLOBALS[$what . '_null']; + $value = $GLOBALS[$GLOBALS['what'] . '_null']; } elseif ($row[$j] == '0' || $row[$j] != '') { $value = $row[$j]; } else { @@ -257,15 +258,12 @@ class ExportHtmlword extends ExportPlugin * * @param string $db the database name * @param string $view the view name - * @param string $crlf the end of line sequence * @param array $aliases Aliases of db/table/columns * * @return string resulting definition */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) + public function getTableDefStandIn($db, $view, $aliases = []) { - global $dbi; - $schema_insert = '<table width="100%" cellspacing="1">' . '<tr class="print-category">' . '<th class="print">' @@ -286,7 +284,7 @@ class ExportHtmlword extends ExportPlugin * Get the unique keys in the view */ $unique_keys = []; - $keys = $dbi->getTableIndexes($db, $view); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); foreach ($keys as $key) { if ($key['Non_unique'] != 0) { continue; @@ -295,7 +293,7 @@ class ExportHtmlword extends ExportPlugin $unique_keys[] = $key['Column_name']; } - $columns = $dbi->getColumns($db, $view); + $columns = $GLOBALS['dbi']->getColumns($db, $view); foreach ($columns as $column) { $col_as = $column['Field']; if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { @@ -339,8 +337,6 @@ class ExportHtmlword extends ExportPlugin $view = false, array $aliases = [] ) { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); $schema_insert = ''; @@ -348,7 +344,7 @@ class ExportHtmlword extends ExportPlugin /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); // Check if we can use Relations [$res_rel, $have_rel] = $this->relation->getRelationsAndStatus( @@ -397,12 +393,12 @@ class ExportHtmlword extends ExportPlugin $schema_insert .= '</tr>'; - $columns = $dbi->getColumns($db, $table); + $columns = $GLOBALS['dbi']->getColumns($db, $table); /** * Get the unique keys in the table */ $unique_keys = []; - $keys = $dbi->getTableIndexes($db, $table); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); foreach ($keys as $key) { if ($key['Non_unique'] != 0) { continue; @@ -466,8 +462,6 @@ class ExportHtmlword extends ExportPlugin */ protected function getTriggers($db, $table) { - global $dbi; - $dump = '<table width="100%" cellspacing="1">'; $dump .= '<tr class="print-category">'; $dump .= '<th class="print">' . __('Name') . '</th>'; @@ -476,7 +470,7 @@ class ExportHtmlword extends ExportPlugin $dump .= '<td class="print"><strong>' . __('Definition') . '</strong></td>'; $dump .= '</tr>'; - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); foreach ($triggers as $trigger) { $dump .= '<tr class="print-category">'; @@ -505,7 +499,6 @@ class ExportHtmlword extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table', 'triggers', 'create_view', * 'stand_in' @@ -524,7 +517,6 @@ class ExportHtmlword extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -534,8 +526,6 @@ class ExportHtmlword extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -552,7 +542,7 @@ class ExportHtmlword extends ExportPlugin break; case 'triggers': $dump = ''; - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); if ($triggers) { $dump .= '<h2>' . __('Triggers') . ' ' . htmlspecialchars($table_alias) @@ -573,7 +563,7 @@ class ExportHtmlword extends ExportPlugin . htmlspecialchars($table_alias) . '</h2>'; // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); + $dump .= $this->getTableDefStandIn($db, $table, $aliases); } return $this->export->outputHandler($dump); diff --git a/libraries/classes/Plugins/Export/ExportJson.php b/libraries/classes/Plugins/Export/ExportJson.php index 0e3a678be9..1591c70f0f 100644 --- a/libraries/classes/Plugins/Export/ExportJson.php +++ b/libraries/classes/Plugins/Export/ExportJson.php @@ -21,10 +21,10 @@ use function __; use function bin2hex; use function explode; use function json_encode; -use function stripslashes; use const JSON_PRETTY_PRINT; use const JSON_UNESCAPED_UNICODE; +use const PHP_EOL; /** * Handles the export for the JSON format @@ -108,8 +108,6 @@ class ExportJson extends ExportPlugin */ public function exportHeader(): bool { - global $crlf; - $data = $this->encode([ 'type' => 'header', 'version' => Version::VERSION, @@ -119,7 +117,7 @@ class ExportJson extends ExportPlugin return false; } - return $this->export->outputHandler('[' . $crlf . $data . ',' . $crlf); + return $this->export->outputHandler('[' . PHP_EOL . $data . ',' . PHP_EOL); } /** @@ -127,9 +125,7 @@ class ExportJson extends ExportPlugin */ public function exportFooter(): bool { - global $crlf; - - return $this->export->outputHandler(']' . $crlf); + return $this->export->outputHandler(']' . PHP_EOL); } /** @@ -140,8 +136,6 @@ class ExportJson extends ExportPlugin */ public function exportDBHeader($db, $dbAlias = ''): bool { - global $crlf; - if (empty($dbAlias)) { $dbAlias = $db; } @@ -151,7 +145,7 @@ class ExportJson extends ExportPlugin return false; } - return $this->export->outputHandler($data . ',' . $crlf); + return $this->export->outputHandler($data . ',' . PHP_EOL); } /** @@ -181,7 +175,6 @@ class ExportJson extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -189,13 +182,10 @@ class ExportJson extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -218,7 +208,7 @@ class ExportJson extends ExportPlugin return false; } - return $this->doExportForQuery($dbi, $sqlQuery, $buffer, $crlf, $aliases, $db, $table); + return $this->doExportForQuery($GLOBALS['dbi'], $sqlQuery, $buffer, $aliases, $db, $table); } /** @@ -238,14 +228,13 @@ class ExportJson extends ExportPlugin DatabaseInterface $dbi, string $sqlQuery, string $buffer, - string $crlf, ?array $aliases, ?string $db, ?string $table ): bool { [$header, $footer] = explode('"@@DATA@@"', $buffer); - if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) { + if (! $this->export->outputHandler($header . PHP_EOL . '[' . PHP_EOL)) { return false; } @@ -263,7 +252,7 @@ class ExportJson extends ExportPlugin $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $columns[$i] = stripslashes($col_as); + $columns[$i] = $col_as; } $record_cnt = 0; @@ -272,7 +261,7 @@ class ExportJson extends ExportPlugin // Output table name as comment if this is the first record of the table if ($record_cnt > 1) { - if (! $this->export->outputHandler(',' . $crlf)) { + if (! $this->export->outputHandler(',' . PHP_EOL)) { return false; } } @@ -314,7 +303,7 @@ class ExportJson extends ExportPlugin } } - return $this->export->outputHandler($crlf . ']' . $crlf . $footer . $crlf); + return $this->export->outputHandler(PHP_EOL . ']' . PHP_EOL . $footer . PHP_EOL); } /** @@ -322,12 +311,9 @@ class ExportJson extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - global $dbi; - $buffer = $this->encode([ 'type' => 'raw', 'data' => '@@DATA@@', @@ -336,6 +322,6 @@ class ExportJson extends ExportPlugin return false; } - return $this->doExportForQuery($dbi, $sqlQuery, $buffer, $crlf, null, null, null); + return $this->doExportForQuery($GLOBALS['dbi'], $sqlQuery, $buffer, null, null, null); } } diff --git a/libraries/classes/Plugins/Export/ExportLatex.php b/libraries/classes/Plugins/Export/ExportLatex.php index 91b298b52f..68514f75ac 100644 --- a/libraries/classes/Plugins/Export/ExportLatex.php +++ b/libraries/classes/Plugins/Export/ExportLatex.php @@ -24,8 +24,8 @@ use function in_array; use function mb_strpos; use function mb_substr; use function str_replace; -use function stripslashes; +use const PHP_EOL; use const PHP_VERSION; /** @@ -54,9 +54,10 @@ class ExportLatex extends ExportPlugin protected function setProperties(): ExportPluginProperties { - global $plugin_param; + $GLOBALS['plugin_param'] = $GLOBALS['plugin_param'] ?? null; + $hide_structure = false; - if ($plugin_param['export_type'] === 'table' && ! $plugin_param['single_table']) { + if ($GLOBALS['plugin_param']['export_type'] === 'table' && ! $GLOBALS['plugin_param']['single_table']) { $hide_structure = true; } @@ -201,22 +202,20 @@ class ExportLatex extends ExportPlugin */ public function exportHeader(): bool { - global $crlf, $cfg, $dbi; - - $head = '% phpMyAdmin LaTeX Dump' . $crlf - . '% version ' . Version::VERSION . $crlf - . '% https://www.phpmyadmin.net/' . $crlf - . '%' . $crlf - . '% ' . __('Host:') . ' ' . $cfg['Server']['host']; - if (! empty($cfg['Server']['port'])) { - $head .= ':' . $cfg['Server']['port']; + $head = '% phpMyAdmin LaTeX Dump' . PHP_EOL + . '% version ' . Version::VERSION . PHP_EOL + . '% https://www.phpmyadmin.net/' . PHP_EOL + . '%' . PHP_EOL + . '% ' . __('Host:') . ' ' . $GLOBALS['cfg']['Server']['host']; + if (! empty($GLOBALS['cfg']['Server']['port'])) { + $head .= ':' . $GLOBALS['cfg']['Server']['port']; } - $head .= $crlf + $head .= PHP_EOL . '% ' . __('Generation Time:') . ' ' - . Util::localisedDate() . $crlf - . '% ' . __('Server version:') . ' ' . $dbi->getVersionString() . $crlf - . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf; + . Util::localisedDate() . PHP_EOL + . '% ' . __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString() . PHP_EOL + . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . PHP_EOL; return $this->export->outputHandler($head); } @@ -241,10 +240,9 @@ class ExportLatex extends ExportPlugin $dbAlias = $db; } - global $crlf; - $head = '% ' . $crlf - . '% ' . __('Database:') . ' \'' . $dbAlias . '\'' . $crlf - . '% ' . $crlf; + $head = '% ' . PHP_EOL + . '% ' . __('Database:') . ' \'' . $dbAlias . '\'' . PHP_EOL + . '% ' . PHP_EOL; return $this->export->outputHandler($head); } @@ -276,7 +274,6 @@ class ExportLatex extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -284,18 +281,19 @@ class ExportLatex extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); - $result = $dbi->tryQuery($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->tryQuery( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $columns_cnt = $result->numFields(); $columns = []; @@ -309,28 +307,22 @@ class ExportLatex extends ExportPlugin $columns_alias[$i] = $col_as; } - $buffer = $crlf . '%' . $crlf . '% ' . __('Data:') . ' ' . $table_alias - . $crlf . '%' . $crlf . ' \\begin{longtable}{|'; + $buffer = PHP_EOL . '%' . PHP_EOL . '% ' . __('Data:') . ' ' . $table_alias + . PHP_EOL . '%' . PHP_EOL . ' \\begin{longtable}{|'; for ($index = 0; $index < $columns_cnt; $index++) { $buffer .= 'l|'; } - $buffer .= '} ' . $crlf; + $buffer .= '} ' . PHP_EOL; - $buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . $crlf; + $buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . PHP_EOL; if (isset($GLOBALS['latex_caption'])) { $buffer .= ' \\caption{' . Util::expandUserString( $GLOBALS['latex_data_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] + [static::class, 'texEscape'], + ['table' => $table_alias, 'database' => $db_alias] ) . '} \\label{' . Util::expandUserString( @@ -353,11 +345,11 @@ class ExportLatex extends ExportPlugin $buffer = '\\hline '; for ($i = 0; $i < $columns_cnt; $i++) { $buffer .= '\\multicolumn{1}{|c|}{\\textbf{' - . self::texEscape(stripslashes($columns_alias[$i])) . '}} & '; + . self::texEscape($columns_alias[$i]) . '}} & '; } $buffer = mb_substr($buffer, 0, -2) . '\\\\ \\hline \hline '; - if (! $this->export->outputHandler($buffer . ' \\endfirsthead ' . $crlf)) { + if (! $this->export->outputHandler($buffer . ' \\endfirsthead ' . PHP_EOL)) { return false; } @@ -367,14 +359,8 @@ class ExportLatex extends ExportPlugin '\\caption{' . Util::expandUserString( $GLOBALS['latex_data_continued_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] + [static::class, 'texEscape'], + ['table' => $table_alias, 'database' => $db_alias] ) . '} \\\\ ' ) @@ -383,7 +369,7 @@ class ExportLatex extends ExportPlugin } } - if (! $this->export->outputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { + if (! $this->export->outputHandler($buffer . '\\endhead \\endfoot' . PHP_EOL)) { return false; } } else { @@ -398,9 +384,7 @@ class ExportLatex extends ExportPlugin // print each row for ($i = 0; $i < $columns_cnt; $i++) { if ($record[$columns[$i]] !== null && isset($record[$columns[$i]])) { - $column_value = self::texEscape( - stripslashes($record[$columns[$i]]) - ); + $column_value = self::texEscape($record[$columns[$i]]); } else { $column_value = $GLOBALS['latex_null']; } @@ -413,13 +397,13 @@ class ExportLatex extends ExportPlugin } } - $buffer .= ' \\\\ \\hline ' . $crlf; + $buffer .= ' \\\\ \\hline ' . PHP_EOL; if (! $this->export->outputHandler($buffer)) { return false; } } - $buffer = ' \\end{longtable}' . $crlf; + $buffer = ' \\end{longtable}' . PHP_EOL; return $this->export->outputHandler($buffer); } @@ -429,11 +413,10 @@ class ExportLatex extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the seperator for a file */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } /** @@ -441,7 +424,6 @@ class ExportLatex extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table', 'triggers', 'create_view', * 'stand_in' @@ -460,7 +442,6 @@ class ExportLatex extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -470,8 +451,6 @@ class ExportLatex extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -487,7 +466,7 @@ class ExportLatex extends ExportPlugin * Get the unique keys in the table */ $unique_keys = []; - $keys = $dbi->getTableIndexes($db, $table); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); foreach ($keys as $key) { if ($key['Non_unique'] != 0) { continue; @@ -499,7 +478,7 @@ class ExportLatex extends ExportPlugin /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); // Check if we can use Relations [$res_rel, $have_rel] = $this->relation->getRelationsAndStatus( @@ -510,8 +489,8 @@ class ExportLatex extends ExportPlugin /** * Displays the table structure */ - $buffer = $crlf . '%' . $crlf . '% ' . __('Structure:') . ' ' - . $table_alias . $crlf . '%' . $crlf . ' \\begin{longtable}{'; + $buffer = PHP_EOL . '%' . PHP_EOL . '% ' . __('Structure:') . ' ' + . $table_alias . PHP_EOL . '%' . PHP_EOL . ' \\begin{longtable}{'; if (! $this->export->outputHandler($buffer)) { return false; } @@ -529,7 +508,7 @@ class ExportLatex extends ExportPlugin $alignment .= 'l|'; } - $buffer = $alignment . '} ' . $crlf; + $buffer = $alignment . '} ' . PHP_EOL; $header = ' \\hline '; $header .= '\\multicolumn{1}{|c|}{\\textbf{' . __('Column') @@ -555,14 +534,8 @@ class ExportLatex extends ExportPlugin $buffer .= ' \\caption{' . Util::expandUserString( $GLOBALS['latex_structure_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] + [static::class, 'texEscape'], + ['table' => $table_alias, 'database' => $db_alias] ) . '} \\label{' . Util::expandUserString( @@ -573,35 +546,29 @@ class ExportLatex extends ExportPlugin 'database' => $db_alias, ] ) - . '} \\\\' . $crlf; + . '} \\\\' . PHP_EOL; } - $buffer .= $header . ' \\\\ \\hline \\hline' . $crlf - . '\\endfirsthead' . $crlf; + $buffer .= $header . ' \\\\ \\hline \\hline' . PHP_EOL + . '\\endfirsthead' . PHP_EOL; // Table caption on next pages if (isset($GLOBALS['latex_caption'])) { $buffer .= ' \\caption{' . Util::expandUserString( $GLOBALS['latex_structure_continued_caption'], - [ - 'texEscape', - static::class, - ], - [ - 'table' => $table_alias, - 'database' => $db_alias, - ] + [static::class, 'texEscape'], + ['table' => $table_alias, 'database' => $db_alias] ) - . '} \\\\ ' . $crlf; + . '} \\\\ ' . PHP_EOL; } - $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; + $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . PHP_EOL; if (! $this->export->outputHandler($buffer)) { return false; } - $fields = $dbi->getColumns($db, $table); + $fields = $GLOBALS['dbi']->getColumns($db, $table); foreach ($fields as $row) { $extracted_columnspec = Util::extractColumnSpec($row['Type']); $type = $extracted_columnspec['print_type']; @@ -664,14 +631,14 @@ class ExportLatex extends ExportPlugin } $buffer = str_replace("\000", ' & ', $local_buffer); - $buffer .= ' \\\\ \\hline ' . $crlf; + $buffer .= ' \\\\ \\hline ' . PHP_EOL; if (! $this->export->outputHandler($buffer)) { return false; } } - $buffer = ' \\end{longtable}' . $crlf; + $buffer = ' \\end{longtable}' . PHP_EOL; return $this->export->outputHandler($buffer); } diff --git a/libraries/classes/Plugins/Export/ExportMediawiki.php b/libraries/classes/Plugins/Export/ExportMediawiki.php index 17c88b8e7d..8ab15928b9 100644 --- a/libraries/classes/Plugins/Export/ExportMediawiki.php +++ b/libraries/classes/Plugins/Export/ExportMediawiki.php @@ -147,7 +147,6 @@ class ExportMediawiki extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table','triggers','create_view', * 'stand_in' @@ -166,7 +165,6 @@ class ExportMediawiki extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -176,8 +174,6 @@ class ExportMediawiki extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -185,7 +181,7 @@ class ExportMediawiki extends ExportPlugin $output = ''; switch ($exportMode) { case 'create_table': - $columns = $dbi->getColumns($db, $table); + $columns = $GLOBALS['dbi']->getColumns($db, $table); $columns = array_values($columns); $row_cnt = count($columns); @@ -256,7 +252,6 @@ class ExportMediawiki extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -264,13 +259,10 @@ class ExportMediawiki extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -296,7 +288,7 @@ class ExportMediawiki extends ExportPlugin // Add the table headers if (isset($GLOBALS['mediawiki_headers'])) { // Get column names - $column_names = $dbi->getColumnNames($db, $table); + $column_names = $GLOBALS['dbi']->getColumnNames($db, $table); // Add column names as table headers if ($column_names !== []) { @@ -315,7 +307,11 @@ class ExportMediawiki extends ExportPlugin } // Get the table data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); while ($row = $result->fetchRow()) { @@ -338,11 +334,10 @@ class ExportMediawiki extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } /** diff --git a/libraries/classes/Plugins/Export/ExportOds.php b/libraries/classes/Plugins/Export/ExportOds.php index 14b67c4f3c..95be16cf16 100644 --- a/libraries/classes/Plugins/Export/ExportOds.php +++ b/libraries/classes/Plugins/Export/ExportOds.php @@ -22,7 +22,6 @@ use function __; use function bin2hex; use function date; use function htmlspecialchars; -use function stripslashes; use function strtotime; /** @@ -188,7 +187,6 @@ class ExportOds extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -196,26 +194,29 @@ class ExportOds extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $what, $dbi; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); // Gets the data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); /** @var FieldMetadata[] $fieldsMeta */ - $fieldsMeta = $dbi->getFieldsMeta($result); + $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); $GLOBALS['ods_buffer'] .= '<table:table table:name="' . htmlspecialchars($table_alias) . '">'; // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { + if (isset($GLOBALS[$GLOBALS['what'] . '_columns'])) { $GLOBALS['ods_buffer'] .= '<table:table-row>'; foreach ($fieldsMeta as $field) { $col_as = $field->name; @@ -225,9 +226,7 @@ class ExportOds extends ExportPlugin $GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">' . '<text:p>' - . htmlspecialchars( - stripslashes($col_as) - ) + . htmlspecialchars($col_as) . '</text:p>' . '</table:table-cell>'; } @@ -247,7 +246,7 @@ class ExportOds extends ExportPlugin if (! isset($row[$j])) { $GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">' . '<text:p>' - . htmlspecialchars($GLOBALS[$what . '_null']) + . htmlspecialchars($GLOBALS[$GLOBALS['what'] . '_null']) . '</text:p>' . '</table:table-cell>'; } elseif ($fieldsMeta[$j]->isBinary && $fieldsMeta[$j]->isBlob) { @@ -316,10 +315,9 @@ class ExportOds extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } } diff --git a/libraries/classes/Plugins/Export/ExportOdt.php b/libraries/classes/Plugins/Export/ExportOdt.php index b4f4183370..65e4b6f8e1 100644 --- a/libraries/classes/Plugins/Export/ExportOdt.php +++ b/libraries/classes/Plugins/Export/ExportOdt.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\OpenDocument; @@ -23,7 +24,6 @@ use function __; use function bin2hex; use function htmlspecialchars; use function str_replace; -use function stripslashes; /** * Handles the export for the ODT class @@ -45,9 +45,10 @@ class ExportOdt extends ExportPlugin protected function setProperties(): ExportPluginProperties { - global $plugin_param; + $GLOBALS['plugin_param'] = $GLOBALS['plugin_param'] ?? null; + $hide_structure = false; - if ($plugin_param['export_type'] === 'table' && ! $plugin_param['single_table']) { + if ($GLOBALS['plugin_param']['export_type'] === 'table' && ! $GLOBALS['plugin_param']['single_table']) { $hide_structure = true; } @@ -215,7 +216,6 @@ class ExportOdt extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -223,21 +223,24 @@ class ExportOdt extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $what, $dbi; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); // Gets the data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); /** @var FieldMetadata[] $fieldsMeta */ - $fieldsMeta = $dbi->getFieldsMeta($result); + $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); $GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"' . ' text:is-list-header="true">'; @@ -251,7 +254,7 @@ class ExportOdt extends ExportPlugin . ' table:number-columns-repeated="' . $fields_cnt . '"/>'; // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { + if (isset($GLOBALS[$GLOBALS['what'] . '_columns'])) { $GLOBALS['odt_buffer'] .= '<table:table-row>'; foreach ($fieldsMeta as $field) { $col_as = $field->name; @@ -261,9 +264,7 @@ class ExportOdt extends ExportPlugin $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">' . '<text:p>' - . htmlspecialchars( - stripslashes($col_as) - ) + . htmlspecialchars($col_as) . '</text:p>' . '</table:table-cell>'; } @@ -283,7 +284,7 @@ class ExportOdt extends ExportPlugin if (! isset($row[$j])) { $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">' . '<text:p>' - . htmlspecialchars($GLOBALS[$what . '_null']) + . htmlspecialchars($GLOBALS[$GLOBALS['what'] . '_null']) . '</text:p>' . '</table:table-cell>'; } elseif ($fieldsMeta[$j]->isBinary && $fieldsMeta[$j]->isBlob) { @@ -324,11 +325,10 @@ class ExportOdt extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } /** @@ -336,22 +336,19 @@ class ExportOdt extends ExportPlugin * * @param string $db the database name * @param string $view the view name - * @param string $crlf the end of line sequence * @param array $aliases Aliases of db/table/columns * * @return string resulting definition */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) + public function getTableDefStandIn($db, $view, $aliases = []) { - global $dbi; - $db_alias = $db; $view_alias = $view; $this->initAlias($aliases, $db_alias, $view_alias); /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); /** * Displays the table structure @@ -377,7 +374,7 @@ class ExportOdt extends ExportPlugin . '</table:table-cell>' . '</table:table-row>'; - $columns = $dbi->getColumns($db, $view); + $columns = $GLOBALS['dbi']->getColumns($db, $view); foreach ($columns as $column) { $col_as = $column['Field'] ?? null; if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { @@ -398,7 +395,6 @@ class ExportOdt extends ExportPlugin * * @param string $db the database name * @param string $table the table name - * @param string $crlf the end of line sequence * @param string $error_url the url to go back in case of error * @param bool $do_relation whether to include relation comments * @param bool $do_comments whether to include the pmadb-style column @@ -416,7 +412,6 @@ class ExportOdt extends ExportPlugin public function getTableDef( $db, $table, - $crlf, $error_url, $do_relation, $do_comments, @@ -426,8 +421,6 @@ class ExportOdt extends ExportPlugin $view = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -437,7 +430,7 @@ class ExportOdt extends ExportPlugin /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); // Check if we can use Relations [$res_rel, $have_rel] = $this->relation->getRelationsAndStatus( @@ -501,7 +494,7 @@ class ExportOdt extends ExportPlugin $GLOBALS['odt_buffer'] .= '</table:table-row>'; - $columns = $dbi->getColumns($db, $table); + $columns = $GLOBALS['dbi']->getColumns($db, $table); foreach ($columns as $column) { $col_as = $field_name = $column['Field']; if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { @@ -580,8 +573,6 @@ class ExportOdt extends ExportPlugin */ protected function getTriggers($db, $table, array $aliases = []) { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -604,7 +595,7 @@ class ExportOdt extends ExportPlugin . '</table:table-cell>' . '</table:table-row>'; - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); foreach ($triggers as $trigger) { $GLOBALS['odt_buffer'] .= '<table:table-row>'; @@ -641,7 +632,6 @@ class ExportOdt extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table', 'triggers', 'create_view', * 'stand_in' @@ -659,7 +649,6 @@ class ExportOdt extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -669,8 +658,6 @@ class ExportOdt extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -684,7 +671,6 @@ class ExportOdt extends ExportPlugin $this->getTableDef( $db, $table, - $crlf, $errorUrl, $do_relation, $do_comments, @@ -696,7 +682,7 @@ class ExportOdt extends ExportPlugin ); break; case 'triggers': - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); if ($triggers) { $GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"' . ' text:is-list-header="true">' @@ -716,7 +702,6 @@ class ExportOdt extends ExportPlugin $this->getTableDef( $db, $table, - $crlf, $errorUrl, $do_relation, $do_comments, @@ -734,7 +719,7 @@ class ExportOdt extends ExportPlugin . htmlspecialchars($table_alias) . '</text:h>'; // export a stand-in definition to resolve view dependencies - $this->getTableDefStandIn($db, $table, $crlf, $aliases); + $this->getTableDefStandIn($db, $table, $aliases); } return true; diff --git a/libraries/classes/Plugins/Export/ExportPdf.php b/libraries/classes/Plugins/Export/ExportPdf.php index 3a8b6ebffa..602da3c188 100644 --- a/libraries/classes/Plugins/Export/ExportPdf.php +++ b/libraries/classes/Plugins/Export/ExportPdf.php @@ -167,7 +167,6 @@ class ExportPdf extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -175,7 +174,6 @@ class ExportPdf extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] @@ -200,9 +198,8 @@ class ExportPdf extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { $pdf = $this->getPdf(); $pdf->setDbAlias('----'); @@ -218,7 +215,6 @@ class ExportPdf extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table', 'triggers', 'create_view', * 'stand_in' @@ -237,7 +233,6 @@ class ExportPdf extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -292,7 +287,7 @@ class ExportPdf extends ExportPlugin case 'stand_in': /* export a stand-in definition to resolve view dependencies * Yet to develop this function - * $pdf->getTableDefStandIn($db, $table, $crlf); + * $pdf->getTableDefStandIn($db, $table); */ } diff --git a/libraries/classes/Plugins/Export/ExportPhparray.php b/libraries/classes/Plugins/Export/ExportPhparray.php index 7bfe9377e3..29753e3386 100644 --- a/libraries/classes/Plugins/Export/ExportPhparray.php +++ b/libraries/classes/Plugins/Export/ExportPhparray.php @@ -19,10 +19,11 @@ use PhpMyAdmin\Version; use function __; use function preg_match; use function preg_replace; -use function stripslashes; use function strtr; use function var_export; +use const PHP_EOL; + /** * Handles the export for the PHP Array class */ @@ -81,11 +82,11 @@ class ExportPhparray extends ExportPlugin public function exportHeader(): bool { $this->export->outputHandler( - '<?php' . $GLOBALS['crlf'] - . '/**' . $GLOBALS['crlf'] - . ' * Export to PHP Array plugin for PHPMyAdmin' . $GLOBALS['crlf'] - . ' * @version ' . Version::VERSION . $GLOBALS['crlf'] - . ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf'] + '<?php' . PHP_EOL + . '/**' . PHP_EOL + . ' * Export to PHP Array plugin for PHPMyAdmin' . PHP_EOL + . ' * @version ' . Version::VERSION . PHP_EOL + . ' */' . PHP_EOL . PHP_EOL ); return true; @@ -112,9 +113,9 @@ class ExportPhparray extends ExportPlugin } $this->export->outputHandler( - '/**' . $GLOBALS['crlf'] + '/**' . PHP_EOL . ' * Database ' . $this->commentString(Util::backquote($dbAlias)) - . $GLOBALS['crlf'] . ' */' . $GLOBALS['crlf'] + . PHP_EOL . ' */' . PHP_EOL ); return true; @@ -147,7 +148,6 @@ class ExportPhparray extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -155,18 +155,19 @@ class ExportPhparray extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $columns_cnt = $result->numFields(); $columns = []; @@ -175,7 +176,7 @@ class ExportPhparray extends ExportPlugin $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $columns[$i] = stripslashes($col_as); + $columns[$i] = $col_as; } $tablefixed = $table; @@ -196,9 +197,9 @@ class ExportPhparray extends ExportPlugin $buffer = ''; $record_cnt = 0; // Output table name as comment - $buffer .= $crlf . '/* ' + $buffer .= PHP_EOL . '/* ' . $this->commentString(Util::backquote($db_alias)) . '.' - . $this->commentString(Util::backquote($table_alias)) . ' */' . $crlf; + . $this->commentString(Util::backquote($table_alias)) . ' */' . PHP_EOL; $buffer .= '$' . $tablefixed . ' = array('; if (! $this->export->outputHandler($buffer)) { return false; @@ -210,9 +211,9 @@ class ExportPhparray extends ExportPlugin $record_cnt++; if ($record_cnt == 1) { - $buffer .= $crlf . ' array('; + $buffer .= PHP_EOL . ' array('; } else { - $buffer .= ',' . $crlf . ' array('; + $buffer .= ',' . PHP_EOL . ' array('; } for ($i = 0; $i < $columns_cnt; $i++) { @@ -230,7 +231,7 @@ class ExportPhparray extends ExportPlugin $buffer = ''; } - $buffer .= $crlf . ');' . $crlf; + $buffer .= PHP_EOL . ');' . PHP_EOL; return $this->export->outputHandler($buffer); } @@ -240,10 +241,9 @@ class ExportPhparray extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } } diff --git a/libraries/classes/Plugins/Export/ExportSql.php b/libraries/classes/Plugins/Export/ExportSql.php index 8f3e1bc6e5..0e085c4254 100644 --- a/libraries/classes/Plugins/Export/ExportSql.php +++ b/libraries/classes/Plugins/Export/ExportSql.php @@ -8,6 +8,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\Charsets; +use PhpMyAdmin\Database\Events; +use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; @@ -87,11 +90,11 @@ class ExportSql extends ExportPlugin protected function setProperties(): ExportPluginProperties { - global $plugin_param, $dbi; + $GLOBALS['plugin_param'] = $GLOBALS['plugin_param'] ?? null; $hideSql = false; $hideStructure = false; - if ($plugin_param['export_type'] === 'table' && ! $plugin_param['single_table']) { + if ($GLOBALS['plugin_param']['export_type'] === 'table' && ! $GLOBALS['plugin_param']['single_table']) { $hideStructure = true; $hideSql = true; } @@ -206,7 +209,7 @@ class ExportSql extends ExportPlugin $generalOptions->addProperty($leaf); // compatibility maximization - $compats = $dbi->getCompatibilities(); + $compats = $GLOBALS['dbi']->getCompatibilities(); if (count($compats) > 0) { $values = []; foreach ($compats as $val) { @@ -267,7 +270,7 @@ class ExportSql extends ExportPlugin $subgroup->setSubgroupHeader($leaf); // server export options - if ($plugin_param['export_type'] === 'server') { + if ($GLOBALS['plugin_param']['export_type'] === 'server') { $leaf = new BoolPropertyItem( 'drop_database', sprintf(__('Add %s statement'), '<code>DROP DATABASE IF EXISTS</code>') @@ -275,7 +278,7 @@ class ExportSql extends ExportPlugin $subgroup->addProperty($leaf); } - if ($plugin_param['export_type'] === 'database') { + if ($GLOBALS['plugin_param']['export_type'] === 'database') { $createClause = '<code>CREATE DATABASE / USE</code>'; $leaf = new BoolPropertyItem( 'create_database', @@ -284,8 +287,8 @@ class ExportSql extends ExportPlugin $subgroup->addProperty($leaf); } - if ($plugin_param['export_type'] === 'table') { - $dropClause = $dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->isView() + if ($GLOBALS['plugin_param']['export_type'] === 'table') { + $dropClause = $GLOBALS['dbi']->getTable($GLOBALS['db'], $GLOBALS['table'])->isView() ? '<code>DROP VIEW</code>' : '<code>DROP TABLE</code>'; } else { @@ -523,23 +526,21 @@ class ExportSql extends ExportPlugin * * @param string $db Database * @param array $aliases Aliases of db/table/columns - * @param string $type Type of exported routine * @param string $name Verbose name of exported routine * @param array $routines List of routines to export * @param string $delimiter Delimiter to use in SQL + * @psalm-param 'FUNCTION'|'PROCEDURE' $type * * @return string SQL query */ protected function exportRoutineSQL( $db, array $aliases, - $type, + string $type, $name, array $routines, $delimiter ) { - global $crlf, $cfg, $dbi; - $text = $this->exportComment() . $this->exportComment($name) . $this->exportComment(); @@ -551,17 +552,17 @@ class ExportSql extends ExportPlugin if (! empty($GLOBALS['sql_drop_table'])) { $procQuery .= 'DROP ' . $type . ' IF EXISTS ' . Util::backquote($routine) - . $delimiter . $crlf; + . $delimiter . "\n"; } - $createQuery = $this->replaceWithAliases( - $dbi->getDefinition($db, $type, $routine), - $aliases, - $db, - '', - $flag - ); - if (! empty($createQuery) && $cfg['Export']['remove_definer_from_definitions']) { + if ($type === 'FUNCTION') { + $definition = Routines::getFunctionDefinition($GLOBALS['dbi'], $db, $routine); + } else { + $definition = Routines::getProcedureDefinition($GLOBALS['dbi'], $db, $routine); + } + + $createQuery = $this->replaceWithAliases($definition, $aliases, $db, '', $flag); + if (! empty($createQuery) && $GLOBALS['cfg']['Export']['remove_definer_from_definitions']) { // Remove definer clause from routine definitions $parser = new Parser($createQuery); $statement = $parser->statements[0]; @@ -574,7 +575,7 @@ class ExportSql extends ExportPlugin $usedAlias = true; } - $procQuery .= $createQuery . $delimiter . $crlf . $crlf; + $procQuery .= $createQuery . $delimiter . "\n\n"; } if ($usedAlias) { @@ -600,20 +601,18 @@ class ExportSql extends ExportPlugin */ public function exportRoutines($db, array $aliases = []): bool { - global $crlf, $dbi; - $dbAlias = $db; $this->initAlias($aliases, $dbAlias); $text = ''; $delimiter = '$$'; - $procedureNames = $dbi->getProceduresOrFunctions($db, 'PROCEDURE'); - $functionNames = $dbi->getProceduresOrFunctions($db, 'FUNCTION'); + $procedureNames = Routines::getProcedureNames($GLOBALS['dbi'], $db); + $functionNames = Routines::getFunctionNames($GLOBALS['dbi'], $db); if ($procedureNames || $functionNames) { - $text .= $crlf - . 'DELIMITER ' . $delimiter . $crlf; + $text .= "\n" + . 'DELIMITER ' . $delimiter . "\n"; if ($procedureNames) { $text .= $this->exportRoutineSQL( @@ -637,7 +636,7 @@ class ExportSql extends ExportPlugin ); } - $text .= 'DELIMITER ;' . $crlf; + $text .= 'DELIMITER ;' . "\n"; } if (! empty($text)) { @@ -654,22 +653,22 @@ class ExportSql extends ExportPlugin * * @return string The formatted comment */ - private function exportComment($text = '') + private function exportComment(string $text = ''): string { if (isset($GLOBALS['sql_include_comments']) && $GLOBALS['sql_include_comments']) { // see https://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html - if (empty($text)) { - return '--' . $GLOBALS['crlf']; + if ($text === '') { + return '--' . "\n"; } $lines = preg_split("/\\r\\n|\\r|\\n/", $text); if ($lines === false) { - return '--' . $GLOBALS['crlf']; + return '--' . "\n"; } $result = []; foreach ($lines as $line) { - $result[] = '-- ' . $line . $GLOBALS['crlf']; + $result[] = '-- ' . $line . "\n"; } return implode('', $result); @@ -686,7 +685,7 @@ class ExportSql extends ExportPlugin private function possibleCRLF() { if (isset($GLOBALS['sql_include_comments']) && $GLOBALS['sql_include_comments']) { - return $GLOBALS['crlf']; + return "\n"; } return ''; @@ -697,33 +696,31 @@ class ExportSql extends ExportPlugin */ public function exportFooter(): bool { - global $crlf, $dbi; - $foot = ''; if (isset($GLOBALS['sql_disable_fk'])) { - $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf; + $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . "\n"; } if (isset($GLOBALS['sql_use_transaction'])) { - $foot .= 'COMMIT;' . $crlf; + $foot .= 'COMMIT;' . "\n"; } // restore connection settings if ($this->sentCharset) { - $foot .= $crlf + $foot .= "\n" . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;' - . $crlf + . "\n" . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;' - . $crlf + . "\n" . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;' - . $crlf; + . "\n"; $this->sentCharset = false; } /* Restore timezone */ if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { - $dbi->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); + $GLOBALS['dbi']->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); } return $this->export->outputHandler($foot); @@ -735,15 +732,13 @@ class ExportSql extends ExportPlugin */ public function exportHeader(): bool { - global $crlf, $cfg, $dbi; - if (isset($GLOBALS['sql_compatibility'])) { $tmpCompat = $GLOBALS['sql_compatibility']; if ($tmpCompat === 'NONE') { $tmpCompat = ''; } - $dbi->tryQuery('SET SQL_MODE="' . $tmpCompat . '"'); + $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . $tmpCompat . '"'); unset($tmpCompat); } @@ -751,9 +746,9 @@ class ExportSql extends ExportPlugin . $this->exportComment('version ' . Version::VERSION) . $this->exportComment('https://www.phpmyadmin.net/') . $this->exportComment(); - $hostString = __('Host:') . ' ' . $cfg['Server']['host']; - if (! empty($cfg['Server']['port'])) { - $hostString .= ':' . $cfg['Server']['port']; + $hostString = __('Host:') . ' ' . $GLOBALS['cfg']['Server']['host']; + if (! empty($GLOBALS['cfg']['Server']['port'])) { + $hostString .= ':' . $GLOBALS['cfg']['Server']['port']; } $head .= $this->exportComment($hostString); @@ -762,7 +757,7 @@ class ExportSql extends ExportPlugin . Util::localisedDate() ) . $this->exportComment( - __('Server version:') . ' ' . $dbi->getVersionString() + __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString() ) . $this->exportComment(__('PHP Version:') . ' ' . PHP_VERSION) . $this->possibleCRLF(); @@ -780,25 +775,25 @@ class ExportSql extends ExportPlugin } if (isset($GLOBALS['sql_disable_fk'])) { - $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf; + $head .= 'SET FOREIGN_KEY_CHECKS=0;' . "\n"; } // We want exported AUTO_INCREMENT columns to have still same value, // do this only for recent MySQL exports if (! isset($GLOBALS['sql_compatibility']) || $GLOBALS['sql_compatibility'] === 'NONE') { - $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf; + $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . "\n"; } if (isset($GLOBALS['sql_use_transaction'])) { - $head .= 'START TRANSACTION;' . $crlf; + $head .= 'START TRANSACTION;' . "\n"; } /* Change timezone if we should export timestamps in UTC */ if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { - $head .= 'SET time_zone = "+00:00";' . $crlf; - $GLOBALS['old_tz'] = $dbi + $head .= 'SET time_zone = "+00:00";' . "\n"; + $GLOBALS['old_tz'] = $GLOBALS['dbi'] ->fetchValue('SELECT @@session.time_zone'); - $dbi->query('SET time_zone = "+00:00"'); + $GLOBALS['dbi']->query('SET time_zone = "+00:00"'); } $head .= $this->possibleCRLF(); @@ -815,18 +810,18 @@ class ExportSql extends ExportPlugin $setNames = Charsets::$mysqlCharsetMap['utf-8']; } - if ($setNames === 'utf8' && $dbi->getVersion() > 50503) { + if ($setNames === 'utf8' && $GLOBALS['dbi']->getVersion() > 50503) { $setNames = 'utf8mb4'; } - $head .= $crlf + $head .= "\n" . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=' - . '@@CHARACTER_SET_CLIENT */;' . $crlf + . '@@CHARACTER_SET_CLIENT */;' . "\n" . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS=' - . '@@CHARACTER_SET_RESULTS */;' . $crlf + . '@@CHARACTER_SET_RESULTS */;' . "\n" . '/*!40101 SET @OLD_COLLATION_CONNECTION=' - . '@@COLLATION_CONNECTION */;' . $crlf - . '/*!40101 SET NAMES ' . $setNames . ' */;' . $crlf . $crlf; + . '@@COLLATION_CONNECTION */;' . "\n" + . '/*!40101 SET NAMES ' . $setNames . ' */;' . "\n\n"; $this->sentCharset = true; } @@ -842,17 +837,11 @@ class ExportSql extends ExportPlugin */ public function exportDBCreate($db, $exportType, $dbAlias = ''): bool { - global $crlf, $dbi; - if (empty($dbAlias)) { $dbAlias = $db; } - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; if (isset($GLOBALS['sql_drop_database'])) { if ( @@ -863,7 +852,7 @@ class ExportSql extends ExportPlugin $compat, isset($GLOBALS['sql_backquotes']) ) - . ';' . $crlf + . ';' . "\n" ) ) { return false; @@ -876,7 +865,7 @@ class ExportSql extends ExportPlugin $createQuery = 'CREATE DATABASE IF NOT EXISTS ' . Util::backquoteCompat($dbAlias, $compat, isset($GLOBALS['sql_backquotes'])); - $collation = $dbi->getDbCollation($db); + $collation = $GLOBALS['dbi']->getDbCollation($db); if (mb_strpos($collation, '_')) { $createQuery .= ' DEFAULT CHARACTER SET ' . mb_substr( @@ -889,7 +878,7 @@ class ExportSql extends ExportPlugin $createQuery .= ' DEFAULT CHARACTER SET ' . $collation; } - $createQuery .= ';' . $crlf; + $createQuery .= ';' . "\n"; if (! $this->export->outputHandler($createQuery)) { return false; } @@ -905,8 +894,6 @@ class ExportSql extends ExportPlugin */ private function exportUseStatement($db, $compat): bool { - global $crlf; - if (isset($GLOBALS['sql_compatibility']) && $GLOBALS['sql_compatibility'] === 'NONE') { $result = $this->export->outputHandler( 'USE ' @@ -915,10 +902,10 @@ class ExportSql extends ExportPlugin $compat, isset($GLOBALS['sql_backquotes']) ) - . ';' . $crlf + . ';' . "\n" ); } else { - $result = $this->export->outputHandler('USE ' . $db . ';' . $crlf); + $result = $this->export->outputHandler('USE ' . $db . ';' . "\n"); } return $result; @@ -936,11 +923,7 @@ class ExportSql extends ExportPlugin $dbAlias = $db; } - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; $head = $this->exportComment() . $this->exportComment( @@ -963,8 +946,6 @@ class ExportSql extends ExportPlugin */ public function exportDBFooter($db): bool { - global $crlf; - $result = true; //add indexes to the sql dump file @@ -995,20 +976,18 @@ class ExportSql extends ExportPlugin */ public function exportEvents($db): bool { - global $crlf, $cfg, $dbi; - $text = ''; $delimiter = '$$'; - $eventNames = $dbi->fetchResult( + $eventNames = $GLOBALS['dbi']->fetchResult( 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE' - . " EVENT_SCHEMA= '" . $dbi->escapeString($db) + . " EVENT_SCHEMA= '" . $GLOBALS['dbi']->escapeString($db) . "';" ); if ($eventNames) { - $text .= $crlf - . 'DELIMITER ' . $delimiter . $crlf; + $text .= "\n" + . 'DELIMITER ' . $delimiter . "\n"; $text .= $this->exportComment() . $this->exportComment(__('Events')) @@ -1018,11 +997,11 @@ class ExportSql extends ExportPlugin if (! empty($GLOBALS['sql_drop_table'])) { $text .= 'DROP EVENT IF EXISTS ' . Util::backquote($eventName) - . $delimiter . $crlf; + . $delimiter . "\n"; } - $eventDef = $dbi->getDefinition($db, 'EVENT', $eventName); - if (! empty($eventDef) && $cfg['Export']['remove_definer_from_definitions']) { + $eventDef = Events::getDefinition($GLOBALS['dbi'], $db, $eventName); + if (! empty($eventDef) && $GLOBALS['cfg']['Export']['remove_definer_from_definitions']) { // remove definer clause from the event definition $parser = new Parser($eventDef); $statement = $parser->statements[0]; @@ -1030,10 +1009,10 @@ class ExportSql extends ExportPlugin $eventDef = $statement->build(); } - $text .= $eventDef . $delimiter . $crlf . $crlf; + $text .= $eventDef . $delimiter . "\n\n"; } - $text .= 'DELIMITER ;' . $crlf; + $text .= 'DELIMITER ;' . "\n"; } if (! empty($text)) { @@ -1102,8 +1081,6 @@ class ExportSql extends ExportPlugin $table, array $metadataTypes ): bool { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); $relationParams = $relationParameters->toArray(); @@ -1164,23 +1141,22 @@ class ExportSql extends ExportPlugin $sqlQuery = 'SELECT `page_nr`, `page_descr` FROM ' . Util::backquote($relationParameters->pdfFeature->database) . '.' . Util::backquote($relationParameters->pdfFeature->pdfPages) - . ' WHERE `db_name` = \'' . $dbi->escapeString($db) . "'"; + . ' WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . "'"; - $result = $dbi->fetchResult($sqlQuery, 'page_nr', 'page_descr'); + $result = $GLOBALS['dbi']->fetchResult($sqlQuery, 'page_nr', 'page_descr'); foreach (array_keys($result) as $page) { // insert row for pdf_page $sqlQueryRow = 'SELECT `db_name`, `page_descr` FROM ' . Util::backquote($relationParameters->pdfFeature->database) . '.' . Util::backquote($relationParameters->pdfFeature->pdfPages) - . ' WHERE `db_name` = \'' . $dbi->escapeString($db) . "'" + . ' WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . "'" . " AND `page_nr` = '" . intval($page) . "'"; if ( ! $this->exportData( $relationParameters->pdfFeature->database->getName(), $relationParameters->pdfFeature->pdfPages->getName(), - $GLOBALS['crlf'], '', $sqlQueryRow, $aliases @@ -1189,9 +1165,9 @@ class ExportSql extends ExportPlugin return false; } - $lastPage = $GLOBALS['crlf'] + $lastPage = "\n" . 'SET @LAST_PAGE = LAST_INSERT_ID();' - . $GLOBALS['crlf']; + . "\n"; if (! $this->export->outputHandler($lastPage)) { return false; } @@ -1207,7 +1183,6 @@ class ExportSql extends ExportPlugin ! $this->exportData( $relationParameters->pdfFeature->database->getName(), $relationParameters->pdfFeature->tableCoords->getName(), - $GLOBALS['crlf'], '', $sqlQueryCoords, $aliases @@ -1241,17 +1216,16 @@ class ExportSql extends ExportPlugin $sqlQuery .= Util::backquote($relationParameters->db) . '.' . Util::backquote((string) $relationParams[$type]) . ' WHERE ' . Util::backquote($dbNameColumn) - . " = '" . $dbi->escapeString($db) . "'"; + . " = '" . $GLOBALS['dbi']->escapeString($db) . "'"; if (isset($table)) { $sqlQuery .= " AND `table_name` = '" - . $dbi->escapeString($table) . "'"; + . $GLOBALS['dbi']->escapeString($table) . "'"; } if ( ! $this->exportData( (string) $relationParameters->db, (string) $relationParams[$type], - $GLOBALS['crlf'], '', $sqlQuery, $aliases @@ -1269,15 +1243,12 @@ class ExportSql extends ExportPlugin * * @param string $db the database name * @param string $view the view name - * @param string $crlf the end of line sequence * @param array $aliases Aliases of db/table/columns * * @return string resulting definition */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) + public function getTableDefStandIn($db, $view, $aliases = []) { - global $dbi; - $dbAlias = $db; $viewAlias = $view; $this->initAlias($aliases, $dbAlias, $viewAlias); @@ -1285,7 +1256,7 @@ class ExportSql extends ExportPlugin if (! empty($GLOBALS['sql_drop_table'])) { $createQuery .= 'DROP VIEW IF EXISTS ' . Util::backquote($viewAlias) - . ';' . $crlf; + . ';' . "\n"; } $createQuery .= 'CREATE TABLE '; @@ -1294,9 +1265,9 @@ class ExportSql extends ExportPlugin $createQuery .= 'IF NOT EXISTS '; } - $createQuery .= Util::backquote($viewAlias) . ' (' . $crlf; + $createQuery .= Util::backquote($viewAlias) . ' (' . "\n"; $tmp = []; - $columns = $dbi->getColumnsFull($db, $view); + $columns = $GLOBALS['dbi']->getColumnsFull($db, $view); foreach ($columns as $columnName => $definition) { $colAlias = $columnName; if (! empty($aliases[$db]['tables'][$view]['columns'][$colAlias])) { @@ -1304,33 +1275,26 @@ class ExportSql extends ExportPlugin } $tmp[] = Util::backquote($colAlias) . ' ' . - $definition['Type'] . $crlf; + $definition['Type'] . "\n"; } - return $createQuery . implode(',', $tmp) . ');' . $crlf; + return $createQuery . implode(',', $tmp) . ');' . "\n"; } /** * Returns CREATE definition that matches $view's structure * - * @param string $db the database name - * @param string $view the view name - * @param string $crlf the end of line sequence - * @param bool $addSemicolon whether to add semicolon and end-of-line at - * the end - * @param array $aliases Aliases of db/table/columns + * @param string $db the database name + * @param string $view the view name + * @param array $aliases Aliases of db/table/columns * * @return string resulting schema */ private function getTableDefForView( $db, $view, - $crlf, - $addSemicolon = true, array $aliases = [] ) { - global $dbi; - $dbAlias = $db; $viewAlias = $view; $this->initAlias($aliases, $dbAlias, $viewAlias); @@ -1339,9 +1303,9 @@ class ExportSql extends ExportPlugin $createQuery .= ' IF NOT EXISTS '; } - $createQuery .= Util::backquote($viewAlias) . '(' . $crlf; + $createQuery .= Util::backquote($viewAlias) . '(' . "\n"; - $columns = $dbi->getColumns($db, $view, true); + $columns = $GLOBALS['dbi']->getColumns($db, $view, true); $firstCol = true; foreach ($columns as $column) { @@ -1353,7 +1317,7 @@ class ExportSql extends ExportPlugin $extractedColumnspec = Util::extractColumnSpec($column['Type']); if (! $firstCol) { - $createQuery .= ',' . $crlf; + $createQuery .= ',' . "\n"; } $createQuery .= ' ' . Util::backquote($colAlias); @@ -1368,7 +1332,7 @@ class ExportSql extends ExportPlugin if (isset($column['Default'])) { $createQuery .= " DEFAULT '" - . $dbi->escapeString($column['Default']) . "'"; + . $GLOBALS['dbi']->escapeString($column['Default']) . "'"; } else { if ($column['Null'] === 'YES') { $createQuery .= ' DEFAULT NULL'; @@ -1377,19 +1341,15 @@ class ExportSql extends ExportPlugin if (! empty($column['Comment'])) { $createQuery .= " COMMENT '" - . $dbi->escapeString($column['Comment']) . "'"; + . $GLOBALS['dbi']->escapeString($column['Comment']) . "'"; } $firstCol = false; } - $createQuery .= $crlf . ')' . ($addSemicolon ? ';' : '') . $crlf; + $createQuery .= "\n" . ');' . "\n"; - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; if ($compat === 'MSSQL') { $createQuery = $this->makeCreateTableMSSQLCompatible($createQuery); @@ -1403,7 +1363,6 @@ class ExportSql extends ExportPlugin * * @param string $db the database name * @param string $table the table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case * of error * @param bool $showDates whether to include creation/ @@ -1420,7 +1379,6 @@ class ExportSql extends ExportPlugin public function getTableDef( $db, $table, - $crlf, $errorUrl, $showDates = false, $addSemicolon = true, @@ -1428,26 +1386,27 @@ class ExportSql extends ExportPlugin $updateIndexesIncrements = true, array $aliases = [] ) { - global $sql_drop_table, $sql_backquotes, $sql_constraints, - $sql_constraints_query, $sql_indexes, $sql_indexes_query, - $sql_auto_increments, $sql_drop_foreign_keys, $dbi, $cfg; + $GLOBALS['sql_drop_table'] = $GLOBALS['sql_drop_table'] ?? null; + $GLOBALS['sql_backquotes'] = $GLOBALS['sql_backquotes'] ?? null; + $GLOBALS['sql_constraints'] = $GLOBALS['sql_constraints'] ?? null; + $GLOBALS['sql_constraints_query'] = $GLOBALS['sql_constraints_query'] ?? null; + $GLOBALS['sql_indexes'] = $GLOBALS['sql_indexes'] ?? null; + $GLOBALS['sql_indexes_query'] = $GLOBALS['sql_indexes_query'] ?? null; + $GLOBALS['sql_auto_increments'] = $GLOBALS['sql_auto_increments'] ?? null; + $GLOBALS['sql_drop_foreign_keys'] = $GLOBALS['sql_drop_foreign_keys'] ?? null; $dbAlias = $db; $tableAlias = $table; $this->initAlias($aliases, $dbAlias, $tableAlias); $schemaCreate = ''; - $newCrlf = $crlf; + $newCrlf = "\n"; - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; - $result = $dbi->tryQuery( + $result = $GLOBALS['dbi']->tryQuery( 'SHOW TABLE STATUS FROM ' . Util::backquote($db) - . ' WHERE Name = \'' . $dbi->escapeString((string) $table) . '\'' + . ' WHERE Name = \'' . $GLOBALS['dbi']->escapeString((string) $table) . '\'' ); if ($result != false) { if ($result->numRows() > 0) { @@ -1460,7 +1419,7 @@ class ExportSql extends ExportPlugin strtotime($tmpres['Create_time']) ) ); - $newCrlf = $this->exportComment() . $crlf; + $newCrlf = $this->exportComment() . "\n"; } if ($showDates && isset($tmpres['Update_time']) && ! empty($tmpres['Update_time'])) { @@ -1470,7 +1429,7 @@ class ExportSql extends ExportPlugin strtotime($tmpres['Update_time']) ) ); - $newCrlf = $this->exportComment() . $crlf; + $newCrlf = $this->exportComment() . "\n"; } if ($showDates && isset($tmpres['Check_time']) && ! empty($tmpres['Check_time'])) { @@ -1480,32 +1439,32 @@ class ExportSql extends ExportPlugin strtotime($tmpres['Check_time']) ) ); - $newCrlf = $this->exportComment() . $crlf; + $newCrlf = $this->exportComment() . "\n"; } } } $schemaCreate .= $newCrlf; - if (! empty($sql_drop_table) && $dbi->getTable($db, $table)->isView()) { + if (! empty($GLOBALS['sql_drop_table']) && $GLOBALS['dbi']->getTable($db, $table)->isView()) { $schemaCreate .= 'DROP VIEW IF EXISTS ' - . Util::backquoteCompat($tableAlias, 'NONE', $sql_backquotes) . ';' - . $crlf; + . Util::backquoteCompat($tableAlias, 'NONE', $GLOBALS['sql_backquotes']) . ';' + . "\n"; } // no need to generate a DROP VIEW here, it was done earlier - if (! empty($sql_drop_table) && ! $dbi->getTable($db, $table)->isView()) { + if (! empty($GLOBALS['sql_drop_table']) && ! $GLOBALS['dbi']->getTable($db, $table)->isView()) { $schemaCreate .= 'DROP TABLE IF EXISTS ' - . Util::backquoteCompat($tableAlias, 'NONE', $sql_backquotes) . ';' - . $crlf; + . Util::backquoteCompat($tableAlias, 'NONE', $GLOBALS['sql_backquotes']) . ';' + . "\n"; } // Complete table dump, // Whether to quote table and column names or not - if ($sql_backquotes) { - $dbi->query('SET SQL_QUOTE_SHOW_CREATE = 1'); + if ($GLOBALS['sql_backquotes']) { + $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 1'); } else { - $dbi->query('SET SQL_QUOTE_SHOW_CREATE = 0'); + $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 0'); } // I don't see the reason why this unbuffered query could cause problems, @@ -1518,13 +1477,13 @@ class ExportSql extends ExportPlugin // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not // produce a displayable result for the default value of a BIT // column, nor does the mysqldump command. See MySQL bug 35796 - $dbi->tryQuery('USE ' . Util::backquote($db)); - $result = $dbi->tryQuery( + $GLOBALS['dbi']->tryQuery('USE ' . Util::backquote($db)); + $result = $GLOBALS['dbi']->tryQuery( 'SHOW CREATE TABLE ' . Util::backquote($db) . '.' . Util::backquote($table) ); // an error can happen, for example the table is crashed - $tmpError = $dbi->getError(); + $tmpError = $GLOBALS['dbi']->getError(); if ($tmpError) { $message = sprintf(__('Error reading structure for table %s:'), $db . '.' . $table); $message .= ' ' . $tmpError; @@ -1552,11 +1511,11 @@ class ExportSql extends ExportPlugin // Convert end of line chars to one that we want (note that MySQL // doesn't return query it will accept in all cases) if (mb_strpos($createQuery, "(\r\n ")) { - $createQuery = str_replace("\r\n", $crlf, $createQuery); + $createQuery = str_replace("\r\n", "\n", $createQuery); } elseif (mb_strpos($createQuery, "(\n ")) { - $createQuery = str_replace("\n", $crlf, $createQuery); + $createQuery = str_replace("\n", "\n", $createQuery); } elseif (mb_strpos($createQuery, "(\r ")) { - $createQuery = str_replace("\r", $crlf, $createQuery); + $createQuery = str_replace("\r", "\n", $createQuery); } /* @@ -1582,7 +1541,10 @@ class ExportSql extends ExportPlugin $statement = $parser->statements[0]; // exclude definition of current user - if ($cfg['Export']['remove_definer_from_definitions'] || isset($GLOBALS['sql_view_current_user'])) { + if ( + $GLOBALS['cfg']['Export']['remove_definer_from_definitions'] + || isset($GLOBALS['sql_view_current_user']) + ) { $statement->options->remove('DEFINER'); } @@ -1629,14 +1591,14 @@ class ExportSql extends ExportPlugin // Views have no constraints, indexes, etc. They do not require any // analysis. if (! $view) { - if (empty($sql_backquotes)) { + if (empty($GLOBALS['sql_backquotes'])) { // Option "Enclose table and column names with backquotes" // was checked. Context::$MODE |= Context::SQL_MODE_NO_ENCLOSING_QUOTES; } // Using appropriate quotes. - if (($compat === 'MSSQL') || ($sql_backquotes === '"')) { + if (($compat === 'MSSQL') || ($GLOBALS['sql_backquotes'] === '"')) { Context::$MODE |= Context::SQL_MODE_ANSI_QUOTES; } } @@ -1757,37 +1719,36 @@ class ExportSql extends ExportPlugin * @var string */ $alterHeader = 'ALTER TABLE ' . - Util::backquoteCompat($tableAlias, $compat, $sql_backquotes); + Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']); /** * The footer of the `ALTER` statement (usually ';') * * @var string */ - $alterFooter = ';' . $crlf; + $alterFooter = ';' . "\n"; // Generating constraints-related query. if (! empty($constraints)) { - $sql_constraints_query = $alterHeader . $crlf . ' ADD ' - . implode(',' . $crlf . ' ADD ', $constraints) + $GLOBALS['sql_constraints_query'] = $alterHeader . "\n" . ' ADD ' + . implode(',' . "\n" . ' ADD ', $constraints) . $alterFooter; - $sql_constraints = $this->generateComment( - $crlf, - $sql_constraints, + $GLOBALS['sql_constraints'] = $this->generateComment( + $GLOBALS['sql_constraints'], __('Constraints for dumped tables'), __('Constraints for table'), $tableAlias, $compat - ) . $sql_constraints_query; + ) . $GLOBALS['sql_constraints_query']; } // Generating indexes-related query. - $sql_indexes_query = ''; + $GLOBALS['sql_indexes_query'] = ''; if (! empty($indexes)) { - $sql_indexes_query .= $alterHeader . $crlf . ' ADD ' - . implode(',' . $crlf . ' ADD ', $indexes) + $GLOBALS['sql_indexes_query'] .= $alterHeader . "\n" . ' ADD ' + . implode(',' . "\n" . ' ADD ', $indexes) . $alterFooter; } @@ -1795,32 +1756,31 @@ class ExportSql extends ExportPlugin // InnoDB supports one FULLTEXT index creation at a time. // So FULLTEXT indexes are created one-by-one after other // indexes where created. - $sql_indexes_query .= $alterHeader . + $GLOBALS['sql_indexes_query'] .= $alterHeader . ' ADD ' . implode($alterFooter . $alterHeader . ' ADD ', $indexesFulltext) . $alterFooter; } if (! empty($indexes) || ! empty($indexesFulltext)) { - $sql_indexes = $this->generateComment( - $crlf, - $sql_indexes, + $GLOBALS['sql_indexes'] = $this->generateComment( + $GLOBALS['sql_indexes'], __('Indexes for dumped tables'), __('Indexes for table'), $tableAlias, $compat - ) . $sql_indexes_query; + ) . $GLOBALS['sql_indexes_query']; } // Generating drop foreign keys-related query. if (! empty($dropped)) { - $sql_drop_foreign_keys = $alterHeader . $crlf . ' DROP ' - . implode(',' . $crlf . ' DROP ', $dropped) + $GLOBALS['sql_drop_foreign_keys'] = $alterHeader . "\n" . ' DROP ' + . implode(',' . "\n" . ' DROP ', $dropped) . $alterFooter; } // Generating auto-increment-related query. if ($autoIncrement !== [] && $updateIndexesIncrements) { - $sqlAutoIncrementsQuery = $alterHeader . $crlf . ' MODIFY ' - . implode(',' . $crlf . ' MODIFY ', $autoIncrement); + $sqlAutoIncrementsQuery = $alterHeader . "\n" . ' MODIFY ' + . implode(',' . "\n" . ' MODIFY ', $autoIncrement); if ( isset($GLOBALS['sql_auto_increment']) && ($statement->entityOptions->has('AUTO_INCREMENT') !== false) @@ -1835,11 +1795,10 @@ class ExportSql extends ExportPlugin } } - $sqlAutoIncrementsQuery .= ';' . $crlf; + $sqlAutoIncrementsQuery .= ';' . "\n"; - $sql_auto_increments = $this->generateComment( - $crlf, - $sql_auto_increments, + $GLOBALS['sql_auto_increments'] = $this->generateComment( + $GLOBALS['sql_auto_increments'], __('AUTO_INCREMENT for dumped tables'), __('AUTO_INCREMENT for table'), $tableAlias, @@ -1867,7 +1826,7 @@ class ExportSql extends ExportPlugin // Restoring old mode. Context::$MODE = $oldMode; - return $warning . $schemaCreate . ($addSemicolon ? ';' . $crlf : ''); + return $warning . $schemaCreate . ($addSemicolon ? ';' . "\n" : ''); } /** @@ -1888,7 +1847,7 @@ class ExportSql extends ExportPlugin $doMime = false, array $aliases = [] ) { - global $sql_backquotes; + $GLOBALS['sql_backquotes'] = $GLOBALS['sql_backquotes'] ?? null; $dbAlias = $db; $tableAlias = $table; @@ -1917,19 +1876,19 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->exportComment( __('MEDIA TYPES FOR TABLE') . ' ' - . Util::backquoteCompat($table, 'NONE', $sql_backquotes) . ':' + . Util::backquoteCompat($table, 'NONE', $GLOBALS['sql_backquotes']) . ':' ); foreach ($mimeMap as $mimeField => $mime) { $schemaCreate .= $this->exportComment( ' ' - . Util::backquoteCompat($mimeField, 'NONE', $sql_backquotes) + . Util::backquoteCompat($mimeField, 'NONE', $GLOBALS['sql_backquotes']) ) . $this->exportComment( ' ' . Util::backquoteCompat( $mime['mimetype'], 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) ); } @@ -1942,7 +1901,7 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->exportComment( __('RELATIONSHIPS FOR TABLE') . ' ' - . Util::backquoteCompat($tableAlias, 'NONE', $sql_backquotes) + . Util::backquoteCompat($tableAlias, 'NONE', $GLOBALS['sql_backquotes']) . ':' ); @@ -1957,7 +1916,7 @@ class ExportSql extends ExportPlugin . Util::backquoteCompat( $relFieldAlias, 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) ) . $this->exportComment( @@ -1965,13 +1924,13 @@ class ExportSql extends ExportPlugin . Util::backquoteCompat( $rel['foreign_table'], 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) . ' -> ' . Util::backquoteCompat( $rel['foreign_field'], 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) ); } else { @@ -1986,7 +1945,7 @@ class ExportSql extends ExportPlugin . Util::backquoteCompat( $relFieldAlias, 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) ) . $this->exportComment( @@ -1994,13 +1953,13 @@ class ExportSql extends ExportPlugin . Util::backquoteCompat( $oneKey['ref_table_name'], 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) . ' -> ' . Util::backquoteCompat( $oneKey['ref_index_list'][$index], 'NONE', - $sql_backquotes + $GLOBALS['sql_backquotes'] ) ); } @@ -2019,9 +1978,8 @@ class ExportSql extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the seperator for a file */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { return $this->export->outputHandler($sqlQuery); } @@ -2031,7 +1989,6 @@ class ExportSql extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table','triggers','create_view', * 'stand_in' @@ -2050,7 +2007,6 @@ class ExportSql extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -2060,16 +2016,10 @@ class ExportSql extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $dbAlias = $db; $tableAlias = $table; $this->initAlias($aliases, $dbAlias, $tableAlias); - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; $formattedTableName = Util::backquoteCompat($tableAlias, $compat, isset($GLOBALS['sql_backquotes'])); $dump = $this->possibleCRLF() @@ -2083,13 +2033,13 @@ class ExportSql extends ExportPlugin __('Table structure for table') . ' ' . $formattedTableName ); $dump .= $this->exportComment(); - $dump .= $this->getTableDef($db, $table, $crlf, $errorUrl, $dates, true, false, true, $aliases); + $dump .= $this->getTableDef($db, $table, $errorUrl, $dates, true, false, true, $aliases); $dump .= $this->getTableComments($db, $table, $relation, $mime, $aliases); break; case 'triggers': $dump = ''; $delimiter = '$$'; - $triggers = $dbi->getTriggers($db, $table, $delimiter); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table, $delimiter); if ($triggers) { $dump .= $this->possibleCRLF() . $this->exportComment() @@ -2101,16 +2051,16 @@ class ExportSql extends ExportPlugin $triggerQuery = ''; foreach ($triggers as $trigger) { if (! empty($GLOBALS['sql_drop_table'])) { - $triggerQuery .= $trigger['drop'] . ';' . $crlf; + $triggerQuery .= $trigger['drop'] . ';' . "\n"; } - $triggerQuery .= 'DELIMITER ' . $delimiter . $crlf; + $triggerQuery .= 'DELIMITER ' . $delimiter . "\n"; $triggerQuery .= $this->replaceWithAliases($trigger['create'], $aliases, $db, $table, $flag); if ($flag) { $usedAlias = true; } - $triggerQuery .= 'DELIMITER ;' . $crlf; + $triggerQuery .= 'DELIMITER ;' . "\n"; } // One warning per table. @@ -2139,10 +2089,10 @@ class ExportSql extends ExportPlugin // delete the stand-in table previously created (if any) if ($exportType !== 'table') { $dump .= 'DROP TABLE IF EXISTS ' - . Util::backquote($tableAlias) . ';' . $crlf; + . Util::backquote($tableAlias) . ';' . "\n"; } - $dump .= $this->getTableDef($db, $table, $crlf, $errorUrl, $dates, true, true, true, $aliases); + $dump .= $this->getTableDef($db, $table, $errorUrl, $dates, true, true, true, $aliases); } else { $dump .= $this->exportComment( sprintf( @@ -2154,10 +2104,10 @@ class ExportSql extends ExportPlugin // delete the stand-in table previously created (if any) if ($exportType !== 'table') { $dump .= 'DROP TABLE IF EXISTS ' - . Util::backquote($tableAlias) . ';' . $crlf; + . Util::backquote($tableAlias) . ';' . "\n"; } - $dump .= $this->getTableDefForView($db, $table, $crlf, true, $aliases); + $dump .= $this->getTableDefForView($db, $table, $aliases); } break; @@ -2170,7 +2120,7 @@ class ExportSql extends ExportPlugin ) . $this->exportComment(); // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); + $dump .= $this->getTableDefStandIn($db, $table, $aliases); } // this one is built by getTableDef() to use in table copy/move @@ -2185,7 +2135,6 @@ class ExportSql extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -2193,15 +2142,14 @@ class ExportSql extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $current_row, $sql_backquotes, $dbi; + $GLOBALS['sql_backquotes'] = $GLOBALS['sql_backquotes'] ?? null; // Do not export data for merge tables - if ($dbi->getTable($db, $table)->isMerge()) { + if ($GLOBALS['dbi']->getTable($db, $table)->isMerge()) { return true; } @@ -2209,17 +2157,13 @@ class ExportSql extends ExportPlugin $tableAlias = $table; $this->initAlias($aliases, $dbAlias, $tableAlias); - if (isset($GLOBALS['sql_compatibility'])) { - $compat = $GLOBALS['sql_compatibility']; - } else { - $compat = 'NONE'; - } + $compat = $GLOBALS['sql_compatibility'] ?? 'NONE'; - $formattedTableName = Util::backquoteCompat($tableAlias, $compat, $sql_backquotes); + $formattedTableName = Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']); // Do not export data for a VIEW, unless asked to export the view as a table // (For a VIEW, this is called only when exporting a single VIEW) - if ($dbi->getTable($db, $table)->isView() && empty($GLOBALS['sql_views_as_tables'])) { + if ($GLOBALS['dbi']->getTable($db, $table)->isView() && empty($GLOBALS['sql_views_as_tables'])) { $head = $this->possibleCRLF() . $this->exportComment() . $this->exportComment('VIEW ' . $formattedTableName) @@ -2230,9 +2174,13 @@ class ExportSql extends ExportPlugin return $this->export->outputHandler($head); } - $result = $dbi->tryQuery($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->tryQuery( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); // a possible error: the table has crashed - $tmpError = $dbi->getError(); + $tmpError = $GLOBALS['dbi']->getError(); if ($tmpError) { $message = sprintf(__('Error reading data for table %s:'), $db . '.' . $table); $message .= ' ' . $tmpError; @@ -2253,7 +2201,7 @@ class ExportSql extends ExportPlugin // Get field information /** @var FieldMetadata[] $fieldsMeta */ - $fieldsMeta = $dbi->getFieldsMeta($result); + $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); $fieldSet = []; for ($j = 0; $j < $fieldsCnt; $j++) { @@ -2262,7 +2210,7 @@ class ExportSql extends ExportPlugin $colAs = $aliases[$db]['tables'][$table]['columns'][$colAs]; } - $fieldSet[$j] = Util::backquoteCompat($colAs, $compat, $sql_backquotes); + $fieldSet[$j] = Util::backquoteCompat($colAs, $compat, $GLOBALS['sql_backquotes']); } if (isset($GLOBALS['sql_type']) && $GLOBALS['sql_type'] === 'UPDATE') { @@ -2273,7 +2221,7 @@ class ExportSql extends ExportPlugin } // avoid EOL blank - $schemaInsert .= Util::backquoteCompat($tableAlias, $compat, $sql_backquotes) . ' SET'; + $schemaInsert .= Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']) . ' SET'; } else { // insert or replace if (isset($GLOBALS['sql_type']) && $GLOBALS['sql_type'] === 'REPLACE') { @@ -2297,7 +2245,7 @@ class ExportSql extends ExportPlugin //truncate table before insert if (isset($GLOBALS['sql_truncate']) && $GLOBALS['sql_truncate'] && $sqlCommand === 'INSERT') { $truncate = 'TRUNCATE TABLE ' - . Util::backquoteCompat($tableAlias, $compat, $sql_backquotes) . ';'; + . Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']) . ';'; $truncatehead = $this->possibleCRLF() . $this->exportComment() . $this->exportComment( @@ -2305,7 +2253,7 @@ class ExportSql extends ExportPlugin . $formattedTableName ) . $this->exportComment() - . $crlf; + . "\n"; $this->export->outputHandler($truncatehead); $this->export->outputHandler($truncate); } @@ -2314,12 +2262,12 @@ class ExportSql extends ExportPlugin if ($GLOBALS['sql_insert_syntax'] === 'complete' || $GLOBALS['sql_insert_syntax'] === 'both') { $fields = implode(', ', $fieldSet); $schemaInsert = $sqlCommand . $insertDelayed . ' INTO ' - . Util::backquoteCompat($tableAlias, $compat, $sql_backquotes) + . Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']) // avoid EOL blank . ' (' . $fields . ') VALUES'; } else { $schemaInsert = $sqlCommand . $insertDelayed . ' INTO ' - . Util::backquoteCompat($tableAlias, $compat, $sql_backquotes) + . Util::backquoteCompat($tableAlias, $compat, $GLOBALS['sql_backquotes']) . ' VALUES'; } } @@ -2334,13 +2282,13 @@ class ExportSql extends ExportPlugin || $GLOBALS['sql_type'] !== 'UPDATE') ) { $separator = ','; - $schemaInsert .= $crlf; + $schemaInsert .= "\n"; } else { $separator = ';'; } while ($row = $result->fetchRow()) { - if ($current_row == 0) { + if ($current_row === 0) { $head = $this->possibleCRLF() . $this->exportComment() . $this->exportComment( @@ -2348,7 +2296,7 @@ class ExportSql extends ExportPlugin . $formattedTableName ) . $this->exportComment() - . $crlf; + . "\n"; if (! $this->export->outputHandler($head)) { return false; } @@ -2356,9 +2304,9 @@ class ExportSql extends ExportPlugin // We need to SET IDENTITY_INSERT ON for MSSQL if ( - isset($GLOBALS['sql_compatibility']) + $current_row === 0 + && isset($GLOBALS['sql_compatibility']) && $GLOBALS['sql_compatibility'] === 'MSSQL' - && $current_row == 0 ) { if ( ! $this->export->outputHandler( @@ -2366,9 +2314,9 @@ class ExportSql extends ExportPlugin . Util::backquoteCompat( $tableAlias, $compat, - $sql_backquotes + $GLOBALS['sql_backquotes'] ) - . ' ON ;' . $crlf + . ' ON ;' . "\n" ) ) { return false; @@ -2377,20 +2325,20 @@ class ExportSql extends ExportPlugin $current_row++; $values = []; - for ($j = 0; $j < $fieldsCnt; $j++) { + foreach ($fieldsMeta as $j => $metaInfo) { // NULL - if (! isset($row[$j])) { + if ($row[$j] === null) { $values[] = 'NULL'; } elseif ( - $fieldsMeta[$j]->isNumeric - && ! $fieldsMeta[$j]->isMappedTypeTimestamp - && ! $fieldsMeta[$j]->isBlob + $metaInfo->isNumeric + && ! $metaInfo->isMappedTypeTimestamp + && ! $metaInfo->isBlob ) { // a number // timestamp is numeric on some MySQL 4.1, BLOBs are // sometimes numeric $values[] = $row[$j]; - } elseif ($fieldsMeta[$j]->isBinary && isset($GLOBALS['sql_hex_for_binary'])) { + } elseif ($metaInfo->isBinary && isset($GLOBALS['sql_hex_for_binary'])) { // a true BLOB // - mysqldump only generates hex data when the --hex-blob // option is used, for fields having the binary attribute @@ -2405,16 +2353,16 @@ class ExportSql extends ExportPlugin } else { $values[] = '0x' . bin2hex($row[$j]); } - } elseif ($fieldsMeta[$j]->isMappedTypeBit) { + } elseif ($metaInfo->isMappedTypeBit) { // detection of 'bit' works only on mysqli extension - $values[] = "b'" . $dbi->escapeString( + $values[] = "b'" . $GLOBALS['dbi']->escapeString( Util::printableBitValue( (int) $row[$j], - (int) $fieldsMeta[$j]->length + $metaInfo->length ) ) . "'"; - } elseif ($fieldsMeta[$j]->isMappedTypeGeometry) { + } elseif ($metaInfo->isMappedTypeGeometry) { // export GIS types as hex $values[] = '0x' . bin2hex($row[$j]); } elseif (! empty($GLOBALS['exporting_metadata']) && $row[$j] === '@LAST_PAGE') { @@ -2422,7 +2370,7 @@ class ExportSql extends ExportPlugin } else { // something else -> treat as a string $values[] = '\'' - . $dbi->escapeString($row[$j]) + . $GLOBALS['dbi']->escapeString($row[$j]) . '\''; } } @@ -2450,58 +2398,57 @@ class ExportSql extends ExportPlugin ); $insertLine .= ' WHERE ' . $tmpUniqueCondition; unset($tmpUniqueCondition, $tmpClauseIsUnique); - } else { + } elseif ($GLOBALS['sql_insert_syntax'] === 'extended' || $GLOBALS['sql_insert_syntax'] === 'both') { // Extended inserts case - if ($GLOBALS['sql_insert_syntax'] === 'extended' || $GLOBALS['sql_insert_syntax'] === 'both') { - if ($current_row == 1) { - $insertLine = $schemaInsert . '(' - . implode(', ', $values) . ')'; - } else { - $insertLine = '(' . implode(', ', $values) . ')'; - $insertLineSize = mb_strlen($insertLine); - $sqlMaxSize = $GLOBALS['sql_max_query_size']; - if (isset($sqlMaxSize) && $sqlMaxSize > 0 && $querySize + $insertLineSize > $sqlMaxSize) { - if (! $this->export->outputHandler(';' . $crlf)) { - return false; - } - - $querySize = 0; - $current_row = 1; - $insertLine = $schemaInsert . $insertLine; + if ($current_row === 1) { + $insertLine = $schemaInsert . '(' + . implode(', ', $values) . ')'; + } else { + $insertLine = '(' . implode(', ', $values) . ')'; + $insertLineSize = mb_strlen($insertLine); + $sqlMaxSize = $GLOBALS['sql_max_query_size']; + if ($sqlMaxSize > 0 && $querySize + $insertLineSize > $sqlMaxSize) { + if (! $this->export->outputHandler(';' . "\n")) { + return false; } - } - $querySize += mb_strlen($insertLine); - // Other inserts case - } else { - $insertLine = $schemaInsert - . '(' . implode(', ', $values) . ')'; + $querySize = 0; + $current_row = 1; + $insertLine = $schemaInsert . $insertLine; + } } - } - unset($values); + $querySize += mb_strlen($insertLine); + } else { + // Other inserts case + $insertLine = $schemaInsert . '(' . implode(', ', $values) . ')'; + } - if (! $this->export->outputHandler(($current_row == 1 ? '' : $separator . $crlf) . $insertLine)) { + if (! $this->export->outputHandler(($current_row === 1 ? '' : $separator . "\n") . $insertLine)) { return false; } } if ($current_row > 0) { - if (! $this->export->outputHandler(';' . $crlf)) { + if (! $this->export->outputHandler(';' . "\n")) { return false; } } // We need to SET IDENTITY_INSERT OFF for MSSQL - if (isset($GLOBALS['sql_compatibility']) && $GLOBALS['sql_compatibility'] === 'MSSQL' && $current_row > 0) { + if ( + isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] === 'MSSQL' + && $current_row > 0 + ) { $outputSucceeded = $this->export->outputHandler( - $crlf . 'SET IDENTITY_INSERT ' + "\n" . 'SET IDENTITY_INSERT ' . Util::backquoteCompat( $tableAlias, $compat, - $sql_backquotes + $GLOBALS['sql_backquotes'] ) - . ' OFF;' . $crlf + . ' OFF;' . "\n" ); if (! $outputSucceeded) { return false; @@ -2518,7 +2465,7 @@ class ExportSql extends ExportPlugin * * @return string MSSQL compatible create table statement */ - private function makeCreateTableMSSQLCompatible($createQuery) + private function makeCreateTableMSSQLCompatible(string $createQuery) { // In MSSQL // 1. No 'IF NOT EXISTS' in CREATE TABLE @@ -2529,7 +2476,7 @@ class ExportSql extends ExportPlugin // 5. No KEY and INDEX inside CREATE TABLE // 6. DOUBLE field doesn't exists, we will use FLOAT instead - $createQuery = (string) preg_replace('/^CREATE TABLE IF NOT EXISTS/', 'CREATE TABLE', (string) $createQuery); + $createQuery = (string) preg_replace('/^CREATE TABLE IF NOT EXISTS/', 'CREATE TABLE', $createQuery); // first we need to replace all lines ended with '" DATE ...,\n' // last preg_replace preserve us from situation with date text // inside DEFAULT field value @@ -2801,7 +2748,6 @@ class ExportSql extends ExportPlugin /** * Generate comment * - * @param string $crlf Carriage return character * @param string|null $sqlStatement SQL statement * @param string $comment1 Comment for dumped table * @param string $comment2 Comment for current table @@ -2811,7 +2757,6 @@ class ExportSql extends ExportPlugin * @return string */ protected function generateComment( - $crlf, ?string $sqlStatement, $comment1, $comment2, @@ -2822,7 +2767,7 @@ class ExportSql extends ExportPlugin if (isset($GLOBALS['no_constraints_comments'])) { $sqlStatement = ''; } else { - $sqlStatement = $crlf + $sqlStatement = "\n" . $this->exportComment() . $this->exportComment($comment1) . $this->exportComment(); @@ -2831,7 +2776,7 @@ class ExportSql extends ExportPlugin // comments for current table if (! isset($GLOBALS['no_constraints_comments'])) { - $sqlStatement .= $crlf + $sqlStatement .= "\n" . $this->exportComment() . $this->exportComment( $comment2 . ' ' . Util::backquoteCompat( diff --git a/libraries/classes/Plugins/Export/ExportTexytext.php b/libraries/classes/Plugins/Export/ExportTexytext.php index 80008ea99b..14b03c7e0f 100644 --- a/libraries/classes/Plugins/Export/ExportTexytext.php +++ b/libraries/classes/Plugins/Export/ExportTexytext.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -21,7 +22,6 @@ use function __; use function htmlspecialchars; use function in_array; use function str_replace; -use function stripslashes; /** * Handles the export for the Texy! text class @@ -153,7 +153,6 @@ class ExportTexytext extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -161,12 +160,11 @@ class ExportTexytext extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $what, $dbi; + $GLOBALS['what'] = $GLOBALS['what'] ?? null; $db_alias = $db; $table_alias = $table; @@ -183,19 +181,22 @@ class ExportTexytext extends ExportPlugin } // Gets the data from the database - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $fields_cnt = $result->numFields(); // If required, get fields name at the first line - if (isset($GLOBALS[$what . '_columns'])) { + if (isset($GLOBALS[$GLOBALS['what'] . '_columns'])) { $text_output = "|------\n"; foreach ($result->getFieldNames() as $col_as) { if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $text_output .= '|' - . htmlspecialchars(stripslashes($col_as)); + $text_output .= '|' . htmlspecialchars($col_as); } $text_output .= "\n|------\n"; @@ -209,7 +210,7 @@ class ExportTexytext extends ExportPlugin $text_output = ''; for ($j = 0; $j < $fields_cnt; $j++) { if (! isset($row[$j])) { - $value = $GLOBALS[$what . '_null']; + $value = $GLOBALS[$GLOBALS['what'] . '_null']; } elseif ($row[$j] == '0' || $row[$j] != '') { $value = $row[$j]; } else { @@ -238,11 +239,10 @@ class ExportTexytext extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } /** @@ -250,22 +250,19 @@ class ExportTexytext extends ExportPlugin * * @param string $db the database name * @param string $view the view name - * @param string $crlf the end of line sequence * @param array $aliases Aliases of db/table/columns * * @return string resulting definition */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) + public function getTableDefStandIn($db, $view, $aliases = []) { - global $dbi; - $text_output = ''; /** * Get the unique keys in the table */ $unique_keys = []; - $keys = $dbi->getTableIndexes($db, $view); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); foreach ($keys as $key) { if ($key['Non_unique'] != 0) { continue; @@ -277,7 +274,7 @@ class ExportTexytext extends ExportPlugin /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); /** * Displays the table structure @@ -290,7 +287,7 @@ class ExportTexytext extends ExportPlugin . '|' . __('Default') . "\n|------\n"; - $columns = $dbi->getColumns($db, $view); + $columns = $GLOBALS['dbi']->getColumns($db, $view); foreach ($columns as $column) { $col_as = $column['Field'] ?? null; if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) { @@ -309,7 +306,6 @@ class ExportTexytext extends ExportPlugin * * @param string $db the database name * @param string $table the table name - * @param string $crlf the end of line sequence * @param string $error_url the url to go back in case of error * @param bool $do_relation whether to include relation comments * @param bool $do_comments whether to include the pmadb-style column @@ -330,7 +326,6 @@ class ExportTexytext extends ExportPlugin public function getTableDef( $db, $table, - $crlf, $error_url, $do_relation, $do_comments, @@ -340,8 +335,6 @@ class ExportTexytext extends ExportPlugin $view = false, array $aliases = [] ) { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); $text_output = ''; @@ -350,7 +343,7 @@ class ExportTexytext extends ExportPlugin * Get the unique keys in the table */ $unique_keys = []; - $keys = $dbi->getTableIndexes($db, $table); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); foreach ($keys as $key) { if ($key['Non_unique'] != 0) { continue; @@ -362,7 +355,7 @@ class ExportTexytext extends ExportPlugin /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); // Check if we can use Relations [$res_rel, $have_rel] = $this->relation->getRelationsAndStatus( @@ -396,7 +389,7 @@ class ExportTexytext extends ExportPlugin $text_output .= "\n|------\n"; - $columns = $dbi->getColumns($db, $table); + $columns = $GLOBALS['dbi']->getColumns($db, $table); foreach ($columns as $column) { $col_as = $column['Field']; if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { @@ -448,8 +441,6 @@ class ExportTexytext extends ExportPlugin */ public function getTriggers($db, $table) { - global $dbi; - $dump = "|------\n"; $dump .= '|' . __('Name'); $dump .= '|' . __('Time'); @@ -457,7 +448,7 @@ class ExportTexytext extends ExportPlugin $dump .= '|' . __('Definition'); $dump .= "\n|------\n"; - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); foreach ($triggers as $trigger) { $dump .= '|' . $trigger['name']; @@ -480,7 +471,6 @@ class ExportTexytext extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table', 'triggers', 'create_view', * 'stand_in' @@ -499,7 +489,6 @@ class ExportTexytext extends ExportPlugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -509,8 +498,6 @@ class ExportTexytext extends ExportPlugin $dates = false, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); @@ -523,7 +510,6 @@ class ExportTexytext extends ExportPlugin $dump .= $this->getTableDef( $db, $table, - $crlf, $errorUrl, $do_relation, $do_comments, @@ -536,7 +522,7 @@ class ExportTexytext extends ExportPlugin break; case 'triggers': $dump = ''; - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); if ($triggers) { $dump .= '== ' . __('Triggers') . ' ' . $table_alias . "\n\n"; $dump .= $this->getTriggers($db, $table); @@ -548,7 +534,6 @@ class ExportTexytext extends ExportPlugin $dump .= $this->getTableDef( $db, $table, - $crlf, $errorUrl, $do_relation, $do_comments, @@ -563,7 +548,7 @@ class ExportTexytext extends ExportPlugin $dump .= '== ' . __('Stand-in structure for view') . ' ' . $table . "\n\n"; // export a stand-in definition to resolve view dependencies - $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases); + $dump .= $this->getTableDefStandIn($db, $table, $aliases); } return $this->export->outputHandler($dump); diff --git a/libraries/classes/Plugins/Export/ExportXml.php b/libraries/classes/Plugins/Export/ExportXml.php index 25c11eca8a..e203c495ea 100644 --- a/libraries/classes/Plugins/Export/ExportXml.php +++ b/libraries/classes/Plugins/Export/ExportXml.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; +use PhpMyAdmin\Database\Events; +use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -21,9 +24,9 @@ use function is_array; use function mb_substr; use function rtrim; use function str_replace; -use function stripslashes; use function strlen; +use const PHP_EOL; use const PHP_VERSION; /** @@ -57,13 +60,14 @@ class ExportXml extends ExportPlugin */ private function initSpecificVariables(): void { - global $table, $tables; - $this->setTable($table); - if (! is_array($tables)) { + $GLOBALS['tables'] = $GLOBALS['tables'] ?? null; + + $this->setTable($GLOBALS['table']); + if (! is_array($GLOBALS['tables'])) { return; } - $this->setTables($tables); + $this->setTables($GLOBALS['tables']); } protected function setProperties(): ExportPluginProperties @@ -147,53 +151,36 @@ class ExportXml extends ExportPlugin } /** - * Generates output for SQL defintions of routines - * - * @param string $db Database name - * @param string $type Item type to be used in XML output - * @param string $dbitype Item type used in DBI queries + * Generates output for SQL definitions. * - * @return string XML with definitions - */ - private function exportRoutinesDefinition($db, $type, $dbitype) - { - global $dbi; - - // Export routines - $routines = $dbi->getProceduresOrFunctions($db, $dbitype); - - return $this->exportDefinitions($db, $type, $dbitype, $routines); - } - - /** - * Generates output for SQL defintions - * - * @param string $db Database name - * @param string $type Item type to be used in XML output - * @param string $dbitype Item type used in DBI queries - * @param array $names Names of items to export + * @param string $db Database name + * @param string $type Item type to be used in XML output + * @param string[] $names Names of items to export + * @psalm-param 'event'|'function'|'procedure' $type * * @return string XML with definitions */ - private function exportDefinitions($db, $type, $dbitype, array $names) + private function exportDefinitions(string $db, string $type, array $names): string { - global $crlf, $dbi; - $head = ''; - if ($names) { - foreach ($names as $name) { - $head .= ' <pma:' . $type . ' name="' - . htmlspecialchars($name) . '">' . $crlf; - - // Do some formatting - $sql = $dbi->getDefinition($db, $dbitype, $name); - $sql = htmlspecialchars(rtrim($sql)); - $sql = str_replace("\n", "\n ", $sql); + foreach ($names as $name) { + $head .= ' <pma:' . $type . ' name="' . htmlspecialchars($name) . '">' . PHP_EOL; - $head .= ' ' . $sql . $crlf; - $head .= ' </pma:' . $type . '>' . $crlf; + if ($type === 'function') { + $definition = Routines::getFunctionDefinition($GLOBALS['dbi'], $db, $name); + } elseif ($type === 'procedure') { + $definition = Routines::getProcedureDefinition($GLOBALS['dbi'], $db, $name); + } else { + $definition = Events::getDefinition($GLOBALS['dbi'], $db, $name); } + + // Do some formatting + $sql = htmlspecialchars(rtrim((string) $definition)); + $sql = str_replace("\n", "\n ", $sql); + + $head .= ' ' . $sql . PHP_EOL; + $head .= ' </pma:' . $type . '>' . PHP_EOL; } return $head; @@ -206,7 +193,7 @@ class ExportXml extends ExportPlugin public function exportHeader(): bool { $this->initSpecificVariables(); - global $crlf, $cfg, $db, $dbi; + $table = $this->getTable(); $tables = $this->getTables(); @@ -223,46 +210,46 @@ class ExportXml extends ExportPlugin $charset = 'utf-8'; } - $head = '<?xml version="1.0" encoding="' . $charset . '"?>' . $crlf - . '<!--' . $crlf - . '- phpMyAdmin XML Dump' . $crlf - . '- version ' . Version::VERSION . $crlf - . '- https://www.phpmyadmin.net' . $crlf - . '-' . $crlf - . '- ' . __('Host:') . ' ' . htmlspecialchars($cfg['Server']['host']); - if (! empty($cfg['Server']['port'])) { - $head .= ':' . $cfg['Server']['port']; + $head = '<?xml version="1.0" encoding="' . $charset . '"?>' . PHP_EOL + . '<!--' . PHP_EOL + . '- phpMyAdmin XML Dump' . PHP_EOL + . '- version ' . Version::VERSION . PHP_EOL + . '- https://www.phpmyadmin.net' . PHP_EOL + . '-' . PHP_EOL + . '- ' . __('Host:') . ' ' . htmlspecialchars($GLOBALS['cfg']['Server']['host']); + if (! empty($GLOBALS['cfg']['Server']['port'])) { + $head .= ':' . $GLOBALS['cfg']['Server']['port']; } - $head .= $crlf + $head .= PHP_EOL . '- ' . __('Generation Time:') . ' ' - . Util::localisedDate() . $crlf - . '- ' . __('Server version:') . ' ' . $dbi->getVersionString() . $crlf - . '- ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf - . '-->' . $crlf . $crlf; + . Util::localisedDate() . PHP_EOL + . '- ' . __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString() . PHP_EOL + . '- ' . __('PHP Version:') . ' ' . PHP_VERSION . PHP_EOL + . '-->' . PHP_EOL . PHP_EOL; $head .= '<pma_xml_export version="1.0"' . ($export_struct ? ' xmlns:pma="https://www.phpmyadmin.net/some_doc_url/"' : '') - . '>' . $crlf; + . '>' . PHP_EOL; if ($export_struct) { - $result = $dbi->fetchResult( + $result = $GLOBALS['dbi']->fetchResult( 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`' - . ' = \'' . $dbi->escapeString($db) . '\' LIMIT 1' + . ' = \'' . $GLOBALS['dbi']->escapeString($GLOBALS['db']) . '\' LIMIT 1' ); $db_collation = $result[0]['DEFAULT_COLLATION_NAME']; $db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME']; - $head .= ' <!--' . $crlf; - $head .= ' - Structure schemas' . $crlf; - $head .= ' -->' . $crlf; - $head .= ' <pma:structure_schemas>' . $crlf; - $head .= ' <pma:database name="' . htmlspecialchars($db) + $head .= ' <!--' . PHP_EOL; + $head .= ' - Structure schemas' . PHP_EOL; + $head .= ' -->' . PHP_EOL; + $head .= ' <pma:structure_schemas>' . PHP_EOL; + $head .= ' <pma:database name="' . htmlspecialchars($GLOBALS['db']) . '" collation="' . htmlspecialchars($db_collation) . '" charset="' . htmlspecialchars($db_charset) - . '">' . $crlf; + . '">' . PHP_EOL; if (count($tables) === 0) { $tables[] = $table; @@ -270,14 +257,14 @@ class ExportXml extends ExportPlugin foreach ($tables as $table) { // Export tables and views - $result = $dbi->fetchResult( - 'SHOW CREATE TABLE ' . Util::backquote($db) . '.' + $result = $GLOBALS['dbi']->fetchResult( + 'SHOW CREATE TABLE ' . Util::backquote($GLOBALS['db']) . '.' . Util::backquote($table), 0 ); $tbl = (string) $result[$table][1]; - $is_view = $dbi->getTable($db, $table) + $is_view = $GLOBALS['dbi']->getTable($GLOBALS['db'], $table) ->isView(); if ($is_view) { @@ -295,20 +282,20 @@ class ExportXml extends ExportPlugin } $head .= ' <pma:' . $type . ' name="' . htmlspecialchars($table) . '">' - . $crlf; + . PHP_EOL; $tbl = ' ' . htmlspecialchars($tbl); $tbl = str_replace("\n", "\n ", $tbl); - $head .= $tbl . ';' . $crlf; - $head .= ' </pma:' . $type . '>' . $crlf; + $head .= $tbl . ';' . PHP_EOL; + $head .= ' </pma:' . $type . '>' . PHP_EOL; if (! isset($GLOBALS['xml_export_triggers']) || ! $GLOBALS['xml_export_triggers']) { continue; } // Export triggers - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $GLOBALS['db'], $table); if (! $triggers) { continue; } @@ -316,45 +303,53 @@ class ExportXml extends ExportPlugin foreach ($triggers as $trigger) { $code = $trigger['create']; $head .= ' <pma:trigger name="' - . htmlspecialchars($trigger['name']) . '">' . $crlf; + . htmlspecialchars($trigger['name']) . '">' . PHP_EOL; // Do some formatting $code = mb_substr(rtrim($code), 0, -3); $code = ' ' . htmlspecialchars($code); $code = str_replace("\n", "\n ", $code); - $head .= $code . $crlf; - $head .= ' </pma:trigger>' . $crlf; + $head .= $code . PHP_EOL; + $head .= ' </pma:trigger>' . PHP_EOL; } unset($trigger, $triggers); } if (isset($GLOBALS['xml_export_functions']) && $GLOBALS['xml_export_functions']) { - $head .= $this->exportRoutinesDefinition($db, 'function', 'FUNCTION'); + $head .= $this->exportDefinitions( + $GLOBALS['db'], + 'function', + Routines::getFunctionNames($GLOBALS['dbi'], $GLOBALS['db']) + ); } if (isset($GLOBALS['xml_export_procedures']) && $GLOBALS['xml_export_procedures']) { - $head .= $this->exportRoutinesDefinition($db, 'procedure', 'PROCEDURE'); + $head .= $this->exportDefinitions( + $GLOBALS['db'], + 'procedure', + Routines::getProcedureNames($GLOBALS['dbi'], $GLOBALS['db']) + ); } if (isset($GLOBALS['xml_export_events']) && $GLOBALS['xml_export_events']) { // Export events - $events = $dbi->fetchResult( + $events = $GLOBALS['dbi']->fetchResult( 'SELECT EVENT_NAME FROM information_schema.EVENTS ' - . "WHERE EVENT_SCHEMA='" . $dbi->escapeString($db) + . "WHERE EVENT_SCHEMA='" . $GLOBALS['dbi']->escapeString($GLOBALS['db']) . "'" ); - $head .= $this->exportDefinitions($db, 'event', 'EVENT', $events); + $head .= $this->exportDefinitions($GLOBALS['db'], 'event', $events); } unset($result); - $head .= ' </pma:database>' . $crlf; - $head .= ' </pma:structure_schemas>' . $crlf; + $head .= ' </pma:database>' . PHP_EOL; + $head .= ' </pma:structure_schemas>' . PHP_EOL; if ($export_data) { - $head .= $crlf; + $head .= PHP_EOL; } } @@ -379,18 +374,16 @@ class ExportXml extends ExportPlugin */ public function exportDBHeader($db, $dbAlias = ''): bool { - global $crlf; - if (empty($dbAlias)) { $dbAlias = $db; } if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) { - $head = ' <!--' . $crlf + $head = ' <!--' . PHP_EOL . ' - ' . __('Database:') . ' \'' - . htmlspecialchars($dbAlias) . '\'' . $crlf - . ' -->' . $crlf . ' <database name="' - . htmlspecialchars($dbAlias) . '">' . $crlf; + . htmlspecialchars($dbAlias) . '\'' . PHP_EOL + . ' -->' . PHP_EOL . ' <database name="' + . htmlspecialchars($dbAlias) . '">' . PHP_EOL; return $this->export->outputHandler($head); } @@ -405,10 +398,8 @@ class ExportXml extends ExportPlugin */ public function exportDBFooter($db): bool { - global $crlf; - if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) { - return $this->export->outputHandler(' </database>' . $crlf); + return $this->export->outputHandler(' </database>' . PHP_EOL); } return true; @@ -431,7 +422,6 @@ class ExportXml extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -439,15 +429,12 @@ class ExportXml extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - // Do not export data for merge tables - if ($dbi->getTable($db, $table)->isMerge()) { + if ($GLOBALS['dbi']->getTable($db, $table)->isMerge()) { return true; } @@ -455,23 +442,24 @@ class ExportXml extends ExportPlugin $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) { - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $columns_cnt = $result->numFields(); - $columns = []; - foreach ($result->getFieldNames() as $column) { - $columns[] = stripslashes($column); - } + $columns = $result->getFieldNames(); $buffer = ' <!-- ' . __('Table') . ' ' - . htmlspecialchars($table_alias) . ' -->' . $crlf; + . htmlspecialchars($table_alias) . ' -->' . PHP_EOL; if (! $this->export->outputHandler($buffer)) { return false; } while ($record = $result->fetchRow()) { $buffer = ' <table name="' - . htmlspecialchars($table_alias) . '">' . $crlf; + . htmlspecialchars($table_alias) . '">' . PHP_EOL; for ($i = 0; $i < $columns_cnt; $i++) { $col_as = $columns[$i]; if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) { @@ -487,10 +475,10 @@ class ExportXml extends ExportPlugin $buffer .= ' <column name="' . htmlspecialchars($col_as) . '">' . htmlspecialchars((string) $record[$i]) - . '</column>' . $crlf; + . '</column>' . PHP_EOL; } - $buffer .= ' </table>' . $crlf; + $buffer .= ' </table>' . PHP_EOL; if (! $this->export->outputHandler($buffer)) { return false; @@ -545,9 +533,7 @@ class ExportXml extends ExportPlugin public static function isAvailable(): bool { - global $db; - // Can't do server export. - return isset($db) && strlen($db) > 0; + return isset($GLOBALS['db']) && strlen($GLOBALS['db']) > 0; } } diff --git a/libraries/classes/Plugins/Export/ExportYaml.php b/libraries/classes/Plugins/Export/ExportYaml.php index 347325fb65..0b3c6c37f6 100644 --- a/libraries/classes/Plugins/Export/ExportYaml.php +++ b/libraries/classes/Plugins/Export/ExportYaml.php @@ -19,7 +19,8 @@ use function __; use function array_key_exists; use function is_numeric; use function str_replace; -use function stripslashes; + +use const PHP_EOL; /** * Handles the export for the YAML format @@ -67,7 +68,7 @@ class ExportYaml extends ExportPlugin */ public function exportHeader(): bool { - $this->export->outputHandler('%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf']); + $this->export->outputHandler('%YAML 1.1' . PHP_EOL . '---' . PHP_EOL); return true; } @@ -77,7 +78,7 @@ class ExportYaml extends ExportPlugin */ public function exportFooter(): bool { - $this->export->outputHandler('...' . $GLOBALS['crlf']); + $this->export->outputHandler('...' . PHP_EOL); return true; } @@ -120,7 +121,6 @@ class ExportYaml extends ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -128,20 +128,21 @@ class ExportYaml extends ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] ): bool { - global $dbi; - $db_alias = $db; $table_alias = $table; $this->initAlias($aliases, $db_alias, $table_alias); - $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $result = $GLOBALS['dbi']->query( + $sqlQuery, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $columns_cnt = $result->numFields(); - $fieldsMeta = $dbi->getFieldsMeta($result); + $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result); $columns = []; foreach ($fieldsMeta as $i => $field) { @@ -150,7 +151,7 @@ class ExportYaml extends ExportPlugin $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as]; } - $columns[$i] = stripslashes($col_as); + $columns[$i] = $col_as; } $record_cnt = 0; @@ -159,10 +160,10 @@ class ExportYaml extends ExportPlugin // Output table name as comment if this is the first record of the table if ($record_cnt == 1) { - $buffer = '# ' . $db_alias . '.' . $table_alias . $crlf; - $buffer .= '-' . $crlf; + $buffer = '# ' . $db_alias . '.' . $table_alias . PHP_EOL; + $buffer .= '-' . PHP_EOL; } else { - $buffer = '-' . $crlf; + $buffer = '-' . PHP_EOL; } for ($i = 0; $i < $columns_cnt; $i++) { @@ -171,13 +172,13 @@ class ExportYaml extends ExportPlugin } if ($record[$i] === null) { - $buffer .= ' ' . $columns[$i] . ': null' . $crlf; + $buffer .= ' ' . $columns[$i] . ': null' . PHP_EOL; continue; } $isNotString = isset($fieldsMeta[$i]) && $fieldsMeta[$i]->isNotType(FieldMetadata::TYPE_STRING); if (is_numeric($record[$i]) && $isNotString) { - $buffer .= ' ' . $columns[$i] . ': ' . $record[$i] . $crlf; + $buffer .= ' ' . $columns[$i] . ': ' . $record[$i] . PHP_EOL; continue; } @@ -196,7 +197,7 @@ class ExportYaml extends ExportPlugin ], $record[$i] ); - $buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . $crlf; + $buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . PHP_EOL; } if (! $this->export->outputHandler($buffer)) { @@ -212,10 +213,9 @@ class ExportYaml extends ExportPlugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the end of line sequence */ - public function exportRawQuery(string $errorUrl, string $sqlQuery, string $crlf): bool + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool { - return $this->exportData('', '', $crlf, $errorUrl, $sqlQuery); + return $this->exportData('', '', $errorUrl, $sqlQuery); } } diff --git a/libraries/classes/Plugins/Export/Helpers/Pdf.php b/libraries/classes/Plugins/Export/Helpers/Pdf.php index d24a4c2c21..1e09d807f5 100644 --- a/libraries/classes/Plugins/Export/Helpers/Pdf.php +++ b/libraries/classes/Plugins/Export/Helpers/Pdf.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export\Helpers; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Dbal\ResultInterface; use PhpMyAdmin\FieldMetadata; @@ -115,10 +116,8 @@ class Pdf extends PdfLib $diskcache = false, $pdfa = false ) { - global $dbi; - parent::__construct($orientation, $unit, $format, $unicode, $encoding, $diskcache, $pdfa); - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); $this->transformations = new Transformations(); } @@ -180,7 +179,8 @@ class Pdf extends PdfLib // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps public function Header(): void { - global $maxY; + $GLOBALS['maxY'] = $GLOBALS['maxY'] ?? null; + // We don't want automatic page breaks while generating header // as this can lead to infinite recursion as auto generated page // will want header as well causing another page break @@ -210,7 +210,7 @@ class Pdf extends PdfLib $this->SetXY($l, $this->tMargin); $this->MultiCell($this->tablewidths[$col], $this->FontSizePt, $txt); $l += $this->tablewidths[$col]; - $maxY = $maxY < $this->GetY() ? $this->GetY() : $maxY; + $GLOBALS['maxY'] = $GLOBALS['maxY'] < $this->GetY() ? $this->GetY() : $GLOBALS['maxY']; } $this->SetXY($this->lMargin, $this->tMargin); @@ -218,7 +218,7 @@ class Pdf extends PdfLib $l = $this->lMargin; foreach ($this->colTitles as $col => $txt) { $this->SetXY($l, $this->tMargin); - $this->Cell($this->tablewidths[$col], $maxY - $this->tMargin, '', 1, 0, 'L', true); + $this->Cell($this->tablewidths[$col], $GLOBALS['maxY'] - $this->tMargin, '', 1, 0, 'L', true); $this->SetXY($l, $this->tMargin); $this->MultiCell($this->tablewidths[$col], $this->FontSizePt, $txt, 0, 'C'); $l += $this->tablewidths[$col]; @@ -231,7 +231,7 @@ class Pdf extends PdfLib // phpcs:enable - $this->dataY = $maxY; + $this->dataY = $GLOBALS['maxY']; $this->setAutoPageBreak(true); } @@ -336,9 +336,7 @@ class Pdf extends PdfLib */ public function getTriggers($db, $table): void { - global $dbi; - - $triggers = $dbi->getTriggers($db, $table); + $triggers = Triggers::getDetails($GLOBALS['dbi'], $db, $table); if ($triggers === []) { return; //prevents printing blank trigger list for any table } @@ -486,8 +484,6 @@ class Pdf extends PdfLib $view = false, array $aliases = [] ): void { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); unset( @@ -502,7 +498,7 @@ class Pdf extends PdfLib /** * Gets fields properties */ - $dbi->selectDb($db); + $GLOBALS['dbi']->selectDb($db); /** * All these three checks do_relation, do_comment and do_mime is @@ -575,7 +571,7 @@ class Pdf extends PdfLib $mime_map = $this->transformations->getMime($db, $table, true); } - $columns = $dbi->getColumns($db, $table); + $columns = $GLOBALS['dbi']->getColumns($db, $table); // some things to set and 'remember' $l = $this->lMargin; @@ -706,8 +702,6 @@ class Pdf extends PdfLib */ public function mysqlReport($query): void { - global $dbi; - unset( $this->tablewidths, $this->colTitles, @@ -720,9 +714,13 @@ class Pdf extends PdfLib /** * Pass 1 for column widths */ - $this->results = $dbi->query($query, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $this->results = $GLOBALS['dbi']->query( + $query, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $this->numFields = $this->results->numFields(); - $this->fields = $dbi->getFieldsMeta($this->results); + $this->fields = $GLOBALS['dbi']->getFieldsMeta($this->results); // sColWidth = starting col width (an average size width) $availableWidth = $this->w - $this->lMargin - $this->rMargin; @@ -849,7 +847,11 @@ class Pdf extends PdfLib // Pass 2 - $this->results = $dbi->query($query, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); + $this->results = $GLOBALS['dbi']->query( + $query, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_UNBUFFERED + ); $this->SetY($this->tMargin); $this->AddPage(); $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9); diff --git a/libraries/classes/Plugins/Export/README.md b/libraries/classes/Plugins/Export/README.md index 26c4c3839f..5dbe091110 100644 --- a/libraries/classes/Plugins/Export/README.md +++ b/libraries/classes/Plugins/Export/README.md @@ -178,7 +178,6 @@ class Export[Name] extends PhpMyAdmin\Plugins\ExportPlugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -188,7 +187,6 @@ class Export[Name] extends PhpMyAdmin\Plugins\ExportPlugin public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] diff --git a/libraries/classes/Plugins/ExportPlugin.php b/libraries/classes/Plugins/ExportPlugin.php index 3358d1f081..0985f637aa 100644 --- a/libraries/classes/Plugins/ExportPlugin.php +++ b/libraries/classes/Plugins/ExportPlugin.php @@ -42,11 +42,11 @@ abstract class ExportPlugin implements Plugin /** * @psalm-suppress InvalidArrayOffset, MixedAssignment, MixedMethodCall */ - final public function __construct() + final public function __construct(Relation $relation, Export $export, Transformations $transformations) { - $this->relation = $GLOBALS['containerBuilder']->get('relation'); - $this->export = $GLOBALS['containerBuilder']->get('export'); - $this->transformations = $GLOBALS['containerBuilder']->get('transformations'); + $this->relation = $relation; + $this->export = $export; + $this->transformations = $transformations; $this->init(); $this->properties = $this->setProperties(); } @@ -90,7 +90,6 @@ abstract class ExportPlugin implements Plugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery SQL query for obtaining data * @param array $aliases Aliases of db/table/columns @@ -98,7 +97,6 @@ abstract class ExportPlugin implements Plugin abstract public function exportData( $db, $table, - $crlf, $errorUrl, $sqlQuery, array $aliases = [] @@ -135,13 +133,9 @@ abstract class ExportPlugin implements Plugin * * @param string $errorUrl the url to go back in case of error * @param string $sqlQuery the rawquery to output - * @param string $crlf the seperator for a file */ - public function exportRawQuery( - string $errorUrl, - string $sqlQuery, - string $crlf - ): bool { + public function exportRawQuery(string $errorUrl, string $sqlQuery): bool + { return false; } @@ -150,7 +144,6 @@ abstract class ExportPlugin implements Plugin * * @param string $db database name * @param string $table table name - * @param string $crlf the end of line sequence * @param string $errorUrl the url to go back in case of error * @param string $exportMode 'create_table','triggers','create_view', * 'stand_in' @@ -168,7 +161,6 @@ abstract class ExportPlugin implements Plugin public function exportStructure( $db, $table, - $crlf, $errorUrl, $exportMode, $exportType, @@ -201,12 +193,11 @@ abstract class ExportPlugin implements Plugin * * @param string $db the database name * @param string $view the view name - * @param string $crlf the end of line sequence * @param array $aliases Aliases of db/table/columns * * @return string resulting definition */ - public function getTableDefStandIn($db, $view, $crlf, $aliases = []) + public function getTableDefStandIn($db, $view, $aliases = []) { return ''; } diff --git a/libraries/classes/Plugins/Import/ImportCsv.php b/libraries/classes/Plugins/Import/ImportCsv.php index 928491cf7d..acc1296b9a 100644 --- a/libraries/classes/Plugins/Import/ImportCsv.php +++ b/libraries/classes/Plugins/Import/ImportCsv.php @@ -154,36 +154,50 @@ class ImportCsv extends AbstractImportCsv /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $error, $message, $dbi; - global $db, $table, $csv_terminated, $csv_enclosed, $csv_escaped, - $csv_new_line, $csv_columns, $errorUrl; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; + $GLOBALS['csv_terminated'] = $GLOBALS['csv_terminated'] ?? null; + $GLOBALS['csv_enclosed'] = $GLOBALS['csv_enclosed'] ?? null; + $GLOBALS['csv_escaped'] = $GLOBALS['csv_escaped'] ?? null; + $GLOBALS['csv_new_line'] = $GLOBALS['csv_new_line'] ?? null; + $GLOBALS['csv_columns'] = $GLOBALS['csv_columns'] ?? null; + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + // $csv_replace and $csv_ignore should have been here, // but we use directly from $_POST - global $timeout_passed, $finished; + + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; $replacements = [ '\\n' => "\n", '\\t' => "\t", '\\r' => "\r", ]; - $csv_terminated = strtr($csv_terminated, $replacements); - $csv_enclosed = strtr($csv_enclosed, $replacements); - $csv_escaped = strtr($csv_escaped, $replacements); - $csv_new_line = strtr($csv_new_line, $replacements); - - [$error, $message] = $this->buildErrorsForParams( - $csv_terminated, - $csv_enclosed, - $csv_escaped, - $csv_new_line, - (string) $errorUrl + $GLOBALS['csv_terminated'] = strtr($GLOBALS['csv_terminated'], $replacements); + $GLOBALS['csv_enclosed'] = strtr($GLOBALS['csv_enclosed'], $replacements); + $GLOBALS['csv_escaped'] = strtr($GLOBALS['csv_escaped'], $replacements); + $GLOBALS['csv_new_line'] = strtr($GLOBALS['csv_new_line'], $replacements); + + [$GLOBALS['error'], $GLOBALS['message']] = $this->buildErrorsForParams( + $GLOBALS['csv_terminated'], + $GLOBALS['csv_enclosed'], + $GLOBALS['csv_escaped'], + $GLOBALS['csv_new_line'], + (string) $GLOBALS['errorUrl'] ); - [$sql_template, $required_fields, $fields] = $this->getSqlTemplateAndRequiredFields($db, $table, $csv_columns); + [$sql_template, $required_fields, $fields] = $this->getSqlTemplateAndRequiredFields( + $GLOBALS['db'], + $GLOBALS['table'], + $GLOBALS['csv_columns'] + ); + + $sqlStatements = []; // Defaults for parser $i = 0; @@ -218,8 +232,8 @@ class ImportCsv extends AbstractImportCsv $buffer = ''; $col_count = 0; $max_cols = 0; - $csv_terminated_len = mb_strlen($csv_terminated); - while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $csv_terminated_len = mb_strlen($GLOBALS['csv_terminated']); + while (! ($GLOBALS['finished'] && $i >= $len) && ! $GLOBALS['error'] && ! $GLOBALS['timeout_passed']) { $data = $this->import->getNextChunk($importHandle); if ($data === false) { // subtract data we didn't handle yet and stop processing @@ -233,23 +247,23 @@ class ImportCsv extends AbstractImportCsv unset($data); // Force a trailing new line at EOF to prevent parsing problems - if ($finished && $buffer) { + if ($GLOBALS['finished'] && $buffer) { $finalch = mb_substr($buffer, -1); - if ($csv_new_line === 'auto' && $finalch != "\r" && $finalch != "\n") { + if ($GLOBALS['csv_new_line'] === 'auto' && $finalch != "\r" && $finalch != "\n") { $buffer .= "\n"; - } elseif ($csv_new_line !== 'auto' && $finalch != $csv_new_line) { - $buffer .= $csv_new_line; + } elseif ($GLOBALS['csv_new_line'] !== 'auto' && $finalch != $GLOBALS['csv_new_line']) { + $buffer .= $GLOBALS['csv_new_line']; } } // Do not parse string when we're not at the end // and don't have new line inside if ( - ($csv_new_line === 'auto' + ($GLOBALS['csv_new_line'] === 'auto' && ! str_contains($buffer, "\r") && ! str_contains($buffer, "\n")) - || ($csv_new_line !== 'auto' - && ! str_contains($buffer, $csv_new_line)) + || ($GLOBALS['csv_new_line'] !== 'auto' + && ! str_contains($buffer, $GLOBALS['csv_new_line'])) ) { continue; } @@ -260,7 +274,7 @@ class ImportCsv extends AbstractImportCsv // Currently parsed char $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } @@ -268,11 +282,11 @@ class ImportCsv extends AbstractImportCsv while ($i < $len) { // Deadlock protection if ($lasti == $i && $lastlen == $len) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid format of CSV input on line %d.') ); - $message->addParam($line); - $error = true; + $GLOBALS['message']->addParam($line); + $GLOBALS['error'] = true; break; } @@ -282,7 +296,7 @@ class ImportCsv extends AbstractImportCsv // This can happen with auto EOL and \r at the end of buffer if (! $csv_finish) { // Grab empty field - if ($ch == $csv_terminated) { + if ($ch == $GLOBALS['csv_terminated']) { if ($i == $len - 1) { break; } @@ -290,7 +304,7 @@ class ImportCsv extends AbstractImportCsv $values[] = ''; $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } @@ -300,7 +314,7 @@ class ImportCsv extends AbstractImportCsv // Grab one field $fallbacki = $i; - if ($ch == $csv_enclosed) { + if ($ch == $GLOBALS['csv_enclosed']) { if ($i == $len - 1) { break; } @@ -308,7 +322,7 @@ class ImportCsv extends AbstractImportCsv $need_end = true; $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } @@ -320,15 +334,15 @@ class ImportCsv extends AbstractImportCsv $value = ''; while ( ($need_end - && ($ch != $csv_enclosed - || $csv_enclosed == $csv_escaped)) + && ($ch != $GLOBALS['csv_enclosed'] + || $GLOBALS['csv_enclosed'] == $GLOBALS['csv_escaped'])) || (! $need_end - && ! ($ch == $csv_terminated - || $ch == $csv_new_line - || ($csv_new_line === 'auto' + && ! ($ch == $GLOBALS['csv_terminated'] + || $ch == $GLOBALS['csv_new_line'] + || ($GLOBALS['csv_new_line'] === 'auto' && ($ch == "\r" || $ch == "\n")))) ) { - if ($ch == $csv_escaped) { + if ($ch == $GLOBALS['csv_escaped']) { if ($i == $len - 1) { $fail = true; break; @@ -336,16 +350,16 @@ class ImportCsv extends AbstractImportCsv $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } if ( - $csv_enclosed == $csv_escaped - && ($ch == $csv_terminated - || $ch == $csv_new_line - || ($csv_new_line === 'auto' + $GLOBALS['csv_enclosed'] == $GLOBALS['csv_escaped'] + && ($ch == $GLOBALS['csv_terminated'] + || $ch == $GLOBALS['csv_new_line'] + || ($GLOBALS['csv_new_line'] === 'auto' && ($ch == "\r" || $ch == "\n"))) ) { break; @@ -354,7 +368,7 @@ class ImportCsv extends AbstractImportCsv $value .= $ch; if ($i == $len - 1) { - if (! $finished) { + if (! $GLOBALS['finished']) { $fail = true; } @@ -363,7 +377,7 @@ class ImportCsv extends AbstractImportCsv $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len <= 1 || $ch != $csv_terminated[0]) { + if ($csv_terminated_len <= 1 || $ch != $GLOBALS['csv_terminated'][0]) { continue; } @@ -379,7 +393,7 @@ class ImportCsv extends AbstractImportCsv if ($fail) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $i += $csv_terminated_len - 1; } @@ -387,13 +401,13 @@ class ImportCsv extends AbstractImportCsv } // Need to strip trailing enclosing char? - if ($need_end && $ch == $csv_enclosed) { - if ($finished && $i == $len - 1) { + if ($need_end && $ch == $GLOBALS['csv_enclosed']) { + if ($GLOBALS['finished'] && $i == $len - 1) { $ch = null; } elseif ($i == $len - 1) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $i += $csv_terminated_len - 1; } @@ -401,7 +415,7 @@ class ImportCsv extends AbstractImportCsv } else { $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } @@ -410,19 +424,19 @@ class ImportCsv extends AbstractImportCsv // Are we at the end? if ( - $ch == $csv_new_line - || ($csv_new_line === 'auto' && ($ch == "\r" || $ch == "\n")) - || ($finished && $i == $len - 1) + $ch == $GLOBALS['csv_new_line'] + || ($GLOBALS['csv_new_line'] === 'auto' && ($ch == "\r" || $ch == "\n")) + || ($GLOBALS['finished'] && $i == $len - 1) ) { $csv_finish = true; } // Go to next char - if ($ch == $csv_terminated) { + if ($ch == $GLOBALS['csv_terminated']) { if ($i == $len - 1) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $i += $csv_terminated_len - 1; } @@ -431,7 +445,7 @@ class ImportCsv extends AbstractImportCsv $i++; $ch = mb_substr($buffer, $i, 1); - if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { + if ($csv_terminated_len > 1 && $ch == $GLOBALS['csv_terminated'][0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } @@ -444,14 +458,14 @@ class ImportCsv extends AbstractImportCsv // End of line if ( ! $csv_finish - && $ch != $csv_new_line - && ($csv_new_line !== 'auto' || ($ch != "\r" && $ch != "\n")) + && $ch != $GLOBALS['csv_new_line'] + && ($GLOBALS['csv_new_line'] !== 'auto' || ($ch != "\r" && $ch != "\n")) ) { continue; } - if ($csv_new_line === 'auto' && $ch == "\r") { // Handle "\r\n" - if ($i >= ($len - 2) && ! $finished) { + if ($GLOBALS['csv_new_line'] === 'auto' && $ch == "\r") { // Handle "\r\n" + if ($i >= ($len - 2) && ! $GLOBALS['finished']) { break; // We need more data to decide new line } @@ -485,13 +499,13 @@ class ImportCsv extends AbstractImportCsv if (count($values) != $required_fields) { // Hack for excel if ($values[count($values) - 1] !== ';') { - $message = Message::error( + $GLOBALS['message'] = Message::error( __( 'Invalid column count in CSV input on line %d.' ) ); - $message->addParam($line); - $error = true; + $GLOBALS['message']->addParam($line); + $GLOBALS['error'] = true; break; } @@ -509,7 +523,7 @@ class ImportCsv extends AbstractImportCsv $sql .= 'NULL'; } else { $sql .= '\'' - . $dbi->escapeString($val) + . $GLOBALS['dbi']->escapeString($val) . '\''; } @@ -532,7 +546,7 @@ class ImportCsv extends AbstractImportCsv * @todo maybe we could add original line to verbose * SQL in comment */ - $this->import->runQuery($sql, $sql, $sql_data); + $this->import->runQuery($sql, $sqlStatements); } $line++; @@ -544,13 +558,13 @@ class ImportCsv extends AbstractImportCsv $lasti = -1; $ch = mb_substr($buffer, 0, 1); if ($max_lines > 0 && $line == $max_lines_constraint) { - $finished = 1; + $GLOBALS['finished'] = 1; break; } } if ($max_lines > 0 && $line == $max_lines_constraint) { - $finished = 1; + $GLOBALS['finished'] = 1; break; } } @@ -571,7 +585,7 @@ class ImportCsv extends AbstractImportCsv array_shift($rows); } - $tbl_name = $this->getTableNameFromImport((string) $db); + $tbl_name = $this->getTableNameFromImport((string) $GLOBALS['db']); $tables[] = [ $tbl_name, @@ -604,34 +618,36 @@ class ImportCsv extends AbstractImportCsv if (isset($_REQUEST['csv_new_db_name']) && strlen($_REQUEST['csv_new_db_name']) > 0) { $newDb = $_REQUEST['csv_new_db_name']; } else { - $result = $dbi->fetchResult('SHOW DATABASES'); + $result = $GLOBALS['dbi']->fetchResult('SHOW DATABASES'); $newDb = 'CSV_DB ' . (count($result) + 1); } - [$db_name, $options] = $this->getDbnameAndOptions($db, $newDb); + [$db_name, $options] = $this->getDbnameAndOptions($GLOBALS['db'], $newDb); /* Non-applicable parameters */ $create = null; /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); + $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sqlStatements); unset($tables, $analyses); } // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); - if (count($values) == 0 || $error !== false) { - return; + if (count($values) == 0 || $GLOBALS['error'] !== false) { + return $sqlStatements; } - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid format of CSV input on line %d.') ); - $message->addParam($line); - $error = true; + $GLOBALS['message']->addParam($line); + $GLOBALS['error'] = true; + + return $sqlStatements; } private function buildErrorsForParams( @@ -641,15 +657,16 @@ class ImportCsv extends AbstractImportCsv string $csvNewLine, string $errUrl ): array { - global $error, $message; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $param_error = false; if (strlen($csvTerminated) === 0) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid parameter for CSV import: %s') ); - $message->addParam(__('Columns terminated with')); - $error = true; + $GLOBALS['message']->addParam(__('Columns terminated with')); + $GLOBALS['error'] = true; $param_error = true; // The default dialog of MS Excel when generating a CSV produces a // semi-colon-separated file with no chance of specifying the @@ -660,29 +677,29 @@ class ImportCsv extends AbstractImportCsv // But the parser won't work correctly with strings so we allow just // one character. } elseif (mb_strlen($csvEnclosed) > 1) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid parameter for CSV import: %s') ); - $message->addParam(__('Columns enclosed with')); - $error = true; + $GLOBALS['message']->addParam(__('Columns enclosed with')); + $GLOBALS['error'] = true; $param_error = true; // I could not find a test case where having no escaping characters // confuses this script. // But the parser won't work correctly with strings so we allow just // one character. } elseif (mb_strlen($csvEscaped) > 1) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid parameter for CSV import: %s') ); - $message->addParam(__('Columns escaped with')); - $error = true; + $GLOBALS['message']->addParam(__('Columns escaped with')); + $GLOBALS['error'] = true; $param_error = true; } elseif (mb_strlen($csvNewLine) != 1 && $csvNewLine !== 'auto') { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('Invalid parameter for CSV import: %s') ); - $message->addParam(__('Lines terminated with')); - $error = true; + $GLOBALS['message']->addParam(__('Lines terminated with')); + $GLOBALS['error'] = true; $param_error = true; } @@ -690,21 +707,21 @@ class ImportCsv extends AbstractImportCsv // indicate that immediately. if ($param_error) { Generator::mysqlDie( - $message->getMessage(), + $GLOBALS['message']->getMessage(), '', false, $errUrl ); } - return [$error, $message]; + return [$GLOBALS['error'], $GLOBALS['message']]; } private function getTableNameFromImport(string $databaseName): string { - global $import_file_name, $dbi; + $GLOBALS['import_file_name'] = $GLOBALS['import_file_name'] ?? null; - $importFileName = basename($import_file_name, '.csv'); + $importFileName = basename($GLOBALS['import_file_name'], '.csv'); $importFileName = mb_strtolower($importFileName); $importFileName = (string) preg_replace('/[^a-zA-Z0-9_]/', '_', $importFileName); @@ -714,7 +731,7 @@ class ImportCsv extends AbstractImportCsv } if (mb_strlen($databaseName)) { - $result = $dbi->fetchResult('SHOW TABLES'); + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); // logic to get table name from filename // if no table then use filename as table name @@ -767,7 +784,8 @@ class ImportCsv extends AbstractImportCsv ?string $table, ?string $csvColumns ): array { - global $dbi, $error, $message; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $requiredFields = 0; $sqlTemplate = ''; @@ -780,7 +798,7 @@ class ImportCsv extends AbstractImportCsv $sqlTemplate .= ' INTO ' . Util::backquote($table); - $tmp_fields = $dbi->getColumns($db, $table); + $tmp_fields = $GLOBALS['dbi']->getColumns($db, $table); if (empty($csvColumns)) { $fields = $tmp_fields; @@ -808,15 +826,15 @@ class ImportCsv extends AbstractImportCsv } if (! $found) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __( 'Invalid column (%s) specified! Ensure that columns' . ' names are spelled correctly, separated by commas' . ', and not enclosed in quotes.' ) ); - $message->addParam($val); - $error = true; + $GLOBALS['message']->addParam($val); + $GLOBALS['error'] = true; break; } diff --git a/libraries/classes/Plugins/Import/ImportLdi.php b/libraries/classes/Plugins/Import/ImportLdi.php index 15f7356956..1c6e94aaff 100644 --- a/libraries/classes/Plugins/Import/ImportLdi.php +++ b/libraries/classes/Plugins/Import/ImportLdi.php @@ -87,76 +87,86 @@ class ImportLdi extends AbstractImportCsv /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $finished, $import_file, $charset_conversion, $table, $dbi; - global $ldi_local_option, $ldi_replace, $ldi_ignore, $ldi_terminated, - $ldi_enclosed, $ldi_escaped, $ldi_new_line, $skip_queries, $ldi_columns; - + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; + $GLOBALS['import_file'] = $GLOBALS['import_file'] ?? null; + $GLOBALS['charset_conversion'] = $GLOBALS['charset_conversion'] ?? null; + $GLOBALS['ldi_local_option'] = $GLOBALS['ldi_local_option'] ?? null; + $GLOBALS['ldi_replace'] = $GLOBALS['ldi_replace'] ?? null; + $GLOBALS['ldi_ignore'] = $GLOBALS['ldi_ignore'] ?? null; + $GLOBALS['ldi_terminated'] = $GLOBALS['ldi_terminated'] ?? null; + $GLOBALS['ldi_enclosed'] = $GLOBALS['ldi_enclosed'] ?? null; + $GLOBALS['ldi_escaped'] = $GLOBALS['ldi_escaped'] ?? null; + $GLOBALS['ldi_new_line'] = $GLOBALS['ldi_new_line'] ?? null; + $GLOBALS['skip_queries'] = $GLOBALS['skip_queries'] ?? null; + $GLOBALS['ldi_columns'] = $GLOBALS['ldi_columns'] ?? null; + + $sqlStatements = []; $compression = ''; if ($importHandle !== null) { $compression = $importHandle->getCompression(); } - if ($import_file === 'none' || $compression !== 'none' || $charset_conversion) { + if ($GLOBALS['import_file'] === 'none' || $compression !== 'none' || $GLOBALS['charset_conversion']) { // We handle only some kind of data! $GLOBALS['message'] = Message::error( __('This plugin does not support compressed imports!') ); $GLOBALS['error'] = true; - return; + return []; } $sql = 'LOAD DATA'; - if (isset($ldi_local_option)) { + if (isset($GLOBALS['ldi_local_option'])) { $sql .= ' LOCAL'; } - $sql .= ' INFILE \'' . $dbi->escapeString($import_file) + $sql .= ' INFILE \'' . $GLOBALS['dbi']->escapeString($GLOBALS['import_file']) . '\''; - if (isset($ldi_replace)) { + if (isset($GLOBALS['ldi_replace'])) { $sql .= ' REPLACE'; - } elseif (isset($ldi_ignore)) { + } elseif (isset($GLOBALS['ldi_ignore'])) { $sql .= ' IGNORE'; } - $sql .= ' INTO TABLE ' . Util::backquote($table); + $sql .= ' INTO TABLE ' . Util::backquote($GLOBALS['table']); - if (strlen((string) $ldi_terminated) > 0) { - $sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\''; + if (strlen((string) $GLOBALS['ldi_terminated']) > 0) { + $sql .= ' FIELDS TERMINATED BY \'' . $GLOBALS['ldi_terminated'] . '\''; } - if (strlen((string) $ldi_enclosed) > 0) { + if (strlen((string) $GLOBALS['ldi_enclosed']) > 0) { $sql .= ' ENCLOSED BY \'' - . $dbi->escapeString($ldi_enclosed) . '\''; + . $GLOBALS['dbi']->escapeString($GLOBALS['ldi_enclosed']) . '\''; } - if (strlen((string) $ldi_escaped) > 0) { + if (strlen((string) $GLOBALS['ldi_escaped']) > 0) { $sql .= ' ESCAPED BY \'' - . $dbi->escapeString($ldi_escaped) . '\''; + . $GLOBALS['dbi']->escapeString($GLOBALS['ldi_escaped']) . '\''; } - if (strlen((string) $ldi_new_line) > 0) { - if ($ldi_new_line === 'auto') { - $ldi_new_line = PHP_EOL == "\n" + if (strlen((string) $GLOBALS['ldi_new_line']) > 0) { + if ($GLOBALS['ldi_new_line'] === 'auto') { + $GLOBALS['ldi_new_line'] = PHP_EOL == "\n" ? '\n' : '\r\n'; } - $sql .= ' LINES TERMINATED BY \'' . $ldi_new_line . '\''; + $sql .= ' LINES TERMINATED BY \'' . $GLOBALS['ldi_new_line'] . '\''; } - if ($skip_queries > 0) { - $sql .= ' IGNORE ' . $skip_queries . ' LINES'; - $skip_queries = 0; + if ($GLOBALS['skip_queries'] > 0) { + $sql .= ' IGNORE ' . $GLOBALS['skip_queries'] . ' LINES'; + $GLOBALS['skip_queries'] = 0; } - if (strlen((string) $ldi_columns) > 0) { + if (strlen((string) $GLOBALS['ldi_columns']) > 0) { $sql .= ' ('; - $tmp = preg_split('/,( ?)/', $ldi_columns); + $tmp = preg_split('/,( ?)/', $GLOBALS['ldi_columns']); if (! is_array($tmp)) { $tmp = []; @@ -177,25 +187,23 @@ class ImportLdi extends AbstractImportCsv $sql .= ')'; } - $this->import->runQuery($sql, $sql, $sql_data); - $this->import->runQuery('', '', $sql_data); - $finished = true; + $this->import->runQuery($sql, $sqlStatements); + $this->import->runQuery('', $sqlStatements); + $GLOBALS['finished'] = true; + + return $sqlStatements; } public static function isAvailable(): bool { - global $plugin_param; - // We need relations enabled and we work only on database. - return isset($plugin_param) && $plugin_param === 'table'; + return isset($GLOBALS['plugin_param']) && $GLOBALS['plugin_param'] === 'table'; } private function setLdiLocalOptionConfig(): void { - global $dbi; - $GLOBALS['cfg']['Import']['ldi_local_option'] = false; - $result = $dbi->tryQuery('SELECT @@local_infile;'); + $result = $GLOBALS['dbi']->tryQuery('SELECT @@local_infile;'); if ($result === false || $result->numRows() <= 0) { return; diff --git a/libraries/classes/Plugins/Import/ImportMediawiki.php b/libraries/classes/Plugins/Import/ImportMediawiki.php index 17bfd6ac1d..1ac1f3a2d0 100644 --- a/libraries/classes/Plugins/Import/ImportMediawiki.php +++ b/libraries/classes/Plugins/Import/ImportMediawiki.php @@ -64,11 +64,15 @@ class ImportMediawiki extends ImportPlugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $error, $timeout_passed, $finished; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; + + $sqlStatements = []; // Defaults for parser @@ -97,7 +101,7 @@ class ImportMediawiki extends ImportPlugin $in_table_header = false; - while (! $finished && ! $error && ! $timeout_passed) { + while (! $GLOBALS['finished'] && ! $GLOBALS['error'] && ! $GLOBALS['timeout_passed']) { $data = $this->import->getNextChunk($importHandle); if ($data === false) { @@ -129,7 +133,7 @@ class ImportMediawiki extends ImportPlugin $full_buffer_lines_count = count($buffer_lines); // If the reading is not finalized, the final line of the current chunk // will not be complete - if (! $finished) { + if (! $GLOBALS['finished']) { $last_chunk_line = $buffer_lines[--$full_buffer_lines_count]; } @@ -231,7 +235,7 @@ class ImportMediawiki extends ImportPlugin ]; // Import the current table data into the database - $this->importDataOneTable($current_table, $sql_data); + $this->importDataOneTable($current_table, $sqlStatements); // Reset table name $cur_table_name = ''; @@ -275,27 +279,29 @@ class ImportMediawiki extends ImportPlugin __('Invalid format of mediawiki input on line: <br>%s.') ); $message->addParam($cur_buffer_line); - $error = true; + $GLOBALS['error'] = true; } } } + + return $sqlStatements; } /** * Imports data from a single table * - * @param array $table containing all table info: - * <code> $table[0] - string - * containing table name - * $table[1] - array[] of - * table headers $table[2] - - * array[][] of table content - * rows </code> - * @param array $sql_data 2-element array with sql data + * @param array $table containing all table info: + * <code> $table[0] - string + * containing table name + * $table[1] - array[] of + * table headers $table[2] - + * array[][] of table content + * rows </code> + * @param string[] $sqlStatements List of SQL statements to be executed * * @global bool $analyze whether to scan for column types */ - private function importDataOneTable(array $table, array &$sql_data): void + private function importDataOneTable(array $table, array &$sqlStatements): void { $analyze = $this->getAnalyze(); if ($analyze) { @@ -317,11 +323,11 @@ class ImportMediawiki extends ImportPlugin $analyses = []; $analyses[] = $this->import->analyzeTable($tables[0]); - $this->executeImportTables($tables, $analyses, $sql_data); + $this->executeImportTables($tables, $analyses, $sqlStatements); } // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); } /** @@ -331,13 +337,11 @@ class ImportMediawiki extends ImportPlugin */ private function setTableName(&$table_name): void { - global $dbi; - if (! empty($table_name)) { return; } - $result = $dbi->fetchResult('SHOW TABLES'); + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); // todo check if the name below already exists $table_name = 'TABLE ' . (count($result) + 1); } @@ -367,34 +371,32 @@ class ImportMediawiki extends ImportPlugin * Sets the database name and additional options and calls Import::buildSql() * Used in PMA_importDataAllTables() and $this->importDataOneTable() * - * @param array $tables structure: - * array( - * array(table_name, array() column_names, array()() - * rows) - * ) - * @param array $analyses structure: - * $analyses = array( - * array(array() column_types, array() column_sizes) - * ) - * @param array $sql_data 2-element array with sql data + * @param array $tables structure: + * array( + * array(table_name, array() column_names, array()() + * rows) + * ) + * @param array $analyses structure: + * $analyses = array( + * array(array() column_types, array() column_sizes) + * ) + * @param string[] $sqlStatements List of SQL statements to be executed * * @global string $db name of the database to import in */ - private function executeImportTables(array &$tables, array &$analyses, array &$sql_data): void + private function executeImportTables(array &$tables, array &$analyses, array &$sqlStatements): void { - global $db; - // $db_name : The currently selected database name, if applicable // No backquotes // $options : An associative array of options - [$db_name, $options] = $this->getDbnameAndOptions($db, 'mediawiki_DB'); + [$db_name, $options] = $this->getDbnameAndOptions($GLOBALS['db'], 'mediawiki_DB'); // Array of SQL strings // Non-applicable parameters $create = null; // Create and execute necessary SQL statements from data - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); + $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sqlStatements); } /** diff --git a/libraries/classes/Plugins/Import/ImportOds.php b/libraries/classes/Plugins/Import/ImportOds.php index 71499abaf8..73cfed759e 100644 --- a/libraries/classes/Plugins/Import/ImportOds.php +++ b/libraries/classes/Plugins/Import/ImportOds.php @@ -99,19 +99,22 @@ class ImportOds extends ImportPlugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $db, $error, $timeout_passed, $finished; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; + $sqlStatements = []; $buffer = ''; /** * Read in the file via Import::getNextChunk so that * it can process compressed files */ - while (! $finished && ! $error && ! $timeout_passed) { + while (! $GLOBALS['finished'] && ! $GLOBALS['error'] && ! $GLOBALS['timeout_passed']) { $data = $this->import->getNextChunk($importHandle); if ($data === false) { /* subtract data we didn't handle yet and stop processing */ @@ -215,18 +218,20 @@ class ImportOds extends ImportPlugin */ /* Set database name to the currently selected one, if applicable */ - [$db_name, $options] = $this->getDbnameAndOptions($db, 'ODS_DB'); + [$db_name, $options] = $this->getDbnameAndOptions($GLOBALS['db'], 'ODS_DB'); /* Non-applicable parameters */ $create = null; /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); + $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sqlStatements); unset($tables, $analyses); /* Commit any possible data in buffers */ - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); + + return $sqlStatements; } /** diff --git a/libraries/classes/Plugins/Import/ImportShp.php b/libraries/classes/Plugins/Import/ImportShp.php index 667eee0e2f..784fac580f 100644 --- a/libraries/classes/Plugins/Import/ImportShp.php +++ b/libraries/classes/Plugins/Import/ImportShp.php @@ -75,16 +75,18 @@ class ImportShp extends ImportPlugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $db, $error, $finished, $import_file, $local_import_file, $message, $dbi; - + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['import_file'] = $GLOBALS['import_file'] ?? null; + $GLOBALS['local_import_file'] = $GLOBALS['local_import_file'] ?? null; + $GLOBALS['message'] = $GLOBALS['message'] ?? null; $GLOBALS['finished'] = false; if ($importHandle === null || $this->zipExtension === null) { - return; + return []; } /** @see ImportShp::readFromBuffer() */ @@ -95,14 +97,14 @@ class ImportShp extends ImportPlugin $shp = new ShapeFileImport(1); // If the zip archive has more than one file, // get the correct content to the buffer from .shp file. - if ($compression === 'application/zip' && $this->zipExtension->getNumberOfFiles($import_file) > 1) { + if ($compression === 'application/zip' && $this->zipExtension->getNumberOfFiles($GLOBALS['import_file']) > 1) { if ($importHandle->openZip('/^.*\.shp$/i') === false) { - $message = Message::error( + $GLOBALS['message'] = Message::error( __('There was an error importing the ESRI shape file: "%s".') ); - $message->addParam($importHandle->getError()); + $GLOBALS['message']->addParam($importHandle->getError()); - return; + return []; } } @@ -113,11 +115,11 @@ class ImportShp extends ImportPlugin // If we can extract the zip archive to 'TempDir' // and use the files in it for import if ($compression === 'application/zip' && $temp !== null) { - $dbf_file_name = $this->zipExtension->findFile($import_file, '/^.*\.dbf$/i'); + $dbf_file_name = $this->zipExtension->findFile($GLOBALS['import_file'], '/^.*\.dbf$/i'); // If the corresponding .dbf file is in the zip archive if ($dbf_file_name) { // Extract the .dbf file and point to it. - $extracted = $this->zipExtension->extract($import_file, $dbf_file_name); + $extracted = $this->zipExtension->extract($GLOBALS['import_file'], $dbf_file_name); if ($extracted !== false) { // remove filename extension, e.g. // dresden_osm.shp/gis.osm_transport_a_v06.dbf @@ -140,12 +142,16 @@ class ImportShp extends ImportPlugin } } } - } elseif (! empty($local_import_file) && ! empty($GLOBALS['cfg']['UploadDir']) && $compression === 'none') { + } elseif ( + ! empty($GLOBALS['local_import_file']) + && ! empty($GLOBALS['cfg']['UploadDir']) + && $compression === 'none' + ) { // If file is in UploadDir, use .dbf file in the same UploadDir // to load extra data. // Replace the .shp with .*, // so the bsShapeFiles library correctly locates .dbf file. - $shp->fileName = mb_substr($import_file, 0, -4) . '.*'; + $shp->fileName = mb_substr($GLOBALS['import_file'], 0, -4) . '.*'; } } @@ -158,13 +164,13 @@ class ImportShp extends ImportPlugin } if ($shp->lastError != '') { - $error = true; - $message = Message::error( + $GLOBALS['error'] = true; + $GLOBALS['message'] = Message::error( __('There was an error importing the ESRI shape file: "%s".') ); - $message->addParam($shp->lastError); + $GLOBALS['message']->addParam($shp->lastError); - return; + return []; } switch ($shp->shapeType) { @@ -188,13 +194,13 @@ class ImportShp extends ImportPlugin $gis_type = 'multipoint'; break; default: - $error = true; - $message = Message::error( + $GLOBALS['error'] = true; + $GLOBALS['message'] = Message::error( __('MySQL Spatial Extension does not support ESRI type "%s".') ); - $message->addParam($shp->getShapeName()); + $GLOBALS['message']->addParam($shp->getShapeName()); - return; + return []; } if (isset($gis_type)) { @@ -237,12 +243,12 @@ class ImportShp extends ImportPlugin } if (count($rows) === 0) { - $error = true; - $message = Message::error( + $GLOBALS['error'] = true; + $GLOBALS['message'] = Message::error( __('The imported file does not contain any data!') ); - return; + return []; } // Column names for spatial column and the rest of the columns, @@ -258,8 +264,8 @@ class ImportShp extends ImportPlugin } // Set table name based on the number of tables - if (strlen((string) $db) > 0) { - $result = $dbi->fetchResult('SHOW TABLES'); + if (strlen((string) $GLOBALS['db']) > 0) { + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); $table_name = 'TABLE ' . (count($result) + 1); } else { $table_name = 'TBL_NAME'; @@ -283,8 +289,8 @@ class ImportShp extends ImportPlugin $analyses[$table_no][Import::FORMATTEDSQL][$spatial_col] = true; // Set database name to the currently selected one, if applicable - if (strlen((string) $db) > 0) { - $db_name = $db; + if (strlen((string) $GLOBALS['db']) > 0) { + $db_name = $GLOBALS['db']; $options = ['create_db' => false]; } else { $db_name = 'SHP_DB'; @@ -293,15 +299,18 @@ class ImportShp extends ImportPlugin // Created and execute necessary SQL statements from data $null_param = null; - $this->import->buildSql($db_name, $tables, $analyses, $null_param, $options, $sql_data); + $sqlStatements = []; + $this->import->buildSql($db_name, $tables, $analyses, $null_param, $options, $sqlStatements); unset($tables, $analyses); - $finished = true; - $error = false; + $GLOBALS['finished'] = true; + $GLOBALS['error'] = false; // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); + + return $sqlStatements; } /** @@ -316,20 +325,22 @@ class ImportShp extends ImportPlugin */ public static function readFromBuffer($length) { - global $buffer, $eof, $importHandle; + $GLOBALS['buffer'] = $GLOBALS['buffer'] ?? null; + $GLOBALS['eof'] = $GLOBALS['eof'] ?? null; + $GLOBALS['importHandle'] = $GLOBALS['importHandle'] ?? null; $import = new Import(); - if (strlen((string) $buffer) < $length) { + if (strlen((string) $GLOBALS['buffer']) < $length) { if ($GLOBALS['finished']) { - $eof = true; + $GLOBALS['eof'] = true; } else { - $buffer .= $import->getNextChunk($importHandle); + $GLOBALS['buffer'] .= $import->getNextChunk($GLOBALS['importHandle']); } } - $result = substr($buffer, 0, $length); - $buffer = substr($buffer, $length); + $result = substr($GLOBALS['buffer'], 0, $length); + $GLOBALS['buffer'] = substr($GLOBALS['buffer'], $length); return $result; } diff --git a/libraries/classes/Plugins/Import/ImportSql.php b/libraries/classes/Plugins/Import/ImportSql.php index a881c1f238..f8eac7d0d1 100644 --- a/libraries/classes/Plugins/Import/ImportSql.php +++ b/libraries/classes/Plugins/Import/ImportSql.php @@ -18,7 +18,6 @@ use PhpMyAdmin\Properties\Plugins\ImportPluginProperties; use PhpMyAdmin\SqlParser\Utils\BufferedQuery; use function __; -use function count; use function implode; use function mb_strlen; use function preg_replace; @@ -38,15 +37,13 @@ class ImportSql extends ImportPlugin protected function setProperties(): ImportPluginProperties { - global $dbi; - $importPluginProperties = new ImportPluginProperties(); $importPluginProperties->setText('SQL'); $importPluginProperties->setExtension('sql'); $importPluginProperties->setOptionsText(__('Options')); - $compats = $dbi->getCompatibilities(); - if (count($compats) > 0) { + $compats = $GLOBALS['dbi']->getCompatibilities(); + if ($compats !== []) { $values = []; foreach ($compats as $val) { $values[$val] = $val; @@ -97,14 +94,15 @@ class ImportSql extends ImportPlugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $error, $timeout_passed, $dbi; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; // Handle compatibility options. - $this->setSQLMode($dbi, $_REQUEST); + $this->setSQLMode($GLOBALS['dbi'], $_REQUEST); $bq = new BufferedQuery(); if (isset($_POST['sql_delimiter'])) { @@ -118,13 +116,15 @@ class ImportSql extends ImportPlugin */ $GLOBALS['finished'] = false; - while (! $error && (! $timeout_passed)) { + $sqlStatements = []; + + while (! $GLOBALS['error'] && ! $GLOBALS['timeout_passed']) { // Getting the first statement, the remaining data and the last // delimiter. $statement = $bq->extract(); // If there is no full statement, we are looking for more data. - if (empty($statement)) { + if ($statement === false || $statement === '') { // Importing new data. $newData = $this->import->getNextChunk($importHandle); @@ -148,21 +148,23 @@ class ImportSql extends ImportPlugin } // Executing the query. - $this->import->runQuery($statement, $statement, $sql_data); + $this->import->runQuery($statement, $sqlStatements); } // Extracting remaining statements. - while (! $error && ! $timeout_passed && ! empty($bq->query)) { + while (! $GLOBALS['error'] && ! $GLOBALS['timeout_passed'] && ! empty($bq->query)) { $statement = $bq->extract(true); - if (empty($statement)) { + if ($statement === false || $statement === '') { continue; } - $this->import->runQuery($statement, $statement, $sql_data); + $this->import->runQuery($statement, $sqlStatements); } // Finishing. - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); + + return $sqlStatements; } /** @@ -171,7 +173,7 @@ class ImportSql extends ImportPlugin * @param DatabaseInterface $dbi Database interface * @param array $request Request array */ - private function setSQLMode($dbi, array $request): void + private function setSQLMode(DatabaseInterface $dbi, array $request): void { $sql_modes = []; if (isset($request['sql_compatibility']) && $request['sql_compatibility'] !== 'NONE') { @@ -182,12 +184,10 @@ class ImportSql extends ImportPlugin $sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO'; } - if (count($sql_modes) <= 0) { + if ($sql_modes === []) { return; } - $dbi->tryQuery( - 'SET SQL_MODE="' . implode(',', $sql_modes) . '"' - ); + $dbi->tryQuery('SET SQL_MODE="' . implode(',', $sql_modes) . '"'); } } diff --git a/libraries/classes/Plugins/Import/ImportXml.php b/libraries/classes/Plugins/Import/ImportXml.php index e54f5da1cb..3d3b3bf052 100644 --- a/libraries/classes/Plugins/Import/ImportXml.php +++ b/libraries/classes/Plugins/Import/ImportXml.php @@ -56,11 +56,13 @@ class ImportXml extends ImportPlugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - public function doImport(?File $importHandle = null, array &$sql_data = []): void + public function doImport(?File $importHandle = null): array { - global $error, $timeout_passed, $finished, $db; + $GLOBALS['error'] = $GLOBALS['error'] ?? null; + $GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null; + $GLOBALS['finished'] = $GLOBALS['finished'] ?? null; $buffer = ''; @@ -68,7 +70,7 @@ class ImportXml extends ImportPlugin * Read in the file via Import::getNextChunk so that * it can process compressed files */ - while (! $finished && ! $error && ! $timeout_passed) { + while (! $GLOBALS['finished'] && ! $GLOBALS['error'] && ! $GLOBALS['timeout_passed']) { $data = $this->import->getNextChunk($importHandle); if ($data === false) { /* subtract data we didn't handle yet and stop processing */ @@ -115,7 +117,7 @@ class ImportXml extends ImportPlugin unset($xml); $GLOBALS['finished'] = false; - return; + return []; } /** @@ -178,7 +180,7 @@ class ImportXml extends ImportPlugin unset($xml); $GLOBALS['finished'] = false; - return; + return []; } /** @@ -225,6 +227,7 @@ class ImportXml extends ImportPlugin ->children(); $data_present = false; + $analyses = null; /** * Only attempt to analyze/collect data if there is data present @@ -338,9 +341,9 @@ class ImportXml extends ImportPlugin */ /* Set database name to the currently selected one, if applicable */ - if (strlen((string) $db)) { + if (strlen((string) $GLOBALS['db'])) { /* Override the database name in the XML file, if one is selected */ - $db_name = $db; + $db_name = $GLOBALS['db']; $options = ['create_db' => false]; } else { /* Set database collation/charset */ @@ -351,11 +354,14 @@ class ImportXml extends ImportPlugin } /* Created and execute necessary SQL statements from data */ - $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sql_data); + $sqlStatements = []; + $this->import->buildSql($db_name, $tables, $analyses, $create, $options, $sqlStatements); unset($analyses, $tables, $create); /* Commit any possible data in buffers */ - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); + + return $sqlStatements; } } diff --git a/libraries/classes/Plugins/Import/README.md b/libraries/classes/Plugins/Import/README.md index 229e19000c..7ed52faf96 100644 --- a/libraries/classes/Plugins/Import/README.md +++ b/libraries/classes/Plugins/Import/README.md @@ -94,18 +94,17 @@ class Import[Name] extends ImportPlugin /** * Handles the whole import logic * - * @param array &$sql_data 2-element array with sql data - * - * @return void + * @return array A list of SQL statements to be executed */ - public function doImport(&$sql_data = []) + public function doImport(?File $importHandle = null): array { // get globals (others are optional) global $error, $timeout_passed, $finished; + $sqlStatements = []; $buffer = ''; while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { - $data = $this->import->getNextChunk(); + $data = $this->import->getNextChunk($importHandle); if ($data === false) { // subtract data we didn't handle yet and stop processing $GLOBALS['offset'] -= strlen($buffer); @@ -119,10 +118,12 @@ class Import[Name] extends ImportPlugin $buffer .= $data; } // PARSE $buffer here, post sql queries using: - $this->import->runQuery($sql, $verbose_sql_with_comments, $sql_data); + $this->import->runQuery($sql, $sqlStatements); } // End of import loop // Commit any possible data in buffers - $this->import->runQuery('', '', $sql_data); + $this->import->runQuery('', $sqlStatements); + + return $sqlStatements; } /* optional: */ diff --git a/libraries/classes/Plugins/Import/ShapeFileImport.php b/libraries/classes/Plugins/Import/ShapeFileImport.php index ad33377de5..84cc36991d 100644 --- a/libraries/classes/Plugins/Import/ShapeFileImport.php +++ b/libraries/classes/Plugins/Import/ShapeFileImport.php @@ -32,8 +32,8 @@ class ShapeFileImport extends ShapeFile */ public function eofSHP(): bool { - global $eof; + $GLOBALS['eof'] = $GLOBALS['eof'] ?? null; - return (bool) $eof; + return (bool) $GLOBALS['eof']; } } diff --git a/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php b/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php index 987080ad21..c0ebfa35d6 100644 --- a/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php +++ b/libraries/classes/Plugins/Import/Upload/UploadNoplugin.php @@ -39,14 +39,14 @@ class UploadNoplugin implements UploadInterface */ public static function getUploadStatus($id) { - global $SESSION_KEY; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; if (trim($id) == '') { return null; } - if (! array_key_exists($id, $_SESSION[$SESSION_KEY])) { - $_SESSION[$SESSION_KEY][$id] = [ + if (! array_key_exists($id, $_SESSION[$GLOBALS['SESSION_KEY']])) { + $_SESSION[$GLOBALS['SESSION_KEY']][$id] = [ 'id' => $id, 'finished' => false, 'percent' => 0, @@ -56,6 +56,6 @@ class UploadNoplugin implements UploadInterface ]; } - return $_SESSION[$SESSION_KEY][$id]; + return $_SESSION[$GLOBALS['SESSION_KEY']][$id]; } } diff --git a/libraries/classes/Plugins/Import/Upload/UploadProgress.php b/libraries/classes/Plugins/Import/Upload/UploadProgress.php index fc971e173b..5369092043 100644 --- a/libraries/classes/Plugins/Import/Upload/UploadProgress.php +++ b/libraries/classes/Plugins/Import/Upload/UploadProgress.php @@ -40,14 +40,14 @@ class UploadProgress implements UploadInterface */ public static function getUploadStatus($id) { - global $SESSION_KEY; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; if (trim($id) == '') { return null; } - if (! array_key_exists($id, $_SESSION[$SESSION_KEY])) { - $_SESSION[$SESSION_KEY][$id] = [ + if (! array_key_exists($id, $_SESSION[$GLOBALS['SESSION_KEY']])) { + $_SESSION[$GLOBALS['SESSION_KEY']][$id] = [ 'id' => $id, 'finished' => false, 'percent' => 0, @@ -57,7 +57,7 @@ class UploadProgress implements UploadInterface ]; } - $ret = $_SESSION[$SESSION_KEY][$id]; + $ret = $_SESSION[$GLOBALS['SESSION_KEY']][$id]; if (! Ajax::progressCheck() || $ret['finished']) { return $ret; @@ -94,7 +94,7 @@ class UploadProgress implements UploadInterface ]; } - $_SESSION[$SESSION_KEY][$id] = $ret; + $_SESSION[$GLOBALS['SESSION_KEY']][$id] = $ret; return $ret; } diff --git a/libraries/classes/Plugins/Import/Upload/UploadSession.php b/libraries/classes/Plugins/Import/Upload/UploadSession.php index 1e94f64e4b..ec576b18e6 100644 --- a/libraries/classes/Plugins/Import/Upload/UploadSession.php +++ b/libraries/classes/Plugins/Import/Upload/UploadSession.php @@ -40,14 +40,14 @@ class UploadSession implements UploadInterface */ public static function getUploadStatus($id) { - global $SESSION_KEY; + $GLOBALS['SESSION_KEY'] = $GLOBALS['SESSION_KEY'] ?? null; if (trim($id) == '') { return null; } - if (! array_key_exists($id, $_SESSION[$SESSION_KEY])) { - $_SESSION[$SESSION_KEY][$id] = [ + if (! array_key_exists($id, $_SESSION[$GLOBALS['SESSION_KEY']])) { + $_SESSION[$GLOBALS['SESSION_KEY']][$id] = [ 'id' => $id, 'finished' => false, 'percent' => 0, @@ -57,7 +57,7 @@ class UploadSession implements UploadInterface ]; } - $ret = $_SESSION[$SESSION_KEY][$id]; + $ret = $_SESSION[$GLOBALS['SESSION_KEY']][$id]; if (! Ajax::sessionCheck() || $ret['finished']) { return $ret; @@ -89,7 +89,7 @@ class UploadSession implements UploadInterface ]; } - $_SESSION[$SESSION_KEY][$id] = $ret; + $_SESSION[$GLOBALS['SESSION_KEY']][$id] = $ret; return $ret; } diff --git a/libraries/classes/Plugins/ImportPlugin.php b/libraries/classes/Plugins/ImportPlugin.php index b02cc344bf..39bc8e16e6 100644 --- a/libraries/classes/Plugins/ImportPlugin.php +++ b/libraries/classes/Plugins/ImportPlugin.php @@ -47,9 +47,9 @@ abstract class ImportPlugin implements Plugin /** * Handles the whole import logic * - * @param array $sql_data 2-element array with sql data + * @return string[] */ - abstract public function doImport(?File $importHandle = null, array &$sql_data = []): void; + abstract public function doImport(?File $importHandle = null): array; /** * Gets the import specific format plugin properties diff --git a/libraries/classes/Plugins/Schema/ExportRelationSchema.php b/libraries/classes/Plugins/Schema/ExportRelationSchema.php index 7a56736011..370e2a2e84 100644 --- a/libraries/classes/Plugins/Schema/ExportRelationSchema.php +++ b/libraries/classes/Plugins/Schema/ExportRelationSchema.php @@ -62,13 +62,11 @@ class ExportRelationSchema */ public function __construct($db, $diagram) { - global $dbi; - $this->db = $db; $this->diagram = $diagram; $this->setPageNumber((int) $_REQUEST['page_number']); $this->setOffline(isset($_REQUEST['offline_export'])); - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); } /** @@ -247,8 +245,6 @@ class ExportRelationSchema */ protected function getFileName($extension): string { - global $dbi; - $pdfFeature = $this->relation->getRelationParameters()->pdfFeature; $filename = $this->db . $extension; @@ -258,7 +254,7 @@ class ExportRelationSchema . Util::backquote($pdfFeature->database) . '.' . Util::backquote($pdfFeature->pdfPages) . ' WHERE page_nr = ' . $this->pageNumber; - $_name_rs = $dbi->queryAsControlUser($_name_sql); + $_name_rs = $GLOBALS['dbi']->queryAsControlUser($_name_sql); $_name_row = $_name_rs->fetchRow(); $filename = $_name_row[0] . $extension; } diff --git a/libraries/classes/Plugins/Schema/Pdf/Pdf.php b/libraries/classes/Plugins/Schema/Pdf/Pdf.php index 32d591d6ad..7e0a7fa188 100644 --- a/libraries/classes/Plugins/Schema/Pdf/Pdf.php +++ b/libraries/classes/Plugins/Schema/Pdf/Pdf.php @@ -98,13 +98,11 @@ class Pdf extends PdfLib $withDoc, $db ) { - global $dbi; - parent::__construct($orientation, $unit, $paper); $this->pageNumber = $pageNumber; $this->withDoc = $withDoc; $this->db = $db; - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); } /** @@ -258,8 +256,6 @@ class Pdf extends PdfLib // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps public function Header(): void { - global $dbi; - // We only show this if we find something in the new pdf_pages table // This function must be named "Header" to work with the TCPDF library @@ -274,9 +270,9 @@ class Pdf extends PdfLib $test_query = 'SELECT * FROM ' . Util::backquote($pdfFeature->database) . '.' . Util::backquote($pdfFeature->pdfPages) - . ' WHERE db_name = \'' . $dbi->escapeString($this->db) + . ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($this->db) . '\' AND page_nr = \'' . $this->pageNumber . '\''; - $test_rs = $dbi->queryAsControlUser($test_query); + $test_rs = $GLOBALS['dbi']->queryAsControlUser($test_query); $pageDesc = (string) $test_rs->fetchValue('page_descr'); $pg_name = ucfirst($pageDesc); diff --git a/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php b/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php index 6c23e0f9d3..bea748e63a 100644 --- a/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php +++ b/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php @@ -479,8 +479,6 @@ class PdfRelationSchema extends ExportRelationSchema */ public function dataDictionaryDoc(array $alltables): void { - global $dbi; - // TOC $this->diagram->AddPage($this->orientation); $this->diagram->Cell(0, 9, __('Table of contents'), 1, 0, 'C'); @@ -512,7 +510,7 @@ class PdfRelationSchema extends ExportRelationSchema $this->diagram->customLinks['doc'][$table]['-'] ); // $this->diagram->Ln(1); - $fields = $dbi->getColumns($this->db, $table); + $fields = $GLOBALS['dbi']->getColumns($this->db, $table); foreach ($fields as $row) { $this->diagram->SetX(20); $field_name = $row['Field']; @@ -580,7 +578,7 @@ class PdfRelationSchema extends ExportRelationSchema /** * Gets table information */ - $showtable = $dbi->getTable($this->db, $table) + $showtable = $GLOBALS['dbi']->getTable($this->db, $table) ->getStatusInfo(); $show_comment = $showtable['Comment'] ?? ''; $create_time = isset($showtable['Create_time']) @@ -602,7 +600,7 @@ class PdfRelationSchema extends ExportRelationSchema /** * Gets fields properties */ - $columns = $dbi->getColumns($this->db, $table); + $columns = $GLOBALS['dbi']->getColumns($this->db, $table); // Find which tables are related with the current one and write it in // an array diff --git a/libraries/classes/Plugins/Schema/TableStats.php b/libraries/classes/Plugins/Schema/TableStats.php index a3c4d83b69..76a957826c 100644 --- a/libraries/classes/Plugins/Schema/TableStats.php +++ b/libraries/classes/Plugins/Schema/TableStats.php @@ -96,8 +96,6 @@ abstract class TableStats $tableDimension, $offline ) { - global $dbi; - $this->diagram = $diagram; $this->db = $db; $this->pageNumber = $pageNumber; @@ -108,7 +106,7 @@ abstract class TableStats $this->offline = $offline; - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); $this->font = new Font(); // checks whether the table exists @@ -127,17 +125,15 @@ abstract class TableStats */ protected function validateTableAndLoadFields(): void { - global $dbi; - $sql = 'DESCRIBE ' . Util::backquote($this->tableName); - $result = $dbi->tryQuery($sql); + $result = $GLOBALS['dbi']->tryQuery($sql); if (! $result || ! $result->numRows()) { $this->showMissingTableError(); exit; } if ($this->showKeys) { - $indexes = Index::getFromTable($this->tableName, $this->db); + $indexes = Index::getFromTable($GLOBALS['dbi'], $this->tableName, $this->db); $all_columns = []; foreach ($indexes as $index) { $all_columns = array_merge( @@ -192,9 +188,7 @@ abstract class TableStats */ protected function loadPrimaryKey(): void { - global $dbi; - - $result = $dbi->query('SHOW INDEX FROM ' . Util::backquote($this->tableName) . ';'); + $result = $GLOBALS['dbi']->query('SHOW INDEX FROM ' . Util::backquote($this->tableName) . ';'); if ($result->numRows() <= 0) { return; } diff --git a/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php index 9ad923351b..a3c6fce0b3 100644 --- a/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/Bool2TextTransformationsPlugin.php @@ -19,10 +19,8 @@ abstract class Bool2TextTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Converts Boolean values to text (default \'T\' and \'F\').' @@ -55,10 +53,8 @@ abstract class Bool2TextTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Bool2Text'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php index 17eb9bfeb4..dcdad6ee45 100644 --- a/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php @@ -30,10 +30,8 @@ abstract class DateFormatTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays a TIME, TIMESTAMP, DATETIME or numeric unix timestamp' @@ -153,10 +151,8 @@ abstract class DateFormatTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Date Format'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php index 9a1fd7877d..c9fc066068 100644 --- a/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/DownloadTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class DownloadTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays a link to download the binary data of the column. You can' @@ -47,13 +45,14 @@ abstract class DownloadTransformationsPlugin extends TransformationsPlugin */ public function applyTransformation($buffer, array $options = [], ?FieldMetadata $meta = null) { - global $row, $fields_meta; + $GLOBALS['row'] = $GLOBALS['row'] ?? null; + $GLOBALS['fields_meta'] = $GLOBALS['fields_meta'] ?? null; if (isset($options[0]) && ! empty($options[0])) { $cn = $options[0]; // filename } else { if (isset($options[1]) && ! empty($options[1])) { - foreach ($fields_meta as $key => $val) { + foreach ($GLOBALS['fields_meta'] as $key => $val) { if ($val->name == $options[1]) { $pos = $key; break; @@ -61,7 +60,7 @@ abstract class DownloadTransformationsPlugin extends TransformationsPlugin } if (isset($pos)) { - $cn = $row[$pos]; + $cn = $GLOBALS['row'][$pos]; } } @@ -88,10 +87,8 @@ abstract class DownloadTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Download'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php index 1932bf306d..f0adabece5 100644 --- a/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/ExternalTransformationsPlugin.php @@ -33,10 +33,8 @@ abstract class ExternalTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'LINUX ONLY: Launches an external application and feeds it the column' @@ -166,10 +164,8 @@ abstract class ExternalTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'External'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php index 21af094bb4..12981d7533 100644 --- a/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/FormattedTransformationsPlugin.php @@ -20,10 +20,8 @@ abstract class FormattedTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays the contents of the column as-is, without running it' @@ -52,10 +50,8 @@ abstract class FormattedTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Formatted'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php index 5904dc01ef..4c4fbb33ae 100644 --- a/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/HexTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class HexTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays hexadecimal representation of data. Optional first' @@ -61,10 +59,8 @@ abstract class HexTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Hex'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php index 496a15290a..9ccadda087 100644 --- a/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/ImageLinkTransformationsPlugin.php @@ -21,10 +21,8 @@ abstract class ImageLinkTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Displays a link to download this image.'); } @@ -54,10 +52,8 @@ abstract class ImageLinkTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'ImageLink'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php index c726d845b2..986a240415 100644 --- a/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/ImageUploadTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class ImageUploadTransformationsPlugin extends IOTransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Image upload functionality which also displays a thumbnail.' @@ -110,10 +108,8 @@ abstract class ImageUploadTransformationsPlugin extends IOTransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Image upload'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php index d453c61cd2..a59ed164af 100644 --- a/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/InlineTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class InlineTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays a clickable thumbnail. The options are the maximum width' @@ -66,10 +64,8 @@ abstract class InlineTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Inline'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php index aac53e9b0f..83ce33d0c7 100644 --- a/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/LongToIPv4TransformationsPlugin.php @@ -21,10 +21,8 @@ abstract class LongToIPv4TransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Converts an (IPv4) Internet network address stored as a BIGINT' @@ -50,10 +48,8 @@ abstract class LongToIPv4TransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Long To IPv4'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php index adb8384865..d5e2694be9 100644 --- a/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/PreApPendTransformationsPlugin.php @@ -20,10 +20,8 @@ abstract class PreApPendTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Prepends and/or Appends text to a string. First option is text' @@ -55,10 +53,8 @@ abstract class PreApPendTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'PreApPend'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php index 7a16c81ad5..cf4a13f37d 100644 --- a/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/RegexValidationTransformationsPlugin.php @@ -23,10 +23,8 @@ abstract class RegexValidationTransformationsPlugin extends IOTransformationsPlu { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Validates the string using regular expression ' @@ -63,10 +61,8 @@ abstract class RegexValidationTransformationsPlugin extends IOTransformationsPlu /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Regex Validation'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php index 383d4a4020..c6467fb38d 100644 --- a/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/SQLTransformationsPlugin.php @@ -20,10 +20,8 @@ abstract class SQLTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Formats text as SQL query with syntax highlighting.'); } @@ -46,10 +44,8 @@ abstract class SQLTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'SQL'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/SubstringTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/SubstringTransformationsPlugin.php index 2c89cac5f8..fa68609d50 100644 --- a/libraries/classes/Plugins/Transformations/Abs/SubstringTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/SubstringTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class SubstringTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays a part of a string. The first option is the number of' @@ -80,10 +78,8 @@ abstract class SubstringTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Substring'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php index fe0ad4ad90..005bdd33b8 100644 --- a/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/TextFileUploadTransformationsPlugin.php @@ -21,10 +21,8 @@ abstract class TextFileUploadTransformationsPlugin extends IOTransformationsPlug { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('File upload functionality for TEXT columns. It does not have a textarea for input.'); } @@ -88,10 +86,8 @@ abstract class TextFileUploadTransformationsPlugin extends IOTransformationsPlug /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Text file upload'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php index 04636ac69c..bec80b1f03 100644 --- a/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/TextImageLinkTransformationsPlugin.php @@ -22,10 +22,8 @@ abstract class TextImageLinkTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays an image and a link; the column contains the filename. The' @@ -67,10 +65,8 @@ abstract class TextImageLinkTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Image Link'; } diff --git a/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php b/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php index e043e652f7..9551dca405 100644 --- a/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php +++ b/libraries/classes/Plugins/Transformations/Abs/TextLinkTransformationsPlugin.php @@ -21,10 +21,8 @@ abstract class TextLinkTransformationsPlugin extends TransformationsPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Displays a link; the column contains the filename. The first option' @@ -65,10 +63,8 @@ abstract class TextLinkTransformationsPlugin extends TransformationsPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'TextLink'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php b/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php index 73d4f1853d..767e5cf269 100644 --- a/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php +++ b/libraries/classes/Plugins/Transformations/Input/Image_JPEG_Upload.php @@ -17,20 +17,16 @@ class Image_JPEG_Upload extends ImageUploadTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Image'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'JPEG'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_FileUpload.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_FileUpload.php index 2b977ea3be..43ccc2164e 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_FileUpload.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_FileUpload.php @@ -16,20 +16,16 @@ class Text_Plain_FileUpload extends TextFileUploadTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptobinary.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptobinary.php index 45debc52ec..f23945093c 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptobinary.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptobinary.php @@ -24,10 +24,8 @@ class Text_Plain_Iptobinary extends IOTransformationsPlugin { /** * Gets the transformation description of the plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Converts an Internet network address in (IPv4/IPv6) format to binary'); } @@ -105,30 +103,24 @@ class Text_Plain_Iptobinary extends IOTransformationsPlugin /** * Gets the transformation name of the plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'IPv4/IPv6 To Binary'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptolong.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptolong.php index 594e3997e5..9a62f81a8e 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptolong.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_Iptolong.php @@ -21,10 +21,8 @@ class Text_Plain_Iptolong extends IOTransformationsPlugin { /** * Gets the transformation description of the plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Converts an Internet network address in (IPv4/IPv6) format into a long integer.'); } @@ -97,30 +95,24 @@ class Text_Plain_Iptolong extends IOTransformationsPlugin /** * Gets the transformation name of the plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'IPv4/IPv6 To Long'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php index 766a8efd9f..57ef379a78 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_JsonEditor.php @@ -18,10 +18,8 @@ class Text_Plain_JsonEditor extends CodeMirrorEditorTransformationPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Syntax highlighted CodeMirror editor for JSON.'); } @@ -48,30 +46,24 @@ class Text_Plain_JsonEditor extends CodeMirrorEditorTransformationPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'JSON'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_RegexValidation.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_RegexValidation.php index aa5089844f..ef3e53b2ba 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_RegexValidation.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_RegexValidation.php @@ -17,20 +17,16 @@ class Text_Plain_RegexValidation extends RegexValidationTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_SqlEditor.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_SqlEditor.php index 24d15db24a..d001dfcfad 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_SqlEditor.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_SqlEditor.php @@ -18,10 +18,8 @@ class Text_Plain_SqlEditor extends CodeMirrorEditorTransformationPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Syntax highlighted CodeMirror editor for SQL.'); } @@ -48,30 +46,24 @@ class Text_Plain_SqlEditor extends CodeMirrorEditorTransformationPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'SQL'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Input/Text_Plain_XmlEditor.php b/libraries/classes/Plugins/Transformations/Input/Text_Plain_XmlEditor.php index 786ed067e5..95c88cc92c 100644 --- a/libraries/classes/Plugins/Transformations/Input/Text_Plain_XmlEditor.php +++ b/libraries/classes/Plugins/Transformations/Input/Text_Plain_XmlEditor.php @@ -18,10 +18,8 @@ class Text_Plain_XmlEditor extends CodeMirrorEditorTransformationPlugin { /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Syntax highlighted CodeMirror editor for XML (and HTML).'); } @@ -48,30 +46,24 @@ class Text_Plain_XmlEditor extends CodeMirrorEditorTransformationPlugin /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'XML'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Download.php b/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Download.php index b80b782b7d..dd3be9a6ed 100644 --- a/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Download.php +++ b/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Download.php @@ -16,20 +16,16 @@ class Application_Octetstream_Download extends DownloadTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Application'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'OctetStream'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Hex.php b/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Hex.php index b7e5a842b6..f383cea09f 100644 --- a/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Hex.php +++ b/libraries/classes/Plugins/Transformations/Output/Application_Octetstream_Hex.php @@ -16,20 +16,16 @@ class Application_Octetstream_Hex extends HexTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Application'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'OctetStream'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Inline.php b/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Inline.php index 3322724e2f..33d358557c 100644 --- a/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Inline.php +++ b/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Inline.php @@ -16,20 +16,16 @@ class Image_JPEG_Inline extends InlineTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Image'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'JPEG'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Link.php b/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Link.php index 4bb5d16b80..c1ba316e42 100644 --- a/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Link.php +++ b/libraries/classes/Plugins/Transformations/Output/Image_JPEG_Link.php @@ -16,20 +16,16 @@ class Image_JPEG_Link extends ImageLinkTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Image'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'JPEG'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Image_PNG_Inline.php b/libraries/classes/Plugins/Transformations/Output/Image_PNG_Inline.php index 6102311fc7..337a29f65b 100644 --- a/libraries/classes/Plugins/Transformations/Output/Image_PNG_Inline.php +++ b/libraries/classes/Plugins/Transformations/Output/Image_PNG_Inline.php @@ -16,20 +16,16 @@ class Image_PNG_Inline extends InlineTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Image'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'PNG'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php b/libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php index e8a2b36c06..f8db9b1e34 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php @@ -16,20 +16,16 @@ class Text_Octetstream_Sql extends SQLTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Octetstream'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Binarytoip.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Binarytoip.php index ff59df1521..8e63858e4e 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Binarytoip.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Binarytoip.php @@ -20,10 +20,8 @@ class Text_Plain_Binarytoip extends TransformationsPlugin { /** * Gets the transformation description of the plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __( 'Converts an Internet network address stored as a binary string' @@ -53,30 +51,24 @@ class Text_Plain_Binarytoip extends TransformationsPlugin /** * Gets the transformation name of the plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'Binary To IPv4/IPv6'; } /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Bool2Text.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Bool2Text.php index dffb3b0cde..bd8f137a13 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Bool2Text.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Bool2Text.php @@ -18,20 +18,16 @@ class Text_Plain_Bool2Text extends Bool2TextTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Dateformat.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Dateformat.php index 832839480c..cac12ed439 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Dateformat.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Dateformat.php @@ -16,20 +16,16 @@ class Text_Plain_Dateformat extends DateFormatTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_External.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_External.php index 24edbf14de..a8941ae149 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_External.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_External.php @@ -16,20 +16,16 @@ class Text_Plain_External extends ExternalTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Formatted.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Formatted.php index 1fd7ac4ba7..be2ec58c7e 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Formatted.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Formatted.php @@ -16,20 +16,16 @@ class Text_Plain_Formatted extends FormattedTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Imagelink.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Imagelink.php index e19128dda9..73f8e913d8 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Imagelink.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Imagelink.php @@ -16,20 +16,16 @@ class Text_Plain_Imagelink extends TextImageLinkTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php index 6d4be8960d..133f4b7a9e 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php @@ -36,10 +36,8 @@ class Text_Plain_Json extends TransformationsPlugin /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Formats text as JSON with syntax highlighting.'); } @@ -64,30 +62,24 @@ class Text_Plain_Json extends TransformationsPlugin /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'JSON'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php index 251bcb8040..a13da15f96 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php @@ -32,20 +32,16 @@ class Text_Plain_Sql extends SQLTransformationsPlugin /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php index e07b41cc10..dbe38ad90f 100644 --- a/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php +++ b/libraries/classes/Plugins/Transformations/Output/Text_Plain_Xml.php @@ -36,10 +36,8 @@ class Text_Plain_Xml extends TransformationsPlugin /** * Gets the transformation description of the specific plugin - * - * @return string */ - public static function getInfo() + public static function getInfo(): string { return __('Formats text as XML with syntax highlighting.'); } @@ -64,30 +62,24 @@ class Text_Plain_Xml extends TransformationsPlugin /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName() + public static function getName(): string { return 'XML'; } diff --git a/libraries/classes/Plugins/Transformations/Text_Plain_Link.php b/libraries/classes/Plugins/Transformations/Text_Plain_Link.php index c3798e9e7a..caed0b6c2a 100644 --- a/libraries/classes/Plugins/Transformations/Text_Plain_Link.php +++ b/libraries/classes/Plugins/Transformations/Text_Plain_Link.php @@ -16,20 +16,16 @@ class Text_Plain_Link extends TextLinkTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Text_Plain_Longtoipv4.php b/libraries/classes/Plugins/Transformations/Text_Plain_Longtoipv4.php index ddbf4d3562..5170da26ed 100644 --- a/libraries/classes/Plugins/Transformations/Text_Plain_Longtoipv4.php +++ b/libraries/classes/Plugins/Transformations/Text_Plain_Longtoipv4.php @@ -16,20 +16,16 @@ class Text_Plain_Longtoipv4 extends LongToIPv4TransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Text_Plain_PreApPend.php b/libraries/classes/Plugins/Transformations/Text_Plain_PreApPend.php index 044a5f9750..e3badb6e99 100644 --- a/libraries/classes/Plugins/Transformations/Text_Plain_PreApPend.php +++ b/libraries/classes/Plugins/Transformations/Text_Plain_PreApPend.php @@ -17,20 +17,16 @@ class Text_Plain_PreApPend extends PreApPendTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/Transformations/Text_Plain_Substring.php b/libraries/classes/Plugins/Transformations/Text_Plain_Substring.php index 6abfe1b437..b3c6e997ad 100644 --- a/libraries/classes/Plugins/Transformations/Text_Plain_Substring.php +++ b/libraries/classes/Plugins/Transformations/Text_Plain_Substring.php @@ -16,20 +16,16 @@ class Text_Plain_Substring extends SubstringTransformationsPlugin { /** * Gets the plugin`s MIME type - * - * @return string */ - public static function getMIMEType() + public static function getMIMEType(): string { return 'Text'; } /** * Gets the plugin`s MIME subtype - * - * @return string */ - public static function getMIMESubtype() + public static function getMIMESubtype(): string { return 'Plain'; } diff --git a/libraries/classes/Plugins/TransformationsInterface.php b/libraries/classes/Plugins/TransformationsInterface.php index ff9069cf92..21e4bad6c8 100644 --- a/libraries/classes/Plugins/TransformationsInterface.php +++ b/libraries/classes/Plugins/TransformationsInterface.php @@ -15,29 +15,21 @@ interface TransformationsInterface { /** * Gets the transformation description - * - * @return string */ - public static function getInfo(); + public static function getInfo(): string; /** * Gets the specific MIME type - * - * @return string */ - public static function getMIMEType(); + public static function getMIMEType(): string; /** * Gets the specific MIME subtype - * - * @return string */ - public static function getMIMESubtype(); + public static function getMIMESubtype(): string; /** * Gets the transformation name of the specific plugin - * - * @return string */ - public static function getName(); + public static function getName(): string; } diff --git a/libraries/classes/Plugins/TwoFactorPlugin.php b/libraries/classes/Plugins/TwoFactorPlugin.php index 38f8bcfab2..bae861a542 100644 --- a/libraries/classes/Plugins/TwoFactorPlugin.php +++ b/libraries/classes/Plugins/TwoFactorPlugin.php @@ -149,9 +149,9 @@ class TwoFactorPlugin */ public function getAppId($return_url) { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; - $url = $config->get('PmaAbsoluteUri'); + $url = $GLOBALS['config']->get('PmaAbsoluteUri'); $parsed = []; if (! empty($url)) { $parsedUrl = parse_url($url); @@ -162,7 +162,7 @@ class TwoFactorPlugin } if (! isset($parsed['scheme']) || strlen($parsed['scheme']) === 0) { - $parsed['scheme'] = $config->isHttps() ? 'https' : 'http'; + $parsed['scheme'] = $GLOBALS['config']->isHttps() ? 'https' : 'http'; } if (! isset($parsed['host']) || strlen($parsed['host']) === 0) { diff --git a/libraries/classes/Query/Utilities.php b/libraries/classes/Query/Utilities.php index 6766ecebe8..ae53636a3a 100644 --- a/libraries/classes/Query/Utilities.php +++ b/libraries/classes/Query/Utilities.php @@ -137,8 +137,6 @@ class Utilities */ public static function usortComparisonCallback(array $a, array $b, string $sortBy, string $sortOrder): int { - global $cfg; - /* No sorting when key is not present */ if (! isset($a[$sortBy], $b[$sortBy])) { return 0; @@ -146,7 +144,7 @@ class Utilities // produces f.e.: // return -1 * strnatcasecmp($a['SCHEMA_TABLES'], $b['SCHEMA_TABLES']) - $compare = $cfg['NaturalOrder'] ? strnatcasecmp( + $compare = $GLOBALS['cfg']['NaturalOrder'] ? strnatcasecmp( (string) $a[$sortBy], (string) $b[$sortBy] ) : strcasecmp( diff --git a/libraries/classes/RecentFavoriteTable.php b/libraries/classes/RecentFavoriteTable.php index 4f07fdfeae..03b815e9bf 100644 --- a/libraries/classes/RecentFavoriteTable.php +++ b/libraries/classes/RecentFavoriteTable.php @@ -70,9 +70,7 @@ class RecentFavoriteTable { $this->template = $template; - global $dbi; - - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); $this->tableType = $type; $server_id = $GLOBALS['server']; if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id])) { @@ -117,13 +115,11 @@ class RecentFavoriteTable */ public function getFromDb(): array { - global $dbi; - // Read from phpMyAdmin database, if recent tables is not in session $sql_query = ' SELECT `tables` FROM ' . $this->getPmaTable() . - " WHERE `username` = '" . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'"; + " WHERE `username` = '" . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) . "'"; - $result = $dbi->tryQueryAsControlUser($sql_query); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sql_query); if ($result) { $value = $result->fetchValue(); if (is_string($value)) { @@ -141,16 +137,14 @@ class RecentFavoriteTable */ public function saveToDb() { - global $dbi; - $username = $GLOBALS['cfg']['Server']['user']; $sql_query = ' REPLACE INTO ' . $this->getPmaTable() . ' (`username`, `tables`)' . - " VALUES ('" . $dbi->escapeString($username) . "', '" - . $dbi->escapeString( + " VALUES ('" . $GLOBALS['dbi']->escapeString($username) . "', '" + . $GLOBALS['dbi']->escapeString( json_encode($this->tables) ) . "')"; - $success = $dbi->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL); + $success = $GLOBALS['dbi']->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL); if (! $success) { $error_msg = ''; @@ -166,7 +160,7 @@ class RecentFavoriteTable $message = Message::error($error_msg); $message->addMessage( - Message::rawError($dbi->getError(DatabaseInterface::CONNECT_CONTROL)), + Message::rawError($GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL)), '<br><br>' ); @@ -269,10 +263,8 @@ class RecentFavoriteTable */ public function add($db, $table) { - global $dbi; - // If table does not exist, do not add._getPmaTable() - if (! $dbi->getColumns($db, $table)) { + if (! $GLOBALS['dbi']->getColumns($db, $table)) { return true; } @@ -304,15 +296,13 @@ class RecentFavoriteTable */ public function removeIfInvalid($db, $table) { - global $dbi; - foreach ($this->tables as $tbl) { if ($tbl['db'] != $db || $tbl['table'] != $table) { continue; } // TODO Figure out a better way to find the existence of a table - if (! $dbi->getColumns($tbl['db'], $tbl['table'])) { + if (! $GLOBALS['dbi']->getColumns($tbl['db'], $tbl['table'])) { return $this->remove($tbl['db'], $tbl['table']); } } diff --git a/libraries/classes/Replication.php b/libraries/classes/Replication.php index fb4170b308..ecbb9539b0 100644 --- a/libraries/classes/Replication.php +++ b/libraries/classes/Replication.php @@ -49,8 +49,6 @@ class Replication */ public function replicaControl(string $action, ?string $control, int $link) { - global $dbi; - $action = mb_strtoupper($action); $control = $control !== null ? mb_strtoupper($control) : ''; @@ -62,7 +60,7 @@ class Replication return -1; } - return $dbi->tryQuery($action . ' SLAVE ' . $control . ';', $link); + return $GLOBALS['dbi']->tryQuery($action . ' SLAVE ' . $control . ';', $link); } /** @@ -89,13 +87,11 @@ class Replication bool $start, int $link ) { - global $dbi; - if ($stop) { $this->replicaControl('STOP', null, $link); } - $out = $dbi->tryQuery( + $out = $GLOBALS['dbi']->tryQuery( 'CHANGE MASTER TO ' . 'MASTER_HOST=\'' . $host . '\',' . 'MASTER_PORT=' . ($port * 1) . ',' . @@ -131,8 +127,6 @@ class Replication $port = null, $socket = null ) { - global $dbi; - $server = []; $server['user'] = $user; $server['password'] = $password; @@ -142,7 +136,7 @@ class Replication // 5th parameter set to true means that it's an auxiliary connection // and we must not go back to login page if it fails - return $dbi->connect(DatabaseInterface::CONNECT_AUXILIARY, $server); + return $GLOBALS['dbi']->connect(DatabaseInterface::CONNECT_AUXILIARY, $server); } /** @@ -156,9 +150,7 @@ class Replication */ public function replicaBinLogPrimary(int $link): array { - global $dbi; - - $data = $dbi->fetchResult('SHOW MASTER STATUS', null, null, $link); + $data = $GLOBALS['dbi']->fetchResult('SHOW MASTER STATUS', null, null, $link); $output = []; if (! empty($data)) { diff --git a/libraries/classes/ReplicationGui.php b/libraries/classes/ReplicationGui.php index 67534e9b95..d62bccfe30 100644 --- a/libraries/classes/ReplicationGui.php +++ b/libraries/classes/ReplicationGui.php @@ -72,11 +72,9 @@ class ReplicationGui */ public function getHtmlForPrimaryReplication(): string { - global $dbi; - if (! isset($_POST['repl_clear_scr'])) { $primaryStatusTable = $this->getHtmlForReplicationStatusTable('primary', true, false); - $replicas = $dbi->fetchResult('SHOW SLAVE HOSTS', null, null); + $replicas = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null); $urlParams = $GLOBALS['urlParams']; $urlParams['primary_add_user'] = true; @@ -124,9 +122,7 @@ class ReplicationGui $serverReplicaStatus, array $serverReplicaReplication ): string { - global $dbi; - - $serverReplicaMultiReplication = $dbi->fetchResult('SHOW ALL SLAVES STATUS'); + $serverReplicaMultiReplication = $GLOBALS['dbi']->fetchResult('SHOW ALL SLAVES STATUS'); if ($serverReplicaStatus) { $urlParams = $GLOBALS['urlParams']; $urlParams['sr_take_action'] = true; @@ -255,9 +251,7 @@ class ReplicationGui $isHidden = false, $hasTitle = true ): string { - global $dbi; - - $replicationInfo = new ReplicationInfo($dbi); + $replicationInfo = new ReplicationInfo($GLOBALS['dbi']); $replicationInfo->load($_POST['primary_connection'] ?? null); $replicationVariables = $replicationInfo->primaryVariables; @@ -325,9 +319,7 @@ class ReplicationGui */ public function getUsernameHostnameLength(): array { - global $dbi; - - $fieldsInfo = $dbi->getColumns('mysql', 'user'); + $fieldsInfo = $GLOBALS['dbi']->getColumns('mysql', 'user'); $usernameLength = 16; $hostnameLength = 41; foreach ($fieldsInfo as $val) { @@ -359,8 +351,6 @@ class ReplicationGui */ public function getHtmlForReplicationPrimaryAddReplicaUser(): string { - global $dbi; - [ $usernameLength, $hostnameLength, @@ -375,7 +365,7 @@ class ReplicationGui $username = $GLOBALS['new_username'] ?? $_POST['username']; } - $currentUser = $dbi->fetchValue('SELECT USER();'); + $currentUser = $GLOBALS['dbi']->fetchValue('SELECT USER();'); if (! empty($currentUser)) { $userHost = str_replace( "'", @@ -489,13 +479,11 @@ class ReplicationGui public function handleRequestForReplicaChangePrimary(): bool { - global $dbi; - $sr = [ - 'username' => $dbi->escapeString($_POST['username']), - 'pma_pw' => $dbi->escapeString($_POST['pma_pw']), - 'hostname' => $dbi->escapeString($_POST['hostname']), - 'port' => (int) $dbi->escapeString($_POST['text_port']), + 'username' => $GLOBALS['dbi']->escapeString($_POST['username']), + 'pma_pw' => $GLOBALS['dbi']->escapeString($_POST['pma_pw']), + 'hostname' => $GLOBALS['dbi']->escapeString($_POST['hostname']), + 'port' => (int) $GLOBALS['dbi']->escapeString($_POST['text_port']), ]; $_SESSION['replication']['m_username'] = $sr['username']; @@ -561,14 +549,12 @@ class ReplicationGui public function handleRequestForReplicaServerControl(): bool { - global $dbi; - /** @var string|null $control */ $control = $_POST['sr_replica_control_param'] ?? null; if ($_POST['sr_replica_action'] === 'reset') { $qStop = $this->replication->replicaControl('STOP', null, DatabaseInterface::CONNECT_USER); - $qReset = $dbi->tryQuery('RESET SLAVE;'); + $qReset = $GLOBALS['dbi']->tryQuery('RESET SLAVE;'); $qStart = $this->replication->replicaControl('START', null, DatabaseInterface::CONNECT_USER); $result = $qStop !== false && $qStop !== -1 && @@ -589,15 +575,13 @@ class ReplicationGui public function handleRequestForReplicaSkipError(): bool { - global $dbi; - $count = 1; if (isset($_POST['sr_skip_errors_count'])) { $count = $_POST['sr_skip_errors_count'] * 1; } $qStop = $this->replication->replicaControl('STOP', null, DatabaseInterface::CONNECT_USER); - $qSkip = $dbi->tryQuery('SET GLOBAL SQL_SLAVE_SKIP_COUNTER = ' . $count . ';'); + $qSkip = $GLOBALS['dbi']->tryQuery('SET GLOBAL SQL_SLAVE_SKIP_COUNTER = ' . $count . ';'); $qStart = $this->replication->replicaControl('START', null, DatabaseInterface::CONNECT_USER); return $qStop !== false && $qStop !== -1 && diff --git a/libraries/classes/ReplicationInfo.php b/libraries/classes/ReplicationInfo.php index 982d8fc726..0b9b928f36 100644 --- a/libraries/classes/ReplicationInfo.php +++ b/libraries/classes/ReplicationInfo.php @@ -80,7 +80,7 @@ final class ReplicationInfo public function load(?string $connection = null): void { - global $urlParams; + $GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null; $this->setPrimaryStatus(); @@ -89,7 +89,7 @@ final class ReplicationInfo if ($this->multiPrimaryStatus) { $this->setDefaultPrimaryConnection($connection); - $urlParams['primary_connection'] = $connection; + $GLOBALS['urlParams']['primary_connection'] = $connection; } } diff --git a/libraries/classes/ResponseRenderer.php b/libraries/classes/ResponseRenderer.php index 95790034ef..840e01f2f7 100644 --- a/libraries/classes/ResponseRenderer.php +++ b/libraries/classes/ResponseRenderer.php @@ -244,16 +244,6 @@ class ResponseRenderer } /** - * Returns a PhpMyAdmin\Footer object - * - * @return Footer - */ - public function getFooter() - { - return $this->footer; - } - - /** * Append HTML code to the current output buffer */ public function addHTML(string $content): void @@ -290,11 +280,11 @@ class ResponseRenderer // if its content was already rendered // and, in this case, the header will be // in the content part of the request - $retval = $this->header->getDisplay(); - $retval .= $this->HTML; - $retval .= $this->footer->getDisplay(); - - return $retval; + return (new Template())->render('base', [ + 'header' => $this->header->getDisplay(), + 'content' => $this->HTML, + 'footer' => $this->footer->getDisplay(), + ]); } /** @@ -302,8 +292,6 @@ class ResponseRenderer */ private function ajaxResponse(): string { - global $dbi; - /* Avoid wrapping in case we're disabled */ if ($this->isDisabled) { return $this->getDisplay(); @@ -328,12 +316,12 @@ class ResponseRenderer $this->addJSON('title', '<title>' . $this->getHeader()->getPageTitle() . '</title>'); } - if (isset($dbi)) { + if (isset($GLOBALS['dbi'])) { $this->addJSON('menu', $this->getHeader()->getMenu()->getDisplay()); } $this->addJSON('scripts', $this->getHeader()->getScripts()->getFiles()); - $this->addJSON('selflink', $this->getFooter()->getSelfUrl()); + $this->addJSON('selflink', $this->footer->getSelfUrl()); $this->addJSON('displayMessage', $this->getHeader()->getMessage()); $debug = $this->footer->getDebugMessage(); @@ -496,7 +484,7 @@ class ResponseRenderer return true; } - $this->getFooter()->setMinimal(); + $this->setMinimalFooter(); $header = $this->getHeader(); $header->setBodyId('loginform'); $header->setTitle('phpMyAdmin'); @@ -505,4 +493,19 @@ class ResponseRenderer return false; } + + public function setMinimalFooter(): void + { + $this->footer->setMinimal(); + } + + public function getSelfUrl(): string + { + return $this->footer->getSelfUrl(); + } + + public function getFooterScripts(): Scripts + { + return $this->footer->getScripts(); + } } diff --git a/libraries/classes/Routing.php b/libraries/classes/Routing.php index 5318d5fb67..47f160f707 100644 --- a/libraries/classes/Routing.php +++ b/libraries/classes/Routing.php @@ -46,9 +46,7 @@ class Routing public static function skipCache(): bool { - global $cfg; - - return ($cfg['environment'] ?? '') === 'development'; + return ($GLOBALS['cfg']['environment'] ?? '') === 'development'; } public static function canWriteCache(): bool @@ -119,39 +117,14 @@ class Routing } /** - * @psalm-return non-empty-string - */ - public static function getCurrentRoute(): string - { - /** @var mixed $route */ - $route = $_GET['route'] ?? $_POST['route'] ?? '/'; - if (! is_string($route) || $route === '') { - $route = '/'; - } - - /** - * See FAQ 1.34. - * - * @see https://docs.phpmyadmin.net/en/latest/faq.html#faq1-34 - */ - $db = isset($_GET['db']) && is_string($_GET['db']) ? $_GET['db'] : ''; - if ($route === '/' && $db !== '') { - $table = isset($_GET['table']) && is_string($_GET['table']) ? $_GET['table'] : ''; - $route = $table === '' ? '/database/structure' : '/sql'; - } - - return $route; - } - - /** * Call associated controller for a route using the dispatcher */ public static function callControllerForRoute( ServerRequest $request, - string $route, Dispatcher $dispatcher, ContainerInterface $container ): void { + $route = $request->getRoute(); $routeInfo = $dispatcher->dispatch($request->getMethod(), rawurldecode($route)); if ($routeInfo[0] === Dispatcher::NOT_FOUND) { diff --git a/libraries/classes/Sanitize.php b/libraries/classes/Sanitize.php index f8366aec60..056459767e 100644 --- a/libraries/classes/Sanitize.php +++ b/libraries/classes/Sanitize.php @@ -46,7 +46,7 @@ class Sanitize $url = strtolower($url); $valid_starts = [ 'https://', - './url.php?url=https%3a%2f%2f', + 'index.php?route=/url&url=https%3a%2f%2f', './doc/html/', './index.php?', ]; diff --git a/libraries/classes/SavedSearches.php b/libraries/classes/SavedSearches.php index 9ac29920b9..fc6f8abe76 100644 --- a/libraries/classes/SavedSearches.php +++ b/libraries/classes/SavedSearches.php @@ -232,8 +232,6 @@ class SavedSearches */ public function save(SavedQueryByExampleSearchesFeature $savedQueryByExampleSearchesFeature): bool { - global $dbi; - if ($this->getSearchName() == null) { $message = Message::error( __('Please provide a name for this bookmarked search.') @@ -266,7 +264,7 @@ class SavedSearches //If it's an insert. if ($this->getId() === null) { $wheres = [ - "search_name = '" . $dbi->escapeString($this->getSearchName()) + "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'", ]; $existingSearches = $this->getList($savedQueryByExampleSearchesFeature, $wheres); @@ -285,15 +283,15 @@ class SavedSearches $sqlQuery = 'INSERT INTO ' . $savedSearchesTbl . '(`username`, `db_name`, `search_name`, `search_data`)' . ' VALUES (' - . "'" . $dbi->escapeString($this->getUsername()) . "'," - . "'" . $dbi->escapeString($this->getDbname()) . "'," - . "'" . $dbi->escapeString($this->getSearchName()) . "'," - . "'" . $dbi->escapeString(json_encode($this->getCriterias())) + . "'" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "'," + . "'" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "'," + . "'" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'," + . "'" . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias())) . "')"; - $dbi->queryAsControlUser($sqlQuery); + $GLOBALS['dbi']->queryAsControlUser($sqlQuery); - $this->setId($dbi->insertId()); + $this->setId($GLOBALS['dbi']->insertId()); return true; } @@ -301,7 +299,7 @@ class SavedSearches //Else, it's an update. $wheres = [ 'id != ' . $this->getId(), - "search_name = '" . $dbi->escapeString($this->getSearchName()) . "'", + "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'", ]; $existingSearches = $this->getList($savedQueryByExampleSearchesFeature, $wheres); @@ -318,12 +316,12 @@ class SavedSearches $sqlQuery = 'UPDATE ' . $savedSearchesTbl . "SET `search_name` = '" - . $dbi->escapeString($this->getSearchName()) . "', " + . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "', " . "`search_data` = '" - . $dbi->escapeString(json_encode($this->getCriterias())) . "' " + . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias())) . "' " . 'WHERE id = ' . $this->getId(); - return (bool) $dbi->queryAsControlUser($sqlQuery); + return (bool) $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } /** @@ -331,8 +329,6 @@ class SavedSearches */ public function delete(SavedQueryByExampleSearchesFeature $savedQueryByExampleSearchesFeature): bool { - global $dbi; - if ($this->getId() == null) { $message = Message::error( __('Missing information to delete the search.') @@ -348,9 +344,9 @@ class SavedSearches . Util::backquote($savedQueryByExampleSearchesFeature->savedSearches); $sqlQuery = 'DELETE FROM ' . $savedSearchesTbl - . "WHERE id = '" . $dbi->escapeString((string) $this->getId()) . "'"; + . "WHERE id = '" . $GLOBALS['dbi']->escapeString((string) $this->getId()) . "'"; - return (bool) $dbi->queryAsControlUser($sqlQuery); + return (bool) $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } /** @@ -358,8 +354,6 @@ class SavedSearches */ public function load(SavedQueryByExampleSearchesFeature $savedQueryByExampleSearchesFeature): bool { - global $dbi; - if ($this->getId() == null) { $message = Message::error( __('Missing information to load the search.') @@ -376,9 +370,9 @@ class SavedSearches . Util::backquote($savedQueryByExampleSearchesFeature->savedSearches); $sqlQuery = 'SELECT id, search_name, search_data ' . 'FROM ' . $savedSearchesTbl . ' ' - . "WHERE id = '" . $dbi->escapeString((string) $this->getId()) . "' "; + . "WHERE id = '" . $GLOBALS['dbi']->escapeString((string) $this->getId()) . "' "; - $resList = $dbi->queryAsControlUser($sqlQuery); + $resList = $GLOBALS['dbi']->queryAsControlUser($sqlQuery); $oneResult = $resList->fetchAssoc(); if ($oneResult === []) { @@ -405,8 +399,6 @@ class SavedSearches */ public function getList(SavedQueryByExampleSearchesFeature $savedQueryByExampleSearchesFeature, array $wheres = []) { - global $dbi; - if ($this->getUsername() == null || $this->getDbname() == null) { return []; } @@ -417,8 +409,8 @@ class SavedSearches $sqlQuery = 'SELECT id, search_name ' . 'FROM ' . $savedSearchesTbl . ' ' . 'WHERE ' - . "username = '" . $dbi->escapeString($this->getUsername()) . "' " - . "AND db_name = '" . $dbi->escapeString($this->getDbname()) . "' "; + . "username = '" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "' " + . "AND db_name = '" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "' "; foreach ($wheres as $where) { $sqlQuery .= 'AND ' . $where . ' '; @@ -426,7 +418,7 @@ class SavedSearches $sqlQuery .= 'order by search_name ASC '; - $resList = $dbi->queryAsControlUser($sqlQuery); + $resList = $GLOBALS['dbi']->queryAsControlUser($sqlQuery); return $resList->fetchAllKeyPair(); } diff --git a/libraries/classes/Scripts.php b/libraries/classes/Scripts.php index d9fb2b7728..66e86729ed 100644 --- a/libraries/classes/Scripts.php +++ b/libraries/classes/Scripts.php @@ -88,8 +88,10 @@ class Scripts { return ! str_contains($filename, 'jquery') && ! str_contains($filename, 'codemirror') - && ! str_contains($filename, 'messages.php') + && ! str_contains($filename, 'index.php') && ! str_contains($filename, 'ajax.js') + && ! str_contains($filename, 'datetimepicker.js') + && ! str_contains($filename, 'validator-messages.js') && ! str_contains($filename, 'cross_framing_protection.js'); } diff --git a/libraries/classes/Server/Plugins.php b/libraries/classes/Server/Plugins.php index 5404b053b8..920e177d8a 100644 --- a/libraries/classes/Server/Plugins.php +++ b/libraries/classes/Server/Plugins.php @@ -26,10 +26,8 @@ class Plugins */ public function getAll(): array { - global $cfg; - $sql = 'SHOW PLUGINS'; - if (! $cfg['Server']['DisableIS']) { + if (! $GLOBALS['cfg']['Server']['DisableIS']) { $sql = 'SELECT * FROM information_schema.PLUGINS ORDER BY PLUGIN_TYPE, PLUGIN_NAME'; } diff --git a/libraries/classes/Server/Privileges.php b/libraries/classes/Server/Privileges.php index ca55811bf6..5bec85a267 100644 --- a/libraries/classes/Server/Privileges.php +++ b/libraries/classes/Server/Privileges.php @@ -11,6 +11,7 @@ use mysqli_stmt; use PhpMyAdmin\ConfigStorage\Features\ConfigurableMenusFeature; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; +use PhpMyAdmin\Database\Routines; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Dbal\MysqliResult; use PhpMyAdmin\Dbal\ResultInterface; @@ -743,12 +744,16 @@ class Privileges $user = null, $host = null ) { - global $pred_username, $pred_hostname, $username, $hostname, $new_username; + $GLOBALS['pred_username'] = $GLOBALS['pred_username'] ?? null; + $GLOBALS['pred_hostname'] = $GLOBALS['pred_hostname'] ?? null; + $GLOBALS['username'] = $GLOBALS['username'] ?? null; + $GLOBALS['hostname'] = $GLOBALS['hostname'] ?? null; + $GLOBALS['new_username'] = $GLOBALS['new_username'] ?? null; [$usernameLength, $hostnameLength] = $this->getUsernameAndHostnameLength(); - if (isset($username) && strlen($username) === 0) { - $pred_username = 'any'; + if (isset($GLOBALS['username']) && strlen($GLOBALS['username']) === 0) { + $GLOBALS['pred_username'] = 'any'; } $currentUser = $this->dbi->fetchValue('SELECT USER();'); @@ -764,17 +769,17 @@ class Privileges ); } - if (! isset($pred_hostname) && isset($hostname)) { - switch (mb_strtolower($hostname)) { + if (! isset($GLOBALS['pred_hostname']) && isset($GLOBALS['hostname'])) { + switch (mb_strtolower($GLOBALS['hostname'])) { case 'localhost': case '127.0.0.1': - $pred_hostname = 'localhost'; + $GLOBALS['pred_hostname'] = 'localhost'; break; case '%': - $pred_hostname = 'any'; + $GLOBALS['pred_hostname'] = 'any'; break; default: - $pred_hostname = 'userdefined'; + $GLOBALS['pred_hostname'] = 'userdefined'; break; } } @@ -794,13 +799,13 @@ class Privileges } return $this->template->render('server/privileges/login_information_fields', [ - 'pred_username' => $pred_username ?? null, - 'pred_hostname' => $pred_hostname ?? null, + 'pred_username' => $GLOBALS['pred_username'] ?? null, + 'pred_hostname' => $GLOBALS['pred_hostname'] ?? null, 'username_length' => $usernameLength, 'hostname_length' => $hostnameLength, - 'username' => $username ?? null, - 'new_username' => $new_username ?? null, - 'hostname' => $hostname ?? null, + 'username' => $GLOBALS['username'] ?? null, + 'new_username' => $GLOBALS['new_username'] ?? null, + 'hostname' => $GLOBALS['hostname'] ?? null, 'this_host' => $thisHost, 'is_change' => $mode === 'change', 'auth_plugin' => $authPlugin, @@ -856,8 +861,6 @@ class Privileges $username = null, $hostname = null ) { - global $dbi; - /* Fallback (standard) value */ $authenticationPlugin = 'mysql_native_password'; $serverVersion = $this->dbi->getVersion(); @@ -865,9 +868,9 @@ class Privileges if (isset($username, $hostname) && $mode === 'change') { $row = $this->dbi->fetchSingleRow( 'SELECT `plugin` FROM `mysql`.`user` WHERE `User` = "' - . $dbi->escapeString($username) + . $GLOBALS['dbi']->escapeString($username) . '" AND `Host` = "' - . $dbi->escapeString($hostname) + . $GLOBALS['dbi']->escapeString($hostname) . '" LIMIT 1' ); // Table 'mysql'.'user' may not exist for some previous @@ -880,9 +883,9 @@ class Privileges $row = $this->dbi->fetchSingleRow( 'SELECT `plugin` FROM `mysql`.`user` WHERE `User` = "' - . $dbi->escapeString($username) + . $GLOBALS['dbi']->escapeString($username) . '" AND `Host` = "' - . $dbi->escapeString($hostname) + . $GLOBALS['dbi']->escapeString($hostname) . '"' ); if (is_array($row) && isset($row['plugin'])) { @@ -931,8 +934,6 @@ class Privileges */ public function updatePassword($errorUrl, $username, $hostname) { - global $dbi; - // similar logic in /user-password $message = null; @@ -1011,8 +1012,8 @@ class Privileges . " `authentication_string` = '" . $hashedPassword . "', `Password` = '', " . " `plugin` = '" . $authenticationPlugin . "'" - . " WHERE `User` = '" . $dbi->escapeString($username) - . "' AND Host = '" . $dbi->escapeString($hostname) . "';"; + . " WHERE `User` = '" . $GLOBALS['dbi']->escapeString($username) + . "' AND Host = '" . $GLOBALS['dbi']->escapeString($hostname) . "';"; } else { // USE 'SET PASSWORD ...' syntax for rest of the versions // Backup the old value, to be reset later @@ -1020,8 +1021,8 @@ class Privileges $origValue = $row['@@old_passwords']; $updatePluginQuery = 'UPDATE `mysql`.`user` SET' . " `plugin` = '" . $authenticationPlugin . "'" - . " WHERE `User` = '" . $dbi->escapeString($username) - . "' AND Host = '" . $dbi->escapeString($hostname) . "';"; + . " WHERE `User` = '" . $GLOBALS['dbi']->escapeString($username) + . "' AND Host = '" . $GLOBALS['dbi']->escapeString($hostname) . "';"; // Update the plugin for the user if (! $this->dbi->tryQuery($updatePluginQuery)) { @@ -1138,22 +1139,27 @@ class Privileges */ public function getRequireClause() { - $arr = isset($_POST['ssl_type']) ? $_POST : $GLOBALS; - if (isset($arr['ssl_type']) && $arr['ssl_type'] === 'SPECIFIED') { + /** @var string|null $sslType */ + $sslType = $_POST['ssl_type'] ?? $GLOBALS['ssl_type'] ?? null; + /** @var string|null $sslCipher */ + $sslCipher = $_POST['ssl_cipher'] ?? $GLOBALS['ssl_cipher'] ?? null; + /** @var string|null $x509Issuer */ + $x509Issuer = $_POST['x509_issuer'] ?? $GLOBALS['x509_issuer'] ?? null; + /** @var string|null $x509Subject */ + $x509Subject = $_POST['x509_subject'] ?? $GLOBALS['x509_subject'] ?? null; + + if ($sslType === 'SPECIFIED') { $require = []; - if (! empty($arr['ssl_cipher'])) { - $require[] = "CIPHER '" - . $this->dbi->escapeString($arr['ssl_cipher']) . "'"; + if (is_string($sslCipher) && $sslCipher !== '') { + $require[] = 'CIPHER \'' . $this->dbi->escapeString($sslCipher) . '\''; } - if (! empty($arr['x509_issuer'])) { - $require[] = "ISSUER '" - . $this->dbi->escapeString($arr['x509_issuer']) . "'"; + if (is_string($x509Issuer) && $x509Issuer !== '') { + $require[] = 'ISSUER \'' . $this->dbi->escapeString($x509Issuer) . '\''; } - if (! empty($arr['x509_subject'])) { - $require[] = "SUBJECT '" - . $this->dbi->escapeString($arr['x509_subject']) . "'"; + if (is_string($x509Subject) && $x509Subject !== '') { + $require[] = 'SUBJECT \'' . $this->dbi->escapeString($x509Subject) . '\''; } if (count($require)) { @@ -1161,9 +1167,9 @@ class Privileges } else { $requireClause = ' REQUIRE NONE'; } - } elseif (isset($arr['ssl_type']) && $arr['ssl_type'] === 'X509') { + } elseif ($sslType === 'X509') { $requireClause = ' REQUIRE X509'; - } elseif (isset($arr['ssl_type']) && $arr['ssl_type'] === 'ANY') { + } elseif ($sslType === 'ANY') { $requireClause = ' REQUIRE SSL'; } else { $requireClause = ' REQUIRE NONE'; @@ -1693,10 +1699,9 @@ class Privileges continue; } - $dbRightsSqls[] = ' - SELECT DISTINCT `' . $dbOrTableName . '` - FROM `mysql`.' . Util::backquote($tableSearchIn) - . $userHostCondition; + $dbRightsSqls[] = 'SELECT DISTINCT `' . $dbOrTableName + . '` FROM `mysql`.' . Util::backquote($tableSearchIn) + . $userHostCondition; } $userDefaults = [ @@ -1962,7 +1967,7 @@ class Privileges $data['tables'] = $tables; } else { // routine - $routineData = $this->dbi->getRoutines($dbname); + $routineData = Routines::getDetails($this->dbi, $dbname); $routines = []; foreach ($routineData as $routine) { @@ -2095,7 +2100,6 @@ class Privileges return $this->template->render('server/privileges/initials_row', [ 'array_initials' => $arrayInitials, 'initial' => $_GET['initial'] ?? null, - 'viewing_mode' => $_GET['viewing_mode'] ?? null, ]); } @@ -2895,20 +2899,16 @@ class Privileges return ''; } - $relParams = []; $urlParams = ['adduser' => 1]; if (! empty($db)) { - $urlParams['dbname'] = $relParams['checkprivsdb'] = $db; + $urlParams['dbname'] = $db; } if (! empty($table)) { - $urlParams['tablename'] = $relParams['checkprivstable'] = $table; + $urlParams['tablename'] = $table; } - return $this->template->render('server/privileges/add_user_fieldset', [ - 'url_params' => $urlParams, - 'rel_params' => $relParams, - ]); + return $this->template->render('server/privileges/add_user_fieldset', ['url_params' => $urlParams]); } /** @@ -3070,6 +3070,7 @@ class Privileges * @param string $hostname host name * @param string|array $dbname database name * @param string $tablename table name + * @psalm-param non-empty-string $route * * @return string */ @@ -3079,10 +3080,9 @@ class Privileges $username, $hostname, $dbname, - $tablename + $tablename, + string $route ) { - global $cfg; - $sql = "SELECT '1' FROM `mysql`.`user`" . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; @@ -3142,17 +3142,17 @@ class Privileges } } - $databaseUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); - $databaseUrlTitle = Util::getTitleForTarget($cfg['DefaultTabDatabase']); - $tableUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); - $tableUrlTitle = Util::getTitleForTarget($cfg['DefaultTabTable']); + $databaseUrl = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); + $databaseUrlTitle = Util::getTitleForTarget($GLOBALS['cfg']['DefaultTabDatabase']); + $tableUrl = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); + $tableUrlTitle = Util::getTitleForTarget($GLOBALS['cfg']['DefaultTabTable']); $changePassword = ''; $userGroup = ''; $changeLoginInfoFields = ''; if (! is_array($dbname) && strlen($dbname) === 0 && ! $userDoesNotExists) { //change login information - $changePassword = $this->getFormForChangePassword($username, $hostname, true); + $changePassword = $this->getFormForChangePassword($username, $hostname, true, $route); $userGroup = $this->getUserGroupForUser($username); $changeLoginInfoFields = $this->getHtmlForLoginInformationFields('change', $username, $hostname); } @@ -3661,7 +3661,7 @@ class Privileges */ public function getRoutineType(string $dbname, string $routineName) { - $routineData = $this->dbi->getRoutines($dbname); + $routineData = Routines::getDetails($this->dbi, $dbname); $routineName = mb_strtolower($routineName); foreach ($routineData as $routine) { @@ -3702,10 +3702,15 @@ class Privileges return $this->parseProcPriv($privileges); } - public function getFormForChangePassword(string $username, string $hostname, bool $editOthers): string - { - global $route; - + /** + * @psalm-param non-empty-string $route + */ + public function getFormForChangePassword( + string $username, + string $hostname, + bool $editOthers, + string $route + ): string { $isPrivileges = $route === '/server/privileges'; $serverVersion = $this->dbi->getVersion(); diff --git a/libraries/classes/Server/Status/Data.php b/libraries/classes/Server/Status/Data.php index ea54b6129c..4a14a1fb4d 100644 --- a/libraries/classes/Server/Status/Data.php +++ b/libraries/classes/Server/Status/Data.php @@ -352,15 +352,13 @@ class Data public function __construct() { - global $dbi; - - $this->replicationInfo = new ReplicationInfo($dbi); + $this->replicationInfo = new ReplicationInfo($GLOBALS['dbi']); $this->replicationInfo->load($_POST['primary_connection'] ?? null); $this->selfUrl = basename($GLOBALS['PMA_PHP_SELF']); // get status from server - $server_status_result = $dbi->tryQuery('SHOW GLOBAL STATUS'); + $server_status_result = $GLOBALS['dbi']->tryQuery('SHOW GLOBAL STATUS'); if ($server_status_result === false) { $server_status = []; $this->dataLoaded = false; @@ -371,7 +369,7 @@ class Data } // for some calculations we require also some server settings - $server_variables = $dbi->fetchResult('SHOW GLOBAL VARIABLES', 0, 1); + $server_variables = $GLOBALS['dbi']->fetchResult('SHOW GLOBAL VARIABLES', 0, 1); // cleanup of some deprecated values $server_status = self::cleanDeprecated($server_status); diff --git a/libraries/classes/Server/Status/Monitor.php b/libraries/classes/Server/Status/Monitor.php index d00f4e7d26..f0dcce4f1d 100644 --- a/libraries/classes/Server/Status/Monitor.php +++ b/libraries/classes/Server/Status/Monitor.php @@ -506,7 +506,7 @@ class Monitor string $database, string $query ): array { - global $cached_affected_rows; + $GLOBALS['cached_affected_rows'] = $GLOBALS['cached_affected_rows'] ?? null; $return = []; @@ -524,7 +524,7 @@ class Monitor $sqlQuery = preg_replace('/^(\s*SELECT)/i', '\\1 SQL_NO_CACHE', $query); $this->dbi->tryQuery($sqlQuery); - $return['affectedRows'] = $cached_affected_rows; + $return['affectedRows'] = $GLOBALS['cached_affected_rows']; $result = $this->dbi->tryQuery('EXPLAIN ' . $sqlQuery); if ($result !== false) { diff --git a/libraries/classes/Server/SysInfo/Base.php b/libraries/classes/Server/SysInfo/Base.php index 771a62c1fa..c99446a26d 100644 --- a/libraries/classes/Server/SysInfo/Base.php +++ b/libraries/classes/Server/SysInfo/Base.php @@ -21,9 +21,9 @@ class Base /** * Gets load information * - * @return array with load data + * @return array<string, int> with load data */ - public function loadavg() + public function loadavg(): array { return ['loadavg' => 0]; } @@ -31,9 +31,9 @@ class Base /** * Gets information about memory usage * - * @return array with memory usage data + * @return array<string, int> with memory usage data */ - public function memory() + public function memory(): array { return []; } @@ -41,7 +41,7 @@ class Base /** * Checks whether class is supported in this environment */ - public function supported(): bool + public static function isSupported(): bool { return true; } diff --git a/libraries/classes/Server/SysInfo/Linux.php b/libraries/classes/Server/SysInfo/Linux.php index 5aae88a2c2..ca664d2d96 100644 --- a/libraries/classes/Server/SysInfo/Linux.php +++ b/libraries/classes/Server/SysInfo/Linux.php @@ -32,7 +32,7 @@ class Linux extends Base * * @return array<string, int> with load data */ - public function loadavg() + public function loadavg(): array { $buf = file_get_contents('/proc/stat'); if ($buf === false) { @@ -66,7 +66,7 @@ class Linux extends Base /** * Checks whether class is supported in this environment */ - public function supported(): bool + public static function isSupported(): bool { return @is_readable('/proc/meminfo') && @is_readable('/proc/stat'); } @@ -74,9 +74,9 @@ class Linux extends Base /** * Gets information about memory usage * - * @return array with memory usage data + * @return array<string, int> with memory usage data */ - public function memory() + public function memory(): array { $content = @file_get_contents('/proc/meminfo'); if ($content === false) { diff --git a/libraries/classes/Server/SysInfo/SunOs.php b/libraries/classes/Server/SysInfo/SunOs.php index a89823e657..91e72ccf15 100644 --- a/libraries/classes/Server/SysInfo/SunOs.php +++ b/libraries/classes/Server/SysInfo/SunOs.php @@ -28,7 +28,7 @@ class SunOs extends Base * * @return string with value */ - private function kstat($key) + private function kstat($key): string { /** @psalm-suppress ForbiddenCode */ $m = shell_exec('kstat -p d ' . $key); @@ -45,19 +45,17 @@ class SunOs extends Base /** * Gets load information * - * @return array with load data + * @return array<string, int> with load data */ - public function loadavg() + public function loadavg(): array { - $load1 = $this->kstat('unix:0:system_misc:avenrun_1min'); - - return ['loadavg' => $load1]; + return ['loadavg' => (int) $this->kstat('unix:0:system_misc:avenrun_1min')]; } /** * Checks whether class is supported in this environment */ - public function supported(): bool + public static function isSupported(): bool { return @is_readable('/proc/meminfo'); } @@ -65,18 +63,18 @@ class SunOs extends Base /** * Gets information about memory usage * - * @return array with memory usage data + * @return array<string, int> with memory usage data */ - public function memory() + public function memory(): array { $pagesize = (int) $this->kstat('unix:0:seg_cache:slab_size'); $mem = []; $mem['MemTotal'] = (int) $this->kstat('unix:0:system_pages:pagestotal') * $pagesize; $mem['MemUsed'] = (int) $this->kstat('unix:0:system_pages:pageslocked') * $pagesize; $mem['MemFree'] = (int) $this->kstat('unix:0:system_pages:pagesfree') * $pagesize; - $mem['SwapTotal'] = (int) $this->kstat('unix:0:vminfo:swap_avail') / 1024; - $mem['SwapUsed'] = (int) $this->kstat('unix:0:vminfo:swap_alloc') / 1024; - $mem['SwapFree'] = (int) $this->kstat('unix:0:vminfo:swap_free') / 1024; + $mem['SwapTotal'] = (int) ((int) $this->kstat('unix:0:vminfo:swap_avail') / 1024); + $mem['SwapUsed'] = (int) ((int) $this->kstat('unix:0:vminfo:swap_alloc') / 1024); + $mem['SwapFree'] = (int) ((int) $this->kstat('unix:0:vminfo:swap_free') / 1024); return $mem; } diff --git a/libraries/classes/Server/SysInfo/SysInfo.php b/libraries/classes/Server/SysInfo/SysInfo.php index 54245d77e4..cdef47a9c8 100644 --- a/libraries/classes/Server/SysInfo/SysInfo.php +++ b/libraries/classes/Server/SysInfo/SysInfo.php @@ -52,23 +52,20 @@ class SysInfo switch ($php_os) { case 'Linux': - $sysInfo = new Linux(); - if ($sysInfo->supported()) { - return $sysInfo; + if (Linux::isSupported()) { + return new Linux(); } break; case 'WINNT': - $sysInfo = new WindowsNt(); - if ($sysInfo->supported()) { - return $sysInfo; + if (WindowsNt::isSupported()) { + return new WindowsNt(); } break; case 'SunOS': - $sysInfo = new SunOs(); - if ($sysInfo->supported()) { - return $sysInfo; + if (SunOs::isSupported()) { + return new SunOs(); } break; diff --git a/libraries/classes/Server/SysInfo/WindowsNt.php b/libraries/classes/Server/SysInfo/WindowsNt.php index f16b3494a6..915aa21a4a 100644 --- a/libraries/classes/Server/SysInfo/WindowsNt.php +++ b/libraries/classes/Server/SysInfo/WindowsNt.php @@ -4,21 +4,21 @@ declare(strict_types=1); namespace PhpMyAdmin\Server\SysInfo; -use COM; +use com; +use Throwable; +use function array_merge; use function class_exists; -use function count; -use function in_array; -use function is_string; -use function trim; +use function intdiv; +use function intval; /** * Windows NT based SysInfo class */ class WindowsNt extends Base { - /** @var COM|null */ - private $wmi; + /** @var object|null */ + private $wmiService = null; /** * The OS name @@ -32,116 +32,150 @@ class WindowsNt extends Base */ public function __construct() { - if (! class_exists('COM')) { - $this->wmi = null; - + if (! class_exists('com')) { return; } - // initialize the wmi object - $objLocator = new COM('WbemScripting.SWbemLocator'); - $this->wmi = $objLocator->ConnectServer(); + /** + * @see https://www.php.net/manual/en/class.com.php + * @see https://docs.microsoft.com/en-us/windows/win32/wmisdk/swbemlocator + * @see https://docs.microsoft.com/en-us/windows/win32/wmisdk/swbemservices + * + * @psalm-suppress MixedAssignment, UndefinedMagicMethod, MixedMethodCall + * @phpstan-ignore-next-line + */ + $this->wmiService = (new com('WbemScripting.SWbemLocator'))->ConnectServer(); } /** * Gets load information * - * @return array with load data + * @return array<string, int> with load data */ - public function loadavg() + public function loadavg(): array { - $sum = 0; - $buffer = $this->getWMI('Win32_Processor', ['LoadPercentage']); - - foreach ($buffer as $load) { - $value = $load['LoadPercentage']; - $sum += $value; - } - - return ['loadavg' => $sum / count($buffer)]; + return ['loadavg' => $this->getLoadPercentage()]; } /** * Checks whether class is supported in this environment */ - public function supported(): bool + public static function isSupported(): bool { - return $this->wmi !== null; + return class_exists('com'); } /** - * Reads data from WMI - * - * @param string $strClass Class to read - * @param array $strValue Values to read + * Gets information about memory usage * - * @return array with results + * @return array<string, int> with memory usage data + * @psalm-return array{ + * MemTotal: int, + * MemFree: int, + * MemUsed: int, + * SwapTotal: int, + * SwapUsed: int, + * SwapPeak: int, + * SwapFree: int + * } */ - private function getWMI($strClass, array $strValue = []) + public function memory(): array { - $arrData = []; - - $objWEBM = $this->wmi->Get($strClass); - // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - $arrProp = $objWEBM->Properties_; - $arrWEBMCol = $objWEBM->Instances_(); - foreach ($arrWEBMCol as $objItem) { - $arrInstance = []; - foreach ($arrProp as $propItem) { - // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - $name = $propItem->Name; - if (! empty($strValue) && ! in_array($name, $strValue)) { - continue; - } - - $value = $objItem->$name; - if (is_string($value)) { - $arrInstance[$name] = trim($value); - } else { - $arrInstance[$name] = $value; - } - } - - $arrData[] = $arrInstance; + return array_merge($this->getSystemMemory(), $this->getPageFileUsage()); + } + + /** + * @return array<string, int> + * @psalm-return array{MemTotal: int, MemFree: int, MemUsed: int} + */ + private function getSystemMemory(): array + { + if ($this->wmiService === null) { + return ['MemTotal' => 0, 'MemFree' => 0, 'MemUsed' => 0]; + } + + /** + * @see https://docs.microsoft.com/en-us/windows/win32/wmisdk/swbemobject-instances- + * @see https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-operatingsystem + * + * @var object[] $instances + * @psalm-suppress MixedMethodCall + * @phpstan-ignore-next-line + */ + $instances = $this->wmiService->Get('Win32_OperatingSystem')->Instances_(); + $totalMemory = 0; + $freeMemory = 0; + foreach ($instances as $instance) { + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + $totalMemory += (int) $instance->TotalVisibleMemorySize; /* @phpstan-ignore-line */ + $freeMemory += (int) $instance->FreePhysicalMemory; /* @phpstan-ignore-line */ + // phpcs:enable } - return $arrData; + return ['MemTotal' => $totalMemory, 'MemFree' => $freeMemory, 'MemUsed' => $totalMemory - $freeMemory]; } /** - * Gets information about memory usage - * - * @return array with memory usage data + * @return array<string, int> + * @psalm-return array{SwapTotal: int, SwapUsed: int, SwapPeak: int, SwapFree: int} */ - public function memory() + private function getPageFileUsage(): array { - $buffer = $this->getWMI( - 'Win32_OperatingSystem', - [ - 'TotalVisibleMemorySize', - 'FreePhysicalMemory', - ] - ); - $mem = []; - $mem['MemTotal'] = $buffer[0]['TotalVisibleMemorySize']; - $mem['MemFree'] = $buffer[0]['FreePhysicalMemory']; - $mem['MemUsed'] = $mem['MemTotal'] - $mem['MemFree']; - - $buffer = $this->getWMI('Win32_PageFileUsage'); - - $mem['SwapTotal'] = 0; - $mem['SwapFree'] = 0; - $mem['SwapUsed'] = 0; - $mem['SwapPeak'] = 0; - - foreach ($buffer as $swapdevice) { - $mem['SwapTotal'] += $swapdevice['AllocatedBaseSize'] * 1024; - $mem['SwapUsed'] += $swapdevice['CurrentUsage'] * 1024; - $mem['SwapPeak'] += $swapdevice['PeakUsage'] * 1024; + if ($this->wmiService === null) { + return ['SwapTotal' => 0, 'SwapUsed' => 0, 'SwapPeak' => 0, 'SwapFree' => 0]; } - $mem['SwapFree'] = $mem['SwapTotal'] - $mem['SwapUsed']; + /** + * @see https://docs.microsoft.com/en-us/windows/win32/wmisdk/swbemobject-instances- + * @see https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-pagefileusage + * + * @var object[] $instances + * @psalm-suppress MixedMethodCall + * @phpstan-ignore-next-line + */ + $instances = $this->wmiService->Get('Win32_PageFileUsage')->Instances_(); + $total = 0; + $used = 0; + $peak = 0; + foreach ($instances as $instance) { + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + $total += intval($instance->AllocatedBaseSize) * 1024; /* @phpstan-ignore-line */ + $used += intval($instance->CurrentUsage) * 1024; /* @phpstan-ignore-line */ + $peak += intval($instance->PeakUsage) * 1024; /* @phpstan-ignore-line */ + // phpcs:enable + } - return $mem; + return ['SwapTotal' => $total, 'SwapUsed' => $used, 'SwapPeak' => $peak, 'SwapFree' => $total - $used]; + } + + private function getLoadPercentage(): int + { + if ($this->wmiService === null) { + return 0; + } + + /** + * @see https://docs.microsoft.com/en-us/windows/win32/wmisdk/swbemobject-instances- + * @see https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processor + * + * @var object[] $instances + * @psalm-suppress MixedMethodCall + * @phpstan-ignore-next-line + */ + $instances = $this->wmiService->Get('Win32_Processor')->Instances_(); + $i = 0; + $sum = 0; + foreach ($instances as $instance) { + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + $sum += (int) $instance->LoadPercentage; /* @phpstan-ignore-line */ + // Can't use count($instances). + $i++; + } + + try { + return intdiv($sum, $i); + } catch (Throwable $throwable) { + return 0; + } } } diff --git a/libraries/classes/Setup/ConfigGenerator.php b/libraries/classes/Setup/ConfigGenerator.php index af5d94a637..9d69a5bab1 100644 --- a/libraries/classes/Setup/ConfigGenerator.php +++ b/libraries/classes/Setup/ConfigGenerator.php @@ -42,24 +42,22 @@ class ConfigGenerator */ public static function getConfigFile(ConfigFile $cf) { - $crlf = isset($_SESSION['eol']) && $_SESSION['eol'] === 'win' - ? "\r\n" - : "\n"; + $eol = isset($_SESSION['eol']) && $_SESSION['eol'] === 'win' ? "\r\n" : "\n"; $conf = $cf->getConfig(); // header - $ret = '<?php' . $crlf - . '/**' . $crlf - . ' * Generated configuration file' . $crlf + $ret = '<?php' . $eol + . '/**' . $eol + . ' * Generated configuration file' . $eol . ' * Generated by: phpMyAdmin ' . Version::VERSION - . ' setup script' . $crlf - . ' * Date: ' . gmdate(DATE_RFC1123) . $crlf - . ' */' . $crlf . $crlf; + . ' setup script' . $eol + . ' * Date: ' . gmdate(DATE_RFC1123) . $eol + . ' */' . $eol . $eol; //servers if (! empty($conf['Servers'])) { - $ret .= self::getServerPart($cf, $crlf, $conf['Servers']); + $ret .= self::getServerPart($cf, $eol, $conf['Servers']); unset($conf['Servers']); } @@ -68,7 +66,7 @@ class ConfigGenerator foreach ($conf as $k => $v) { $k = preg_replace('/[^A-Za-z0-9_]/', '_', (string) $k); - $ret .= self::getVarExport($k, $v, $crlf); + $ret .= self::getVarExport($k, $v, $eol); if (! isset($persistKeys[$k])) { continue; } @@ -83,10 +81,10 @@ class ConfigGenerator } $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); - $ret .= self::getVarExport($k, $cf->getDefault($k), $crlf); + $ret .= self::getVarExport($k, $cf->getDefault($k), $eol); } - return $ret . $crlf; + return $ret . $eol; } /** @@ -94,27 +92,27 @@ class ConfigGenerator * * @param string $var_name configuration name * @param mixed $var_value configuration value(s) - * @param string $crlf line ending + * @param string $eol line ending * * @return string */ - private static function getVarExport($var_name, $var_value, $crlf) + private static function getVarExport($var_name, $var_value, string $eol) { if ($var_name === 'blowfish_secret') { $secret = self::getBlowfishSecretKey($var_value); - return sprintf('$cfg[\'blowfish_secret\'] = \sodium_hex2bin(\'%s\');%s', sodium_bin2hex($secret), $crlf); + return sprintf('$cfg[\'blowfish_secret\'] = \sodium_hex2bin(\'%s\');%s', sodium_bin2hex($secret), $eol); } if (! is_array($var_value) || empty($var_value)) { return "\$cfg['" . $var_name . "'] = " - . var_export($var_value, true) . ';' . $crlf; + . var_export($var_value, true) . ';' . $eol; } if (self::isZeroBasedArray($var_value)) { return "\$cfg['" . $var_name . "'] = " - . self::exportZeroBasedArray($var_value, $crlf) - . ';' . $crlf; + . self::exportZeroBasedArray($var_value, $eol) + . ';' . $eol; } $ret = ''; @@ -122,7 +120,7 @@ class ConfigGenerator foreach ($var_value as $k => $v) { $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k); $ret .= "\$cfg['" . $var_name . "']['" . $k . "'] = " - . var_export($v, true) . ';' . $crlf; + . var_export($v, true) . ';' . $eol; } return $ret; @@ -148,11 +146,11 @@ class ConfigGenerator * Exports continuous 0-based array * * @param array $array Array to export - * @param string $crlf Newline string + * @param string $eol Newline string * * @return string */ - private static function exportZeroBasedArray(array $array, $crlf) + private static function exportZeroBasedArray(array $array, string $eol) { $retv = []; foreach ($array as $v) { @@ -168,7 +166,7 @@ class ConfigGenerator // more than 4 values - value per line $imax = count($retv); for ($i = 0; $i < $imax; $i++) { - $ret .= ($i > 0 ? ',' : '') . $crlf . ' ' . $retv[$i]; + $ret .= ($i > 0 ? ',' : '') . $eol . ' ' . $retv[$i]; } return $ret . ']'; @@ -178,36 +176,36 @@ class ConfigGenerator * Generate server part of config file * * @param ConfigFile $cf Config file - * @param string $crlf Carriage return char + * @param string $eol Carriage return char * @param array $servers Servers list * * @return string|null */ - protected static function getServerPart(ConfigFile $cf, $crlf, array $servers) + protected static function getServerPart(ConfigFile $cf, string $eol, array $servers) { if ($cf->getServerCount() === 0) { return null; } - $ret = '/* Servers configuration */' . $crlf . '$i = 0;' . $crlf . $crlf; + $ret = '/* Servers configuration */' . $eol . '$i = 0;' . $eol . $eol; foreach ($servers as $id => $server) { $ret .= '/* Server: ' . strtr($cf->getServerName($id) . ' [' . $id . '] ', '*/', '-') - . '*/' . $crlf - . '$i++;' . $crlf; + . '*/' . $eol + . '$i++;' . $eol; foreach ($server as $k => $v) { $k = preg_replace('/[^A-Za-z0-9_]/', '_', (string) $k); $ret .= "\$cfg['Servers'][\$i]['" . $k . "'] = " . (is_array($v) && self::isZeroBasedArray($v) - ? self::exportZeroBasedArray($v, $crlf) + ? self::exportZeroBasedArray($v, $eol) : var_export($v, true)) - . ';' . $crlf; + . ';' . $eol; } - $ret .= $crlf; + $ret .= $eol; } - $ret .= '/* End of servers configuration */' . $crlf . $crlf; + $ret .= '/* End of servers configuration */' . $eol . $eol; return $ret; } diff --git a/libraries/classes/Sql.php b/libraries/classes/Sql.php index 2053d2dbcc..8beae20045 100644 --- a/libraries/classes/Sql.php +++ b/libraries/classes/Sql.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Features\BookmarkFeature; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Dbal\ResultInterface; +use PhpMyAdmin\Display\DisplayParts; use PhpMyAdmin\Display\Results as DisplayResults; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Html\MySQLDocumentation; @@ -81,24 +82,27 @@ class Sql /** * Handle remembered sorting order, only for single table query * - * @param string $db database name - * @param string $table table name - * @param array $analyzedSqlResults the analyzed query results - * @param string $fullSqlQuery SQL query + * @param string $db database name + * @param string $table table name + * @param string $fullSqlQuery SQL query */ private function handleSortOrder( $db, $table, - array &$analyzedSqlResults, + StatementInfo $statementInfo, &$fullSqlQuery - ): void { + ): StatementInfo { + if ($statementInfo->statement === null || $statementInfo->parser === null) { + return $statementInfo; + } + $tableObject = new Table($table, $db); - if (empty($analyzedSqlResults['order'])) { + if (empty($statementInfo->order)) { // Retrieving the name of the column we should sort after. $sortCol = $tableObject->getUiProp(Table::PROP_SORTED_COLUMN); if (empty($sortCol)) { - return; + return $statementInfo; } // Remove the name of the table from the retrieved field name. @@ -110,38 +114,42 @@ class Sql // Create the new query. $fullSqlQuery = Query::replaceClause( - $analyzedSqlResults['statement'], - $analyzedSqlResults['parser']->list, + $statementInfo->statement, + $statementInfo->parser->list, 'ORDER BY ' . $sortCol ); // TODO: Avoid reparsing the query. - $analyzedSqlResults = Query::getAll($fullSqlQuery); + $statementInfo = StatementInfo::fromArray(Query::getAll($fullSqlQuery)); } else { // Store the remembered table into session. $tableObject->setUiProp( Table::PROP_SORTED_COLUMN, Query::getClause( - $analyzedSqlResults['statement'], - $analyzedSqlResults['parser']->list, + $statementInfo->statement, + $statementInfo->parser->list, 'ORDER BY' ) ); } + + return $statementInfo; } /** * Append limit clause to SQL query * - * @param array $analyzedSqlResults the analyzed query results - * * @return string limit clause appended SQL query */ - private function getSqlWithLimitClause(array $analyzedSqlResults) + private function getSqlWithLimitClause(StatementInfo $statementInfo) { + if ($statementInfo->statement === null || $statementInfo->parser === null) { + return ''; + } + return Query::replaceClause( - $analyzedSqlResults['statement'], - $analyzedSqlResults['parser']->list, + $statementInfo->statement, + $statementInfo->parser->list, 'LIMIT ' . $_SESSION['tmpval']['pos'] . ', ' . $_SESSION['tmpval']['max_rows'] ); @@ -187,7 +195,7 @@ class Sql $resultSetColumnNames[] = $oneMeta->name; } - foreach (Index::getFromTable($table, $db) as $index) { + foreach (Index::getFromTable($this->dbi, $table, $db) as $index) { if (! $index->isUnique()) { continue; } @@ -340,103 +348,86 @@ class Sql } /** - * Function to check whether to remember the sorting order or not - * - * @param array $analyzedSqlResults the analyzed query and other variables set - * after analyzing the query + * Function to check whether to remember the sorting order or not. */ - private function isRememberSortingOrder(array $analyzedSqlResults): bool + private function isRememberSortingOrder(StatementInfo $statementInfo): bool { - return isset($analyzedSqlResults['select_expr'], $analyzedSqlResults['select_tables']) - && $GLOBALS['cfg']['RememberSorting'] - && ! ($analyzedSqlResults['is_count'] - || $analyzedSqlResults['is_export'] - || $analyzedSqlResults['is_func'] - || $analyzedSqlResults['is_analyse']) - && $analyzedSqlResults['select_from'] - && (empty($analyzedSqlResults['select_expr']) - || ((count($analyzedSqlResults['select_expr']) === 1) - && ($analyzedSqlResults['select_expr'][0] === '*'))) - && count($analyzedSqlResults['select_tables']) === 1; + return $GLOBALS['cfg']['RememberSorting'] + && ! ($statementInfo->isCount + || $statementInfo->isExport + || $statementInfo->isFunction + || $statementInfo->isAnalyse) + && $statementInfo->selectFrom + && (empty($statementInfo->selectExpression) + || ((count($statementInfo->selectExpression) === 1) + && ($statementInfo->selectExpression[0] === '*'))) + && count($statementInfo->selectTables) === 1; } /** - * Function to check whether the LIMIT clause should be appended or not - * - * @param array $analyzedSqlResults the analyzed query and other variables set - * after analyzing the query + * Function to check whether the LIMIT clause should be appended or not. */ - private function isAppendLimitClause(array $analyzedSqlResults): bool + private function isAppendLimitClause(StatementInfo $statementInfo): bool { // Assigning LIMIT clause to an syntactically-wrong query // is not needed. Also we would want to show the true query // and the true error message to the query executor - return (isset($analyzedSqlResults['parser']) - && count($analyzedSqlResults['parser']->errors) === 0) + return (isset($statementInfo->parser) + && count($statementInfo->parser->errors) === 0) && ($_SESSION['tmpval']['max_rows'] !== 'all') - && ! ($analyzedSqlResults['is_export'] - || $analyzedSqlResults['is_analyse']) - && ($analyzedSqlResults['select_from'] - || $analyzedSqlResults['is_subquery']) - && empty($analyzedSqlResults['limit']); + && ! ($statementInfo->isExport + || $statementInfo->isAnalyse) + && ($statementInfo->selectFrom + || $statementInfo->isSubquery) + && empty($statementInfo->limit); } /** * Function to check whether this query is for just browsing * - * @param array<string, mixed> $analyzedSqlResults the analyzed query and other variables set - * after analyzing the query - * @param bool|null $findRealEnd whether the real end should be found + * @param bool|null $findRealEnd whether the real end should be found */ - public static function isJustBrowsing(array $analyzedSqlResults, ?bool $findRealEnd): bool + public static function isJustBrowsing(StatementInfo $statementInfo, ?bool $findRealEnd): bool { - return ! $analyzedSqlResults['is_group'] - && ! $analyzedSqlResults['is_func'] - && empty($analyzedSqlResults['union']) - && empty($analyzedSqlResults['distinct']) - && $analyzedSqlResults['select_from'] - && (count($analyzedSqlResults['select_tables']) === 1) - && (empty($analyzedSqlResults['statement']->where) - || (count($analyzedSqlResults['statement']->where) === 1 - && $analyzedSqlResults['statement']->where[0]->expr === '1')) - && empty($analyzedSqlResults['group']) + return ! $statementInfo->isGroup + && ! $statementInfo->isFunction + && empty($statementInfo->union) + && empty($statementInfo->distinct) + && $statementInfo->selectFrom + && (count($statementInfo->selectTables) === 1) + && (empty($statementInfo->statement->where) + || (count($statementInfo->statement->where) === 1 + && $statementInfo->statement->where[0]->expr === '1')) + && empty($statementInfo->group) && ! isset($findRealEnd) - && ! $analyzedSqlResults['is_subquery'] - && ! $analyzedSqlResults['join'] - && empty($analyzedSqlResults['having']); + && ! $statementInfo->isSubquery + && ! $statementInfo->join + && empty($statementInfo->having); } /** - * Function to check whether the related transformation information should be deleted - * - * @param array $analyzedSqlResults the analyzed query and other variables set - * after analyzing the query + * Function to check whether the related transformation information should be deleted. */ - private function isDeleteTransformationInfo(array $analyzedSqlResults): bool + private function isDeleteTransformationInfo(StatementInfo $statementInfo): bool { - return ! empty($analyzedSqlResults['querytype']) - && (($analyzedSqlResults['querytype'] === 'ALTER') - || ($analyzedSqlResults['querytype'] === 'DROP')); + return ! empty($statementInfo->queryType) + && (($statementInfo->queryType === 'ALTER') + || ($statementInfo->queryType === 'DROP')); } /** * Function to check whether the user has rights to drop the database * - * @param array $analyzedSqlResults the analyzed query and other variables set - * after analyzing the query - * @param bool $allowUserDropDatabase whether the user is allowed to drop db - * @param bool $isSuperUser whether this user is a superuser + * @param bool $allowUserDropDatabase whether the user is allowed to drop db + * @param bool $isSuperUser whether this user is a superuser */ public function hasNoRightsToDropDatabase( - array $analyzedSqlResults, + StatementInfo $statementInfo, $allowUserDropDatabase, $isSuperUser ): bool { - return ! $allowUserDropDatabase - && isset($analyzedSqlResults['drop_database']) - && $analyzedSqlResults['drop_database'] - && ! $isSuperUser; + return ! $allowUserDropDatabase && $statementInfo->dropDatabase && ! $isSuperUser; } /** @@ -511,9 +502,9 @@ class Sql && ($GLOBALS['cfg']['TablePrimaryKeyOrder'] !== 'NONE') ) { $primaryKey = null; - $primary = Index::getPrimary($table, $db); + $primary = Index::getPrimary($this->dbi, $table, $db); - if ($primary !== false) { + if ($primary !== null) { $primarycols = $primary->getColumns(); foreach ($primarycols as $col) { @@ -674,11 +665,10 @@ class Sql * Function to count the total number of rows for the same 'SELECT' query without * the 'LIMIT' clause that may have been programmatically added * - * @param int|string $numRows number of rows affected/changed by the query - * @param bool $justBrowsing whether just browsing or not - * @param string $db the current database - * @param string $table the current table - * @param array $analyzedSqlResults the analyzed query and other variables set after analyzing the query + * @param int|string $numRows number of rows affected/changed by the query + * @param bool $justBrowsing whether just browsing or not + * @param string $db the current database + * @param string $table the current table * @psalm-param int|numeric-string $numRows * * @return int|string unlimited number of rows @@ -689,14 +679,14 @@ class Sql bool $justBrowsing, string $db, string $table, - array $analyzedSqlResults + StatementInfo $statementInfo ) { /* Shortcut for not analyzed/empty query */ - if ($analyzedSqlResults === []) { + if ($statementInfo->statement === null || $statementInfo->parser === null) { return 0; } - if (! $this->isAppendLimitClause($analyzedSqlResults)) { + if (! $this->isAppendLimitClause($statementInfo)) { // if we did not append a limit, set this to get a correct // "Showing rows..." message // $_SESSION['tmpval']['max_rows'] = 'all'; @@ -706,7 +696,7 @@ class Sql // result are less than max_rows to display, there is no need // to count total rows for that query again $unlimNumRows = $_SESSION['tmpval']['pos'] + $numRows; - } elseif ($analyzedSqlResults['querytype'] === 'SELECT' || $analyzedSqlResults['is_subquery']) { + } elseif ($statementInfo->queryType === 'SELECT' || $statementInfo->isSubquery) { // c o u n t q u e r y // If we are "just browsing", there is only one table (and no join), @@ -735,8 +725,8 @@ class Sql ->countRecords(true); } } else { - $statement = $analyzedSqlResults['statement']; - $tokenList = $analyzedSqlResults['parser']->list; + $statement = $statementInfo->statement; + $tokenList = $statementInfo->parser->list; $replaces = [ // Remove ORDER BY to decrease unnecessary sorting time [ @@ -769,7 +759,6 @@ class Sql /** * Function to handle all aspects relating to executing the query * - * @param array $analyzedSqlResults analyzed sql results * @param string $fullSqlQuery full sql query * @param bool $isGotoFile whether to go to a file * @param string $db current database @@ -787,7 +776,7 @@ class Sql * } */ private function executeTheQuery( - array $analyzedSqlResults, + StatementInfo $statementInfo, $fullSqlQuery, $isGotoFile, string $db, @@ -846,13 +835,13 @@ class Sql // Gets the number of rows affected/returned // (This must be done immediately after the query because // mysql_affected_rows() reports about the last query done) - $numRows = $this->getNumberOfRowsAffectedOrChanged($analyzedSqlResults['is_affected'], $result); + $numRows = $this->getNumberOfRowsAffectedOrChanged($statementInfo->isAffected, $result); $profilingResults = Profiling::getInformation($this->dbi); - $justBrowsing = self::isJustBrowsing($analyzedSqlResults, $findRealEnd ?? null); + $justBrowsing = self::isJustBrowsing($statementInfo, $findRealEnd ?? null); - $unlimNumRows = $this->countQueryResults($numRows, $justBrowsing, $db, $table ?? '', $analyzedSqlResults); + $unlimNumRows = $this->countQueryResults($numRows, $justBrowsing, $db, $table ?? '', $statementInfo); $this->cleanupRelations($db, $table ?? '', $_POST['dropped_column'] ?? null, ! empty($_POST['purge'])); @@ -862,7 +851,7 @@ class Sql ) { // to refresh the list of indexes (Ajax mode) - $indexes = Index::getFromTable($table, $db); + $indexes = Index::getFromTable($this->dbi, $table, $db); $indexesDuplicates = Index::findDuplicates($table, $db); $template = new Template(); @@ -886,17 +875,16 @@ class Sql /** * Delete related transformation information * - * @param string $db current database - * @param string $table current table - * @param array $analyzedSqlResults analyzed sql results + * @param string $db current database + * @param string $table current table */ - private function deleteTransformationInfo(string $db, string $table, array $analyzedSqlResults): void + private function deleteTransformationInfo(string $db, string $table, StatementInfo $statementInfo): void { - if (! isset($analyzedSqlResults['statement'])) { + if (! isset($statementInfo->statement)) { return; } - $statement = $analyzedSqlResults['statement']; + $statement = $statementInfo->statement; if ($statement instanceof AlterStatement) { if ( ! empty($statement->altered[0]) @@ -913,19 +901,18 @@ class Sql /** * Function to get the message for the no rows returned case * - * @param string|null $messageToShow message to show - * @param array $analyzedSqlResults analyzed sql results - * @param int|string $numRows number of rows + * @param string|null $messageToShow message to show + * @param int|string $numRows number of rows */ private function getMessageForNoRowsReturned( ?string $messageToShow, - array $analyzedSqlResults, + StatementInfo $statementInfo, $numRows ): Message { - if ($analyzedSqlResults['querytype'] === 'DELETE"') { + if ($statementInfo->queryType === 'DELETE"') { $message = Message::getMessageForDeletedRows($numRows); - } elseif ($analyzedSqlResults['is_insert']) { - if ($analyzedSqlResults['querytype'] === 'REPLACE') { + } elseif ($statementInfo->isInsert) { + if ($statementInfo->queryType === 'REPLACE') { // For REPLACE we get DELETED + INSERTED row count, // so we have to call it affected $message = Message::getMessageForAffectedRows($numRows); @@ -945,7 +932,7 @@ class Sql $inserted->addParam($insertId + $numRows - 1); $message->addMessage($inserted); } - } elseif ($analyzedSqlResults['is_affected']) { + } elseif ($statementInfo->isAffected) { $message = Message::getMessageForAffectedRows($numRows); // Ok, here is an explanation for the !$is_select. @@ -955,7 +942,7 @@ class Sql // fact that $message_to_show is sent for every case. // The $message_to_show containing a success message and sent with // the form should not have priority over errors - } elseif ($messageToShow && $analyzedSqlResults['querytype'] !== 'SELECT') { + } elseif ($messageToShow && $statementInfo->queryType !== 'SELECT') { $message = Message::rawSuccess(htmlspecialchars($messageToShow)); } elseif (! empty($GLOBALS['show_as_php'])) { $message = Message::success(__('Showing as PHP code')); @@ -995,7 +982,6 @@ class Sql * 6-> When searching using the SEARCH tab which returns zero results * 7-> When changing the structure of the table except change operation * - * @param array $analyzedSqlResults analyzed sql results * @param string $db current database * @param string|null $table current table * @param string|null $messageToShow message to show @@ -1011,7 +997,7 @@ class Sql * @return string html */ private function getQueryResponseForNoResultsReturned( - array $analyzedSqlResults, + StatementInfo $statementInfo, string $db, ?string $table, ?string $messageToShow, @@ -1023,14 +1009,14 @@ class Sql $sqlQuery, ?string $completeQuery ): string { - if ($this->isDeleteTransformationInfo($analyzedSqlResults)) { - $this->deleteTransformationInfo($db, $table ?? '', $analyzedSqlResults); + if ($this->isDeleteTransformationInfo($statementInfo)) { + $this->deleteTransformationInfo($db, $table ?? '', $statementInfo); } if (isset($extraData['error'])) { $message = Message::rawError($extraData['error']); } else { - $message = $this->getMessageForNoRowsReturned($messageToShow, $analyzedSqlResults, $numRows); + $message = $this->getMessageForNoRowsReturned($messageToShow, $statementInfo, $numRows); } $queryMessage = Generator::getMessage($message, $GLOBALS['sql_query'], 'success'); @@ -1055,19 +1041,19 @@ class Sql $response = ResponseRenderer::getInstance(); $response->addJSON($extraData ?? []); - if (empty($analyzedSqlResults['is_select']) || isset($extraData['error'])) { + if (empty($statementInfo->isSelect) || isset($extraData['error'])) { return $queryMessage; } - $displayParts = [ - 'edit_lnk' => null, - 'del_lnk' => null, - 'sort_lnk' => '1', - 'nav_bar' => '0', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; + $displayParts = DisplayParts::fromArray([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => true, + 'hasNavigationBar' => false, + 'hasBookmarkForm' => true, + 'hasTextButton' => true, + 'hasPrintLink' => true, + ]); $sqlQueryResultsTable = $this->getHtmlForSqlQueryResultsTable( $displayResultsObject, @@ -1077,7 +1063,7 @@ class Sql $numRows, null, $result, - $analyzedSqlResults, + $statementInfo, true ); @@ -1119,7 +1105,7 @@ class Sql 'db' => $db, 'table' => $table, 'sql_query' => $sqlQuery, - 'is_procedure' => ! empty($analyzedSqlResults['procedure']), + 'is_procedure' => ! empty($statementInfo->isProcedure), ]); } @@ -1163,34 +1149,32 @@ class Sql * Function to get html for the sql query results table * * @param DisplayResults $displayResultsObject instance of DisplayResult - * @param array $displayParts the parts to display * @param bool $editable whether the result table is * editable or not * @param int|string $unlimNumRows unlimited number of rows * @param int|string $numRows number of rows * @param array|null $showTable table definitions * @param ResultInterface|false|null $result result of the executed query - * @param array $analyzedSqlResults analyzed sql results * @param bool $isLimitedDisplay Show only limited operations or not * @psalm-param int|numeric-string $unlimNumRows * @psalm-param int|numeric-string $numRows */ private function getHtmlForSqlQueryResultsTable( $displayResultsObject, - array $displayParts, + DisplayParts $displayParts, $editable, $unlimNumRows, $numRows, ?array $showTable, $result, - array $analyzedSqlResults, + StatementInfo $statementInfo, $isLimitedDisplay = false ): string { $printView = isset($_POST['printview']) && $_POST['printview'] == '1' ? '1' : null; $tableHtml = ''; $isBrowseDistinct = ! empty($_POST['is_browse_distinct']); - if ($analyzedSqlResults['is_procedure']) { + if ($statementInfo->isProcedure) { do { if ($result === null) { $result = $this->dbi->storeResult(); @@ -1210,37 +1194,37 @@ class Sql $displayResultsObject->setProperties( $numRows, $fieldsMeta, - $analyzedSqlResults['is_count'], - $analyzedSqlResults['is_export'], - $analyzedSqlResults['is_func'], - $analyzedSqlResults['is_analyse'], + $statementInfo->isCount, + $statementInfo->isExport, + $statementInfo->isFunction, + $statementInfo->isAnalyse, $numRows, $fieldsCount, $GLOBALS['querytime'], $GLOBALS['text_dir'], - $analyzedSqlResults['is_maint'], - $analyzedSqlResults['is_explain'], - $analyzedSqlResults['is_show'], + $statementInfo->isMaint, + $statementInfo->isExplain, + $statementInfo->isShow, $showTable, $printView, $editable, $isBrowseDistinct ); - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; + $displayParts = DisplayParts::fromArray([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => true, + 'hasNavigationBar' => true, + 'hasBookmarkForm' => true, + 'hasTextButton' => true, + 'hasPrintLink' => true, + ]); $tableHtml .= $displayResultsObject->getTable( $result, $displayParts, - $analyzedSqlResults, + $statementInfo, $isLimitedDisplay ); } @@ -1258,17 +1242,17 @@ class Sql $displayResultsObject->setProperties( $unlimNumRows, $fieldsMeta, - $analyzedSqlResults['is_count'], - $analyzedSqlResults['is_export'], - $analyzedSqlResults['is_func'], - $analyzedSqlResults['is_analyse'], + $statementInfo->isCount, + $statementInfo->isExport, + $statementInfo->isFunction, + $statementInfo->isAnalyse, $numRows, $fieldsCount, $GLOBALS['querytime'], $GLOBALS['text_dir'], - $analyzedSqlResults['is_maint'], - $analyzedSqlResults['is_explain'], - $analyzedSqlResults['is_show'], + $statementInfo->isMaint, + $statementInfo->isExplain, + $statementInfo->isShow, $showTable, $printView, $editable, @@ -1279,7 +1263,7 @@ class Sql $tableHtml .= $displayResultsObject->getTable( $result, $displayParts, - $analyzedSqlResults, + $statementInfo, $isLimitedDisplay ); } @@ -1366,7 +1350,6 @@ class Sql * Function to display results when the executed query returns non empty results * * @param ResultInterface|false|null $result executed query results - * @param array $analyzedSqlResults analysed sql results * @param string $db current database * @param string|null $table current table * @param array|null $sqlData sql data @@ -1385,7 +1368,7 @@ class Sql */ private function getQueryResponseForResultsReturned( $result, - array $analyzedSqlResults, + StatementInfo $statementInfo, string $db, ?string $table, ?array $sqlData, @@ -1398,7 +1381,7 @@ class Sql $sqlQuery, ?string $completeQuery ): string { - global $showtable; + $GLOBALS['showtable'] = $GLOBALS['showtable'] ?? null; // If we are retrieving the full value of a truncated field or the original // value of a transformed field, show it here @@ -1414,8 +1397,8 @@ class Sql } // Should be initialized these parameters before parsing - if (! is_array($showtable)) { - $showtable = null; + if (! is_array($GLOBALS['showtable'])) { + $GLOBALS['showtable'] = null; } $response = ResponseRenderer::getInstance(); @@ -1432,7 +1415,7 @@ class Sql $updatableView = false; - $statement = $analyzedSqlResults['statement'] ?? null; + $statement = $statementInfo->statement; if ($statement instanceof SelectStatement) { if ($statement->expr && $statement->expr[0]->expr === '*' && $table) { $_table = new Table($table, $db); @@ -1440,9 +1423,9 @@ class Sql } if ( - $analyzedSqlResults['join'] - || $analyzedSqlResults['is_subquery'] - || count($analyzedSqlResults['select_tables']) !== 1 + $statementInfo->join + || $statementInfo->isSubquery + || count($statementInfo->selectTables) !== 1 ) { $justOneTable = false; } @@ -1458,38 +1441,38 @@ class Sql $_SESSION['tmpval']['possible_as_geometry'] = $editable; - $displayParts = [ - 'edit_lnk' => $displayResultsObject::UPDATE_ROW, - 'del_lnk' => $displayResultsObject::DELETE_ROW, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '0', - 'pview_lnk' => '1', - ]; + $displayParts = DisplayParts::fromArray([ + 'hasEditLink' => true, + 'deleteLink' => DisplayParts::DELETE_ROW, + 'hasSortLink' => true, + 'hasNavigationBar' => true, + 'hasBookmarkForm' => true, + 'hasTextButton' => false, + 'hasPrintLink' => true, + ]); if (! $editable) { - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '1', - 'nav_bar' => '1', - 'bkm_form' => '1', - 'text_btn' => '1', - 'pview_lnk' => '1', - ]; + $displayParts = DisplayParts::fromArray([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => true, + 'hasNavigationBar' => true, + 'hasBookmarkForm' => true, + 'hasTextButton' => true, + 'hasPrintLink' => true, + ]); } if (isset($_POST['printview']) && $_POST['printview'] == '1') { - $displayParts = [ - 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE, - 'sort_lnk' => '0', - 'nav_bar' => '0', - 'bkm_form' => '0', - 'text_btn' => '0', - 'pview_lnk' => '0', - ]; + $displayParts = DisplayParts::fromArray([ + 'hasEditLink' => false, + 'deleteLink' => DisplayParts::NO_DELETE, + 'hasSortLink' => false, + 'hasNavigationBar' => false, + 'hasBookmarkForm' => false, + 'hasTextButton' => false, + 'hasPrintLink' => false, + ]); } if (! isset($_POST['printview']) || $_POST['printview'] != '1') { @@ -1524,16 +1507,16 @@ class Sql $editable, $unlimNumRows, $numRows, - $showtable, + $GLOBALS['showtable'], $result, - $analyzedSqlResults + $statementInfo ); $bookmarkSupportHtml = ''; $bookmarkFeature = $this->relation->getRelationParameters()->bookmarkFeature; if ( $bookmarkFeature !== null - && $displayParts['bkm_form'] == '1' + && $displayParts->hasBookmarkForm && empty($_GET['id_bookmark']) && $sqlQuery ) { @@ -1563,7 +1546,6 @@ class Sql /** * Function to execute the query and send the response * - * @param array|null $analyzedSqlResults analysed sql results * @param bool $isGotoFile whether goto file or not * @param string $db current database * @param string|null $table current table @@ -1579,7 +1561,7 @@ class Sql * @param string|null $completeQuery complete query */ public function executeQueryAndSendQueryResponse( - $analyzedSqlResults, + ?StatementInfo $statementInfo, $isGotoFile, string $db, ?string $table, @@ -1594,19 +1576,15 @@ class Sql $sqlQuery, $completeQuery ): string { - if ($analyzedSqlResults == null) { + if ($statementInfo === null) { // Parse and analyze the query - [ - $analyzedSqlResults, - $db, - $tableFromSql, - ] = ParseAnalyze::sqlQuery($sqlQuery, $db); + [$statementInfo, $db, $tableFromSql] = ParseAnalyze::sqlQuery($sqlQuery, $db); $table = $tableFromSql ?: $table; } return $this->executeQueryAndGetQueryResponse( - $analyzedSqlResults, // analyzed_sql_results + $statementInfo, $isGotoFile, // is_gotofile $db, // db $table, // table @@ -1626,7 +1604,6 @@ class Sql /** * Function to execute the query and send the response * - * @param array $analyzedSqlResults analysed sql results * @param bool $isGotoFile whether goto file or not * @param string $db current database * @param string|null $table current table @@ -1644,7 +1621,7 @@ class Sql * @return string html */ public function executeQueryAndGetQueryResponse( - array $analyzedSqlResults, + StatementInfo $statementInfo, $isGotoFile, string $db, ?string $table, @@ -1668,13 +1645,12 @@ class Sql // Handling is also not required if we came from the "Sort by key" // drop-down. if ( - $analyzedSqlResults !== [] - && $this->isRememberSortingOrder($analyzedSqlResults) - && empty($analyzedSqlResults['union']) + $this->isRememberSortingOrder($statementInfo) + && empty($statementInfo->union) && ! isset($_POST['sort_by_key']) ) { if (! isset($_SESSION['sql_from_query_box'])) { - $this->handleSortOrder($db, $table, $analyzedSqlResults, $sqlQuery); + $statementInfo = $this->handleSortOrder($db, $table, $statementInfo, $sqlQuery); } else { unset($_SESSION['sql_from_query_box']); } @@ -1694,8 +1670,8 @@ class Sql $fullSqlQuery = $sqlQuery; // Do append a "LIMIT" clause? - if ($this->isAppendLimitClause($analyzedSqlResults)) { - $fullSqlQuery = $this->getSqlWithLimitClause($analyzedSqlResults); + if ($this->isAppendLimitClause($statementInfo)) { + $fullSqlQuery = $this->getSqlWithLimitClause($statementInfo); } $GLOBALS['reload'] = $this->hasCurrentDbChanged($db); @@ -1708,7 +1684,7 @@ class Sql $profilingResults, $extraData, ] = $this->executeTheQuery( - $analyzedSqlResults, + $statementInfo, $fullSqlQuery, $isGotoFile, $db, @@ -1725,9 +1701,9 @@ class Sql $warningMessages = $this->operations->getWarningMessagesArray(); // No rows returned -> move back to the calling page - if (($numRows == 0 && $unlimNumRows == 0) || $analyzedSqlResults['is_affected']) { + if (($numRows == 0 && $unlimNumRows == 0) || $statementInfo->isAffected) { $htmlOutput = $this->getQueryResponseForNoResultsReturned( - $analyzedSqlResults, + $statementInfo, $db, $table, $messageToShow, @@ -1743,7 +1719,7 @@ class Sql // At least one row is returned -> displays a table with results $htmlOutput = $this->getQueryResponseForResultsReturned( $result, - $analyzedSqlResults, + $statementInfo, $db, $table, $sqlData, diff --git a/libraries/classes/SqlQueryForm.php b/libraries/classes/SqlQueryForm.php index 3fbc2b064f..f3bb312ca5 100644 --- a/libraries/classes/SqlQueryForm.php +++ b/libraries/classes/SqlQueryForm.php @@ -64,8 +64,6 @@ class SqlQueryForm $display_tab = false, $delimiter = ';' ) { - global $dbi; - if (! $display_tab) { $display_tab = 'full'; } @@ -92,12 +90,17 @@ class SqlQueryForm [$legend, $query, $columns_list] = $this->init($query); } - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $bookmarkFeature = $relation->getRelationParameters()->bookmarkFeature; $bookmarks = []; if ($display_tab === 'full' && $bookmarkFeature !== null) { - $bookmark_list = Bookmark::getList($bookmarkFeature, $dbi, $GLOBALS['cfg']['Server']['user'], $db); + $bookmark_list = Bookmark::getList( + $bookmarkFeature, + $GLOBALS['dbi'], + $GLOBALS['cfg']['Server']['user'], + $db + ); foreach ($bookmark_list as $bookmarkItem) { $bookmarks[] = [ @@ -140,8 +143,6 @@ class SqlQueryForm */ public function init($query) { - global $dbi; - $columns_list = []; if (strlen($GLOBALS['db']) === 0) { // prepare for server related @@ -164,7 +165,7 @@ class SqlQueryForm $tmp_db_link .= htmlspecialchars($db) . '</a>'; $legend = sprintf(__('Run SQL query/queries on database %s'), $tmp_db_link); if (empty($query)) { - $query = Util::expandUserString($GLOBALS['cfg']['DefaultQueryDatabase'], 'backquote'); + $query = Util::expandUserString($GLOBALS['cfg']['DefaultQueryDatabase'], [Util::class, 'backquote']); } } else { $db = $GLOBALS['db']; @@ -172,14 +173,14 @@ class SqlQueryForm // Get the list and number of fields // we do a try_query here, because we could be in the query window, // trying to synchronize and the table has not yet been created - $columns_list = $dbi->getColumns($db, $GLOBALS['table'], true); + $columns_list = $GLOBALS['dbi']->getColumns($db, $GLOBALS['table'], true); $scriptName = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $tmp_tbl_link = '<a href="' . $scriptName . Url::getCommon(['db' => $db, 'table' => $table], '&') . '">'; $tmp_tbl_link .= htmlspecialchars($db) . '.' . htmlspecialchars($table) . '</a>'; $legend = sprintf(__('Run SQL query/queries on table %s'), $tmp_tbl_link); if (empty($query)) { - $query = Util::expandUserString($GLOBALS['cfg']['DefaultQueryTable'], 'backquote'); + $query = Util::expandUserString($GLOBALS['cfg']['DefaultQueryTable'], [Util::class, 'backquote']); } } diff --git a/libraries/classes/StatementInfo.php b/libraries/classes/StatementInfo.php new file mode 100644 index 0000000000..e36959d555 --- /dev/null +++ b/libraries/classes/StatementInfo.php @@ -0,0 +1,232 @@ +<?php + +declare(strict_types=1); + +namespace PhpMyAdmin; + +use PhpMyAdmin\SqlParser\Parser; +use PhpMyAdmin\SqlParser\Statement; + +/** + * @psalm-immutable + */ +class StatementInfo +{ + /** @var bool */ + public $distinct; + /** @var bool */ + public $dropDatabase; + /** @var bool */ + public $group; + /** @var bool */ + public $having; + /** @var bool */ + public $isAffected; + /** @var bool */ + public $isAnalyse; + /** @var bool */ + public $isCount; + /** @var bool */ + public $isDelete; + /** @var bool */ + public $isExplain; + /** @var bool */ + public $isExport; + /** @var bool */ + public $isFunction; + /** @var bool */ + public $isGroup; + /** @var bool */ + public $isInsert; + /** @var bool */ + public $isMaint; + /** @var bool */ + public $isProcedure; + /** @var bool */ + public $isReplace; + /** @var bool */ + public $isSelect; + /** @var bool */ + public $isShow; + /** @var bool */ + public $isSubquery; + /** @var bool */ + public $join; + /** @var bool */ + public $limit; + /** @var bool */ + public $offset; + /** @var bool */ + public $order; + /** @var string|false */ + public $queryType; + /** @var bool */ + public $reload; + /** @var bool */ + public $selectFrom; + /** @var bool */ + public $union; + /** @var Parser|null */ + public $parser; + /** @var Statement|null */ + public $statement; + /** + * @var array<int, array<int, string|null>> + * @psalm-var list<array{string|null, string|null}> + */ + public $selectTables; + /** + * @var array<int, string|null> + * @psalm-var list<string|null> + */ + public $selectExpression; + + /** + * @param string|false $queryType + * @param array<int, array<int, string|null>> $selectTables + * @param array<int, string|null> $selectExpression + * @psalm-param list<array{string|null, string|null}> $selectTables + * @psalm-param list<string|null> $selectExpression + */ + private function __construct( + bool $distinct, + bool $dropDatabase, + bool $group, + bool $having, + bool $isAffected, + bool $isAnalyse, + bool $isCount, + bool $isDelete, + bool $isExplain, + bool $isExport, + bool $isFunction, + bool $isGroup, + bool $isInsert, + bool $isMaint, + bool $isProcedure, + bool $isReplace, + bool $isSelect, + bool $isShow, + bool $isSubquery, + bool $join, + bool $limit, + bool $offset, + bool $order, + $queryType, + bool $reload, + bool $selectFrom, + bool $union, + ?SqlParser\Parser $parser, + ?SqlParser\Statement $statement, + array $selectTables, + array $selectExpression + ) { + $this->distinct = $distinct; + $this->dropDatabase = $dropDatabase; + $this->group = $group; + $this->having = $having; + $this->isAffected = $isAffected; + $this->isAnalyse = $isAnalyse; + $this->isCount = $isCount; + $this->isDelete = $isDelete; + $this->isExplain = $isExplain; + $this->isExport = $isExport; + $this->isFunction = $isFunction; + $this->isGroup = $isGroup; + $this->isInsert = $isInsert; + $this->isMaint = $isMaint; + $this->isProcedure = $isProcedure; + $this->isReplace = $isReplace; + $this->isSelect = $isSelect; + $this->isShow = $isShow; + $this->isSubquery = $isSubquery; + $this->join = $join; + $this->limit = $limit; + $this->offset = $offset; + $this->order = $order; + $this->queryType = $queryType; + $this->reload = $reload; + $this->selectFrom = $selectFrom; + $this->union = $union; + $this->parser = $parser; + $this->statement = $statement; + $this->selectTables = $selectTables; + $this->selectExpression = $selectExpression; + } + + /** + * @param array<string, array<int, array<int, string|null>|string|null>|bool|string|Parser|Statement> $info + * @psalm-param array{ + * distinct: bool, + * drop_database: bool, + * group: bool, + * having: bool, + * is_affected: bool, + * is_analyse: bool, + * is_count: bool, + * is_delete: bool, + * is_explain: bool, + * is_export: bool, + * is_func: bool, + * is_group: bool, + * is_insert: bool, + * is_maint: bool, + * is_procedure: bool, + * is_replace: bool, + * is_select: bool, + * is_show: bool, + * is_subquery: bool, + * join: bool, + * limit: bool, + * offset: bool, + * order: bool, + * querytype: ( + * 'ALTER'|'ANALYZE'|'CALL'|'CHECK'|'CHECKSUM'|'CREATE'|'DELETE'|'DROP'| + * 'EXPLAIN'|'INSERT'|'LOAD'|'OPTIMIZE'|'REPAIR'|'REPLACE'|'SELECT'|'SET'|'SHOW'|'UPDATE'|false + * ), + * reload: bool, + * select_from: bool, + * union: bool, + * parser?: Parser, + * statement?: Statement, + * select_tables?: list<array{string|null, string|null}>, + * select_expr?: list<string|null> + * } $info + */ + public static function fromArray(array $info): self + { + return new self( + $info['distinct'], + $info['drop_database'], + $info['group'], + $info['having'], + $info['is_affected'], + $info['is_analyse'], + $info['is_count'], + $info['is_delete'], + $info['is_explain'], + $info['is_export'], + $info['is_func'], + $info['is_group'], + $info['is_insert'], + $info['is_maint'], + $info['is_procedure'], + $info['is_replace'], + $info['is_select'], + $info['is_show'], + $info['is_subquery'], + $info['join'], + $info['limit'], + $info['offset'], + $info['order'], + $info['querytype'], + $info['reload'], + $info['select_from'], + $info['union'], + $info['parser'] ?? null, + $info['statement'] ?? null, + $info['select_tables'] ?? [], + $info['select_expr'] ?? [] + ); + } +} diff --git a/libraries/classes/StorageEngine.php b/libraries/classes/StorageEngine.php index 0c3d689f2b..d954c39b23 100644 --- a/libraries/classes/StorageEngine.php +++ b/libraries/classes/StorageEngine.php @@ -103,18 +103,16 @@ class StorageEngine */ public static function getStorageEngines() { - global $dbi; - static $storage_engines = null; if ($storage_engines == null) { - $storage_engines = $dbi->fetchResult('SHOW STORAGE ENGINES', 'Engine'); - if (! $dbi->isMariaDB() && $dbi->getVersion() >= 50708) { + $storage_engines = $GLOBALS['dbi']->fetchResult('SHOW STORAGE ENGINES', 'Engine'); + if (! $GLOBALS['dbi']->isMariaDB() && $GLOBALS['dbi']->getVersion() >= 50708) { $disabled = (string) SessionCache::get( 'disabled_storage_engines', /** @return mixed|false */ - static function () use ($dbi) { - return $dbi->fetchValue( + static function () { + return $GLOBALS['dbi']->fetchValue( 'SELECT @@disabled_storage_engines' ); } @@ -141,14 +139,13 @@ class StorageEngine */ public static function hasMroongaEngine(): bool { - global $dbi; $cacheKey = 'storage-engine.mroonga.has.mroonga_command'; if (Cache::has($cacheKey)) { return (bool) Cache::get($cacheKey, false); } - $supportsMroonga = $dbi->tryQuery('SELECT mroonga_command(\'object_list\');') !== false; + $supportsMroonga = $GLOBALS['dbi']->tryQuery('SELECT mroonga_command(\'object_list\');') !== false; Cache::set($cacheKey, $supportsMroonga); return $supportsMroonga; @@ -164,13 +161,15 @@ class StorageEngine */ public static function getMroongaLengths(string $dbName, string $tableName): array { - global $dbi; $cacheKey = 'storage-engine.mroonga.object_list.' . $dbName; - $dbi->selectDb($dbName);// Needed for mroonga_command calls + $GLOBALS['dbi']->selectDb($dbName);// Needed for mroonga_command calls if (! Cache::has($cacheKey)) { - $result = $dbi->fetchSingleRow('SELECT mroonga_command(\'object_list\');', DatabaseInterface::FETCH_NUM); + $result = $GLOBALS['dbi']->fetchSingleRow( + 'SELECT mroonga_command(\'object_list\');', + DatabaseInterface::FETCH_NUM + ); $objectList = (array) json_decode($result[0] ?? '', true); foreach ($objectList as $mroongaName => $mroongaData) { /** @@ -200,7 +199,7 @@ class StorageEngine continue; } - $result = $dbi->fetchSingleRow( + $result = $GLOBALS['dbi']->fetchSingleRow( 'SELECT mroonga_command(\'object_inspect ' . $mroongaName . '\');', DatabaseInterface::FETCH_NUM ); @@ -400,8 +399,6 @@ class StorageEngine */ public function getVariablesStatus() { - global $dbi; - $variables = $this->getVariables(); $like = $this->getVariablesLikePattern(); @@ -414,7 +411,7 @@ class StorageEngine $mysql_vars = []; $sql_query = 'SHOW GLOBAL VARIABLES ' . $like . ';'; - $res = $dbi->query($sql_query); + $res = $GLOBALS['dbi']->query($sql_query); foreach ($res as $row) { if (isset($variables[$row['Variable_name']])) { $mysql_vars[$row['Variable_name']] = $variables[$row['Variable_name']]; diff --git a/libraries/classes/Table.php b/libraries/classes/Table.php index 380e3966da..2dd86fe6ea 100644 --- a/libraries/classes/Table.php +++ b/libraries/classes/Table.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Features\DisplayFeature; use PhpMyAdmin\ConfigStorage\Features\RelationFeature; use PhpMyAdmin\ConfigStorage\Features\UiPreferencesFeature; use PhpMyAdmin\ConfigStorage\Relation; +use PhpMyAdmin\Database\Triggers; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Plugins\Export\ExportSql; @@ -519,8 +520,6 @@ class Table implements Stringable $columnsWithIndex = null, $oldColumnName = null ) { - global $dbi; - $strLength = strlen($length); $isTimestamp = mb_stripos($type, 'TIMESTAMP') !== false; @@ -536,7 +535,7 @@ class Table implements Stringable if ( $strLength !== 0 && ! preg_match($pattern, $type) - && Compatibility::isIntegersSupportLength($type, $length, $dbi) + && Compatibility::isIntegersSupportLength($type, $length, $GLOBALS['dbi']) ) { // Note: The variable $length here can contain several other things // besides length - ENUM/SET value or length of DECIMAL (eg. 12,3) @@ -607,13 +606,13 @@ class Table implements Stringable } else { // Invalid BOOLEAN value $query .= ' DEFAULT \'' - . $dbi->escapeString($defaultValue) . '\''; + . $GLOBALS['dbi']->escapeString($defaultValue) . '\''; } } elseif ($type === 'BINARY' || $type === 'VARBINARY') { $query .= ' DEFAULT 0x' . $defaultValue; } else { $query .= ' DEFAULT \'' - . $dbi->escapeString((string) $defaultValue) . '\''; + . $GLOBALS['dbi']->escapeString((string) $defaultValue) . '\''; } break; @@ -654,7 +653,7 @@ class Table implements Stringable } if (! empty($comment)) { - $query .= " COMMENT '" . $dbi->escapeString($comment) . "'"; + $query .= " COMMENT '" . $GLOBALS['dbi']->escapeString($comment) . "'"; } // move column @@ -893,9 +892,7 @@ class Table implements Stringable array $whereFields, array $newFields ) { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $relationParameters = $relation->getRelationParameters(); $relationParams = $relationParameters->toArray(); $lastId = -1; @@ -914,14 +911,14 @@ class Table implements Stringable $whereParts = []; foreach ($whereFields as $where => $value) { $whereParts[] = Util::backquote($where) . ' = \'' - . $dbi->escapeString((string) $value) . '\''; + . $GLOBALS['dbi']->escapeString((string) $value) . '\''; } $newParts = []; $newValueParts = []; foreach ($newFields as $where => $value) { $newParts[] = Util::backquote($where); - $newValueParts[] = $dbi->escapeString((string) $value); + $newValueParts[] = $GLOBALS['dbi']->escapeString((string) $value); } $tableCopyQuery = ' @@ -932,7 +929,7 @@ class Table implements Stringable // must use DatabaseInterface::QUERY_BUFFERED here, since we execute // another query inside the loop - $tableCopyRs = $dbi->queryAsControlUser($tableCopyQuery); + $tableCopyRs = $GLOBALS['dbi']->queryAsControlUser($tableCopyQuery); foreach ($tableCopyRs as $tableCopyRow) { $valueParts = []; @@ -941,7 +938,7 @@ class Table implements Stringable continue; } - $valueParts[] = $dbi->escapeString($val); + $valueParts[] = $GLOBALS['dbi']->escapeString($val); } $newTableQuery = 'INSERT IGNORE INTO ' @@ -952,8 +949,8 @@ class Table implements Stringable . implode('\', \'', $valueParts) . '\', \'' . implode('\', \'', $newValueParts) . '\')'; - $dbi->queryAsControlUser($newTableQuery); - $lastId = $dbi->insertId(); + $GLOBALS['dbi']->queryAsControlUser($newTableQuery); + $lastId = $GLOBALS['dbi']->insertId(); } return $lastId; @@ -980,9 +977,8 @@ class Table implements Stringable $mode, bool $addDropIfExists ): bool { - global $errorUrl, $dbi; - - $relation = new Relation($dbi); + $GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null; + $relation = new Relation($GLOBALS['dbi']); // Try moving the tables directly, using native `RENAME` statement. if ($move && $what === 'data') { @@ -1037,7 +1033,7 @@ class Table implements Stringable // Selecting the database could avoid some problems with replicated // databases, when moving table from replicated one to not replicated one. - $dbi->selectDb($targetDb); + $GLOBALS['dbi']->selectDb($targetDb); /** * The full name of target table, quoted. @@ -1069,7 +1065,14 @@ class Table implements Stringable /** * The old structure of the table.. */ - $sqlStructure = $exportSqlPlugin->getTableDef($sourceDb, $sourceTable, "\n", $errorUrl, false, false); + $sqlStructure = $exportSqlPlugin->getTableDef( + $sourceDb, + $sourceTable, + "\n", + $GLOBALS['errorUrl'], + false, + false + ); unset($noConstraintsComments); @@ -1084,7 +1087,7 @@ class Table implements Stringable // Find server's SQL mode so the builder can generate correct // queries. // One of the options that alters the behaviour is `ANSI_QUOTES`. - Context::setMode((string) $dbi->fetchValue('SELECT @@sql_mode')); + Context::setMode((string) $GLOBALS['dbi']->fetchValue('SELECT @@sql_mode')); // ----------------------------------------------------------------- // Phase 1: Dropping existent element of the same name (if exists @@ -1111,7 +1114,7 @@ class Table implements Stringable $dropQuery = $statement->build() . ';'; // Executing it. - $dbi->query($dropQuery); + $GLOBALS['dbi']->query($dropQuery); $GLOBALS['sql_query'] .= "\n" . $dropQuery; // If an existing table gets deleted, maintain any entries for @@ -1145,11 +1148,11 @@ class Table implements Stringable // This is to avoid some issues when renaming databases with views // See: https://github.com/phpmyadmin/phpmyadmin/issues/16422 if ($move) { - $dbi->selectDb($targetDb); + $GLOBALS['dbi']->selectDb($targetDb); } // Executing it - $dbi->query($sqlStructure); + $GLOBALS['dbi']->query($sqlStructure); $GLOBALS['sql_query'] .= "\n" . $sqlStructure; } @@ -1185,7 +1188,7 @@ class Table implements Stringable // Executing it. if ($mode === 'one_table') { - $dbi->query($GLOBALS['sql_constraints_query']); + $GLOBALS['dbi']->query($GLOBALS['sql_constraints_query']); } $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_constraints_query']; @@ -1226,7 +1229,7 @@ class Table implements Stringable // Executing it. if ($mode === 'one_table' || $mode === 'db_copy') { - $dbi->query($sqlIndex); + $GLOBALS['dbi']->query($sqlIndex); } $GLOBALS['sql_indexes'] .= $sqlIndex; @@ -1256,7 +1259,7 @@ class Table implements Stringable $GLOBALS['sql_auto_increments'] = $statement->build() . ';'; // Executing it. - $dbi->query($GLOBALS['sql_auto_increments']); + $GLOBALS['dbi']->query($GLOBALS['sql_auto_increments']); $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_auto_increments']; } @@ -1270,7 +1273,7 @@ class Table implements Stringable // Copy the data unless this is a VIEW if (($what === 'data' || $what === 'dataonly') && ! $table->isView()) { $sqlSetMode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"; - $dbi->query($sqlSetMode); + $GLOBALS['dbi']->query($sqlSetMode); $GLOBALS['sql_query'] .= "\n\n" . $sqlSetMode . ';'; $oldTable = new Table($sourceTable, $sourceDb); @@ -1281,7 +1284,7 @@ class Table implements Stringable . ') SELECT ' . implode(', ', $nonGeneratedCols) . ' FROM ' . $source; - $dbi->query($sqlInsertData); + $GLOBALS['dbi']->query($sqlInsertData); $GLOBALS['sql_query'] .= "\n\n" . $sqlInsertData . ';'; } } @@ -1292,7 +1295,7 @@ class Table implements Stringable if ($move) { // This could avoid some problems with replicated databases, when // moving table from replicated one to not replicated one - $dbi->selectDb($sourceDb); + $GLOBALS['dbi']->selectDb($sourceDb); $sourceTableObj = new Table($sourceTable, $sourceDb); if ($sourceTableObj->isView()) { @@ -1302,7 +1305,7 @@ class Table implements Stringable } $sqlDropQuery .= ' ' . $source; - $dbi->query($sqlDropQuery); + $GLOBALS['dbi']->query($sqlDropQuery); // Rename table in configuration storage $relation->renameTable($sourceDb, $targetDb, $sourceTable, $targetTable); @@ -1320,7 +1323,7 @@ class Table implements Stringable if ($relationParameters->columnCommentsFeature !== null) { // Get all comments and MIME-Types for current table - $commentsCopyRs = $dbi->queryAsControlUser( + $commentsCopyRs = $GLOBALS['dbi']->queryAsControlUser( 'SELECT column_name, comment' . ($relationParameters->browserTransformationFeature !== null ? ', mimetype, transformation, transformation_options' @@ -1331,10 +1334,10 @@ class Table implements Stringable . Util::backquote($relationParameters->columnCommentsFeature->columnInfo) . ' WHERE ' . ' db_name = \'' - . $dbi->escapeString($sourceDb) . '\'' + . $GLOBALS['dbi']->escapeString($sourceDb) . '\'' . ' AND ' . ' table_name = \'' - . $dbi->escapeString((string) $sourceTable) . '\'' + . $GLOBALS['dbi']->escapeString((string) $sourceTable) . '\'' ); // Write every comment as new copied entry. [MIME] @@ -1346,20 +1349,20 @@ class Table implements Stringable . ($relationParameters->browserTransformationFeature !== null ? ', mimetype, transformation, transformation_options' : '') - . ') VALUES(\'' . $dbi->escapeString($targetDb) - . '\',\'' . $dbi->escapeString($targetTable) . '\',\'' - . $dbi->escapeString($commentsCopyRow['column_name']) + . ') VALUES(\'' . $GLOBALS['dbi']->escapeString($targetDb) + . '\',\'' . $GLOBALS['dbi']->escapeString($targetTable) . '\',\'' + . $GLOBALS['dbi']->escapeString($commentsCopyRow['column_name']) . '\',\'' - . $dbi->escapeString($commentsCopyRow['comment']) + . $GLOBALS['dbi']->escapeString($commentsCopyRow['comment']) . '\'' . ($relationParameters->browserTransformationFeature !== null - ? ',\'' . $dbi->escapeString($commentsCopyRow['mimetype']) - . '\',\'' . $dbi->escapeString($commentsCopyRow['transformation']) - . '\',\'' . $dbi->escapeString($commentsCopyRow['transformation_options']) + ? ',\'' . $GLOBALS['dbi']->escapeString($commentsCopyRow['mimetype']) + . '\',\'' . $GLOBALS['dbi']->escapeString($commentsCopyRow['transformation']) + . '\',\'' . $GLOBALS['dbi']->escapeString($commentsCopyRow['transformation_options']) . '\'' : '') . ')'; - $dbi->queryAsControlUser($newCommentQuery); + $GLOBALS['dbi']->queryAsControlUser($newCommentQuery); } unset($commentsCopyRs); @@ -1495,11 +1498,7 @@ class Table implements Stringable } // If the table is moved to a different database drop its triggers first - $triggers = $this->dbi->getTriggers( - $this->getDbName(), - $this->getName(), - '' - ); + $triggers = Triggers::getDetails($this->dbi, $this->getDbName(), $this->getName(), ''); $handleTriggers = $this->getDbName() != $newDb && $triggers; if ($handleTriggers) { foreach ($triggers as $trigger) { @@ -2058,7 +2057,7 @@ class Table implements Stringable */ public function getIndex($index) { - return Index::singleton($this->dbName, $this->name, $index); + return Index::singleton($this->dbi, $this->dbName, $this->name, $index); } /** diff --git a/libraries/classes/Table/ColumnsDefinition.php b/libraries/classes/Table/ColumnsDefinition.php index 37b1dba35f..d8281639cf 100644 --- a/libraries/classes/Table/ColumnsDefinition.php +++ b/libraries/classes/Table/ColumnsDefinition.php @@ -13,7 +13,6 @@ use PhpMyAdmin\Query\Compatibility; use PhpMyAdmin\StorageEngine; use PhpMyAdmin\Table; use PhpMyAdmin\Transformations; -use PhpMyAdmin\Url; use PhpMyAdmin\Util; use function array_keys; @@ -37,58 +36,57 @@ use function trim; */ final class ColumnsDefinition { + /** @var DatabaseInterface */ + private $dbi; + + /** @var Relation */ + private $relation; + + /** @var Transformations */ + private $transformations; + + public function __construct(DatabaseInterface $dbi, Relation $relation, Transformations $transformations) + { + $this->dbi = $dbi; + $this->relation = $relation; + $this->transformations = $transformations; + } + /** - * @param Transformations $transformations Transformations - * @param Relation $relation Relation - * @param DatabaseInterface $dbi Database Interface instance - * @param string $action Action - * @param int $num_fields The number of fields - * @param string|null $regenerate Use regeneration - * @param array|null $selected Selected - * @param array|null $fields_meta Fields meta + * @param int $num_fields The number of fields + * @param string|null $regenerate Use regeneration + * @param array|null $selected Selected + * @param array|null $fields_meta Fields meta + * @psalm-param '/table/create'|'/table/add-field'|'/table/structure/save' $action * * @return array<string, mixed> */ - public static function displayForm( - Transformations $transformations, - Relation $relation, - DatabaseInterface $dbi, + public function displayForm( string $action, $num_fields = 0, $regenerate = null, ?array $selected = null, $fields_meta = null ): array { - global $db, $table, $cfg, $col_priv, $is_reload_priv, $mime_map; - - Util::checkParameters([ - 'server', - 'db', - 'table', - 'action', - 'num_fields', - ]); + $GLOBALS['col_priv'] = $GLOBALS['col_priv'] ?? null; + $GLOBALS['is_reload_priv'] = $GLOBALS['is_reload_priv'] ?? null; + $GLOBALS['mime_map'] = $GLOBALS['mime_map'] ?? null; $length_values_input_size = 8; $content_cells = []; - $form_params = ['db' => $db]; + $form_params = ['db' => $GLOBALS['db']]; - if ($action == Url::getFromRoute('/table/create')) { + if ($action === '/table/create') { $form_params['reload'] = 1; } else { - if ($action == Url::getFromRoute('/table/add-field')) { - $form_params = array_merge( - $form_params, - [ - 'field_where' => Util::getValueByKey($_POST, 'field_where'), - ] - ); + if ($action === '/table/add-field') { + $form_params = array_merge($form_params, ['field_where' => $_POST['field_where'] ?? null]); if (isset($_POST['field_where'])) { $form_params['after_field'] = $_POST['after_field']; } } - $form_params['table'] = $table; + $form_params['table'] = $GLOBALS['table']; } $form_params['orig_num_fields'] = $num_fields; @@ -96,8 +94,8 @@ final class ColumnsDefinition $form_params = array_merge( $form_params, [ - 'orig_field_where' => Util::getValueByKey($_POST, 'field_where'), - 'orig_after_field' => Util::getValueByKey($_POST, 'after_field'), + 'orig_field_where' => $_POST['field_where'] ?? null, + 'orig_after_field' => $_POST['after_field'] ?? null, ] ); @@ -107,22 +105,21 @@ final class ColumnsDefinition } } - $is_backup = ($action != Url::getFromRoute('/table/create') - && $action != Url::getFromRoute('/table/add-field')); + $is_backup = $action !== '/table/create' && $action !== '/table/add-field'; - $relationParameters = $relation->getRelationParameters(); + $relationParameters = $this->relation->getRelationParameters(); - $comments_map = $relation->getComments($db, $table); + $comments_map = $this->relation->getComments($GLOBALS['db'], $GLOBALS['table']); $move_columns = []; if (isset($fields_meta)) { - $move_columns = $dbi->getTable($db, $table)->getColumnsMeta(); + $move_columns = $this->dbi->getTable($GLOBALS['db'], $GLOBALS['table'])->getColumnsMeta(); } $available_mime = []; - if ($relationParameters->browserTransformationFeature !== null && $cfg['BrowseMIME']) { - $mime_map = $transformations->getMime($db, $table); - $available_mime = $transformations->getAvailableMimeTypes(); + if ($relationParameters->browserTransformationFeature !== null && $GLOBALS['cfg']['BrowseMIME']) { + $GLOBALS['mime_map'] = $this->transformations->getMime($GLOBALS['db'], $GLOBALS['table']); + $available_mime = $this->transformations->getAvailableMimeTypes(); } $mime_types = [ @@ -147,12 +144,12 @@ final class ColumnsDefinition $regenerate = 1; } - $foreigners = $relation->getForeigners($db, $table, '', 'foreign'); + $foreigners = $this->relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign'); $child_references = null; // From MySQL 5.6.6 onwards columns with foreign keys can be renamed. // Hence, no need to get child references - if ($dbi->getVersion() < 50606) { - $child_references = $relation->getChildReferences($db, $table); + if ($this->dbi->getVersion() < 50606) { + $child_references = $this->relation->getChildReferences($GLOBALS['db'], $GLOBALS['table']); } for ($columnNumber = 0; $columnNumber < $num_fields; $columnNumber++) { @@ -254,8 +251,8 @@ final class ColumnsDefinition $submit_attribute = Util::getValueByKey($_POST, 'field_attribute.' . $columnNumber, false); $comments_map[$columnMeta['Field']] = Util::getValueByKey($_POST, 'field_comments.' . $columnNumber); - $mime_map[$columnMeta['Field']] = array_merge( - $mime_map[$columnMeta['Field']] ?? [], + $GLOBALS['mime_map'][$columnMeta['Field']] = array_merge( + $GLOBALS['mime_map'][$columnMeta['Field']] ?? [], [ 'mimetype' => Util::getValueByKey($_POST, 'field_mimetype.' . $columnNumber), 'transformation' => Util::getValueByKey( @@ -277,7 +274,7 @@ final class ColumnsDefinition 'STORED GENERATED', ]; if (in_array($columnMeta['Extra'], $virtual)) { - $tableObj = new Table($table, $db); + $tableObj = new Table($GLOBALS['table'], $GLOBALS['db']); $expressions = $tableObj->getColumnGenerationExpression($columnMeta['Field']); $columnMeta['Expression'] = is_array($expressions) ? $expressions[$columnMeta['Field']] : null; } @@ -333,8 +330,8 @@ final class ColumnsDefinition // Variable tell if current column is bound in a foreign key constraint or not. // MySQL version from 5.6.6 allow renaming columns with foreign keys - if (isset($columnMeta['Field'], $form_params['table']) && $dbi->getVersion() < 50606) { - $columnMeta['column_status'] = $relation->checkChildForeignReferences( + if (isset($columnMeta['Field'], $form_params['table']) && $this->dbi->getVersion() < 50606) { + $columnMeta['column_status'] = $this->relation->checkChildForeignReferences( $form_params['db'], $form_params['table'], $columnMeta['Field'], @@ -383,49 +380,15 @@ final class ColumnsDefinition $form_params = array_merge( $form_params, [ - 'field_default_value_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Default', - '' - ), - 'field_default_type_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'DefaultType', - '' - ), - 'field_collation_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Collation', - '' - ), - 'field_attribute_orig[' . $columnNumber . ']' => trim( - Util::getValueByKey($extracted_columnspec, 'attribute', '') - ), - 'field_null_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Null', - '' - ), - 'field_extra_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Extra', - '' - ), - 'field_comments_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Comment', - '' - ), - 'field_virtuality_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Virtuality', - '' - ), - 'field_expression_orig[' . $columnNumber . ']' => Util::getValueByKey( - $columnMeta, - 'Expression', - '' - ), + 'field_default_value_orig[' . $columnNumber . ']' => $columnMeta['Default'] ?? '', + 'field_default_type_orig[' . $columnNumber . ']' => $columnMeta['DefaultType'] ?? '', + 'field_collation_orig[' . $columnNumber . ']' => $columnMeta['Collation'] ?? '', + 'field_attribute_orig[' . $columnNumber . ']' => trim($extracted_columnspec['attribute'] ?? ''), + 'field_null_orig[' . $columnNumber . ']' => $columnMeta['Null'] ?? '', + 'field_extra_orig[' . $columnNumber . ']' => $columnMeta['Extra'] ?? '', + 'field_comments_orig[' . $columnNumber . ']' => $columnMeta['Comment'] ?? '', + 'field_virtuality_orig[' . $columnNumber . ']' => $columnMeta['Virtuality'] ?? '', + 'field_expression_orig[' . $columnNumber . ']' => $columnMeta['Expression'] ?? '', ] ); } @@ -458,14 +421,14 @@ final class ColumnsDefinition 'is_backup' => $is_backup, 'move_columns' => $move_columns, 'available_mime' => $available_mime, - 'mime_map' => $mime_map ?? [], + 'mime_map' => $GLOBALS['mime_map'] ?? [], ]; } $partitionDetails = TablePartitionDefinition::getDetails(); - $charsets = Charsets::getCharsets($dbi, $cfg['Server']['DisableIS']); - $collations = Charsets::getCollations($dbi, $cfg['Server']['DisableIS']); + $charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); + $collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']); $charsetsList = []; foreach ($charsets as $charset) { $collationsList = []; @@ -484,7 +447,7 @@ final class ColumnsDefinition } $storageEngines = StorageEngine::getArray(); - $isIntegersLengthRestricted = Compatibility::isIntegersLengthRestricted($dbi); + $isIntegersLengthRestricted = Compatibility::isIntegersLengthRestricted($this->dbi); return [ 'is_backup' => $is_backup, @@ -507,19 +470,20 @@ final class ColumnsDefinition 'storage_engines' => $storageEngines, 'connection' => $_POST['connection'] ?? null, 'change_column' => $_POST['change_column'] ?? $_GET['change_column'] ?? null, - 'is_virtual_columns_supported' => Compatibility::isVirtualColumnsSupported($dbi->getVersion()), + 'is_virtual_columns_supported' => Compatibility::isVirtualColumnsSupported($this->dbi->getVersion()), 'is_integers_length_restricted' => $isIntegersLengthRestricted, - 'browse_mime' => $cfg['BrowseMIME'] ?? null, - 'supports_stored_keyword' => Compatibility::supportsStoredKeywordForVirtualColumns($dbi->getVersion()), - 'server_version' => $dbi->getVersion(), - 'max_rows' => intval($cfg['MaxRows']), - 'char_editing' => $cfg['CharEditing'] ?? null, - 'attribute_types' => $dbi->types->getAttributes(), - 'privs_available' => ($col_priv ?? false) && ($is_reload_priv ?? false), - 'max_length' => $dbi->getVersion() >= 50503 ? 1024 : 255, + 'browse_mime' => $GLOBALS['cfg']['BrowseMIME'] ?? null, + 'supports_stored_keyword' => Compatibility::supportsStoredKeywordForVirtualColumns( + $this->dbi->getVersion() + ), + 'server_version' => $this->dbi->getVersion(), + 'max_rows' => intval($GLOBALS['cfg']['MaxRows']), + 'char_editing' => $GLOBALS['cfg']['CharEditing'] ?? null, + 'attribute_types' => $this->dbi->types->getAttributes(), + 'privs_available' => ($GLOBALS['col_priv'] ?? false) && ($GLOBALS['is_reload_priv'] ?? false), + 'max_length' => $this->dbi->getVersion() >= 50503 ? 1024 : 255, 'have_partitioning' => Partition::havePartitioning(), - 'dbi' => $dbi, - 'disable_is' => $cfg['Server']['DisableIS'], + 'disable_is' => $GLOBALS['cfg']['Server']['DisableIS'], ]; } } diff --git a/libraries/classes/Table/Indexes.php b/libraries/classes/Table/Indexes.php index 96f0857ee8..12c64cb153 100644 --- a/libraries/classes/Table/Indexes.php +++ b/libraries/classes/Table/Indexes.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Table; +use PhpMyAdmin\Common; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Html\Generator; @@ -44,7 +45,7 @@ final class Indexes */ public function doSaveData(Index $index, bool $renameMode, string $db, string $table): void { - global $containerBuilder; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; $error = false; if ($renameMode && Compatibility::isCompatibleRenameIndex($this->dbi->getVersion())) { @@ -90,7 +91,7 @@ final class Indexes Generator::getMessage($message, $sql_query, 'success') ); - $indexes = Index::getFromTable($table, $db); + $indexes = Index::getFromTable($this->dbi, $table, $db); $indexesDuplicates = Index::findDuplicates($table, $db); $this->response->addJSON( @@ -106,8 +107,8 @@ final class Indexes ); } else { /** @var StructureController $controller */ - $controller = $containerBuilder->get(StructureController::class); - $controller(); + $controller = $GLOBALS['containerBuilder']->get(StructureController::class); + $controller(Common::getRequest()); } } else { $this->response->setRequestStatus(false); diff --git a/libraries/classes/Template.php b/libraries/classes/Template.php index b638cdd0cd..eb04e5ba57 100644 --- a/libraries/classes/Template.php +++ b/libraries/classes/Template.php @@ -10,7 +10,6 @@ use PhpMyAdmin\Twig\Extensions\Node\TransNode; use PhpMyAdmin\Twig\FlashMessagesExtension; use PhpMyAdmin\Twig\I18nExtension; use PhpMyAdmin\Twig\MessageExtension; -use PhpMyAdmin\Twig\RelationExtension; use PhpMyAdmin\Twig\SanitizeExtension; use PhpMyAdmin\Twig\TableExtension; use PhpMyAdmin\Twig\TrackerExtension; @@ -64,7 +63,7 @@ class Template public static function getTwigEnvironment(?string $cacheDir): Environment { - global $cfg, $containerBuilder; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; /* Twig expects false when cache is not configured */ if ($cacheDir === null) { @@ -77,9 +76,9 @@ class Template 'cache' => $cacheDir, ]); - $twig->addRuntimeLoader(new ContainerRuntimeLoader($containerBuilder)); + $twig->addRuntimeLoader(new ContainerRuntimeLoader($GLOBALS['containerBuilder'])); - if (is_array($cfg) && ($cfg['environment'] ?? '') === 'development') { + if (is_array($GLOBALS['cfg']) && ($GLOBALS['cfg']['environment'] ?? '') === 'development') { $twig->enableDebug(); $twig->addExtension(new DebugExtension()); // This will enable debug for the extension to print lines @@ -87,7 +86,7 @@ class Template TransNode::$enableAddDebugInfo = true; } - if ($cfg['environment'] === 'production') { + if ($GLOBALS['cfg']['environment'] === 'production') { $twig->disableDebug(); TransNode::$enableAddDebugInfo = false; } @@ -97,7 +96,6 @@ class Template $twig->addExtension(new FlashMessagesExtension()); $twig->addExtension(new I18nExtension()); $twig->addExtension(new MessageExtension()); - $twig->addExtension(new RelationExtension()); $twig->addExtension(new SanitizeExtension()); $twig->addExtension(new TableExtension()); $twig->addExtension(new TrackerExtension()); diff --git a/libraries/classes/ThemeManager.php b/libraries/classes/ThemeManager.php index 9c10859f21..4648e6c512 100644 --- a/libraries/classes/ThemeManager.php +++ b/libraries/classes/ThemeManager.php @@ -179,11 +179,11 @@ class ThemeManager */ public function getThemeCookie() { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; $name = $this->getThemeCookieName(); - if ($config->issetCookie($name)) { - return $config->getCookie($name); + if ($GLOBALS['config']->issetCookie($name)) { + return $GLOBALS['config']->getCookie($name); } return false; diff --git a/libraries/classes/Tracker.php b/libraries/classes/Tracker.php index fb97c6de32..c824c5f211 100644 --- a/libraries/classes/Tracker.php +++ b/libraries/classes/Tracker.php @@ -69,8 +69,6 @@ class Tracker */ public static function isActive(): bool { - global $dbi; - $trackingEnabled = Cache::get(self::TRACKER_ENABLED_CACHE_KEY, false); if (! $trackingEnabled) { return false; @@ -80,7 +78,7 @@ class Tracker * We need to avoid attempt to track any queries from {@link Relation::getRelationParameters()} */ Cache::set(self::TRACKER_ENABLED_CACHE_KEY, false); - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $relationParameters = $relation->getRelationParameters(); /* Restore original state */ Cache::set(self::TRACKER_ENABLED_CACHE_KEY, true); @@ -125,8 +123,6 @@ class Tracker */ public static function isTracked($dbName, $tableName): bool { - global $dbi; - $trackingEnabled = Cache::get(self::TRACKER_ENABLED_CACHE_KEY, false); if (! $trackingEnabled) { return false; @@ -140,7 +136,7 @@ class Tracker * We need to avoid attempt to track any queries from {@link Relation::getRelationParameters()} */ Cache::set(self::TRACKER_ENABLED_CACHE_KEY, false); - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $trackingFeature = $relation->getRelationParameters()->trackingFeature; /* Restore original state */ Cache::set(self::TRACKER_ENABLED_CACHE_KEY, true); @@ -153,11 +149,11 @@ class Tracker . ' ORDER BY version DESC LIMIT 1', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbName), - $dbi->escapeString($tableName) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString($tableName) ); - $result = $dbi->fetchValue($sqlQuery, 0, DatabaseInterface::CONNECT_CONTROL) == 1; + $result = $GLOBALS['dbi']->fetchValue($sqlQuery, 0, DatabaseInterface::CONNECT_CONTROL) == 1; self::$trackingCache[$dbName][$tableName] = $result; @@ -196,29 +192,29 @@ class Tracker $trackingSet = '', bool $isView = false ): bool { - global $sql_backquotes, $export_type, $dbi; - - $relation = new Relation($dbi); + $GLOBALS['sql_backquotes'] = $GLOBALS['sql_backquotes'] ?? null; + $GLOBALS['export_type'] = $GLOBALS['export_type'] ?? null; + $relation = new Relation($GLOBALS['dbi']); if ($trackingSet == '') { $trackingSet = $GLOBALS['cfg']['Server']['tracking_default_statements']; } $exportSqlPlugin = Plugins::getPlugin('export', 'sql', [ - 'export_type' => (string) $export_type, + 'export_type' => (string) $GLOBALS['export_type'], 'single_table' => false, ]); if (! $exportSqlPlugin instanceof ExportSql) { return false; } - $sql_backquotes = true; + $GLOBALS['sql_backquotes'] = true; $date = Util::date('Y-m-d H:i:s'); // Get data definition snapshot of table - $columns = $dbi->getColumns($dbName, $tableName, true); + $columns = $GLOBALS['dbi']->getColumns($dbName, $tableName, true); // int indices to reduce size $columns = array_values($columns); // remove Privileges to reduce size @@ -226,7 +222,7 @@ class Tracker unset($columns[$i]['Privileges']); } - $indexes = $dbi->getTableIndexes($dbName, $tableName); + $indexes = $GLOBALS['dbi']->getTableIndexes($dbName, $tableName); $snapshot = [ 'COLUMNS' => $columns, @@ -235,7 +231,7 @@ class Tracker $snapshot = serialize($snapshot); // Get DROP TABLE / DROP VIEW and CREATE TABLE SQL statements - $sql_backquotes = true; + $GLOBALS['sql_backquotes'] = true; $createSql = ''; @@ -250,7 +246,7 @@ class Tracker } $createSql .= self::getLogComment() . - $exportSqlPlugin->getTableDef($dbName, $tableName, "\n", ''); + $exportSqlPlugin->getTableDef($dbName, $tableName, ''); // Save version $trackingFeature = $relation->getRelationParameters()->trackingFeature; @@ -264,18 +260,18 @@ class Tracker . ' values (\'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\')', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbName), - $dbi->escapeString($tableName), - $dbi->escapeString($version), - $dbi->escapeString($date), - $dbi->escapeString($date), - $dbi->escapeString($snapshot), - $dbi->escapeString($createSql), - $dbi->escapeString("\n"), - $dbi->escapeString($trackingSet) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString($tableName), + $GLOBALS['dbi']->escapeString($version), + $GLOBALS['dbi']->escapeString($date), + $GLOBALS['dbi']->escapeString($date), + $GLOBALS['dbi']->escapeString($snapshot), + $GLOBALS['dbi']->escapeString($createSql), + $GLOBALS['dbi']->escapeString("\n"), + $GLOBALS['dbi']->escapeString($trackingSet) ); - $dbi->queryAsControlUser($sqlQuery); + $GLOBALS['dbi']->queryAsControlUser($sqlQuery); // Deactivate previous version return self::deactivateTracking($dbName, $tableName, (int) $version - 1); @@ -290,9 +286,7 @@ class Tracker */ public static function deleteTracking($dbName, $tableName, $version = ''): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $trackingFeature = $relation->getRelationParameters()->trackingFeature; if ($trackingFeature === null) { return false; @@ -302,14 +296,14 @@ class Tracker '/*NOTRACK*/' . "\n" . 'DELETE FROM %s.%s WHERE `db_name` = \'%s\' AND `table_name` = \'%s\'', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbName), - $dbi->escapeString($tableName) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString($tableName) ); if ($version) { - $sqlQuery .= " AND `version` = '" . $dbi->escapeString($version) . "'"; + $sqlQuery .= " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "'"; } - return (bool) $dbi->queryAsControlUser($sqlQuery); + return (bool) $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } /** @@ -327,9 +321,7 @@ class Tracker $query, $trackingSet = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE' ): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $date = Util::date('Y-m-d H:i:s'); @@ -357,18 +349,18 @@ class Tracker . ' values (\'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\')', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbName), - $dbi->escapeString(''), - $dbi->escapeString($version), - $dbi->escapeString($date), - $dbi->escapeString($date), - $dbi->escapeString(''), - $dbi->escapeString($createSql), - $dbi->escapeString("\n"), - $dbi->escapeString($trackingSet) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString(''), + $GLOBALS['dbi']->escapeString($version), + $GLOBALS['dbi']->escapeString($date), + $GLOBALS['dbi']->escapeString($date), + $GLOBALS['dbi']->escapeString(''), + $GLOBALS['dbi']->escapeString($createSql), + $GLOBALS['dbi']->escapeString("\n"), + $GLOBALS['dbi']->escapeString($trackingSet) ); - return (bool) $dbi->queryAsControlUser($sqlQuery); + return (bool) $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } /** @@ -385,9 +377,7 @@ class Tracker $version, $newState ): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $trackingFeature = $relation->getRelationParameters()->trackingFeature; if ($trackingFeature === null) { return false; @@ -399,12 +389,12 @@ class Tracker Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), $newState, - $dbi->escapeString($dbName), - $dbi->escapeString($tableName), - $dbi->escapeString((string) $version) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString($tableName), + $GLOBALS['dbi']->escapeString((string) $version) ); - return (bool) $dbi->queryAsControlUser($sqlQuery); + return (bool) $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } /** @@ -425,9 +415,7 @@ class Tracker $type, $newData ): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); if ($type === 'DDL') { $saveTo = 'schema_sql'; @@ -443,7 +431,7 @@ class Tracker if (is_array($newData)) { foreach ($newData as $data) { $newDataProcessed .= '# log ' . $date . ' ' . $data['username'] - . $dbi->escapeString($data['statement']) . "\n"; + . $GLOBALS['dbi']->escapeString($data['statement']) . "\n"; } } else { $newDataProcessed = $newData; @@ -460,12 +448,12 @@ class Tracker Util::backquote($trackingFeature->tracking), $saveTo, $newDataProcessed, - $dbi->escapeString($dbName), - $dbi->escapeString($tableName), - $dbi->escapeString($version) + $GLOBALS['dbi']->escapeString($dbName), + $GLOBALS['dbi']->escapeString($tableName), + $GLOBALS['dbi']->escapeString($version) ); - $result = $dbi->queryAsControlUser($sqlQuery); + $result = $GLOBALS['dbi']->queryAsControlUser($sqlQuery); return (bool) $result; } @@ -508,9 +496,7 @@ class Tracker */ public static function getVersion(string $dbname, string $tablename, ?string $statement = null) { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $trackingFeature = $relation->getRelationParameters()->trackingFeature; if ($trackingFeature === null) { return -1; @@ -520,15 +506,15 @@ class Tracker 'SELECT MAX(version) FROM %s.%s WHERE `db_name` = \'%s\' AND `table_name` = \'%s\'', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbname), - $dbi->escapeString($tablename) + $GLOBALS['dbi']->escapeString($dbname), + $GLOBALS['dbi']->escapeString($tablename) ); if ($statement != '') { $sqlQuery .= " AND FIND_IN_SET('" . $statement . "',tracking) > 0"; } - $result = $dbi->tryQueryAsControlUser($sqlQuery); + $result = $GLOBALS['dbi']->tryQueryAsControlUser($sqlQuery); if ($result === false) { return -1; @@ -553,9 +539,7 @@ class Tracker */ public static function getTrackedData($dbname, $tablename, $version) { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $trackingFeature = $relation->getRelationParameters()->trackingFeature; if ($trackingFeature === null) { return []; @@ -565,17 +549,17 @@ class Tracker 'SELECT * FROM %s.%s WHERE `db_name` = \'%s\'', Util::backquote($trackingFeature->database), Util::backquote($trackingFeature->tracking), - $dbi->escapeString($dbname) + $GLOBALS['dbi']->escapeString($dbname) ); if (! empty($tablename)) { $sqlQuery .= " AND `table_name` = '" - . $dbi->escapeString($tablename) . "' "; + . $GLOBALS['dbi']->escapeString($tablename) . "' "; } - $sqlQuery .= " AND `version` = '" . $dbi->escapeString($version) + $sqlQuery .= " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' ORDER BY `version` DESC LIMIT 1"; - $mixed = $dbi->queryAsControlUser($sqlQuery)->fetchAssoc(); + $mixed = $GLOBALS['dbi']->queryAsControlUser($sqlQuery)->fetchAssoc(); // PHP 7.4 fix for accessing array offset on null if ($mixed === []) { @@ -834,9 +818,7 @@ class Tracker */ public static function handleQuery($query): void { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); // If query is marked as untouchable, leave if (mb_strstr($query, '/*NOTRACK*/')) { @@ -929,7 +911,7 @@ class Tracker Util::backquote($trackingFeature->tracking), Util::backquote($saveTo), Util::backquote($saveTo), - $dbi->escapeString($query), + $GLOBALS['dbi']->escapeString($query), $date ); @@ -937,7 +919,7 @@ class Tracker // the tablename attribute in pma_tracking too if ($result['identifier'] === 'RENAME TABLE') { $sqlQuery .= ', `table_name` = \'' - . $dbi->escapeString($result['tablename_after_rename']) + . $GLOBALS['dbi']->escapeString($result['tablename_after_rename']) . '\' '; } @@ -947,11 +929,11 @@ class Tracker // 3. the statements // we want to track $sqlQuery .= " WHERE FIND_IN_SET('" . $result['identifier'] . "',tracking) > 0" . - " AND `db_name` = '" . $dbi->escapeString($dbname ?? '') . "' " . + " AND `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " . " AND `table_name` = '" - . $dbi->escapeString($result['tablename']) . "' " . - " AND `version` = '" . $dbi->escapeString((string) $version) . "' "; + . $GLOBALS['dbi']->escapeString($result['tablename']) . "' " . + " AND `version` = '" . $GLOBALS['dbi']->escapeString((string) $version) . "' "; - $dbi->queryAsControlUser($sqlQuery); + $GLOBALS['dbi']->queryAsControlUser($sqlQuery); } } diff --git a/libraries/classes/Tracking.php b/libraries/classes/Tracking.php index 8c5c6fa209..36d2f36700 100644 --- a/libraries/classes/Tracking.php +++ b/libraries/classes/Tracking.php @@ -138,8 +138,6 @@ class Tracking $textDir, $lastVersion = null ) { - global $cfg; - $selectableTablesSqlResult = $this->getSqlResultForSelectableTables($db); $selectableTablesEntries = []; $selectableTablesNumRows = 0; @@ -174,7 +172,7 @@ class Tracking 'last_version' => $lastVersion, 'versions' => $versions, 'type' => $type, - 'default_statements' => $cfg['Server']['tracking_default_statements'], + 'default_statements' => $GLOBALS['cfg']['Server']['tracking_default_statements'], 'text_dir' => $textDir, ]); } @@ -1160,10 +1158,8 @@ class Tracking */ public function extractTableNames(array $table_list, $db, $testing = false) { - global $cfg; - $untracked_tables = []; - $sep = $cfg['NavigationTreeTableSeparator']; + $sep = $GLOBALS['cfg']['NavigationTreeTableSeparator']; foreach ($table_list as $value) { if (is_array($value) && array_key_exists('is' . $sep . 'group', $value) && $value['is' . $sep . 'group']) { diff --git a/libraries/classes/Transformations.php b/libraries/classes/Transformations.php index 81df453a03..2169fb01cb 100644 --- a/libraries/classes/Transformations.php +++ b/libraries/classes/Transformations.php @@ -63,11 +63,11 @@ class Transformations * * @param string $optionString comma separated options * - * @return array options + * @return string[] */ - public function getOptions($optionString) + public function getOptions($optionString): array { - if (strlen($optionString) === 0) { + if ($optionString === '') { return []; } @@ -278,13 +278,18 @@ class Transformations * @param bool $strict whether to include only results having a mimetype set * @param bool $fullName whether to use full column names as the key * - * @return array|null [field_name][field_key] = field_value + * @psalm-return array<string, array{ + * column_name: string, + * mimetype: string, + * transformation: string, + * transformation_options: string, + * input_transformation: string, + * input_transformation_options: string + * }>|null */ - public function getMime($db, $table, $strict = false, $fullName = false) + public function getMime($db, $table, $strict = false, $fullName = false): ?array { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature; if ($browserTransformationFeature === null) { return null; @@ -304,14 +309,25 @@ class Transformations . '`input_transformation_options`' . ' FROM ' . Util::backquote($browserTransformationFeature->database) . '.' . Util::backquote($browserTransformationFeature->columnInfo) - . ' WHERE `db_name` = \'' . $dbi->escapeString($db) . '\'' - . ' AND `table_name` = \'' . $dbi->escapeString($table) . '\'' + . ' WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\'' + . ' AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\'' . ' AND ( `mimetype` != \'\'' . (! $strict ? ' OR `transformation` != \'\'' . ' OR `transformation_options` != \'\'' . ' OR `input_transformation` != \'\'' . ' OR `input_transformation_options` != \'\'' : '') . ')'; - $result = $dbi->fetchResult($com_qry, 'column_name', null, DatabaseInterface::CONNECT_CONTROL); + + /** + * @psalm-var array<string, array{ + * column_name: string, + * mimetype: string, + * transformation: string, + * transformation_options: string, + * input_transformation: string, + * input_transformation_options: string + * }> $result + */ + $result = $GLOBALS['dbi']->fetchResult($com_qry, 'column_name', null, DatabaseInterface::CONNECT_CONTROL); foreach ($result as $column => $values) { // convert mimetype to new format (f.e. Text_Plain, etc) @@ -360,9 +376,7 @@ class Transformations $inputTransformOpts, $forcedelete = false ): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature; if ($browserTransformationFeature === null) { return false; @@ -386,11 +400,11 @@ class Transformations `comment` FROM ' . Util::backquote($browserTransformationFeature->database) . '.' . Util::backquote($browserTransformationFeature->columnInfo) . ' - WHERE `db_name` = \'' . $dbi->escapeString($db) . '\' - AND `table_name` = \'' . $dbi->escapeString($table) . '\' - AND `column_name` = \'' . $dbi->escapeString($key) . '\''; + WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\' + AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\' + AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key) . '\''; - $test_rs = $dbi->queryAsControlUser($test_qry); + $test_rs = $GLOBALS['dbi']->queryAsControlUser($test_qry); if ($test_rs->numRows() > 0) { $row = $test_rs->fetchAssoc(); @@ -401,15 +415,15 @@ class Transformations . Util::backquote($browserTransformationFeature->columnInfo) . ' SET ' . '`mimetype` = \'' - . $dbi->escapeString($mimetype) . '\', ' + . $GLOBALS['dbi']->escapeString($mimetype) . '\', ' . '`transformation` = \'' - . $dbi->escapeString($transformation) . '\', ' + . $GLOBALS['dbi']->escapeString($transformation) . '\', ' . '`transformation_options` = \'' - . $dbi->escapeString($transformationOpts) . '\', ' + . $GLOBALS['dbi']->escapeString($transformationOpts) . '\', ' . '`input_transformation` = \'' - . $dbi->escapeString($inputTransform) . '\', ' + . $GLOBALS['dbi']->escapeString($inputTransform) . '\', ' . '`input_transformation_options` = \'' - . $dbi->escapeString($inputTransformOpts) . '\''; + . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\''; } else { $upd_query = 'DELETE FROM ' . Util::backquote($browserTransformationFeature->database) @@ -417,10 +431,10 @@ class Transformations } $upd_query .= ' - WHERE `db_name` = \'' . $dbi->escapeString($db) . '\' - AND `table_name` = \'' . $dbi->escapeString($table) + WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\' + AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\' - AND `column_name` = \'' . $dbi->escapeString($key) + AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key) . '\''; } elseif ($has_value) { $upd_query = 'INSERT INTO ' @@ -430,18 +444,18 @@ class Transformations . 'transformation, transformation_options, ' . 'input_transformation, input_transformation_options) ' . ' VALUES(' - . '\'' . $dbi->escapeString($db) . '\',' - . '\'' . $dbi->escapeString($table) . '\',' - . '\'' . $dbi->escapeString($key) . '\',' - . '\'' . $dbi->escapeString($mimetype) . '\',' - . '\'' . $dbi->escapeString($transformation) . '\',' - . '\'' . $dbi->escapeString($transformationOpts) . '\',' - . '\'' . $dbi->escapeString($inputTransform) . '\',' - . '\'' . $dbi->escapeString($inputTransformOpts) . '\')'; + . '\'' . $GLOBALS['dbi']->escapeString($db) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($table) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($key) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($mimetype) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($transformation) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($transformationOpts) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($inputTransform) . '\',' + . '\'' . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\')'; } if (isset($upd_query)) { - return (bool) $dbi->queryAsControlUser($upd_query); + return (bool) $GLOBALS['dbi']->queryAsControlUser($upd_query); } return false; @@ -461,9 +475,7 @@ class Transformations */ public function clear($db, $table = '', $column = ''): bool { - global $dbi; - - $relation = new Relation($dbi); + $relation = new Relation($GLOBALS['dbi']); $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature; if ($browserTransformationFeature === null) { return false; @@ -485,6 +497,6 @@ class Transformations $delete_sql .= '`db_name` = \'' . $db . '\' '; } - return (bool) $dbi->tryQuery($delete_sql); + return (bool) $GLOBALS['dbi']->tryQuery($delete_sql); } } diff --git a/libraries/classes/Twig/AssetExtension.php b/libraries/classes/Twig/AssetExtension.php index 5f6bbd9eb3..a1023d5e38 100644 --- a/libraries/classes/Twig/AssetExtension.php +++ b/libraries/classes/Twig/AssetExtension.php @@ -22,12 +22,12 @@ final class AssetExtension extends AbstractExtension public function getImagePath(?string $filename = null, ?string $fallback = null): string { - global $theme; + $GLOBALS['theme'] = $GLOBALS['theme'] ?? null; - if (! $theme instanceof Theme) { + if (! $GLOBALS['theme'] instanceof Theme) { return ''; } - return $theme->getImgPath($filename, $fallback); + return $GLOBALS['theme']->getImgPath($filename, $fallback); } } diff --git a/libraries/classes/Twig/RelationExtension.php b/libraries/classes/Twig/RelationExtension.php deleted file mode 100644 index 2d6e1a457a..0000000000 --- a/libraries/classes/Twig/RelationExtension.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace PhpMyAdmin\Twig; - -use PhpMyAdmin\ConfigStorage\Relation; -use Twig\Extension\AbstractExtension; -use Twig\TwigFunction; - -class RelationExtension extends AbstractExtension -{ - /** - * Returns a list of functions to add to the existing list. - * - * @return TwigFunction[] - */ - public function getFunctions() - { - global $dbi; - - $relation = new Relation($dbi); - - return [ - new TwigFunction( - 'foreign_dropdown', - [$relation, 'foreignDropdown'], - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_display_field', - [$relation, 'getDisplayField'], - ['is_safe' => ['html']] - ), - new TwigFunction( - 'get_foreign_data', - [$relation, 'getForeignData'] - ), - new TwigFunction( - 'get_tables', - [$relation, 'getTables'] - ), - new TwigFunction( - 'search_column_in_foreigners', - [$relation, 'searchColumnInForeigners'] - ), - ]; - } -} diff --git a/libraries/classes/TwoFactor.php b/libraries/classes/TwoFactor.php index 72d00b7040..ee56e61b19 100644 --- a/libraries/classes/TwoFactor.php +++ b/libraries/classes/TwoFactor.php @@ -53,9 +53,7 @@ class TwoFactor */ public function __construct($user) { - global $dbi; - - (new Relation($dbi))->initRelationParamsCache(); + (new Relation($GLOBALS['dbi']))->initRelationParamsCache(); $this->userPreferences = new UserPreferences(); $this->user = $user; diff --git a/libraries/classes/Url.php b/libraries/classes/Url.php index c6bf3f5ed1..dfb363b7d8 100644 --- a/libraries/classes/Url.php +++ b/libraries/classes/Url.php @@ -47,7 +47,7 @@ class Url $indent = 0, $skip = [] ) { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; if (is_array($db)) { $params =& $db; @@ -66,7 +66,7 @@ class Url $params['server'] = $GLOBALS['server']; } - if (empty($config->getCookie('pma_lang')) && ! empty($GLOBALS['lang'])) { + if (empty($GLOBALS['config']->getCookie('pma_lang')) && ! empty($GLOBALS['lang'])) { $params['lang'] = $GLOBALS['lang']; } @@ -211,20 +211,22 @@ class Url */ public static function getCommonRaw(array $params = [], $divider = '?', $encrypt = true) { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; // avoid overwriting when creating navigation panel links to servers if ( isset($GLOBALS['server']) && $GLOBALS['server'] != $GLOBALS['cfg']['ServerDefault'] && ! isset($params['server']) - && ! $config->get('is_setup') + && ! $GLOBALS['config']->get('is_setup') ) { $params['server'] = $GLOBALS['server']; } // Can be null when the user is missing an extension. - if ($config !== null && empty($config->getCookie('pma_lang')) && ! empty($GLOBALS['lang'])) { + if ( + $GLOBALS['config'] !== null && empty($GLOBALS['config']->getCookie('pma_lang')) && ! empty($GLOBALS['lang']) + ) { $params['lang'] = $GLOBALS['lang']; } @@ -245,11 +247,11 @@ class Url */ public static function buildHttpQuery($params, $encrypt = true) { - global $config; + $GLOBALS['config'] = $GLOBALS['config'] ?? null; $separator = self::getArgSeparator(); - if (! $encrypt || ! $config->get('URLQueryEncryption')) { + if (! $encrypt || ! $GLOBALS['config']->get('URLQueryEncryption')) { return http_build_query($params, '', $separator); } @@ -268,8 +270,6 @@ class Url 'hostname', 'dbname', 'tablename', - 'checkprivsdb', - 'checkprivstable', ]; $paramsToEncrypt = []; foreach ($params as $paramKey => $paramValue) { diff --git a/libraries/classes/UrlRedirector.php b/libraries/classes/UrlRedirector.php index 86ab1270b6..c7411c9567 100644 --- a/libraries/classes/UrlRedirector.php +++ b/libraries/classes/UrlRedirector.php @@ -19,11 +19,11 @@ final class UrlRedirector */ public static function redirect(): void { - global $containerBuilder, $dbi; + $GLOBALS['containerBuilder'] = $GLOBALS['containerBuilder'] ?? null; // Load database service because services.php is not available here - $dbi = DatabaseInterface::load(); - $containerBuilder->set(DatabaseInterface::class, $dbi); + $GLOBALS['dbi'] = DatabaseInterface::load(); + $GLOBALS['containerBuilder']->set(DatabaseInterface::class, $GLOBALS['dbi']); // Only output the http headers $response = ResponseRenderer::getInstance(); @@ -46,7 +46,7 @@ final class UrlRedirector * * @var Template $template */ - $template = $containerBuilder->get('template'); + $template = $GLOBALS['containerBuilder']->get('template'); echo $template->render('javascript/redirect', [ 'url' => Sanitize::escapeJsString((string) $_GET['url']), ]); diff --git a/libraries/classes/UserPassword.php b/libraries/classes/UserPassword.php index 2e0173f78a..b15476c3d8 100644 --- a/libraries/classes/UserPassword.php +++ b/libraries/classes/UserPassword.php @@ -65,13 +65,13 @@ class UserPassword */ public function changePassword($password): string { - global $auth_plugin, $dbi; + $GLOBALS['auth_plugin'] = $GLOBALS['auth_plugin'] ?? null; $hashing_function = $this->changePassHashingFunction(); - [$username, $hostname] = $dbi->getCurrentUserAndHost(); + [$username, $hostname] = $GLOBALS['dbi']->getCurrentUserAndHost(); - $serverVersion = $dbi->getVersion(); + $serverVersion = $GLOBALS['dbi']->getVersion(); if (isset($_POST['authentication_plugin']) && ! empty($_POST['authentication_plugin'])) { $orig_auth_plugin = $_POST['authentication_plugin']; @@ -84,8 +84,8 @@ class UserPassword $isPerconaOrMySql = Compatibility::isMySqlOrPerconaDb(); if ($isPerconaOrMySql && $serverVersion >= 50706) { - $sql_query = 'ALTER USER \'' . $dbi->escapeString($username) - . '\'@\'' . $dbi->escapeString($hostname) + $sql_query = 'ALTER USER \'' . $GLOBALS['dbi']->escapeString($username) + . '\'@\'' . $GLOBALS['dbi']->escapeString($hostname) . '\' IDENTIFIED WITH ' . $orig_auth_plugin . ' BY ' . ($password == '' ? '\'\'' : '\'***\''); } elseif ( @@ -102,7 +102,7 @@ class UserPassword $value = 0; } - $dbi->tryQuery('SET `old_passwords` = ' . $value . ';'); + $GLOBALS['dbi']->tryQuery('SET `old_passwords` = ' . $value . ';'); } $this->changePassUrlParamsAndSubmitQuery( @@ -114,7 +114,7 @@ class UserPassword $orig_auth_plugin ); - $auth_plugin->handlePasswordChange($password); + $GLOBALS['auth_plugin']->handlePasswordChange($password); return $sql_query; } @@ -153,19 +153,17 @@ class UserPassword $hashing_function, $orig_auth_plugin ): void { - global $dbi; - $err_url = Url::getFromRoute('/user-password'); - $serverVersion = $dbi->getVersion(); + $serverVersion = $GLOBALS['dbi']->getVersion(); if (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50706) { - $local_query = 'ALTER USER \'' . $dbi->escapeString($username) - . '\'@\'' . $dbi->escapeString($hostname) . '\'' + $local_query = 'ALTER USER \'' . $GLOBALS['dbi']->escapeString($username) + . '\'@\'' . $GLOBALS['dbi']->escapeString($hostname) . '\'' . ' IDENTIFIED with ' . $orig_auth_plugin . ' BY ' . ($password == '' ? '\'\'' - : '\'' . $dbi->escapeString($password) . '\''); + : '\'' . $GLOBALS['dbi']->escapeString($password) . '\''); } elseif ( Compatibility::isMariaDb() && $serverVersion >= 50200 @@ -175,11 +173,11 @@ class UserPassword if ($orig_auth_plugin === 'mysql_native_password') { // Set the hashing method used by PASSWORD() // to be 'mysql_native_password' type - $dbi->tryQuery('SET old_passwords = 0;'); + $GLOBALS['dbi']->tryQuery('SET old_passwords = 0;'); } elseif ($orig_auth_plugin === 'sha256_password') { // Set the hashing method used by PASSWORD() // to be 'sha256_password' type - $dbi->tryQuery('SET `old_passwords` = 2;'); + $GLOBALS['dbi']->tryQuery('SET `old_passwords` = 2;'); } $hashedPassword = $this->serverPrivileges->getHashedPassword($_POST['pma_pw']); @@ -188,18 +186,18 @@ class UserPassword . " `authentication_string` = '" . $hashedPassword . "', `Password` = '', " . " `plugin` = '" . $orig_auth_plugin . "'" - . " WHERE `User` = '" . $dbi->escapeString($username) - . "' AND Host = '" . $dbi->escapeString($hostname) . "';"; + . " WHERE `User` = '" . $GLOBALS['dbi']->escapeString($username) + . "' AND Host = '" . $GLOBALS['dbi']->escapeString($hostname) . "';"; } else { $local_query = 'SET password = ' . ($password == '' ? '\'\'' : $hashing_function . '(\'' - . $dbi->escapeString($password) . '\')'); + . $GLOBALS['dbi']->escapeString($password) . '\')'); } - if (! @$dbi->tryQuery($local_query)) { + if (! @$GLOBALS['dbi']->tryQuery($local_query)) { Generator::mysqlDie( - $dbi->getError(), + $GLOBALS['dbi']->getError(), $sql_query, false, $err_url @@ -207,11 +205,14 @@ class UserPassword } // Flush privileges after successful password change - $dbi->tryQuery('FLUSH PRIVILEGES;'); + $GLOBALS['dbi']->tryQuery('FLUSH PRIVILEGES;'); } - public function getFormForChangePassword(?string $username, ?string $hostname): string + /** + * @psalm-param non-empty-string $route + */ + public function getFormForChangePassword(?string $username, ?string $hostname, string $route): string { - return $this->serverPrivileges->getFormForChangePassword($username ?? '', $hostname ?? '', false); + return $this->serverPrivileges->getFormForChangePassword($username ?? '', $hostname ?? '', false, $route); } } diff --git a/libraries/classes/UserPreferences.php b/libraries/classes/UserPreferences.php index 6bc524acba..a845e1c3f6 100644 --- a/libraries/classes/UserPreferences.php +++ b/libraries/classes/UserPreferences.php @@ -38,9 +38,7 @@ class UserPreferences public function __construct() { - global $dbi; - - $this->relation = new Relation($dbi); + $this->relation = new Relation($GLOBALS['dbi']); $this->template = new Template(); } @@ -75,8 +73,6 @@ class UserPreferences */ public function load(): array { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); if ($relationParameters->userPreferencesFeature === null) { // no pmadb table, use session storage @@ -100,9 +96,13 @@ class UserPreferences $query = 'SELECT `config_data`, UNIX_TIMESTAMP(`timevalue`) ts' . ' FROM ' . $query_table . ' WHERE `username` = \'' - . $dbi->escapeString((string) $relationParameters->user) + . $GLOBALS['dbi']->escapeString((string) $relationParameters->user) . '\''; - $row = $dbi->fetchSingleRow($query, DatabaseInterface::FETCH_ASSOC, DatabaseInterface::CONNECT_CONTROL); + $row = $GLOBALS['dbi']->fetchSingleRow( + $query, + DatabaseInterface::FETCH_ASSOC, + DatabaseInterface::CONNECT_CONTROL + ); if (! is_array($row) || ! isset($row['config_data']) || ! isset($row['ts'])) { return ['config_data' => [], 'mtime' => time(), 'type' => 'db']; } @@ -125,8 +125,6 @@ class UserPreferences */ public function save(array $config_array) { - global $dbi; - $relationParameters = $this->relation->getRelationParameters(); $server = $GLOBALS['server'] ?? $GLOBALS['cfg']['ServerDefault']; $cache_key = 'server_' . $server; @@ -152,34 +150,37 @@ class UserPreferences . Util::backquote($relationParameters->userPreferencesFeature->userConfig); $query = 'SELECT `username` FROM ' . $query_table . ' WHERE `username` = \'' - . $dbi->escapeString($relationParameters->user) + . $GLOBALS['dbi']->escapeString($relationParameters->user) . '\''; - $has_config = $dbi->fetchValue($query, 0, DatabaseInterface::CONNECT_CONTROL); + $has_config = $GLOBALS['dbi']->fetchValue($query, 0, DatabaseInterface::CONNECT_CONTROL); $config_data = json_encode($config_array); if ($has_config) { $query = 'UPDATE ' . $query_table . ' SET `timevalue` = NOW(), `config_data` = \'' - . $dbi->escapeString($config_data) + . $GLOBALS['dbi']->escapeString($config_data) . '\'' . ' WHERE `username` = \'' - . $dbi->escapeString($relationParameters->user) + . $GLOBALS['dbi']->escapeString($relationParameters->user) . '\''; } else { $query = 'INSERT INTO ' . $query_table . ' (`username`, `timevalue`,`config_data`) ' . 'VALUES (\'' - . $dbi->escapeString($relationParameters->user) . '\', NOW(), ' - . '\'' . $dbi->escapeString($config_data) . '\')'; + . $GLOBALS['dbi']->escapeString($relationParameters->user) . '\', NOW(), ' + . '\'' . $GLOBALS['dbi']->escapeString($config_data) . '\')'; } if (isset($_SESSION['cache'][$cache_key]['userprefs'])) { unset($_SESSION['cache'][$cache_key]['userprefs']); } - if (! $dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { + if (! $GLOBALS['dbi']->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) { $message = Message::error(__('Could not save configuration')); - $message->addMessage(Message::error($dbi->getError(DatabaseInterface::CONNECT_CONTROL)), '<br><br>'); + $message->addMessage( + Message::error($GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL)), + '<br><br>' + ); if (! $this->hasAccessToDatabase($relationParameters->db)) { /** * When phpMyAdmin cached the configuration storage parameters, it checked if the database can be diff --git a/libraries/classes/Util.php b/libraries/classes/Util.php index 8338d8e003..6cd6342ecf 100644 --- a/libraries/classes/Util.php +++ b/libraries/classes/Util.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin; use PhpMyAdmin\Dbal\ResultInterface; use PhpMyAdmin\Html\Generator; -use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Context; @@ -22,7 +21,6 @@ use function array_map; use function array_merge; use function array_shift; use function array_unique; -use function basename; use function bin2hex; use function chr; use function count; @@ -44,7 +42,6 @@ use function implode; use function in_array; use function ini_get; use function is_array; -use function is_callable; use function is_object; use function is_scalar; use function is_string; @@ -203,8 +200,6 @@ class Util */ public static function getMySQLDocuURL(string $link, string $anchor = ''): string { - global $dbi; - // Fixup for newly used names: $link = str_replace('_', '-', mb_strtolower($link)); @@ -214,8 +209,8 @@ class Util $mysql = '5.5'; $lang = 'en'; - if (isset($dbi)) { - $serverVersion = $dbi->getVersion(); + if (isset($GLOBALS['dbi'])) { + $serverVersion = $GLOBALS['dbi']->getVersion(); if ($serverVersion >= 80000) { $mysql = '8.0'; } elseif ($serverVersion >= 50700) { @@ -266,8 +261,6 @@ class Util */ private static function checkRowCount($db, array $table) { - global $dbi; - $rowCount = 0; if ($table['Rows'] === null) { @@ -283,7 +276,7 @@ class Util $tableIsView = $table['TABLE_TYPE'] === 'VIEW'; if ($tableIsView || Utilities::isSystemSchema($db)) { - $rowCount = $dbi + $rowCount = $GLOBALS['dbi'] ->getTable($db, $table['Name']) ->countRecords(); } @@ -301,11 +294,9 @@ class Util */ public static function getTableList($db): array { - global $dbi; - $sep = $GLOBALS['cfg']['NavigationTreeTableSeparator']; - $tables = $dbi->getTablesFull($db); + $tables = $GLOBALS['dbi']->getTablesFull($db); if ($GLOBALS['cfg']['NaturalOrder']) { uksort($tables, 'strnatcasecmp'); @@ -807,46 +798,6 @@ class Util } /** - * Function added to avoid path disclosures. - * Called by each script that needs parameters, it displays - * an error message and, by default, stops the execution. - * - * @param string[] $params The names of the parameters needed by the calling - * script - * @param bool $request Check parameters in request - */ - public static function checkParameters($params, $request = false): void - { - $reportedScriptName = basename($GLOBALS['PMA_PHP_SELF']); - $foundError = false; - $errorMessage = ''; - if ($request) { - $array = $_REQUEST; - } else { - $array = $GLOBALS; - } - - foreach ($params as $param) { - if (isset($array[$param])) { - continue; - } - - $errorMessage .= $reportedScriptName - . ': ' . __('Missing parameter:') . ' ' - . $param - . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) - . '[br]'; - $foundError = true; - } - - if (! $foundError) { - return; - } - - Core::fatalError($errorMessage); - } - - /** * Build a condition and with a value * * @param string|int|float|null $row The row value @@ -865,8 +816,6 @@ class Util string $conditionKey, string $condition ): array { - global $dbi; - if ($row === null) { return ['IS NULL', $condition]; } @@ -911,7 +860,7 @@ class Util . self::printableBitValue((int) $row, (int) $meta->length) . "'"; } else { $conditionValue = '= \'' - . $dbi->escapeString($row) . '\''; + . $GLOBALS['dbi']->escapeString($row) . '\''; } return [$conditionValue, $condition]; @@ -938,8 +887,6 @@ class Util $restrictToTable = false, array $expressions = [] ): array { - global $dbi; - $primaryKey = ''; $uniqueKey = ''; $nonPrimaryCondition = ''; @@ -981,7 +928,7 @@ class Util // because there is some caching in the function). if ( $meta->table !== $meta->orgtable - && ! $dbi->getTable($GLOBALS['db'], $meta->table)->isView() + && ! $GLOBALS['dbi']->getTable($GLOBALS['db'], $meta->table)->isView() ) { $meta->table = $meta->orgtable; } @@ -1594,24 +1541,16 @@ class Util * Formats user string, expanding @VARIABLES@, accepting strftime format * string. * - * @param string $string Text where to do expansion. - * @param array|string $escape Function to call for escaping variable values. - * Can also be an array of: - * - the escape method name - * - the class that contains the method - * - location of the class (for inclusion) - * @param array $updates Array with overrides for default parameters - * (obtained from GLOBALS). - * - * @return string + * @param string $string Text where to do expansion. + * @param callable|null $escape Function to call for escaping variable values. + * @param array<string, string|null> $updates Array with overrides for default parameters (obtained from GLOBALS). + * @psalm-param callable(string):string|null $escape */ public static function expandUserString( - $string, - $escape = null, + string $string, + ?callable $escape = null, array $updates = [] - ) { - global $dbi; - + ): string { /* Content */ $vars = []; $vars['http_host'] = Core::getenv('HTTP_HOST'); @@ -1653,20 +1592,7 @@ class Util /* Optional escaping */ if ($escape !== null) { - if (is_array($escape)) { - $escapeClass = new $escape[1](); - $escapeMethod = $escape[0]; - } - - foreach ($replace as $key => $val) { - if (isset($escapeClass, $escapeMethod)) { - $replace[$key] = $escapeClass->$escapeMethod($val); - } elseif ($escape === 'backquote') { - $replace[$key] = self::backquote($val); - } elseif (is_callable($escape)) { - $replace[$key] = $escape($val); - } - } + $replace = array_map($escape, $replace); } /* Backward compatibility in 3.5.x */ @@ -1676,7 +1602,7 @@ class Util /* Fetch columns list if required */ if (str_contains($string, '@COLUMNS@')) { - $columnsList = $dbi->getColumns($GLOBALS['db'], $GLOBALS['table']); + $columnsList = $GLOBALS['dbi']->getColumns($GLOBALS['db'], $GLOBALS['table']); // sometimes the table no longer exists at this point if ($columnsList !== null) { @@ -1712,13 +1638,11 @@ class Util */ public static function getSupportedDatatypes($html = false, $selected = '') { - global $dbi; - if ($html) { $retval = Generator::getSupportedDatatypes($selected); } else { $retval = []; - foreach ($dbi->types->getColumns() as $value) { + foreach ($GLOBALS['dbi']->types->getColumns() as $value) { if (is_array($value)) { foreach ($value as $subvalue) { if ($subvalue === '-') { @@ -1770,11 +1694,9 @@ class Util */ public static function currentUserHasPrivilege(string $priv, ?string $db = null, ?string $tbl = null): bool { - global $dbi; - // Get the username for the current user in the format // required to use in the information schema database. - [$user, $host] = $dbi->getCurrentUserAndHost(); + [$user, $host] = $GLOBALS['dbi']->getCurrentUserAndHost(); // MySQL is started with --skip-grant-tables if ($user === '') { @@ -1792,7 +1714,7 @@ class Util . "WHERE GRANTEE='%s' AND PRIVILEGE_TYPE='%s'"; // Check global privileges first. - $userPrivileges = $dbi->fetchValue( + $userPrivileges = $GLOBALS['dbi']->fetchValue( sprintf( $query, 'USER_PRIVILEGES', @@ -1813,13 +1735,13 @@ class Util } $query .= " AND '%s' LIKE `TABLE_SCHEMA`"; - $schemaPrivileges = $dbi->fetchValue( + $schemaPrivileges = $GLOBALS['dbi']->fetchValue( sprintf( $query, 'SCHEMA_PRIVILEGES', $username, $priv, - $dbi->escapeString($db) + $GLOBALS['dbi']->escapeString($db) ) ); if ($schemaPrivileges) { @@ -1830,14 +1752,14 @@ class Util // find any valid privileges, try table-wise privileges. if ($tbl !== null) { $query .= " AND TABLE_NAME='%s'"; - $tablePrivileges = $dbi->fetchValue( + $tablePrivileges = $GLOBALS['dbi']->fetchValue( sprintf( $query, 'TABLE_PRIVILEGES', $username, $priv, - $dbi->escapeString($db), - $dbi->escapeString($tbl) + $GLOBALS['dbi']->escapeString($db), + $GLOBALS['dbi']->escapeString($tbl) ) ); if ($tablePrivileges) { @@ -1861,13 +1783,11 @@ class Util */ public static function getServerType(): string { - global $dbi; - - if ($dbi->isMariaDB()) { + if ($GLOBALS['dbi']->isMariaDB()) { return 'MariaDB'; } - if ($dbi->isPercona()) { + if ($GLOBALS['dbi']->isPercona()) { return 'Percona Server'; } @@ -2068,9 +1988,7 @@ class Util */ public static function getCollateForIS() { - global $dbi; - - $names = $dbi->getLowerCaseNames(); + $names = $GLOBALS['dbi']->getLowerCaseNames(); if ($names === '0') { return 'COLLATE utf8_bin'; } @@ -2150,8 +2068,6 @@ class Util */ public static function getDbInfo($db, string $subPart) { - global $cfg, $dbi; - /** * limits for table list */ @@ -2169,7 +2085,7 @@ class Util /** * whether to display extended stats */ - $isShowStats = $cfg['ShowStats']; + $isShowStats = $GLOBALS['cfg']['ShowStats']; /** * whether selected db is information_schema @@ -2190,8 +2106,8 @@ class Util $tooltipAliasName = []; // Special speedup for newer MySQL Versions (in 4.0 format changed) - if ($cfg['SkipLockedTables'] === true) { - $dbInfoResult = $dbi->query( + if ($GLOBALS['cfg']['SkipLockedTables'] === true) { + $dbInfoResult = $GLOBALS['dbi']->query( 'SHOW OPEN TABLES FROM ' . self::backquote($db) . ' WHERE In_use > 0;' ); @@ -2246,7 +2162,7 @@ class Util $tableGroup = $_REQUEST['tbl_group']; // include the table with the exact name of the group if such // exists - $groupTable = $dbi->getTablesFull( + $groupTable = $GLOBALS['dbi']->getTablesFull( $db, $tableGroup, false, @@ -2263,7 +2179,7 @@ class Util // all tables in db // - get the total number of tables // (needed for proper working of the MaxTableList feature) - $tables = $dbi->getTables($db); + $tables = $GLOBALS['dbi']->getTables($db); $totalNumTables = count($tables); if ($subPart !== '_export') { // fetch the details for a possible limited subset @@ -2272,18 +2188,16 @@ class Util } } - $tables = array_merge( - $groupTable, - $dbi->getTablesFull( - $db, - $groupWithSeparator !== false ? $groupWithSeparator : '', - $groupWithSeparator !== false, - $limitOffset, - $limitCount, - $sort, - $sortOrder, - $tableType - ) + // We must use union operator here instead of array_merge to preserve numerical keys + $tables = $groupTable + $GLOBALS['dbi']->getTablesFull( + $db, + $groupWithSeparator !== false ? $groupWithSeparator : '', + $groupWithSeparator !== false, + $limitOffset, + $limitCount, + $sort, + $sortOrder, + $tableType ); } @@ -2325,8 +2239,6 @@ class Util */ public static function getTablesWhenOpen($db, ResultInterface $dbInfoResult): array { - global $dbi; - $sotCache = []; $tables = []; @@ -2343,8 +2255,8 @@ class Util && is_scalar($_REQUEST['tbl_group']) && strlen((string) $_REQUEST['tbl_group']) > 0 ) { - $group = $dbi->escapeMysqlLikeString((string) $_REQUEST['tbl_group']); - $groupWithSeparator = $dbi->escapeMysqlLikeString( + $group = $GLOBALS['dbi']->escapeMysqlLikeString((string) $_REQUEST['tbl_group']); + $groupWithSeparator = $GLOBALS['dbi']->escapeMysqlLikeString( $_REQUEST['tbl_group'] . $GLOBALS['cfg']['NavigationTreeTableSeparator'] ); @@ -2366,7 +2278,7 @@ class Util } } - $dbInfoResult = $dbi->query('SHOW FULL TABLES FROM ' . self::backquote($db) . $tblGroupSql); + $dbInfoResult = $GLOBALS['dbi']->query('SHOW FULL TABLES FROM ' . self::backquote($db) . $tblGroupSql); unset($tblGroupSql, $whereAdded); if ($dbInfoResult->numRows() > 0) { @@ -2388,7 +2300,7 @@ class Util if (count($names) > 0) { $tables = array_merge( $tables, - $dbi->getTablesFull($db, $names) + $GLOBALS['dbi']->getTablesFull($db, $names) ); } @@ -2635,7 +2547,7 @@ class Util */ public static function isInteger($input): bool { - return ctype_digit((string) $input); + return is_scalar($input) && ctype_digit((string) $input); } /** diff --git a/libraries/classes/Utils/ForeignKey.php b/libraries/classes/Utils/ForeignKey.php index 165c02c3e7..217296f6d7 100644 --- a/libraries/classes/Utils/ForeignKey.php +++ b/libraries/classes/Utils/ForeignKey.php @@ -18,8 +18,6 @@ final class ForeignKey */ public static function isSupported($engine): bool { - global $dbi; - $engine = strtoupper((string) $engine); if (($engine === 'INNODB') || ($engine === 'PBXT')) { return true; @@ -27,7 +25,7 @@ final class ForeignKey if ($engine === 'NDBCLUSTER' || $engine === 'NDB') { $ndbver = strtolower( - $dbi->fetchValue('SELECT @@ndb_version_string') ?: '' + $GLOBALS['dbi']->fetchValue('SELECT @@ndb_version_string') ?: '' ); if (substr($ndbver, 0, 4) === 'ndb-') { $ndbver = substr($ndbver, 4); @@ -44,8 +42,6 @@ final class ForeignKey */ public static function isCheckEnabled(): bool { - global $dbi; - if ($GLOBALS['cfg']['DefaultForeignKeyChecks'] === 'enable') { return true; } @@ -54,7 +50,7 @@ final class ForeignKey return false; } - return $dbi->getVariable('FOREIGN_KEY_CHECKS') === 'ON'; + return $GLOBALS['dbi']->getVariable('FOREIGN_KEY_CHECKS') === 'ON'; } /** @@ -62,16 +58,14 @@ final class ForeignKey */ public static function handleDisableCheckInit(): bool { - global $dbi; - - $defaultCheckValue = $dbi->getVariable('FOREIGN_KEY_CHECKS') === 'ON'; + $defaultCheckValue = $GLOBALS['dbi']->getVariable('FOREIGN_KEY_CHECKS') === 'ON'; if (isset($_REQUEST['fk_checks'])) { if (empty($_REQUEST['fk_checks'])) { // Disable foreign key checks - $dbi->setVariable('FOREIGN_KEY_CHECKS', 'OFF'); + $GLOBALS['dbi']->setVariable('FOREIGN_KEY_CHECKS', 'OFF'); } else { // Enable foreign key checks - $dbi->setVariable('FOREIGN_KEY_CHECKS', 'ON'); + $GLOBALS['dbi']->setVariable('FOREIGN_KEY_CHECKS', 'ON'); } } @@ -85,8 +79,6 @@ final class ForeignKey */ public static function handleDisableCheckCleanup(bool $defaultCheckValue): void { - global $dbi; - - $dbi->setVariable('FOREIGN_KEY_CHECKS', $defaultCheckValue ? 'ON' : 'OFF'); + $GLOBALS['dbi']->setVariable('FOREIGN_KEY_CHECKS', $defaultCheckValue ? 'ON' : 'OFF'); } } diff --git a/libraries/classes/Utils/Gis.php b/libraries/classes/Utils/Gis.php index f35d75324b..9b2c9839ef 100644 --- a/libraries/classes/Utils/Gis.php +++ b/libraries/classes/Utils/Gis.php @@ -22,20 +22,18 @@ final class Gis */ public static function convertToWellKnownText($data, $includeSRID = false): string { - global $dbi; - // Convert to WKT format $hex = bin2hex($data); $spatialAsText = 'ASTEXT'; $spatialSrid = 'SRID'; $axisOrder = ''; - $mysqlVersionInt = $dbi->getVersion(); + $mysqlVersionInt = $GLOBALS['dbi']->getVersion(); if ($mysqlVersionInt >= 50600) { $spatialAsText = 'ST_ASTEXT'; $spatialSrid = 'ST_SRID'; } - if ($mysqlVersionInt >= 80001 && ! $dbi->isMariaDb()) { + if ($mysqlVersionInt >= 80001 && ! $GLOBALS['dbi']->isMariaDb()) { $axisOrder = ', \'axis-order=long-lat\''; } @@ -44,7 +42,7 @@ final class Gis $wktsql .= ', ' . $spatialSrid . "(x'" . $hex . "')"; } - $wktresult = $dbi->tryQuery($wktsql); + $wktresult = $GLOBALS['dbi']->tryQuery($wktsql); $wktarr = []; if ($wktresult) { $wktarr = $wktresult->fetchRow(); @@ -129,8 +127,6 @@ final class Gis $binary = true, $display = false ): array { - global $dbi; - $funcs = []; if ($display) { $funcs[] = ['display' => ' ']; @@ -246,7 +242,7 @@ final class Gis } $spatialPrefix = ''; - if ($dbi->getVersion() >= 50601) { + if ($GLOBALS['dbi']->getVersion() >= 50601) { // If MySQL version is greater than or equal 5.6.1, // use the ST_ prefix. $spatialPrefix = 'ST_'; diff --git a/libraries/classes/Utils/HttpRequest.php b/libraries/classes/Utils/HttpRequest.php index b9dc488768..67ff7f62ef 100644 --- a/libraries/classes/Utils/HttpRequest.php +++ b/libraries/classes/Utils/HttpRequest.php @@ -58,27 +58,23 @@ class HttpRequest public function __construct() { - global $cfg; - - $this->proxyUrl = $cfg['ProxyUrl']; - $this->proxyUser = $cfg['ProxyUser']; - $this->proxyPass = $cfg['ProxyPass']; + $this->proxyUrl = $GLOBALS['cfg']['ProxyUrl']; + $this->proxyUser = $GLOBALS['cfg']['ProxyUser']; + $this->proxyPass = $GLOBALS['cfg']['ProxyPass']; } public static function setProxySettingsFromEnv(): void { - global $cfg; - $httpProxy = getenv('http_proxy'); $urlInfo = parse_url((string) $httpProxy); if (PHP_SAPI !== 'cli' || ! is_array($urlInfo)) { return; } - $cfg['ProxyUrl'] = ($urlInfo['host'] ?? '') + $GLOBALS['cfg']['ProxyUrl'] = ($urlInfo['host'] ?? '') . (isset($urlInfo['port']) ? ':' . $urlInfo['port'] : ''); - $cfg['ProxyUser'] = $urlInfo['user'] ?? ''; - $cfg['ProxyPass'] = $urlInfo['pass'] ?? ''; + $GLOBALS['cfg']['ProxyUser'] = $urlInfo['user'] ?? ''; + $GLOBALS['cfg']['ProxyPass'] = $urlInfo['pass'] ?? ''; } /** diff --git a/libraries/classes/Utils/SessionCache.php b/libraries/classes/Utils/SessionCache.php index 99333e952b..4a408f2a97 100644 --- a/libraries/classes/Utils/SessionCache.php +++ b/libraries/classes/Utils/SessionCache.php @@ -8,12 +8,11 @@ final class SessionCache { private static function key(): string { - global $cfg, $server; + $GLOBALS['server'] = $GLOBALS['server'] ?? null; + $key = 'server_' . $GLOBALS['server']; - $key = 'server_' . $server; - - if (isset($cfg['Server']['user'])) { - return $key . '_' . $cfg['Server']['user']; + if (isset($GLOBALS['cfg']['Server']['user'])) { + return $key . '_' . $GLOBALS['cfg']['Server']['user']; } return $key; diff --git a/libraries/classes/Version.php b/libraries/classes/Version.php index d474435094..24a8ae8406 100644 --- a/libraries/classes/Version.php +++ b/libraries/classes/Version.php @@ -14,12 +14,12 @@ use const VERSION_SUFFIX; final class Version { // The VERSION_SUFFIX constant is defined at libraries/constants.php - public const VERSION = '5.2.1-dev' . VERSION_SUFFIX; - public const SERIES = '5.2'; + public const VERSION = '5.3.0-dev' . VERSION_SUFFIX; + public const SERIES = '5.3'; public const MAJOR = 5; - public const MINOR = 2; - public const PATCH = 1; - public const ID = 50201; + public const MINOR = 3; + public const PATCH = 0; + public const ID = 50300; public const PRE_RELEASE_NAME = 'dev'; public const IS_DEV = true; } diff --git a/libraries/classes/VersionInformation.php b/libraries/classes/VersionInformation.php index cf4899a344..c325c3f456 100644 --- a/libraries/classes/VersionInformation.php +++ b/libraries/classes/VersionInformation.php @@ -15,6 +15,7 @@ use function explode; use function intval; use function is_numeric; use function is_object; +use function is_string; use function json_decode; use function preg_match; use function strlen; @@ -228,7 +229,7 @@ class VersionInformation $myVersion = $this->getMySQLVersion(); } - if ($myVersion !== null && $version !== null && $operator !== null) { + if (is_string($myVersion) && is_string($version) && is_string($operator)) { return version_compare($myVersion, $version, $operator); } @@ -252,10 +253,8 @@ class VersionInformation */ protected function getMySQLVersion() { - global $dbi; - - if (isset($dbi)) { - return $dbi->getVersionString(); + if (isset($GLOBALS['dbi'])) { + return $GLOBALS['dbi']->getVersionString(); } return null; diff --git a/libraries/classes/ZipExtension.php b/libraries/classes/ZipExtension.php index d2e49b76df..1c6330d198 100644 --- a/libraries/classes/ZipExtension.php +++ b/libraries/classes/ZipExtension.php @@ -46,10 +46,10 @@ class ZipExtension * @param string $file path to zip file * @param string $specificEntry regular expression to match a file * - * @return array ($error_message, $file_data); $error_message - * is empty if no error + * @return array<string, string> + * @psalm-return array{error: string, data: string} */ - public function getContents($file, $specificEntry = null) + public function getContents($file, $specificEntry = null): array { /** * This function is used to "import" a SQL file which has been exported earlier diff --git a/libraries/config.values.php b/libraries/config.values.php index e16a9279db..eb7c7f047d 100644 --- a/libraries/config.values.php +++ b/libraries/config.values.php @@ -376,7 +376,7 @@ return [ /** * Basic validator assignments (functions from libraries/config/Validator.php - * and 'validators' object in js/config.js) + * and 'window.validators' object in js/config.js) * Use only full paths and form ids */ '_validators' => [ diff --git a/libraries/routes.php b/libraries/routes.php index de2f9590cd..9eadbe66bd 100644 --- a/libraries/routes.php +++ b/libraries/routes.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Controllers\CheckRelationsController; use PhpMyAdmin\Controllers\CollationConnectionController; use PhpMyAdmin\Controllers\ColumnController; use PhpMyAdmin\Controllers\Config; +use PhpMyAdmin\Controllers\Console\Bookmark; use PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Controllers\DatabaseController; use PhpMyAdmin\Controllers\ErrorReportController; @@ -17,11 +18,12 @@ use PhpMyAdmin\Controllers\GisDataEditorController; use PhpMyAdmin\Controllers\GitInfoController; use PhpMyAdmin\Controllers\HomeController; use PhpMyAdmin\Controllers\Import; +use PhpMyAdmin\Controllers\JavaScriptMessagesController; use PhpMyAdmin\Controllers\LicenseController; use PhpMyAdmin\Controllers\LintController; use PhpMyAdmin\Controllers\LogoutController; use PhpMyAdmin\Controllers\NavigationController; -use PhpMyAdmin\Controllers\NormalizationController; +use PhpMyAdmin\Controllers\Normalization; use PhpMyAdmin\Controllers\PhpInfoController; use PhpMyAdmin\Controllers\Preferences; use PhpMyAdmin\Controllers\RecentTablesListController; @@ -52,6 +54,10 @@ return static function (RouteCollector $routes): void { $routes->post('/get', Config\GetConfigController::class); $routes->post('/set', Config\SetConfigController::class); }); + $routes->addGroup('/console/bookmark', static function (RouteCollector $routes): void { + $routes->post('/add', Bookmark\AddController::class); + $routes->get('/refresh', Bookmark\RefreshController::class); + }); $routes->addGroup('/database', static function (RouteCollector $routes): void { $routes->addGroup('/central-columns', static function (RouteCollector $routes): void { $routes->addRoute(['GET', 'POST'], '', Database\CentralColumnsController::class); @@ -71,6 +77,7 @@ return static function (RouteCollector $routes): void { $routes->addRoute(['GET', 'POST'], '', Database\OperationsController::class); $routes->post('/collation', Database\Operations\CollationController::class); }); + $routes->get('/privileges', Database\PrivilegesController::class); $routes->addRoute(['GET', 'POST'], '/qbe', Database\QueryByExampleController::class); $routes->addRoute(['GET', 'POST'], '/routines', Database\RoutinesController::class); $routes->addRoute(['GET', 'POST'], '/search', Database\SearchController::class); @@ -127,8 +134,26 @@ return static function (RouteCollector $routes): void { $routes->get('/license', LicenseController::class); $routes->addRoute(['GET', 'POST'], '/lint', LintController::class); $routes->addRoute(['GET', 'POST'], '/logout', LogoutController::class); + $routes->get('/messages', JavaScriptMessagesController::class); $routes->addRoute(['GET', 'POST'], '/navigation', NavigationController::class); - $routes->addRoute(['GET', 'POST'], '/normalization', NormalizationController::class); + $routes->addGroup('/normalization', static function (RouteCollector $routes): void { + $routes->addRoute(['GET', 'POST'], '', Normalization\MainController::class); + $routes->post('/1nf/step1', Normalization\FirstNormalForm\FirstStepController::class); + $routes->post('/1nf/step2', Normalization\FirstNormalForm\SecondStepController::class); + $routes->post('/1nf/step3', Normalization\FirstNormalForm\ThirdStepController::class); + $routes->post('/1nf/step4', Normalization\FirstNormalForm\FourthStepController::class); + $routes->post('/2nf/create-new-tables', Normalization\SecondNormalForm\CreateNewTablesController::class); + $routes->post('/2nf/new-tables', Normalization\SecondNormalForm\NewTablesController::class); + $routes->post('/2nf/step1', Normalization\SecondNormalForm\FirstStepController::class); + $routes->post('/3nf/create-new-tables', Normalization\ThirdNormalForm\CreateNewTablesController::class); + $routes->post('/3nf/new-tables', Normalization\ThirdNormalForm\NewTablesController::class); + $routes->post('/3nf/step1', Normalization\ThirdNormalForm\FirstStepController::class); + $routes->post('/add-new-primary', Normalization\AddNewPrimaryController::class); + $routes->post('/get-columns', Normalization\GetColumnsController::class); + $routes->post('/create-new-column', Normalization\CreateNewColumnController::class); + $routes->post('/move-repeating-group', Normalization\MoveRepeatingGroup::class); + $routes->post('/partial-dependencies', Normalization\PartialDependenciesController::class); + }); $routes->get('/phpinfo', PhpInfoController::class); $routes->addGroup('/preferences', static function (RouteCollector $routes): void { $routes->addRoute(['GET', 'POST'], '/export', Preferences\ExportController::class); @@ -239,6 +264,7 @@ return static function (RouteCollector $routes): void { $routes->post('/repair', Table\Partition\RepairController::class); $routes->post('/truncate', Table\Partition\TruncateController::class); }); + $routes->get('/privileges', Table\PrivilegesController::class); $routes->addRoute(['GET', 'POST'], '/operations', Table\OperationsController::class); $routes->addRoute(['GET', 'POST'], '/recent-favorite', Table\RecentFavoriteController::class); $routes->addRoute(['GET', 'POST'], '/relation', Table\RelationController::class); diff --git a/libraries/services.php b/libraries/services.php index 59f1bb587f..e64e85dad7 100644 --- a/libraries/services.php +++ b/libraries/services.php @@ -8,7 +8,7 @@ use PhpMyAdmin\ConfigStorage\RelationCleanup; return [ 'services' => [ 'advisor' => [ - 'class' => PhpMyAdmin\Advisor::class, + 'class' => PhpMyAdmin\Advisory\Advisor::class, 'arguments' => [ '$dbi' => '@dbi', '$expression' => '@expression_language', @@ -87,6 +87,7 @@ return [ 'expression_language' => [ 'class' => Symfony\Component\ExpressionLanguage\ExpressionLanguage::class, ], + 'file_listing' => ['class' => PhpMyAdmin\FileListing::class], 'flash' => [ 'class' => PhpMyAdmin\FlashMessages::class, ], @@ -102,7 +103,7 @@ return [ ], 'insert_edit' => [ 'class' => PhpMyAdmin\InsertEdit::class, - 'arguments' => ['@dbi'], + 'arguments' => ['@dbi', '@relation', '@transformations', '@file_listing', '@template'], ], 'navigation' => [ 'class' => PhpMyAdmin\Navigation\Navigation::class, @@ -201,6 +202,10 @@ return [ 'class' => PhpMyAdmin\Server\Status\Processes::class, 'arguments' => ['@dbi'], ], + 'table_columns_definition' => [ + 'class' => PhpMyAdmin\Table\ColumnsDefinition::class, + 'arguments' => ['$dbi' => '@dbi', '$relation' => '@relation', '$transformations' => '@transformations'], + ], 'table_indexes' => [ 'class' => PhpMyAdmin\Table\Indexes::class, 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], @@ -235,6 +240,9 @@ return [ 'user_preferences' => [ 'class' => PhpMyAdmin\UserPreferences::class, ], + 'version_information' => [ + 'class' => PhpMyAdmin\VersionInformation::class, + ], PhpMyAdmin\DatabaseInterface::class => 'dbi', PhpMyAdmin\FlashMessages::class => 'flash', PhpMyAdmin\ResponseRenderer::class => 'response', diff --git a/libraries/services_controllers.php b/libraries/services_controllers.php index 19d91d33db..75ea182533 100644 --- a/libraries/services_controllers.php +++ b/libraries/services_controllers.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Controllers\CheckRelationsController; use PhpMyAdmin\Controllers\CollationConnectionController; use PhpMyAdmin\Controllers\ColumnController; use PhpMyAdmin\Controllers\Config; +use PhpMyAdmin\Controllers\Console; use PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Controllers\DatabaseController; use PhpMyAdmin\Controllers\ErrorReportController; @@ -21,7 +22,7 @@ use PhpMyAdmin\Controllers\LicenseController; use PhpMyAdmin\Controllers\LintController; use PhpMyAdmin\Controllers\LogoutController; use PhpMyAdmin\Controllers\NavigationController; -use PhpMyAdmin\Controllers\NormalizationController; +use PhpMyAdmin\Controllers\Normalization; use PhpMyAdmin\Controllers\PhpInfoController; use PhpMyAdmin\Controllers\Preferences; use PhpMyAdmin\Controllers\RecentTablesListController; @@ -95,12 +96,19 @@ return [ '$config' => '@config', ], ], + Console\Bookmark\AddController::class => [ + 'class' => Console\Bookmark\AddController::class, + 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + ], + Console\Bookmark\RefreshController::class => [ + 'class' => Console\Bookmark\RefreshController::class, + 'arguments' => ['$response' => '@response', '$template' => '@template'], + ], Database\CentralColumns\PopulateColumnsController::class => [ 'class' => Database\CentralColumns\PopulateColumnsController::class, 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$centralColumns' => '@central_columns', ], ], @@ -109,7 +117,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$centralColumns' => '@central_columns', ], ], @@ -118,7 +125,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$relation' => '@relation', '$transformations' => '@transformations', '$dbi' => '@dbi', @@ -129,7 +135,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$databaseDesigner' => '@designer', '$designerCommon' => '@designer_common', ], @@ -139,7 +144,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$events' => '@events', '$dbi' => '@dbi', ], @@ -149,7 +153,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$export' => '@export', '$exportOptions' => '@export_options', ], @@ -159,7 +162,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -183,7 +185,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -192,7 +193,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$operations' => '@operations', '$dbi' => '@dbi', ], @@ -202,7 +202,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$operations' => '@operations', '$checkUserPrivileges' => '@check_user_privileges', '$relation' => '@relation', @@ -215,7 +214,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$privileges' => '@server_privileges', '$dbi' => '@dbi', ], @@ -225,7 +223,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$relation' => '@relation', '$dbi' => '@dbi', ], @@ -235,7 +232,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$checkUserPrivileges' => '@check_user_privileges', '$dbi' => '@dbi', ], @@ -245,7 +241,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -254,7 +249,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -263,7 +257,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$sqlQueryForm' => '@sql_query_form', ], ], @@ -272,7 +265,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', ], ], Database\Structure\AddPrefixController::class => [ @@ -280,7 +272,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', ], ], Database\Structure\AddPrefixTableController::class => [ @@ -288,7 +279,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$structureController' => '@' . Database\StructureController::class, ], @@ -298,7 +288,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$structureController' => '@' . Database\StructureController::class, ], @@ -308,7 +297,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$structureController' => '@' . Database\StructureController::class, ], @@ -318,7 +306,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$structureController' => '@' . Database\StructureController::class, ], @@ -328,7 +315,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', ], ], Database\Structure\CopyFormController::class => [ @@ -336,7 +322,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', ], ], Database\Structure\CopyTableController::class => [ @@ -344,7 +329,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$operations' => '@operations', '$structureController' => '@' . Database\StructureController::class, ], @@ -354,7 +338,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$structureController' => '@' . Database\StructureController::class, ], ], @@ -363,7 +346,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -372,7 +354,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$relationCleanup' => '@relation_cleanup', '$structureController' => '@' . Database\StructureController::class, @@ -383,7 +364,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', ], ], Database\Structure\EmptyTableController::class => [ @@ -391,7 +371,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$relation' => '@relation', '$relationCleanup' => '@relation_cleanup', @@ -405,7 +384,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$relation' => '@relation', ], ], @@ -414,7 +392,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -423,7 +400,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', '$structureController' => '@' . Database\StructureController::class, ], @@ -433,7 +409,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -442,7 +417,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$relation' => '@relation', '$replication' => '@replication', '$relationCleanup' => '@relation_cleanup', @@ -456,7 +430,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$tracking' => '@tracking', '$dbi' => '@dbi', ], @@ -466,7 +439,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', '$dbi' => '@dbi', ], ], @@ -621,8 +593,124 @@ return [ '$relation' => '@relation', ], ], - NormalizationController::class => [ - 'class' => NormalizationController::class, + Normalization\FirstNormalForm\FirstStepController::class => [ + 'class' => Normalization\FirstNormalForm\FirstStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\FirstNormalForm\FourthStepController::class => [ + 'class' => Normalization\FirstNormalForm\FourthStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\FirstNormalForm\SecondStepController::class => [ + 'class' => Normalization\FirstNormalForm\SecondStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\FirstNormalForm\ThirdStepController::class => [ + 'class' => Normalization\FirstNormalForm\ThirdStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\SecondNormalForm\CreateNewTablesController::class => [ + 'class' => Normalization\SecondNormalForm\CreateNewTablesController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\SecondNormalForm\FirstStepController::class => [ + 'class' => Normalization\SecondNormalForm\FirstStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\SecondNormalForm\NewTablesController::class => [ + 'class' => Normalization\SecondNormalForm\NewTablesController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\ThirdNormalForm\CreateNewTablesController::class => [ + 'class' => Normalization\ThirdNormalForm\CreateNewTablesController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\ThirdNormalForm\FirstStepController::class => [ + 'class' => Normalization\ThirdNormalForm\FirstStepController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\ThirdNormalForm\NewTablesController::class => [ + 'class' => Normalization\ThirdNormalForm\NewTablesController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\AddNewPrimaryController::class => [ + 'class' => Normalization\AddNewPrimaryController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\CreateNewColumnController::class => [ + 'class' => Normalization\CreateNewColumnController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\GetColumnsController::class => [ + 'class' => Normalization\GetColumnsController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\MainController::class => [ + 'class' => Normalization\MainController::class, + 'arguments' => ['$response' => '@response', '$template' => '@template'], + ], + Normalization\MoveRepeatingGroup::class => [ + 'class' => Normalization\MoveRepeatingGroup::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$normalization' => '@normalization', + ], + ], + Normalization\PartialDependenciesController::class => [ + 'class' => Normalization\PartialDependenciesController::class, 'arguments' => [ '$response' => '@response', '$template' => '@template', @@ -1080,12 +1168,10 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$transformations' => '@transformations', '$config' => '@config', - '$relation' => '@relation', '$dbi' => '@dbi', + '$columnsDefinition' => '@table_columns_definition', ], ], Table\ChangeController::class => [ @@ -1093,8 +1179,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$insertEdit' => '@insert_edit', '$relation' => '@relation', ], @@ -1104,8 +1188,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$changeController' => '@' . Table\ChangeController::class, ], ], @@ -1114,8 +1196,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1124,12 +1204,10 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$transformations' => '@transformations', '$config' => '@config', - '$relation' => '@relation', '$dbi' => '@dbi', + '$columnsDefinition' => '@table_columns_definition', ], ], Table\DeleteConfirmController::class => [ @@ -1137,8 +1215,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', ], ], Table\DeleteRowsController::class => [ @@ -1146,8 +1222,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1156,8 +1230,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', ], ], Table\DropColumnController::class => [ @@ -1165,8 +1237,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$flash' => '@flash', '$relationCleanup' => '@relation_cleanup', @@ -1177,8 +1247,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$export' => '@export_options', ], ], @@ -1187,8 +1255,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$exportController' => '@' . Table\ExportController::class, ], ], @@ -1197,8 +1263,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1207,8 +1271,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1217,8 +1279,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1227,8 +1287,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1237,8 +1295,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$indexes' => '@table_indexes', ], @@ -1248,8 +1304,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$indexes' => '@table_indexes', ], @@ -1259,8 +1313,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$model' => '@table_maintenance', '$config' => '@config', ], @@ -1270,8 +1322,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$model' => '@table_maintenance', '$config' => '@config', ], @@ -1281,8 +1331,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$model' => '@table_maintenance', '$config' => '@config', ], @@ -1292,8 +1340,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$model' => '@table_maintenance', '$config' => '@config', ], @@ -1303,8 +1349,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$model' => '@table_maintenance', '$config' => '@config', ], @@ -1314,8 +1358,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1324,8 +1366,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1334,8 +1374,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1344,8 +1382,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1354,8 +1390,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1364,8 +1398,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1374,8 +1406,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$maintenance' => '@partitioning_maintenance', ], ], @@ -1384,8 +1414,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$operations' => '@operations', '$checkUserPrivileges' => '@check_user_privileges', '$relation' => '@relation', @@ -1397,8 +1425,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$privileges' => '@server_privileges', '$dbi' => '@dbi', ], @@ -1408,8 +1434,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', ], ], Table\RelationController::class => [ @@ -1417,8 +1441,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$relation' => '@relation', '$dbi' => '@dbi', ], @@ -1428,8 +1450,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$insertEdit' => '@insert_edit', '$transformations' => '@transformations', '$relation' => '@relation', @@ -1441,8 +1461,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$search' => '@table_search', '$relation' => '@relation', '$dbi' => '@dbi', @@ -1453,8 +1471,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$sqlQueryForm' => '@sql_query_form', ], ], @@ -1463,8 +1479,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, ], @@ -1474,8 +1488,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$sqlController' => '@' . Sql\SqlController::class, '$structureController' => '@' . Table\StructureController::class, ], @@ -1485,8 +1497,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$sql' => '@sql', ], ], @@ -1495,8 +1505,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$centralColumns' => '@central_columns', '$structureController' => '@' . Table\StructureController::class, ], @@ -1506,8 +1514,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$centralColumns' => '@central_columns', '$structureController' => '@' . Table\StructureController::class, ], @@ -1517,11 +1523,8 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', - '$relation' => '@relation', - '$transformations' => '@transformations', '$dbi' => '@dbi', + '$columnsDefinition' => '@table_columns_definition', ], ], Table\Structure\FulltextController::class => [ @@ -1529,8 +1532,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, ], @@ -1540,8 +1541,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1550,8 +1549,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$createAddField' => '@create_add_field', '$structureController' => '@' . Table\StructureController::class, @@ -1562,8 +1559,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, ], @@ -1573,8 +1568,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', ], ], Table\Structure\SaveController::class => [ @@ -1582,8 +1575,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$relation' => '@relation', '$transformations' => '@transformations', '$dbi' => '@dbi', @@ -1595,8 +1586,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, ], @@ -1606,8 +1595,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, ], @@ -1617,8 +1604,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$relation' => '@relation', '$transformations' => '@transformations', '$createAddField' => '@create_add_field', @@ -1632,8 +1617,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$tracking' => '@tracking', ], ], @@ -1642,8 +1625,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$dbi' => '@dbi', ], ], @@ -1652,8 +1633,6 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', - '$db' => '%db%', - '$table' => '%table%', '$search' => '@table_search', '$relation' => '@relation', '$dbi' => '@dbi', @@ -1681,6 +1660,7 @@ return [ '$response' => '@response', '$template' => '@template', '$themeManager' => '@theme_manager', + '$userPreferences' => '@user_preferences', ], ], Transformation\OverviewController::class => [ @@ -1715,6 +1695,7 @@ return [ 'arguments' => [ '$response' => '@response', '$template' => '@template', + '$versionInformation' => '@version_information', ], ], View\CreateController::class => [ |