Merge branch 'QA_4_9' into QA_5_0
This commit is contained in:
commit
5f12e75bfd
1
.gitignore
vendored
1
.gitignore
vendored
@ -61,3 +61,4 @@ composer.lock
|
||||
phpstan.neon
|
||||
libraries/cache/
|
||||
js/dist/
|
||||
/setup/styles.css.map
|
||||
|
||||
17
ChangeLog
17
ChangeLog
@ -214,6 +214,23 @@ phpMyAdmin - ChangeLog
|
||||
- issue #15677 Fix show process-list triggers a php exception
|
||||
- issue #15697 Fix uncaught php error: "Call to a member function get() on null" in db_export.php when exporting a table from the list
|
||||
|
||||
4.9.11 (2023-02-07)
|
||||
- issue [security] Fix an XSS attack through the drag-and-drop upload feature
|
||||
|
||||
4.9.10 (2022-02-10)
|
||||
- issue #17308 Fix broken pagination links in the navigation sidebar
|
||||
|
||||
4.9.9 (2022-01-22)
|
||||
- issue #17305 Fix syntax error for PHP 5
|
||||
- issue #17307 Fix hide_connection_errors being undefined when a controluser is set
|
||||
|
||||
4.9.8 (2022-01-20)
|
||||
- issue #14321 Display a correct error page when "$cfg['Servers'][$i]['SignonURL']" is empty for auth_type=signon
|
||||
- issue #14321 [security] Remove leaked HTML on signon page redirect before login for auth_type=signon
|
||||
- issue [security] Add configuration directive $cfg['Servers'][$i]['hide_connection_errors'] to allow hiding host names and other error details when login fails
|
||||
- issue [security] Add configuration directive $cfg['URLQueryEncryption'] to allow encrypting senstive information in the URL
|
||||
- issue [security] Fix a scenario where an authenticated user can disable two factor authentication
|
||||
|
||||
4.9.7 (2020-10-15)
|
||||
- issue #16397 Fix compatibility problems with older PHP versions (also issue #16399)
|
||||
- issue #16396 Fix broken two-factor authentication
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
"samyoul/u2f-php-server": "<1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-openssl": "Cookie encryption",
|
||||
"ext-openssl": "For encryption performance",
|
||||
"ext-curl": "Updates checking",
|
||||
"ext-opcache": "Better performance",
|
||||
"ext-zlib": "For gz import and export",
|
||||
@ -78,7 +78,10 @@
|
||||
"ext-mbstring": "For best performance",
|
||||
"tecnickcom/tcpdf": "For PDF support",
|
||||
"pragmarx/google2fa-qrcode": "For 2FA authentication",
|
||||
"samyoul/u2f-php-server": "For FIDO U2F authentication"
|
||||
"pragmarx/google2fa": "For 2FA authentication",
|
||||
"bacon/bacon-qr-code": "For 2FA authentication",
|
||||
"samyoul/u2f-php-server": "For FIDO U2F authentication",
|
||||
"paragonie/sodium_compat": "For modern encryption support"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-webdriver/webdriver": "^1.7.1",
|
||||
@ -88,7 +91,9 @@
|
||||
"pragmarx/google2fa-qrcode": "^1.0.1",
|
||||
"samyoul/u2f-php-server": "^1.1",
|
||||
"squizlabs/php_codesniffer": "^3.0",
|
||||
"tecnickcom/tcpdf": "^6.3"
|
||||
"tecnickcom/tcpdf": "^6.3",
|
||||
"paragonie/random_compat": ">=2",
|
||||
"paragonie/sodium_compat": "^1.17"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -107,6 +112,11 @@
|
||||
]
|
||||
},
|
||||
"config":{
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true,
|
||||
"composer/package-versions-deprecated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +149,13 @@ $cfg['SaveDir'] = '';
|
||||
*/
|
||||
//$cfg['SendErrorReports'] = 'always';
|
||||
|
||||
/**
|
||||
* 'URLQueryEncryption' defines whether phpMyAdmin will encrypt sensitive data from the URL query string.
|
||||
* 'URLQueryEncryptionSecretKey' is a 32 bytes long secret key used to encrypt/decrypt the URL query string.
|
||||
*/
|
||||
//$cfg['URLQueryEncryption'] = true;
|
||||
//$cfg['URLQueryEncryptionSecretKey'] = '';
|
||||
|
||||
/**
|
||||
* You can find more configuration options in the documentation
|
||||
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
|
||||
|
||||
@ -1485,6 +1485,20 @@ Server connection settings
|
||||
after logout (doesn't affect config authentication method). Should be
|
||||
absolute including protocol.
|
||||
|
||||
.. config:option:: $cfg['Servers'][$i]['hide_connection_errors']
|
||||
|
||||
:type: boolean
|
||||
:default: false
|
||||
|
||||
.. versionadded:: 4.9.8
|
||||
|
||||
Whether to show or hide detailed MySQL/MariaDB connection errors on the login page.
|
||||
|
||||
.. note::
|
||||
|
||||
This error message can contain the target database server hostname or IP address,
|
||||
which may reveal information about your network to an attacker.
|
||||
|
||||
Generic settings
|
||||
----------------
|
||||
|
||||
@ -1753,6 +1767,27 @@ Generic settings
|
||||
When enabled, a user can drag a file in to their browser and phpMyAdmin will
|
||||
attempt to import the file.
|
||||
|
||||
.. config:option:: $cfg['URLQueryEncryption']
|
||||
|
||||
:type: boolean
|
||||
:default: false
|
||||
|
||||
.. versionadded:: 4.9.8
|
||||
|
||||
Define whether phpMyAdmin will encrypt sensitive data (like database name
|
||||
and table name) from the URL query string. Default is to not encrypt the URL
|
||||
query string.
|
||||
|
||||
.. config:option:: $cfg['URLQueryEncryptionSecretKey']
|
||||
|
||||
:type: string
|
||||
:default: ``''``
|
||||
|
||||
.. versionadded:: 4.9.8
|
||||
|
||||
A secret key used to encrypt/decrypt the URL query string.
|
||||
Should be 32 bytes long.
|
||||
|
||||
Cookie authentication options
|
||||
-----------------------------
|
||||
|
||||
|
||||
@ -132,7 +132,7 @@ var DragDropImport = {
|
||||
var filename = $this.parent('span').attr('data-filename');
|
||||
$('body').append('<div class="pma_drop_result"><h2>' +
|
||||
Messages.dropImportImportResultHeader + ' - ' +
|
||||
filename + '<span class="close">x</span></h2>' + value.message + '</div>');
|
||||
Functions.escapeHtml(filename) + '<span class="close">x</span></h2>' + value.message + '</div>');
|
||||
$('.pma_drop_result').draggable(); // to make this dialog draggable
|
||||
}
|
||||
});
|
||||
|
||||
@ -161,7 +161,7 @@ Navigation.loadChildNodes = function (isNode, $expandElem, callback) {
|
||||
}
|
||||
|
||||
var url = $('#pma_navigation').find('a.navigation_url').attr('href');
|
||||
$.get(url, params, function (data) {
|
||||
$.post(url, params, function (data) {
|
||||
if (typeof data !== 'undefined' && data.success === true) {
|
||||
$destination.find('div.list_container').remove(); // FIXME: Hack, there shouldn't be a list container there
|
||||
if (isNode) {
|
||||
@ -1070,14 +1070,12 @@ Navigation.selectCurrentDatabase = function () {
|
||||
Navigation.treePagination = function ($this) {
|
||||
var $msgbox = Functions.ajaxShowMessage();
|
||||
var isDbSelector = $this.closest('div.pageselector').is('.dbselector');
|
||||
var url;
|
||||
var params;
|
||||
var url = 'navigation.php';
|
||||
var params = 'ajax_request=true';
|
||||
if ($this[0].tagName === 'A') {
|
||||
url = $this.attr('href');
|
||||
params = 'ajax_request=true';
|
||||
params += PMA_commonParams.get('arg_separator') + $this.getPostData();
|
||||
} else { // tagName === 'SELECT'
|
||||
url = 'navigation.php';
|
||||
params = $this.closest('form').serialize() + CommonParams.get('arg_separator') + 'ajax_request=true';
|
||||
params += PMA_commonParams.get('arg_separator') + $this.closest('form').serialize();
|
||||
}
|
||||
var searchClause = Navigation.FastFilter.getSearchClause();
|
||||
if (searchClause) {
|
||||
|
||||
@ -342,7 +342,10 @@ class StructureController extends AbstractController
|
||||
// got to be eliminated in long run
|
||||
$db = &$this->db;
|
||||
$table = &$this->table;
|
||||
$url_params = [];
|
||||
$url_params = [
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
];
|
||||
include_once ROOT_PATH . 'libraries/tbl_common.inc.php';
|
||||
$this->_db_is_system_schema = $db_is_system_schema;
|
||||
$this->_url_query = Url::getCommonRaw([
|
||||
@ -1280,14 +1283,6 @@ class StructureController extends AbstractController
|
||||
'DistinctValues' => Util::getIcon('b_browse', __('Distinct values')),
|
||||
];
|
||||
|
||||
$edit_view_url = '';
|
||||
if ($this->_tbl_is_view && ! $this->_db_is_system_schema) {
|
||||
$edit_view_url = Url::getCommon([
|
||||
'db' => $this->db,
|
||||
'table' => $this->table,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays Space usage and row statistics
|
||||
*/
|
||||
@ -1359,10 +1354,6 @@ class StructureController extends AbstractController
|
||||
|
||||
$engine = $this->table_obj->getStorageEngine();
|
||||
return $this->template->render('table/structure/display_structure', [
|
||||
'url_params' => [
|
||||
'db' => $this->db,
|
||||
'table' => $this->table,
|
||||
],
|
||||
'collations' => $collations,
|
||||
'is_foreign_key_supported' => Util::isForeignKeySupported($engine),
|
||||
'displayIndexesHtml' => Index::getHtmlForDisplayIndexes(),
|
||||
@ -1374,11 +1365,11 @@ class StructureController extends AbstractController
|
||||
'tbl_is_view' => $this->_tbl_is_view,
|
||||
'mime_map' => $mime_map,
|
||||
'url_query' => $this->_url_query,
|
||||
'url_params' => $url_params,
|
||||
'titles' => $titles,
|
||||
'tbl_storage_engine' => $this->_tbl_storage_engine,
|
||||
'primary' => $primary_index,
|
||||
'columns_with_unique_index' => $columns_with_unique_index,
|
||||
'edit_view_url' => $edit_view_url,
|
||||
'columns_list' => $columns_list,
|
||||
'table_stats' => isset($tablestats) ? $tablestats : null,
|
||||
'fields' => $fields,
|
||||
|
||||
@ -1304,4 +1304,36 @@ class Core
|
||||
$hmac = hash_hmac('sha256', $sqlQuery, $secret . $cfg['blowfish_secret']);
|
||||
return hash_equals($hmac, $signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function populateRequestWithEncryptedQueryParams()
|
||||
{
|
||||
if (
|
||||
(! isset($_GET['eq']) || ! is_string($_GET['eq']))
|
||||
&& (! isset($_POST['eq']) || ! is_string($_POST['eq']))
|
||||
) {
|
||||
unset($_GET['eq'], $_POST['eq'], $_REQUEST['eq']);
|
||||
return;
|
||||
}
|
||||
|
||||
$isFromPost = isset($_POST['eq']);
|
||||
$decryptedQuery = Url::decryptQuery($isFromPost ? $_POST['eq'] : $_GET['eq']);
|
||||
unset($_GET['eq'], $_POST['eq'], $_REQUEST['eq']);
|
||||
if ($decryptedQuery === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlQueryParams = (array) json_decode($decryptedQuery);
|
||||
foreach ($urlQueryParams as $urlQueryParamKey => $urlQueryParamValue) {
|
||||
if ($isFromPost) {
|
||||
$_POST[$urlQueryParamKey] = $urlQueryParamValue;
|
||||
} else {
|
||||
$_GET[$urlQueryParamKey] = $urlQueryParamValue;
|
||||
}
|
||||
|
||||
$_REQUEST[$urlQueryParamKey] = $urlQueryParamValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
161
libraries/classes/Crypto/Crypto.php
Normal file
161
libraries/classes/Crypto/Crypto.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace PhpMyAdmin\Crypto;
|
||||
|
||||
use Exception;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Random;
|
||||
|
||||
final class Crypto
|
||||
{
|
||||
/** @var bool */
|
||||
private $hasRandomBytesSupport;
|
||||
|
||||
/** @var bool */
|
||||
private $hasSodiumSupport;
|
||||
|
||||
/**
|
||||
* @param bool $forceFallback Force the usage of the fallback functions.
|
||||
*/
|
||||
public function __construct($forceFallback = false)
|
||||
{
|
||||
$this->hasRandomBytesSupport = ! $forceFallback && is_callable('random_bytes');
|
||||
$this->hasSodiumSupport = ! $forceFallback
|
||||
&& $this->hasRandomBytesSupport
|
||||
&& is_callable('sodium_crypto_secretbox')
|
||||
&& is_callable('sodium_crypto_secretbox_open')
|
||||
&& defined('SODIUM_CRYPTO_SECRETBOX_NONCEBYTES')
|
||||
&& defined('SODIUM_CRYPTO_SECRETBOX_KEYBYTES');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
if ($this->hasSodiumSupport) {
|
||||
return $this->encryptWithSodium($plaintext);
|
||||
}
|
||||
|
||||
return $this->encryptWithPhpseclib($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ciphertext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->hasSodiumSupport) {
|
||||
return $this->decryptWithSodium($ciphertext);
|
||||
}
|
||||
|
||||
return $this->decryptWithPhpseclib($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getEncryptionKey()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$keyLength = $this->hasSodiumSupport ? SODIUM_CRYPTO_SECRETBOX_KEYBYTES : 32;
|
||||
|
||||
$key = $PMA_Config->get('URLQueryEncryptionSecretKey');
|
||||
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$key = isset($_SESSION['URLQueryEncryptionSecretKey']) ? $_SESSION['URLQueryEncryptionSecretKey'] : null;
|
||||
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$key = $this->hasRandomBytesSupport ? random_bytes($keyLength) : Random::string($keyLength);
|
||||
$_SESSION['URLQueryEncryptionSecretKey'] = $key;
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encryptWithPhpseclib($plaintext)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$cipher = new AES(AES::MODE_CBC);
|
||||
$iv = $this->hasRandomBytesSupport ? random_bytes(16) : Random::string(16);
|
||||
$cipher->setIV($iv);
|
||||
$cipher->setKey($key);
|
||||
$ciphertext = $cipher->encrypt($plaintext);
|
||||
$hmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
|
||||
|
||||
return $hmac . $iv . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function decryptWithPhpseclib($encrypted)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$hmac = mb_substr($encrypted, 0, 32, '8bit');
|
||||
$iv = mb_substr($encrypted, 32, 16, '8bit');
|
||||
$ciphertext = mb_substr($encrypted, 48, null, '8bit');
|
||||
$calculatedHmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
|
||||
if (! hash_equals($hmac, $calculatedHmac)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cipher = new AES(AES::MODE_CBC);
|
||||
$cipher->setIV($iv);
|
||||
$cipher->setKey($key);
|
||||
|
||||
return $cipher->decrypt($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encryptWithSodium($plaintext)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
$ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
|
||||
|
||||
return $nonce . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function decryptWithSodium($encrypted)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$nonce = mb_substr($encrypted, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$ciphertext = mb_substr($encrypted, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
try {
|
||||
$decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($decrypted === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
}
|
||||
@ -1630,17 +1630,22 @@ class DatabaseInterface
|
||||
*/
|
||||
public function initRelationParamsCache()
|
||||
{
|
||||
if (strlen($GLOBALS['db'])) {
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (empty($cfgRelation['db'])) {
|
||||
$this->relation->fixPmaTables($GLOBALS['db'], false);
|
||||
}
|
||||
}
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (empty($cfgRelation['db']) && isset($GLOBALS['dblist'])) {
|
||||
if ($GLOBALS['dblist']->databases->exists('phpmyadmin')) {
|
||||
$this->relation->fixPmaTables('phpmyadmin', false);
|
||||
}
|
||||
$storageDbName = isset($GLOBALS['cfg']['Server']['pmadb']) ? $GLOBALS['cfg']['Server']['pmadb'] : '';
|
||||
// Use "phpmyadmin" as a default database name to check to keep the behavior consistent
|
||||
$storageDbName = $storageDbName !== null
|
||||
&& is_string($storageDbName)
|
||||
&& $storageDbName !== '' ? $storageDbName : 'phpmyadmin';
|
||||
|
||||
// This will make users not having explicitly listed databases
|
||||
// have config values filled by the default phpMyAdmin storage table name values
|
||||
$this->relation->fixPmaTables($storageDbName, false);
|
||||
|
||||
// This global will be changed if fixPmaTables did find one valid table
|
||||
$storageDbName = isset($GLOBALS['cfg']['Server']['pmadb']) ? $GLOBALS['cfg']['Server']['pmadb'] : '';
|
||||
|
||||
// Empty means that until now no pmadb was found eligible
|
||||
if (empty($storageDbName)) {
|
||||
$this->relation->fixPmaTables($GLOBALS['db'], false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2522,6 +2527,8 @@ class DatabaseInterface
|
||||
|
||||
$server = [];
|
||||
|
||||
$server['hide_connection_errors'] = $cfg['Server']['hide_connection_errors'];
|
||||
|
||||
if (! empty($cfg['Server']['controlhost'])) {
|
||||
$server['host'] = $cfg['Server']['controlhost'];
|
||||
} else {
|
||||
@ -2592,6 +2599,10 @@ class DatabaseInterface
|
||||
$server['compress'] = false;
|
||||
}
|
||||
|
||||
if (! isset($server['hide_connection_errors'])) {
|
||||
$server['hide_connection_errors'] = false;
|
||||
}
|
||||
|
||||
return [
|
||||
$user,
|
||||
$password,
|
||||
|
||||
@ -121,15 +121,27 @@ class DbiMysqli implements DbiExtension
|
||||
$host = $server['host'];
|
||||
}
|
||||
|
||||
$return_value = $mysqli->real_connect(
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
'',
|
||||
$server['port'],
|
||||
(string) $server['socket'],
|
||||
$client_flags
|
||||
);
|
||||
if ($server['hide_connection_errors']) {
|
||||
$return_value = @$mysqli->real_connect(
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
'',
|
||||
$server['port'],
|
||||
(string) $server['socket'],
|
||||
$client_flags
|
||||
);
|
||||
} else {
|
||||
$return_value = $mysqli->real_connect(
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
'',
|
||||
$server['port'],
|
||||
(string) $server['socket'],
|
||||
$client_flags
|
||||
);
|
||||
}
|
||||
|
||||
if ($return_value === false || $return_value === null) {
|
||||
/*
|
||||
@ -151,7 +163,20 @@ class DbiMysqli implements DbiExtension
|
||||
);
|
||||
$server['ssl'] = true;
|
||||
return self::connect($user, $password, $server);
|
||||
} elseif ($error_number === 1045 && $server['hide_connection_errors']) {
|
||||
trigger_error(
|
||||
sprintf(
|
||||
__(
|
||||
'Error 1045: Access denied for user. Additional error information'
|
||||
. ' may be available, but is being hidden by the %s configuration directive.'
|
||||
),
|
||||
'[code][doc@cfg_Servers_hide_connection_errors]'
|
||||
. '$cfg[\'Servers\'][$i][\'hide_connection_errors\'][/doc][/code]'
|
||||
),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -1609,10 +1609,9 @@ class Results
|
||||
}
|
||||
|
||||
$tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
|
||||
. $tmp_txt . '" title="' . $tmp_txt . '">';
|
||||
$tmp_url = 'sql.php' . Url::getCommon($url_params_full_text);
|
||||
. $tmp_txt . '" title="' . $tmp_txt . '" />';
|
||||
|
||||
return Util::linkOrButton($tmp_url, $tmp_image);
|
||||
return Util::linkOrButton('sql.php', $url_params_full_text, $tmp_image);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1730,16 +1729,14 @@ class Results
|
||||
'session_max_rows' => $session_max_rows,
|
||||
'is_browse_distinct' => $this->__get('is_browse_distinct'),
|
||||
];
|
||||
$single_order_url = 'sql.php' . Url::getCommon($_single_url_params);
|
||||
$multi_order_url = 'sql.php' . Url::getCommon($_multi_url_params);
|
||||
|
||||
// Displays the sorting URL
|
||||
// enable sort order swapping for image
|
||||
$order_link = $this->_getSortOrderLink(
|
||||
$order_img,
|
||||
$fields_meta,
|
||||
$single_order_url,
|
||||
$multi_order_url
|
||||
$_single_url_params,
|
||||
$_multi_url_params
|
||||
);
|
||||
|
||||
$sorted_header_html .= $this->_getDraggableClassForSortableColumns(
|
||||
@ -2041,10 +2038,10 @@ class Results
|
||||
/**
|
||||
* Get sort order link
|
||||
*
|
||||
* @param string $order_img the sort order image
|
||||
* @param stdClass $fields_meta set of field properties
|
||||
* @param string $order_url the url for sort
|
||||
* @param string $multi_order_url the url for sort
|
||||
* @param string $order_img the sort order image
|
||||
* @param array $fields_meta set of field properties
|
||||
* @param array $order_url_params the url params for sort
|
||||
* @param array $multi_order_url_params the url params for sort
|
||||
*
|
||||
* @return string the sort order link
|
||||
*
|
||||
@ -2055,8 +2052,8 @@ class Results
|
||||
private function _getSortOrderLink(
|
||||
$order_img,
|
||||
$fields_meta,
|
||||
$order_url,
|
||||
$multi_order_url
|
||||
$order_url_params,
|
||||
$multi_order_url_params
|
||||
) {
|
||||
$order_link_params = [
|
||||
'class' => 'sortlink',
|
||||
@ -2064,10 +2061,13 @@ class Results
|
||||
|
||||
$order_link_content = htmlspecialchars($fields_meta->name);
|
||||
$inner_link_content = $order_link_content . $order_img
|
||||
. '<input type="hidden" value="' . $multi_order_url . '">';
|
||||
. '<input type="hidden" value="sql.php'
|
||||
. Url::getCommon($multi_order_url_params, '?', false)
|
||||
. '" />';
|
||||
|
||||
return Util::linkOrButton(
|
||||
$order_url,
|
||||
'sql.php',
|
||||
$order_url_params,
|
||||
$inner_link_content,
|
||||
$order_link_params
|
||||
);
|
||||
@ -2517,7 +2517,7 @@ class Results
|
||||
// 1. Prepares the row
|
||||
|
||||
// In print view these variable needs to be initialized
|
||||
$del_url = $del_str = $edit_anchor_class
|
||||
$del_url = $del_str = $edit_anchor_class = $editCopyUrlParams = $delUrlParams
|
||||
= $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
|
||||
|
||||
// 1.2 Defines the URLs for the modify/delete link(s)
|
||||
@ -2550,7 +2550,7 @@ class Results
|
||||
// 1.2.1 Modify link(s) - update row case
|
||||
if ($displayParts['edit_lnk'] == self::UPDATE_ROW) {
|
||||
list($edit_url, $copy_url, $edit_str, $copy_str,
|
||||
$edit_anchor_class)
|
||||
$edit_anchor_class, $editCopyUrlParams)
|
||||
= $this->_getModifiedLinks(
|
||||
$where_clause,
|
||||
$clause_is_unique,
|
||||
@ -2559,7 +2559,7 @@ class Results
|
||||
} // end if (1.2.1)
|
||||
|
||||
// 1.2.2 Delete/Kill link(s)
|
||||
list($del_url, $del_str, $js_conf)
|
||||
list($del_url, $del_str, $js_conf, $delUrlParams)
|
||||
= $this->_getDeleteAndKillLinks(
|
||||
$where_clause,
|
||||
$clause_is_unique,
|
||||
@ -2586,7 +2586,9 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
);
|
||||
} elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
|
||||
$table_body_html .= $this->_getPlacedLinks(
|
||||
@ -2603,7 +2605,9 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
);
|
||||
} // end if (1.3)
|
||||
} // end if (1)
|
||||
@ -2645,7 +2649,9 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
);
|
||||
}
|
||||
} // end if (3)
|
||||
@ -3247,15 +3253,9 @@ class Results
|
||||
'goto' => 'sql.php',
|
||||
];
|
||||
|
||||
$edit_url = 'tbl_change.php'
|
||||
. Url::getCommon(
|
||||
$_url_params + ['default_action' => 'update']
|
||||
);
|
||||
$edit_url = 'tbl_change.php';
|
||||
|
||||
$copy_url = 'tbl_change.php'
|
||||
. Url::getCommon(
|
||||
$_url_params + ['default_action' => 'insert']
|
||||
);
|
||||
$copy_url = 'tbl_change.php';
|
||||
|
||||
$edit_str = $this->_getActionLinkContent(
|
||||
'b_edit',
|
||||
@ -3278,6 +3278,7 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$edit_anchor_class,
|
||||
$_url_params
|
||||
];
|
||||
}
|
||||
|
||||
@ -3330,7 +3331,7 @@ class Results
|
||||
'message_to_show' => __('The row has been deleted.'),
|
||||
'goto' => $lnk_goto,
|
||||
];
|
||||
$del_url = 'sql.php' . Url::getCommon($_url_params);
|
||||
$del_url = 'sql.php';
|
||||
|
||||
$js_conf = 'DELETE FROM ' . Sanitize::jsFormat($this->__get('table'))
|
||||
. ' WHERE ' . Sanitize::jsFormat($where_clause, false)
|
||||
@ -3355,20 +3356,21 @@ class Results
|
||||
'goto' => $lnk_goto,
|
||||
];
|
||||
|
||||
$del_url = 'sql.php' . Url::getCommon($_url_params);
|
||||
$del_url = 'sql.php';
|
||||
$js_conf = $kill;
|
||||
$del_str = Util::getIcon(
|
||||
'b_drop',
|
||||
__('Kill')
|
||||
);
|
||||
} else {
|
||||
$del_url = $del_str = $js_conf = null;
|
||||
$del_url = $del_str = $js_conf = $_url_params = null;
|
||||
}
|
||||
|
||||
return [
|
||||
$del_url,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$_url_params
|
||||
];
|
||||
}
|
||||
|
||||
@ -3415,20 +3417,22 @@ class Results
|
||||
/**
|
||||
* Prepare placed links
|
||||
*
|
||||
* @param string $dir the direction of links should place
|
||||
* @param string $del_url the url for delete row
|
||||
* @param array $displayParts which elements to display
|
||||
* @param integer $row_no the index of current row
|
||||
* @param string $where_clause the where clause of the sql
|
||||
* @param string $where_clause_html the html encoded where clause
|
||||
* @param array $condition_array array of keys (primary, unique, condition)
|
||||
* @param string $edit_url the url for edit row
|
||||
* @param string $copy_url the url for copy row
|
||||
* @param string $edit_anchor_class the class for html element for edit
|
||||
* @param string $edit_str the label for edit row
|
||||
* @param string $copy_str the label for copy row
|
||||
* @param string $del_str the label for delete row
|
||||
* @param string|null $js_conf text for the JS confirmation
|
||||
* @param string $dir the direction of links should place
|
||||
* @param string $del_url the url for delete row
|
||||
* @param array $displayParts which elements to display
|
||||
* @param integer $row_no the index of current row
|
||||
* @param string $where_clause the where clause of the sql
|
||||
* @param string $where_clause_html the html encoded where clause
|
||||
* @param array $condition_array array of keys (primary, unique, condition)
|
||||
* @param string $edit_url the url for edit row
|
||||
* @param string $copy_url the url for copy row
|
||||
* @param string $edit_anchor_class the class for html element for edit
|
||||
* @param string $edit_str the label for edit row
|
||||
* @param string $copy_str the label for copy row
|
||||
* @param string $del_str the label for delete row
|
||||
* @param string $js_conf text for the JS confirmation
|
||||
* @param array $editCopyUrlParams URL parameters
|
||||
* @param array $delUrlParams URL parameters
|
||||
*
|
||||
* @return string html content
|
||||
*
|
||||
@ -3450,7 +3454,9 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
?string $js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
) {
|
||||
|
||||
if (! isset($js_conf)) {
|
||||
@ -3471,7 +3477,9 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
);
|
||||
}
|
||||
|
||||
@ -4781,8 +4789,8 @@ class Results
|
||||
/**
|
||||
* Generates HTML to display the Create view in span tag
|
||||
*
|
||||
* @param array $analyzed_sql_results analyzed sql results
|
||||
* @param string $url_query String with URL Parameters
|
||||
* @param array $analyzed_sql_results analyzed sql results
|
||||
* @param array $urlParams URL Parameters
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
@ -4790,13 +4798,14 @@ class Results
|
||||
*
|
||||
* @see _getResultsOperations()
|
||||
*/
|
||||
private function _getLinkForCreateView(array $analyzed_sql_results, $url_query)
|
||||
private function _getLinkForCreateView(array $analyzed_sql_results, $urlParams)
|
||||
{
|
||||
$results_operations_html = '';
|
||||
if (empty($analyzed_sql_results['procedure'])) {
|
||||
$results_operations_html .= '<span>'
|
||||
. Util::linkOrButton(
|
||||
'view_create.php' . $url_query,
|
||||
'view_create.php',
|
||||
$urlParams,
|
||||
Util::getIcon(
|
||||
'b_view_add',
|
||||
__('Create view'),
|
||||
@ -4843,6 +4852,7 @@ class Results
|
||||
{
|
||||
return Util::linkOrButton(
|
||||
'#',
|
||||
null,
|
||||
Util::getIcon(
|
||||
'b_insrow',
|
||||
__('Copy to clipboard'),
|
||||
@ -4866,6 +4876,7 @@ class Results
|
||||
{
|
||||
return Util::linkOrButton(
|
||||
'#',
|
||||
null,
|
||||
Util::getIcon(
|
||||
'b_print',
|
||||
__('Print'),
|
||||
@ -4911,7 +4922,6 @@ class Results
|
||||
'printview' => '1',
|
||||
'sql_query' => $this->__get('sql_query'),
|
||||
];
|
||||
$url_query = Url::getCommon($_url_params);
|
||||
|
||||
if (! $header_shown) {
|
||||
$results_operations_html .= $header;
|
||||
@ -4921,8 +4931,7 @@ class Results
|
||||
// show only view and not other options
|
||||
if ($only_view) {
|
||||
$results_operations_html .= $this->_getLinkForCreateView(
|
||||
$analyzed_sql_results,
|
||||
$url_query
|
||||
$analyzed_sql_results, $_url_params
|
||||
);
|
||||
|
||||
if ($header_shown) {
|
||||
@ -4976,7 +4985,8 @@ class Results
|
||||
}
|
||||
|
||||
$results_operations_html .= Util::linkOrButton(
|
||||
'tbl_export.php' . Url::getCommon($_url_params),
|
||||
'tbl_export.php',
|
||||
$_url_params,
|
||||
Util::getIcon(
|
||||
'b_tblexport',
|
||||
__('Export'),
|
||||
@ -4987,7 +4997,8 @@ class Results
|
||||
|
||||
// prepare chart
|
||||
$results_operations_html .= Util::linkOrButton(
|
||||
'tbl_chart.php' . Url::getCommon($_url_params),
|
||||
'tbl_chart.php',
|
||||
$_url_params,
|
||||
Util::getIcon(
|
||||
'b_chart',
|
||||
__('Display chart'),
|
||||
@ -5009,8 +5020,8 @@ class Results
|
||||
if ($geometry_found) {
|
||||
$results_operations_html
|
||||
.= Util::linkOrButton(
|
||||
'tbl_gis_visualization.php'
|
||||
. Url::getCommon($_url_params),
|
||||
'tbl_gis_visualization.php',
|
||||
$_url_params,
|
||||
Util::getIcon(
|
||||
'b_globe',
|
||||
__('Visualize GIS data'),
|
||||
@ -5035,8 +5046,7 @@ class Results
|
||||
}
|
||||
|
||||
$results_operations_html .= $this->_getLinkForCreateView(
|
||||
$analyzed_sql_results,
|
||||
$url_query
|
||||
$analyzed_sql_results, $_url_params
|
||||
);
|
||||
|
||||
if ($header_shown) {
|
||||
@ -5364,7 +5374,8 @@ class Results
|
||||
$tag_params['class'] = 'ajax';
|
||||
}
|
||||
$result .= Util::linkOrButton(
|
||||
'sql.php' . Url::getCommon($_url_params),
|
||||
'sql.php',
|
||||
$_url_params,
|
||||
$displayedData,
|
||||
$tag_params
|
||||
);
|
||||
@ -5438,6 +5449,7 @@ class Results
|
||||
* Prepares an Edit link
|
||||
*
|
||||
* @param string $edit_url edit url
|
||||
* @param array $urlParams URL parameters
|
||||
* @param string $class css classes for td element
|
||||
* @param string $edit_str text for the edit link
|
||||
* @param string $where_clause where clause
|
||||
@ -5451,6 +5463,7 @@ class Results
|
||||
*/
|
||||
private function _getEditLink(
|
||||
$edit_url,
|
||||
$urlParams,
|
||||
$class,
|
||||
$edit_str,
|
||||
$where_clause,
|
||||
@ -5460,7 +5473,7 @@ class Results
|
||||
if (! empty($edit_url)) {
|
||||
$ret .= '<td class="' . $class . ' center print_ignore">'
|
||||
. '<span class="nowrap">'
|
||||
. Util::linkOrButton($edit_url, $edit_str);
|
||||
. Util::linkOrButton($edit_url, $urlParams, $edit_str);
|
||||
/*
|
||||
* Where clause for selecting this row uniquely is provided as
|
||||
* a hidden input. Used by jQuery scripts for handling grid editing
|
||||
@ -5479,6 +5492,7 @@ class Results
|
||||
* Prepares an Copy link
|
||||
*
|
||||
* @param string $copy_url copy url
|
||||
* @param array $urlParams URL parameters
|
||||
* @param string $copy_str text for the copy link
|
||||
* @param string $where_clause where clause
|
||||
* @param string $where_clause_html url encoded where clause
|
||||
@ -5492,6 +5506,7 @@ class Results
|
||||
*/
|
||||
private function _getCopyLink(
|
||||
$copy_url,
|
||||
$urlParams,
|
||||
$copy_str,
|
||||
$where_clause,
|
||||
$where_clause_html,
|
||||
@ -5504,8 +5519,8 @@ class Results
|
||||
$ret .= $class . ' ';
|
||||
}
|
||||
|
||||
$ret .= 'center print_ignore"><span class="nowrap">'
|
||||
. Util::linkOrButton($copy_url, $copy_str);
|
||||
$ret .= 'center print_ignore" ' . ' ><span class="nowrap">'
|
||||
. Util::linkOrButton($copy_url, $urlParams, $copy_str);
|
||||
|
||||
/*
|
||||
* Where clause for selecting this row uniquely is provided as
|
||||
@ -5524,10 +5539,11 @@ class Results
|
||||
/**
|
||||
* Prepares a Delete link
|
||||
*
|
||||
* @param string $del_url delete url
|
||||
* @param string $del_str text for the delete link
|
||||
* @param string $js_conf text for the JS confirmation
|
||||
* @param string $class css classes for the td element
|
||||
* @param string $del_url delete url
|
||||
* @param array $delUrlParams URL parameters
|
||||
* @param string $del_str text for the delete link
|
||||
* @param string $js_conf text for the JS confirmation
|
||||
* @param string $class css classes for the td element
|
||||
*
|
||||
* @return string the generated HTML
|
||||
*
|
||||
@ -5535,7 +5551,7 @@ class Results
|
||||
*
|
||||
* @see _getTableBody(), _getCheckboxAndLinks()
|
||||
*/
|
||||
private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
|
||||
private function _getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, $class)
|
||||
{
|
||||
|
||||
$ret = '';
|
||||
@ -5551,6 +5567,7 @@ class Results
|
||||
$ret .= 'center print_ignore">'
|
||||
. Util::linkOrButton(
|
||||
$del_url,
|
||||
$delUrlParams,
|
||||
$del_str,
|
||||
['class' => 'delete_row requireConfirm' . $ajax]
|
||||
)
|
||||
@ -5579,6 +5596,8 @@ class Results
|
||||
* @param string $copy_str text for the copy link
|
||||
* @param string $del_str text for the delete link
|
||||
* @param string $js_conf text for the JS confirmation
|
||||
* @param array $editCopyUrlParams URL parameters
|
||||
* @param array $delUrlParams URL parameters
|
||||
*
|
||||
* @return string the generated HTML
|
||||
*
|
||||
@ -5600,13 +5619,17 @@ class Results
|
||||
$edit_str,
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams
|
||||
) {
|
||||
$ret = '';
|
||||
$editUrlParams = $editCopyUrlParams + ['default_action' => 'update'];
|
||||
$copyUrlParams = $editCopyUrlParams + ['default_action' => 'insert'];
|
||||
|
||||
if ($position == self::POSITION_LEFT) {
|
||||
$ret .= $this->_getCheckboxForMultiRowSubmissions(
|
||||
$del_url,
|
||||
$del_url . Url::getCommon($delUrlParams),
|
||||
$displayParts,
|
||||
$row_no,
|
||||
$where_clause_html,
|
||||
@ -5617,6 +5640,7 @@ class Results
|
||||
|
||||
$ret .= $this->_getEditLink(
|
||||
$edit_url,
|
||||
$editUrlParams,
|
||||
$class,
|
||||
$edit_str,
|
||||
$where_clause,
|
||||
@ -5625,18 +5649,22 @@ class Results
|
||||
|
||||
$ret .= $this->_getCopyLink(
|
||||
$copy_url,
|
||||
$copyUrlParams,
|
||||
$copy_str,
|
||||
$where_clause,
|
||||
$where_clause_html,
|
||||
''
|
||||
);
|
||||
|
||||
$ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
|
||||
$ret .= $this->_getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, '');
|
||||
|
||||
} elseif ($position == self::POSITION_RIGHT) {
|
||||
$ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
|
||||
|
||||
$ret .= $this->_getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, '');
|
||||
|
||||
$ret .= $this->_getCopyLink(
|
||||
$copy_url,
|
||||
$copyUrlParams,
|
||||
$copy_str,
|
||||
$where_clause,
|
||||
$where_clause_html,
|
||||
@ -5645,6 +5673,7 @@ class Results
|
||||
|
||||
$ret .= $this->_getEditLink(
|
||||
$edit_url,
|
||||
$editUrlParams,
|
||||
$class,
|
||||
$edit_str,
|
||||
$where_clause,
|
||||
@ -5652,7 +5681,7 @@ class Results
|
||||
);
|
||||
|
||||
$ret .= $this->_getCheckboxForMultiRowSubmissions(
|
||||
$del_url,
|
||||
$del_url . Url::getCommon($delUrlParams),
|
||||
$displayParts,
|
||||
$row_no,
|
||||
$where_clause_html,
|
||||
@ -5662,7 +5691,7 @@ class Results
|
||||
);
|
||||
} else { // $position == self::POSITION_NONE
|
||||
$ret .= $this->_getCheckboxForMultiRowSubmissions(
|
||||
$del_url,
|
||||
$del_url . Url::getCommon($delUrlParams),
|
||||
$displayParts,
|
||||
$row_no,
|
||||
$where_clause_html,
|
||||
|
||||
@ -218,6 +218,7 @@ class ErrorReport
|
||||
unset($queryArray["table"]);
|
||||
unset($queryArray["token"]);
|
||||
unset($queryArray["server"]);
|
||||
unset($queryArray["eq"]);
|
||||
$query = http_build_query($queryArray);
|
||||
} else {
|
||||
$query = '';
|
||||
|
||||
@ -499,16 +499,17 @@ class Export
|
||||
*/
|
||||
$back_button = '<p id="export_back_button">[ <a href="';
|
||||
if ($export_type == 'server') {
|
||||
$back_button .= 'server_export.php" data-post="' . Url::getCommon([], '');
|
||||
$back_button .= 'server_export.php" data-post="' . Url::getCommon([], '', false);
|
||||
} elseif ($export_type == 'database') {
|
||||
$back_button .= 'db_export.php" data-post="' . Url::getCommon(['db' => $db], '');
|
||||
$back_button .= 'db_export.php" data-post="' . Url::getCommon(['db' => $db], '', false);
|
||||
} else {
|
||||
$back_button .= 'tbl_export.php" data-post="' . Url::getCommon(
|
||||
[
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
],
|
||||
''
|
||||
'',
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -738,7 +738,7 @@ class Index
|
||||
$r .= '" ' . $row_span . '>'
|
||||
. ' <a class="';
|
||||
$r .= 'ajax';
|
||||
$r .= '" href="tbl_indexes.php" data-post="' . Url::getCommon($this_params, '')
|
||||
$r .= '" href="tbl_indexes.php" data-post="' . Url::getCommon($this_params, '', false)
|
||||
. '">' . Util::getIcon('b_edit', __('Edit')) . '</a>'
|
||||
. '</td>' . "\n";
|
||||
$this_params = $GLOBALS['url_params'];
|
||||
@ -764,7 +764,8 @@ class Index
|
||||
$r .= '<input type="hidden" class="drop_primary_key_index_msg"'
|
||||
. ' value="' . $js_msg . '">';
|
||||
$r .= Util::linkOrButton(
|
||||
'sql.php' . Url::getCommon($this_params),
|
||||
'sql.php',
|
||||
$this_params,
|
||||
Util::getIcon('b_drop', __('Drop')),
|
||||
['class' => 'drop_primary_key_index_anchor ajax']
|
||||
);
|
||||
|
||||
@ -295,12 +295,12 @@ class InsertEdit
|
||||
|
||||
if (! $is_show) {
|
||||
return ' : <a href="tbl_change.php" data-post="'
|
||||
. Url::getCommon($this_url_params, '') . '">'
|
||||
. Url::getCommon($this_url_params, '', false) . '">'
|
||||
. $this->showTypeOrFunctionLabel($which)
|
||||
. '</a>';
|
||||
}
|
||||
return '<th><a href="tbl_change.php" data-post="'
|
||||
. Url::getCommon($this_url_params, '')
|
||||
. Url::getCommon($this_url_params, '', false)
|
||||
. '" title="' . __('Hide') . '">'
|
||||
. $this->showTypeOrFunctionLabel($which)
|
||||
. '</a></th>';
|
||||
@ -888,7 +888,7 @@ class InsertEdit
|
||||
'rownumber' => $rownumber,
|
||||
'data' => $data,
|
||||
],
|
||||
''
|
||||
'', false
|
||||
) . '">'
|
||||
. str_replace("'", "\'", $titles['Browse']) . '</a>';
|
||||
return $html_output;
|
||||
@ -1740,6 +1740,7 @@ class InsertEdit
|
||||
return '<span class="open_gis_editor">'
|
||||
. Util::linkOrButton(
|
||||
'#',
|
||||
null,
|
||||
$edit_str,
|
||||
[],
|
||||
'_blank'
|
||||
|
||||
@ -92,7 +92,8 @@ class Navigation
|
||||
$hasStartChar = strpos($logo['link'], '?');
|
||||
$logo['link'] .= Url::getCommon(
|
||||
[],
|
||||
is_bool($hasStartChar) ? '?' : Url::getArgSeparator()
|
||||
is_bool($hasStartChar) ? '?' : Url::getArgSeparator(),
|
||||
false
|
||||
);
|
||||
}
|
||||
$logo['attributes'] = '';
|
||||
|
||||
@ -123,13 +123,13 @@ class NavigationTree
|
||||
$this->pos = $this->getNavigationDbPos();
|
||||
}
|
||||
// Get the active node
|
||||
if (isset($_REQUEST['aPath'])) {
|
||||
$this->aPath[0] = $this->parsePath($_REQUEST['aPath']);
|
||||
$this->pos2Name[0] = $_REQUEST['pos2_name'];
|
||||
$this->pos2Value[0] = (int) $_REQUEST['pos2_value'];
|
||||
if (isset($_REQUEST['pos3_name'])) {
|
||||
$this->pos3Name[0] = $_REQUEST['pos3_name'];
|
||||
$this->pos3Value[0] = (int) $_REQUEST['pos3_value'];
|
||||
if (isset($_POST['aPath'])) {
|
||||
$this->aPath[0] = $this->parsePath($_POST['aPath']);
|
||||
$this->pos2Name[0] = $_POST['pos2_name'];
|
||||
$this->pos2Value[0] = (int) $_POST['pos2_value'];
|
||||
if (isset($_POST['pos3_name'])) {
|
||||
$this->pos3Name[0] = $_POST['pos3_name'];
|
||||
$this->pos3Value[0] = (int) $_POST['pos3_value'];
|
||||
}
|
||||
} else {
|
||||
if (isset($_POST['n0_aPath'])) {
|
||||
@ -150,8 +150,8 @@ class NavigationTree
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_REQUEST['vPath'])) {
|
||||
$this->vPath[0] = $this->parsePath($_REQUEST['vPath']);
|
||||
if (isset($_POST['vPath'])) {
|
||||
$this->vPath[0] = $this->parsePath($_POST['vPath']);
|
||||
} else {
|
||||
if (isset($_POST['n0_vPath'])) {
|
||||
$count = 0;
|
||||
@ -163,11 +163,11 @@ class NavigationTree
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_REQUEST['searchClause'])) {
|
||||
$this->searchClause = $_REQUEST['searchClause'];
|
||||
if (isset($_POST['searchClause'])) {
|
||||
$this->searchClause = $_POST['searchClause'];
|
||||
}
|
||||
if (isset($_REQUEST['searchClause2'])) {
|
||||
$this->searchClause2 = $_REQUEST['searchClause2'];
|
||||
if (isset($_POST['searchClause2'])) {
|
||||
$this->searchClause2 = $_POST['searchClause2'];
|
||||
}
|
||||
// Initialise the tree by creating a root node
|
||||
$node = NodeFactory::getInstance('NodeDatabaseContainer', 'root');
|
||||
@ -1168,7 +1168,7 @@ class NavigationTree
|
||||
}
|
||||
|
||||
foreach ($icons as $key => $icon) {
|
||||
$link = vsprintf($iconLinks[$key], $args);
|
||||
$link = $this->encryptQueryParams(vsprintf($iconLinks[$key], $args));
|
||||
if ($linkClass != '') {
|
||||
$retval .= "<a class='$linkClass' href='$link'>";
|
||||
$retval .= "{$icon}</a>";
|
||||
@ -1186,7 +1186,7 @@ class NavigationTree
|
||||
foreach ($node->parents(true) as $parent) {
|
||||
$args[] = urlencode($parent->realName);
|
||||
}
|
||||
$link = vsprintf($node->links['text'], $args);
|
||||
$link = $this->encryptQueryParams(vsprintf($node->links['text'], $args));
|
||||
$title = isset($node->links['title']) ? $node->links['title'] : $node->title ?? '';
|
||||
if ($node->type == Node::CONTAINER) {
|
||||
$retval .= " <a class='hover_show_full' href='$link'>";
|
||||
@ -1572,4 +1572,23 @@ class NavigationTree
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encryptQueryParams($link)
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
if (! $PMA_Config->get('URLQueryEncryption')) {
|
||||
return $link;
|
||||
}
|
||||
|
||||
$url = parse_url($link);
|
||||
parse_str(htmlspecialchars_decode($url['query']), $query);
|
||||
|
||||
return $url['path'] . '?' . htmlspecialchars(Url::buildHttpQuery($query));
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,7 +681,7 @@ class NodeDatabase extends Node
|
||||
];
|
||||
$ret = '<span class="dbItemControls">'
|
||||
. '<a href="navigation.php" data-post="'
|
||||
. Url::getCommon($params, '') . '"'
|
||||
. Url::getCommon($params, '', false) . '"'
|
||||
. ' class="showUnhide ajax">'
|
||||
. Util::getImage(
|
||||
'show',
|
||||
|
||||
@ -51,7 +51,7 @@ abstract class NodeDatabaseChild extends Node
|
||||
|
||||
$ret = '<span class="navItemControls">'
|
||||
. '<a href="navigation.php" data-post="'
|
||||
. Url::getCommon($params, '') . '"'
|
||||
. Url::getCommon($params, '', false) . '"'
|
||||
. ' class="hideNavItem ajax">'
|
||||
. Util::getImage('hide', __('Hide'))
|
||||
. '</a></span>';
|
||||
|
||||
@ -1589,7 +1589,8 @@ class Operations
|
||||
{
|
||||
return '<li>'
|
||||
. Util::linkOrButton(
|
||||
'sql.php' . Url::getCommon(array_merge($url_params, $params)),
|
||||
'sql.php',
|
||||
array_merge($url_params, $params),
|
||||
$action_message,
|
||||
['class' => 'maintain_action ajax']
|
||||
)
|
||||
@ -1649,7 +1650,8 @@ class Operations
|
||||
public function getDeleteDataOrTablelink(array $url_params, $syntax, $link, $htmlId)
|
||||
{
|
||||
return '<li>' . Util::linkOrButton(
|
||||
'sql.php' . Url::getCommon($url_params),
|
||||
'sql.php',
|
||||
$url_params,
|
||||
$link,
|
||||
[
|
||||
'id' => $htmlId,
|
||||
|
||||
@ -12,6 +12,7 @@ namespace PhpMyAdmin\Plugins\Auth;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Plugins\AuthenticationPlugin;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
@ -28,6 +29,7 @@ class AuthenticationSignon extends AuthenticationPlugin
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
Response::getInstance()->disable();
|
||||
unset($_SESSION['LAST_SIGNON_URL']);
|
||||
if (empty($GLOBALS['cfg']['Server']['SignonURL'])) {
|
||||
Core::fatalError('You must set SignonURL!');
|
||||
|
||||
@ -133,7 +133,7 @@ class ReplicationGui
|
||||
}
|
||||
|
||||
$urlParams['sr_slave_control_parm'] = 'IO_THREAD';
|
||||
$slaveControlIoLink = Url::getCommon($urlParams, '');
|
||||
$slaveControlIoLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
if ($serverSlaveReplication[0]['Slave_SQL_Running'] == 'No') {
|
||||
$urlParams['sr_slave_action'] = 'start';
|
||||
@ -142,7 +142,7 @@ class ReplicationGui
|
||||
}
|
||||
|
||||
$urlParams['sr_slave_control_parm'] = 'SQL_THREAD';
|
||||
$slaveControlSqlLink = Url::getCommon($urlParams, '');
|
||||
$slaveControlSqlLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
if ($serverSlaveReplication[0]['Slave_IO_Running'] == 'No'
|
||||
|| $serverSlaveReplication[0]['Slave_SQL_Running'] == 'No'
|
||||
@ -153,21 +153,21 @@ class ReplicationGui
|
||||
}
|
||||
|
||||
$urlParams['sr_slave_control_parm'] = null;
|
||||
$slaveControlFullLink = Url::getCommon($urlParams, '');
|
||||
$slaveControlFullLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
$urlParams['sr_slave_action'] = 'reset';
|
||||
$slaveControlResetLink = Url::getCommon($urlParams, '');
|
||||
$slaveControlResetLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
$urlParams = $GLOBALS['url_params'];
|
||||
$urlParams['sr_take_action'] = true;
|
||||
$urlParams['sr_slave_skip_error'] = true;
|
||||
$slaveSkipErrorLink = Url::getCommon($urlParams, '');
|
||||
$slaveSkipErrorLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
$urlParams = $GLOBALS['url_params'];
|
||||
$urlParams['sl_configure'] = true;
|
||||
$urlParams['repl_clear_scr'] = true;
|
||||
|
||||
$reconfigureMasterLink = Url::getCommon($urlParams, '');
|
||||
$reconfigureMasterLink = Url::getCommon($urlParams, '', false);
|
||||
|
||||
$slaveStatusTable = $this->getHtmlForReplicationStatusTable('slave', true, false);
|
||||
|
||||
|
||||
@ -221,7 +221,7 @@ class RteList
|
||||
*/
|
||||
public function getRoutineRow(array $routine, $rowclass = '')
|
||||
{
|
||||
global $url_query, $db, $titles;
|
||||
global $url_query, $url_params, $db, $titles;
|
||||
|
||||
$sql_drop = sprintf(
|
||||
'DROP %s IF EXISTS %s',
|
||||
@ -348,7 +348,11 @@ class RteList
|
||||
$retval .= " </td>\n";
|
||||
$retval .= " <td>\n";
|
||||
$retval .= Util::linkOrButton(
|
||||
'sql.php' . $url_query . '&sql_query=' . urlencode($sql_drop) . '&goto=db_routines.php' . urlencode("?db={$db}"),
|
||||
'sql.php',
|
||||
array_merge(
|
||||
$url_params,
|
||||
['sql_query' => $sql_drop, 'goto' => 'db_routines.php' . Url::getCommon(['db' => $db])]
|
||||
),
|
||||
$titles['Drop'],
|
||||
['class' => 'ajax drop_anchor']
|
||||
);
|
||||
@ -375,7 +379,7 @@ class RteList
|
||||
*/
|
||||
public function getTriggerRow(array $trigger, $rowclass = '')
|
||||
{
|
||||
global $url_query, $db, $table, $titles;
|
||||
global $url_query, $url_params, $db, $table, $titles;
|
||||
|
||||
$retval = " <tr class='$rowclass'>\n";
|
||||
$retval .= " <td>\n";
|
||||
@ -392,8 +396,8 @@ class RteList
|
||||
$retval .= " </td>\n";
|
||||
if (empty($table)) {
|
||||
$retval .= " <td>\n";
|
||||
$retval .= "<a href='db_triggers.php{$url_query}"
|
||||
. "&table=" . urlencode($trigger['table']) . "'>"
|
||||
$retval .= "<a href='db_triggers.php"
|
||||
. Url::getCommon(array_merge($url_params, ['table' => $trigger['table']])) . "'>"
|
||||
. htmlspecialchars($trigger['table']) . "</a>";
|
||||
$retval .= " </td>\n";
|
||||
}
|
||||
@ -422,7 +426,11 @@ class RteList
|
||||
$retval .= " <td>\n";
|
||||
if (Util::currentUserHasPrivilege('TRIGGER', $db)) {
|
||||
$retval .= Util::linkOrButton(
|
||||
'sql.php' . $url_query . '&sql_query=' . urlencode($trigger['drop']) . '&goto=db_triggers.php' . urlencode("?db={$db}"),
|
||||
'sql.php',
|
||||
array_merge(
|
||||
$url_params,
|
||||
['sql_query' => $trigger['drop'], 'goto' => 'db_triggers.php' . Url::getCommon(['db' => $db])]
|
||||
),
|
||||
$titles['Drop'],
|
||||
['class' => 'ajax drop_anchor']
|
||||
);
|
||||
@ -451,7 +459,7 @@ class RteList
|
||||
*/
|
||||
public function getEventRow(array $event, $rowclass = '')
|
||||
{
|
||||
global $url_query, $db, $titles;
|
||||
global $url_query, $url_params, $db, $titles;
|
||||
|
||||
$sql_drop = sprintf(
|
||||
'DROP EVENT IF EXISTS %s',
|
||||
@ -500,7 +508,11 @@ class RteList
|
||||
$retval .= " <td>\n";
|
||||
if (Util::currentUserHasPrivilege('EVENT', $db)) {
|
||||
$retval .= Util::linkOrButton(
|
||||
'sql.php' . $url_query . '&sql_query=' . urlencode($sql_drop) . '&goto=db_events.php' . urlencode("?db={$db}"),
|
||||
'sql.php',
|
||||
array_merge(
|
||||
$url_params,
|
||||
['sql_query' => $sql_drop, 'goto' => 'db_events.php' . Url::getCommon(['db' => $db])]
|
||||
),
|
||||
$titles['Drop'],
|
||||
['class' => 'ajax drop_anchor']
|
||||
);
|
||||
|
||||
@ -2985,7 +2985,7 @@ class Privileges
|
||||
|
||||
$html .= ' href="server_privileges.php';
|
||||
if ($linktype == 'revoke') {
|
||||
$html .= '" data-post="' . Url::getCommon($params, '');
|
||||
$html .= '" data-post="' . Url::getCommon($params, '', false);
|
||||
} else {
|
||||
$html .= Url::getCommon($params);
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ class UserGroups
|
||||
'viewUsers' => 1,
|
||||
'userGroup' => $groupName,
|
||||
],
|
||||
''
|
||||
'', false
|
||||
)
|
||||
. '">'
|
||||
. Util::getIcon('b_usrlist', __('View users'))
|
||||
@ -130,7 +130,7 @@ class UserGroups
|
||||
'editUserGroup' => 1,
|
||||
'userGroup' => $groupName,
|
||||
],
|
||||
''
|
||||
'', false
|
||||
)
|
||||
. '">'
|
||||
. Util::getIcon('b_edit', __('Edit')) . '</a>';
|
||||
@ -142,7 +142,7 @@ class UserGroups
|
||||
'deleteUserGroup' => 1,
|
||||
'userGroup' => $groupName,
|
||||
],
|
||||
''
|
||||
'', false
|
||||
)
|
||||
. '">'
|
||||
. Util::getIcon('b_drop', __('Delete')) . '</a>';
|
||||
|
||||
@ -649,7 +649,7 @@ class Tracking
|
||||
'report' => 'true',
|
||||
'version' => $_POST['version'],
|
||||
$deleteParam => $lineNumber - $offset,
|
||||
], '');
|
||||
], '', false);
|
||||
$entry['line_number'] = $lineNumber;
|
||||
$entries[] = $entry;
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Crypto\Crypto;
|
||||
|
||||
/**
|
||||
* Static methods for URL/hidden inputs generating
|
||||
*
|
||||
@ -161,14 +163,15 @@ class Url
|
||||
*
|
||||
* @param mixed $params optional, Contains an associative array with url params
|
||||
* @param string $divider optional character to use instead of '?'
|
||||
* @param bool $encrypt whether to encrypt URL params
|
||||
*
|
||||
* @return string string with URL parameters
|
||||
* @access public
|
||||
*/
|
||||
public static function getCommon($params = [], $divider = '?')
|
||||
public static function getCommon($params = [], $divider = '?', $encrypt = true)
|
||||
{
|
||||
return htmlspecialchars(
|
||||
Url::getCommonRaw($params, $divider)
|
||||
Url::getCommonRaw($params, $divider, $encrypt)
|
||||
);
|
||||
}
|
||||
|
||||
@ -197,15 +200,15 @@ class Url
|
||||
*
|
||||
* @param mixed $params optional, Contains an associative array with url params
|
||||
* @param string $divider optional character to use instead of '?'
|
||||
* @param bool $encrypt whether to encrypt URL params
|
||||
*
|
||||
* @return string string with URL parameters
|
||||
* @access public
|
||||
*/
|
||||
public static function getCommonRaw($params = [], $divider = '?')
|
||||
public static function getCommonRaw($params = [], $divider = '?', $encrypt = true)
|
||||
{
|
||||
/** @var Config $PMA_Config */
|
||||
global $PMA_Config;
|
||||
$separator = Url::getArgSeparator();
|
||||
|
||||
// avoid overwriting when creating navi panel links to servers
|
||||
if (isset($GLOBALS['server'])
|
||||
@ -222,7 +225,7 @@ class Url
|
||||
$params['lang'] = $GLOBALS['lang'];
|
||||
}
|
||||
|
||||
$query = http_build_query($params, '', $separator);
|
||||
$query = self::buildHttpQuery($params, $encrypt);
|
||||
|
||||
if ($divider != '?' || strlen($query) > 0) {
|
||||
return $divider . $query;
|
||||
@ -231,6 +234,81 @@ class Url
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
* @param bool $encrypt whether to encrypt URL params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function buildHttpQuery($params, $encrypt = true)
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$separator = self::getArgSeparator();
|
||||
|
||||
if (! $encrypt || ! $PMA_Config->get('URLQueryEncryption')) {
|
||||
return http_build_query($params, '', $separator);
|
||||
}
|
||||
|
||||
$data = $params;
|
||||
$keys = [
|
||||
'db',
|
||||
'table',
|
||||
'field',
|
||||
'sql_query',
|
||||
'sql_signature',
|
||||
'where_clause',
|
||||
'goto',
|
||||
'back',
|
||||
'message_to_show',
|
||||
'username',
|
||||
'hostname',
|
||||
'dbname',
|
||||
'tablename',
|
||||
'checkprivsdb',
|
||||
'checkprivstable',
|
||||
];
|
||||
$paramsToEncrypt = [];
|
||||
foreach ($params as $paramKey => $paramValue) {
|
||||
if (! in_array($paramKey, $keys)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramsToEncrypt[$paramKey] = $paramValue;
|
||||
unset($data[$paramKey]);
|
||||
}
|
||||
|
||||
if ($paramsToEncrypt !== []) {
|
||||
$data['eq'] = self::encryptQuery(json_encode($paramsToEncrypt));
|
||||
}
|
||||
|
||||
return http_build_query($data, '', $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encryptQuery($query)
|
||||
{
|
||||
$crypto = new Crypto();
|
||||
|
||||
return strtr(base64_encode($crypto->encrypt($query)), '+/', '-_');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function decryptQuery($query)
|
||||
{
|
||||
$crypto = new Crypto();
|
||||
|
||||
return $crypto->decrypt(base64_decode(strtr($query, '-_', '+/')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns url separator
|
||||
*
|
||||
|
||||
@ -1096,7 +1096,8 @@ class Util
|
||||
$explain_params['sql_query'] = 'EXPLAIN ' . $sql_query;
|
||||
$explain_link = ' [ '
|
||||
. self::linkOrButton(
|
||||
'import.php' . Url::getCommon($explain_params),
|
||||
'import.php',
|
||||
$explain_params,
|
||||
__('Explain SQL')
|
||||
) . ' ]';
|
||||
} elseif (preg_match(
|
||||
@ -1107,7 +1108,8 @@ class Util
|
||||
= mb_substr($sql_query, 8);
|
||||
$explain_link = ' [ '
|
||||
. self::linkOrButton(
|
||||
'import.php' . Url::getCommon($explain_params),
|
||||
'import.php',
|
||||
$explain_params,
|
||||
__('Skip Explain SQL')
|
||||
) . ']';
|
||||
$url = 'https://mariadb.org/explain_analyzer/analyze/'
|
||||
@ -1116,6 +1118,7 @@ class Util
|
||||
$explain_link .= ' ['
|
||||
. self::linkOrButton(
|
||||
htmlspecialchars('url.php?url=' . urlencode($url)),
|
||||
null,
|
||||
sprintf(__('Analyze Explain at %s'), 'mariadb.org'),
|
||||
[],
|
||||
'_blank'
|
||||
@ -1131,9 +1134,8 @@ class Util
|
||||
if (! empty($cfg['SQLQuery']['Edit'])
|
||||
&& empty($GLOBALS['show_as_php'])
|
||||
) {
|
||||
$edit_link .= Url::getCommon($url_params);
|
||||
$edit_link = ' [ '
|
||||
. self::linkOrButton($edit_link, __('Edit'))
|
||||
. self::linkOrButton($edit_link, $url_params, __('Edit'))
|
||||
. ' ]';
|
||||
} else {
|
||||
$edit_link = '';
|
||||
@ -1145,14 +1147,16 @@ class Util
|
||||
if (! empty($GLOBALS['show_as_php'])) {
|
||||
$php_link = ' [ '
|
||||
. self::linkOrButton(
|
||||
'import.php' . Url::getCommon($url_params),
|
||||
'import.php',
|
||||
$url_params,
|
||||
__('Without PHP code')
|
||||
)
|
||||
. ' ]';
|
||||
|
||||
$php_link .= ' [ '
|
||||
. self::linkOrButton(
|
||||
'import.php' . Url::getCommon($url_params),
|
||||
'import.php',
|
||||
$url_params,
|
||||
__('Submit query')
|
||||
)
|
||||
. ' ]';
|
||||
@ -1161,7 +1165,8 @@ class Util
|
||||
$php_params['show_as_php'] = 1;
|
||||
$php_link = ' [ '
|
||||
. self::linkOrButton(
|
||||
'import.php' . Url::getCommon($php_params),
|
||||
'import.php',
|
||||
$php_params,
|
||||
__('Create PHP code')
|
||||
)
|
||||
. ' ]';
|
||||
@ -1177,7 +1182,7 @@ class Util
|
||||
) {
|
||||
$refresh_link = 'sql.php' . Url::getCommon($url_params);
|
||||
$refresh_link = ' [ '
|
||||
. self::linkOrButton($refresh_link, __('Refresh')) . ']';
|
||||
. self::linkOrButton('import.php', $url_params, __('Refresh')) . ']';
|
||||
} else {
|
||||
$refresh_link = '';
|
||||
} //refresh
|
||||
@ -1216,6 +1221,7 @@ class Util
|
||||
$inline_edit_link = ' ['
|
||||
. self::linkOrButton(
|
||||
'#',
|
||||
null,
|
||||
_pgettext('Inline edit query', 'Edit inline'),
|
||||
['class' => 'inline_edit_sql']
|
||||
)
|
||||
@ -1785,20 +1791,26 @@ class Util
|
||||
* - URL components are over Suhosin limits
|
||||
* - There is SQL query in the parameters
|
||||
*
|
||||
* @param string $url the URL
|
||||
* @param string $message the link message
|
||||
* @param mixed $tag_params string: js confirmation; array: additional tag
|
||||
* params (f.e. style="")
|
||||
* @param string $target target
|
||||
* @param string $urlPath the URL
|
||||
* @param array|null $urlParams URL parameters
|
||||
* @param string $message the link message
|
||||
* @param mixed $tag_params string: js confirmation; array: additional tag params (f.e. style="")
|
||||
* @param string $target target
|
||||
*
|
||||
* @return string the results to be echoed or saved in an array
|
||||
*/
|
||||
public static function linkOrButton(
|
||||
$url,
|
||||
$urlPath,
|
||||
$urlParams,
|
||||
$message,
|
||||
$tag_params = [],
|
||||
$target = ''
|
||||
) {
|
||||
$url = $urlPath;
|
||||
if (is_array($urlParams)) {
|
||||
$url = $urlPath . Url::getCommon($urlParams, '?', false);
|
||||
}
|
||||
|
||||
$url_length = strlen($url);
|
||||
|
||||
if (! is_array($tag_params)) {
|
||||
@ -1857,6 +1869,11 @@ class Util
|
||||
) {
|
||||
$url .= '?' . explode('&', $parts[1], 2)[0];
|
||||
}
|
||||
} else {
|
||||
$url = $urlPath;
|
||||
if (is_array($urlParams)) {
|
||||
$url = $urlPath . Url::getCommon($urlParams);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tag_params as $par_name => $par_value) {
|
||||
@ -2427,13 +2444,15 @@ class Util
|
||||
|
||||
$_url_params[$name] = 0;
|
||||
$list_navigator_html .= '<a' . $class . $title1 . ' href="' . $script
|
||||
. Url::getCommon($_url_params) . '">' . $caption1
|
||||
. '</a>';
|
||||
. '" data-post="'
|
||||
. Url::getCommon($_url_params, '', false)
|
||||
. '">' . $caption1 . '</a>';
|
||||
|
||||
$_url_params[$name] = $pos - $max_count;
|
||||
$list_navigator_html .= ' <a' . $class . $title2
|
||||
. ' href="' . $script . Url::getCommon($_url_params) . '">'
|
||||
. $caption2 . '</a>';
|
||||
$list_navigator_html .= ' <a' . $class . $title2 . ' href="' . $script
|
||||
. '" data-post="'
|
||||
. Url::getCommon($_url_params, '', false)
|
||||
. '">' . $caption2 . '</a>';
|
||||
}
|
||||
|
||||
$list_navigator_html .= '<form action="' . basename($script)
|
||||
@ -2464,17 +2483,19 @@ class Util
|
||||
|
||||
$_url_params[$name] = $pos + $max_count;
|
||||
$list_navigator_html .= '<a' . $class . $title3 . ' href="' . $script
|
||||
. Url::getCommon($_url_params) . '" >' . $caption3
|
||||
. '</a>';
|
||||
. '" data-post="'
|
||||
. Url::getCommon($_url_params, '', false)
|
||||
. '" >' . $caption3 . '</a>';
|
||||
|
||||
$_url_params[$name] = floor($count / $max_count) * $max_count;
|
||||
if ($_url_params[$name] == $count) {
|
||||
$_url_params[$name] = $count - $max_count;
|
||||
}
|
||||
|
||||
$list_navigator_html .= ' <a' . $class . $title4
|
||||
. ' href="' . $script . Url::getCommon($_url_params) . '" >'
|
||||
. $caption4 . '</a>';
|
||||
$list_navigator_html .= ' <a' . $class . $title4 . ' href="' . $script
|
||||
. '" data-post="'
|
||||
. Url::getCommon($_url_params, '', false)
|
||||
. '" >' . $caption4 . '</a>';
|
||||
}
|
||||
$list_navigator_html .= '</div>' . "\n";
|
||||
}
|
||||
@ -4969,9 +4990,7 @@ class Util
|
||||
$urlParams['tbl_group'] = $_REQUEST['tbl_group'];
|
||||
}
|
||||
|
||||
$url = 'db_structure.php' . Url::getCommon($urlParams);
|
||||
|
||||
return self::linkOrButton($url, $title . $orderImg, $orderLinkParams);
|
||||
return self::linkOrButton('db_structure.php', $urlParams, $title . $orderImg, $orderLinkParams);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -137,6 +137,8 @@ if (! defined('PMA_NO_SESSION')) {
|
||||
Session::setUp($GLOBALS['PMA_Config'], $GLOBALS['error_handler']);
|
||||
}
|
||||
|
||||
Core::populateRequestWithEncryptedQueryParams();
|
||||
|
||||
/**
|
||||
* init some variables LABEL_variables_init
|
||||
*/
|
||||
|
||||
@ -606,6 +606,13 @@ $cfg['Servers'][$i]['tracking_add_drop_table'] = true;
|
||||
*/
|
||||
$cfg['Servers'][$i]['tracking_add_drop_database'] = true;
|
||||
|
||||
/**
|
||||
* Whether to show or hide detailed MySQL/MariaDB connection errors on the login page.
|
||||
*
|
||||
* @global bool $cfg['Servers'][$i]['hide_connection_errors']
|
||||
*/
|
||||
$cfg['Servers'][$i]['hide_connection_errors'] = false;
|
||||
|
||||
/**
|
||||
* Default server (0 = no default server)
|
||||
*
|
||||
@ -820,6 +827,20 @@ $cfg['UseDbSearch'] = true;
|
||||
*/
|
||||
$cfg['IgnoreMultiSubmitErrors'] = false;
|
||||
|
||||
/**
|
||||
* Define whether phpMyAdmin will encrypt sensitive data from the URL query string.
|
||||
*
|
||||
* @global bool $cfg['URLQueryEncryption']
|
||||
*/
|
||||
$cfg['URLQueryEncryption'] = false;
|
||||
|
||||
/**
|
||||
* A secret key used to encrypt/decrypt the URL query string. Should be 32 bytes long.
|
||||
*
|
||||
* @global string $cfg['URLQueryEncryptionSecretKey']
|
||||
*/
|
||||
$cfg['URLQueryEncryptionSecretKey'] = '';
|
||||
|
||||
/**
|
||||
* allow login to any user entered server in cookie based authentication
|
||||
*
|
||||
|
||||
@ -247,20 +247,7 @@ if [ ! -d libraries/tcpdf ] ; then
|
||||
echo "* Running composer"
|
||||
composer config platform.php "$PHP_REQ"
|
||||
composer update --no-dev
|
||||
|
||||
# Parse the required versions from composer.json
|
||||
PACKAGES_VERSIONS=''
|
||||
case "$branch" in
|
||||
QA_4*) PACKAGE_LIST="tecnickcom/tcpdf pragmarx/google2fa bacon/bacon-qr-code samyoul/u2f-php-server" ;;
|
||||
*) PACKAGE_LIST="tecnickcom/tcpdf pragmarx/google2fa-qrcode samyoul/u2f-php-server" ;;
|
||||
esac
|
||||
|
||||
for PACKAGES in $PACKAGE_LIST
|
||||
do
|
||||
PACKAGES_VERSIONS="$PACKAGES_VERSIONS $PACKAGES:`awk "/require-dev/ {printline = 1; print; next } printline" composer.json | grep "$PACKAGES" | awk -F [\\"] '{print $4}'`"
|
||||
done
|
||||
composer require --update-no-dev $PACKAGES_VERSIONS
|
||||
|
||||
composer require --update-no-dev tecnickcom/tcpdf:\^6.3 pragmarx/google2fa:\^3.0.0 bacon/bacon-qr-code:\^1.0.0 samyoul/u2f-php-server:\^1.1
|
||||
mv composer.json.backup composer.json
|
||||
echo "* Cleanup of composer packages"
|
||||
rm -rf \
|
||||
@ -290,8 +277,8 @@ if [ ! -d libraries/tcpdf ] ; then
|
||||
vendor/twig/twig/test \
|
||||
vendor/google/recaptcha/examples/ \
|
||||
vendor/google/recaptcha/tests/
|
||||
find vendor/phpseclib/phpseclib/phpseclib/Crypt/ -maxdepth 1 -type f -not -name AES.php -not -name Base.php -not -name Random.php -not -name Rijndael.php -print0 | xargs -0 rm
|
||||
find vendor/tecnickcom/tcpdf/fonts/ -maxdepth 1 -type f -not -name 'dejavusans.*' -not -name 'dejavusansb.*' -not -name 'helvetica.php' -print0 | xargs -0 rm
|
||||
find vendor/phpseclib/phpseclib/phpseclib/Crypt/ -maxdepth 1 -type f -not -name AES.php -not -name Base.php -not -name Random.php -not -name Rijndael.php -print0 | xargs -0 rm -f
|
||||
find vendor/tecnickcom/tcpdf/fonts/ -maxdepth 1 -type f -not -name 'dejavusans.*' -not -name 'dejavusansb.*' -not -name 'helvetica.php' -print0 | xargs -0 rm -f
|
||||
if [ $do_tag -eq 1 ] ; then
|
||||
echo "* Commiting composer.lock"
|
||||
git add --force composer.lock
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
'back': 'db_tracking.php',
|
||||
'table': version.table_name,
|
||||
'delete_tracking': true
|
||||
}, '') }}">
|
||||
}, '', false) }}">
|
||||
{{ get_icon('b_drop', 'Delete tracking'|trans) }}
|
||||
</a>
|
||||
</td>
|
||||
@ -63,7 +63,7 @@
|
||||
'goto': 'tbl_tracking.php',
|
||||
'back': 'db_tracking.php',
|
||||
'table': version.table_name
|
||||
}, '') }}">
|
||||
}, '', false) }}">
|
||||
{{ get_icon('b_versions', 'Versions'|trans) }}
|
||||
</a>
|
||||
<a href="tbl_tracking.php" data-post="
|
||||
@ -74,7 +74,7 @@
|
||||
'table': version.table_name,
|
||||
'report': true,
|
||||
'version': version.version
|
||||
}, '') }}">
|
||||
}, '', false) }}">
|
||||
{{ get_icon('b_report', 'Tracking report'|trans) }}
|
||||
</a>
|
||||
<a href="tbl_tracking.php" data-post="
|
||||
@ -85,7 +85,7 @@
|
||||
'table': version.table_name,
|
||||
'snapshot': true,
|
||||
'version': version.version
|
||||
}, '') }}">
|
||||
}, '', false) }}">
|
||||
{{ get_icon('b_props', 'Structure snapshot'|trans) }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@ -43,12 +43,12 @@
|
||||
<td colspan="6" class="center">
|
||||
{% if has_previous %}
|
||||
{% if has_icons %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(previous_params, '') }}" title="
|
||||
<a href="server_binlog.php" data-post="{{ get_common(previous_params, '', false) }}" title="
|
||||
{%- trans %}Previous{% context %}Previous page{% endtrans %}">
|
||||
«
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(previous_params, '') }}">
|
||||
<a href="server_binlog.php" data-post="{{ get_common(previous_params, '', false) }}">
|
||||
{% trans %}Previous{% context %}Previous page{% endtrans %} «
|
||||
</a>
|
||||
{% endif %}
|
||||
@ -56,11 +56,11 @@
|
||||
{% endif %}
|
||||
|
||||
{% if is_full_query %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(full_queries_params, '') }}" title="{% trans 'Truncate shown queries' %}">
|
||||
<a href="server_binlog.php" data-post="{{ get_common(full_queries_params, '', false) }}" title="{% trans 'Truncate shown queries' %}">
|
||||
<img src="{{ image_path }}s_partialtext.png" alt="{% trans 'Truncate shown queries' %}">
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(full_queries_params, '') }}" title="{% trans 'Show full queries' %}">
|
||||
<a href="server_binlog.php" data-post="{{ get_common(full_queries_params, '', false) }}" title="{% trans 'Show full queries' %}">
|
||||
<img src="{{ image_path }}s_fulltext.png" alt="{% trans 'Show full queries' %}">
|
||||
</a>
|
||||
{% endif %}
|
||||
@ -68,12 +68,12 @@
|
||||
{% if has_next %}
|
||||
-
|
||||
{% if has_icons %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(next_params, '') }}" title="
|
||||
<a href="server_binlog.php" data-post="{{ get_common(next_params, '', false) }}" title="
|
||||
{%- trans %}Next{% context %}Next page{% endtrans %}">
|
||||
»
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="server_binlog.php" data-post="{{ get_common(next_params, '') }}">
|
||||
<a href="server_binlog.php" data-post="{{ get_common(next_params, '', false) }}">
|
||||
{% trans %}Next{% context %}Next page{% endtrans %} »
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@ -310,7 +310,7 @@
|
||||
{{ 'Note: Enabling the database statistics here might cause heavy traffic between the web server and the MySQL server.'|trans|notice }}
|
||||
<ul>
|
||||
<li class="li_switch_dbstats">
|
||||
<a href="server_databases.php" data-post="{{ get_common({'statistics': '1'}, '') }}" title="{% trans 'Enable statistics' %}">
|
||||
<a href="server_databases.php" data-post="{{ get_common({'statistics': '1'}, '', false) }}" title="{% trans 'Enable statistics' %}">
|
||||
<strong>{% trans 'Enable statistics' %}</strong>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a href="server_replication.php" data-post="{{ get_common(url_params, '') }}" id="master_addslaveuser_href">
|
||||
<a href="server_replication.php" data-post="{{ get_common(url_params, '', false) }}" id="master_addslaveuser_href">
|
||||
{% trans 'Add slave replication user' %}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
{% apply format('<a href="server_replication.php" data-post="' ~ get_common(url_params|merge({
|
||||
'sl_configure': true,
|
||||
'repl_clear_scr': true
|
||||
})) ~ '">', '</a>')|raw %}
|
||||
}, '', false)) ~ '">', '</a>')|raw %}
|
||||
{% trans 'This server is not configured as slave in a replication process. Would you like to %sconfigure%s it?' %}
|
||||
{% endapply %}
|
||||
{% endif %}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<th>{% trans 'Processes' %}</th>
|
||||
{% for column in columns %}
|
||||
<th>
|
||||
<a href="server_status_processes.php" data-post="{{ get_common(column.params) }}" class="sortlink">
|
||||
<a href="server_status_processes.php" data-post="{{ get_common(column.params, '', false) }}" class="sortlink">
|
||||
{{ column.name }}
|
||||
{% if column.is_sorted %}
|
||||
<img class="icon ic_s_desc soimg" alt="
|
||||
@ -15,7 +15,7 @@
|
||||
{% endif %}
|
||||
</a>
|
||||
{% if column.has_full_query %}
|
||||
<a href="server_status_processes.php" data-post="{{ get_common(refresh_params, '') }}">
|
||||
<a href="server_status_processes.php" data-post="{{ get_common(refresh_params, '', false) }}">
|
||||
{% if column.is_full %}
|
||||
{{ get_image(
|
||||
's_partialtext',
|
||||
@ -40,7 +40,7 @@
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="ajax kill_process" href="server_status_processes.php" data-post="{{ get_common({'kill': row.id}, '') }}">
|
||||
<a class="ajax kill_process" href="server_status_processes.php" data-post="{{ get_common({'kill': row.id}, '', false) }}">
|
||||
{% trans 'Kill' %}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
</a>
|
||||
|
|
||||
<a class="delete-server" href="{{ get_common(server.params.remove) }}" data-post="
|
||||
{{- get_common({ token: server.params.token }, '') }}">
|
||||
{{- get_common({ token: server.params.token }, '', false) }}">
|
||||
{% trans 'Delete' %}
|
||||
</a>
|
||||
</small>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<span class="curr_value">{{ current_value }}</span>
|
||||
<a href="browse_foreigners.php" data-post="{{ get_common(params, '') }}" class="ajax browse_foreign">
|
||||
<a href="browse_foreigners.php" data-post="{{ get_common(params, '', false) }}" class="ajax browse_foreign">
|
||||
{% trans 'Browse foreign values' %}
|
||||
</a>
|
||||
|
||||
@ -22,9 +22,8 @@
|
||||
{% if one_key['constraint'] is defined %}
|
||||
<input type="hidden" class="drop_foreign_key_msg" value="
|
||||
{{- js_msg }}">
|
||||
{% set drop_url = 'sql.php' ~ get_common(this_params) %}
|
||||
{% set drop_str = get_icon('b_drop', 'Drop'|trans) %}
|
||||
{{ link_or_button(drop_url, drop_str, {'class': 'drop_foreign_key_anchor ajax'}) }}
|
||||
{{ link_or_button('sql.php', this_params, drop_str, {'class': 'drop_foreign_key_anchor ajax'}) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
value="{{ criteria_values[column_index] }}"
|
||||
{% endif %}>
|
||||
<a class="ajax browse_foreign" href="browse_foreigners.php" data-post="
|
||||
{{- get_common({'db': db, 'table': table}, '') -}}
|
||||
{{- get_common({'db': db, 'table': table}, '', false) -}}
|
||||
&field={{ column_name|url_encode }}&fieldkey=
|
||||
{{- column_index }}&fromsearch=1">
|
||||
{{ titles['Browse']|replace({"'": "\\'"})|raw }}
|
||||
@ -34,10 +34,9 @@
|
||||
class="textfield"
|
||||
id="field_{{ column_index }}">
|
||||
{% if in_fbs %}
|
||||
{% set edit_url = 'gis_data_editor.php' ~ get_common() %}
|
||||
{% set edit_str = get_icon('b_edit', 'Edit/Insert'|trans) %}
|
||||
<span class="open_search_gis_editor">
|
||||
{{ link_or_button(edit_url, edit_str, [], '_blank') }}
|
||||
{{ link_or_button('gis_data_editor.php', [], edit_str, [], '_blank') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% elseif column_type starts with 'enum'
|
||||
|
||||
@ -134,7 +134,7 @@
|
||||
{% if partitions is empty %}
|
||||
<input class="btn btn-secondary" type="submit" name="edit_partitioning" value="{% trans 'Partition table' %}">
|
||||
{% else %}
|
||||
{{ link_or_button(remove_url, 'Remove partitioning'|trans, {
|
||||
{{ link_or_button('sql.php', remove_url_params, 'Remove partitioning'|trans, {
|
||||
'class': 'button ajax',
|
||||
'id': 'remove_partitioning'
|
||||
}) }}
|
||||
|
||||
@ -372,9 +372,9 @@
|
||||
{# Work on the table #}
|
||||
<div id="structure-action-links">
|
||||
{% if tbl_is_view and not db_is_system_schema %}
|
||||
{% set edit_view_url = 'view_create.php' ~ edit_view_url %}
|
||||
{{ link_or_button(
|
||||
edit_view_url,
|
||||
'view_create.php',
|
||||
{'db': db, 'table': table},
|
||||
get_icon('b_edit', 'Edit view'|trans, true)
|
||||
) }}
|
||||
{% endif %}
|
||||
@ -481,7 +481,6 @@
|
||||
} only %}
|
||||
|
||||
{% set remove_sql = 'ALTER TABLE ' ~ backquote(table) ~ ' REMOVE PARTITIONING' %}
|
||||
{% set remove_url = 'sql.php' ~ url_query ~ '&sql_query=' ~ remove_sql|url_encode %}
|
||||
|
||||
{% include 'table/structure/display_partitions.twig' with {
|
||||
'db': db,
|
||||
@ -496,7 +495,7 @@
|
||||
'sub_partition_expression': has_sub_partitions ? first_sub_partition.getExpression(),
|
||||
'action_icons': action_icons,
|
||||
'range_or_list': range_or_list,
|
||||
'remove_url': remove_url
|
||||
'remove_url_params': url_params|merge({'sql_query': remove_sql})
|
||||
} only %}
|
||||
{% else %}
|
||||
{% include 'table/structure/display_partitions.twig' with {
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
{{- get_common(url_params|merge({
|
||||
'version': version['version'],
|
||||
'submit_delete_version': true
|
||||
}), '') }}">
|
||||
}), '', false) }}">
|
||||
{{ get_icon('b_drop', 'Delete version'|trans) }}
|
||||
</a>
|
||||
</td>
|
||||
@ -69,14 +69,14 @@
|
||||
{{- get_common(url_params|merge({
|
||||
'version': version['version'],
|
||||
'report': 'true'
|
||||
}), '') }}">
|
||||
}), '', false) }}">
|
||||
{{ get_icon('b_report', 'Tracking report'|trans) }}
|
||||
</a>
|
||||
<a href="tbl_tracking.php" data-post="
|
||||
{{- get_common(url_params|merge({
|
||||
'version': version['version'],
|
||||
'snapshot': 'true'
|
||||
}), '') }}">
|
||||
}), '', false) }}">
|
||||
{{ get_icon('b_props', 'Structure snapshot'|trans) }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@ -29,6 +29,7 @@ class PageSettingsTest extends PmaTestCase
|
||||
{
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->enableBc();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
$GLOBALS['server'] = 1;
|
||||
$GLOBALS['db'] = 'db';
|
||||
$GLOBALS['table'] = '';
|
||||
|
||||
@ -250,7 +250,7 @@ class ProcessesControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
$killProcess = 'href="server_status_processes.php" data-post="'
|
||||
. Url::getCommon(['kill' => $process['Id']], '') . '"';
|
||||
. Url::getCommon(['kill' => $process['Id']], '', false) . '"';
|
||||
$this->assertStringContainsString(
|
||||
$killProcess,
|
||||
$html
|
||||
|
||||
@ -13,6 +13,7 @@ use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Tests\PmaTestCase;
|
||||
use PhpMyAdmin\Url;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@ -52,6 +53,7 @@ class CoreTest extends PmaTestCase
|
||||
$GLOBALS['db'] = '';
|
||||
$GLOBALS['table'] = '';
|
||||
$GLOBALS['PMA_PHP_SELF'] = 'http://example.net/';
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1537,4 +1539,61 @@ class CoreTest extends PmaTestCase
|
||||
// Must work now, (good secret and blowfish_secret)
|
||||
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testPopulateRequestWithEncryptedQueryParams()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryption', true);
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$_GET = ['pos' => '0', 'eq' => Url::encryptQuery('{"db":"test_db","table":"test_table"}')];
|
||||
$_REQUEST = $_GET;
|
||||
|
||||
Core::populateRequestWithEncryptedQueryParams();
|
||||
|
||||
$expected = ['pos' => '0', 'db' => 'test_db', 'table' => 'test_table'];
|
||||
|
||||
$this->assertEquals($expected, $_GET);
|
||||
$this->assertEquals($expected, $_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @dataProvider providerForTestPopulateRequestWithEncryptedQueryParamsWithInvalidParam
|
||||
*/
|
||||
public function testPopulateRequestWithEncryptedQueryParamsWithInvalidParam($encrypted, $decrypted)
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryption', true);
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$_GET = $encrypted;
|
||||
$_REQUEST = $encrypted;
|
||||
|
||||
Core::populateRequestWithEncryptedQueryParams();
|
||||
|
||||
$this->assertEquals($decrypted, $_GET);
|
||||
$this->assertEquals($decrypted, $_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[][][]
|
||||
*/
|
||||
public function providerForTestPopulateRequestWithEncryptedQueryParamsWithInvalidParam()
|
||||
{
|
||||
return [
|
||||
[[], []],
|
||||
[['eq' => []], []],
|
||||
[['eq' => ''], []],
|
||||
[['eq' => 'invalid'], []],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
114
test/classes/Crypto/CryptoTest.php
Normal file
114
test/classes/Crypto/CryptoTest.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace PhpMyAdmin\Tests\Crypto;
|
||||
|
||||
use PhpMyAdmin\Crypto\Crypto;
|
||||
use PhpMyAdmin\Tests\PmaTestCase;
|
||||
|
||||
/**
|
||||
* @covers \PhpMyAdmin\Crypto\Crypto
|
||||
*/
|
||||
class CryptoTest extends PmaTestCase
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testWithValidKeyFromConfig()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$cryptoWithSodium = new Crypto();
|
||||
$encrypted = $cryptoWithSodium->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
|
||||
$this->assertArrayNotHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
|
||||
$cryptoWithPhpseclib = new Crypto(true);
|
||||
$encrypted = $cryptoWithPhpseclib->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
|
||||
$this->assertArrayNotHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testWithValidKeyFromSession()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = ['URLQueryEncryptionSecretKey' => str_repeat('a', 32)];
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', '');
|
||||
|
||||
$cryptoWithSodium = new Crypto();
|
||||
$encrypted = $cryptoWithSodium->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
|
||||
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
|
||||
$cryptoWithPhpseclib = new Crypto(true);
|
||||
$encrypted = $cryptoWithPhpseclib->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
|
||||
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testWithNewSessionKey()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', '');
|
||||
|
||||
$cryptoWithSodium = new Crypto();
|
||||
$encrypted = $cryptoWithSodium->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
|
||||
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
$this->assertEquals(32, mb_strlen($_SESSION['URLQueryEncryptionSecretKey'], '8bit'));
|
||||
|
||||
$cryptoWithPhpseclib = new Crypto(true);
|
||||
$encrypted = $cryptoWithPhpseclib->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
|
||||
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
|
||||
$this->assertEquals(32, mb_strlen($_SESSION['URLQueryEncryptionSecretKey'], '8bit'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptWithInvalidKey()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$cryptoWithSodium = new Crypto();
|
||||
$encrypted = $cryptoWithSodium->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
|
||||
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('b', 32));
|
||||
|
||||
$cryptoWithSodium = new Crypto();
|
||||
$this->assertNull($cryptoWithSodium->decrypt($encrypted));
|
||||
|
||||
$cryptoWithPhpseclib = new Crypto(true);
|
||||
$encrypted = $cryptoWithPhpseclib->encrypt('test');
|
||||
$this->assertNotSame('test', $encrypted);
|
||||
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
|
||||
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$cryptoWithPhpseclib = new Crypto(true);
|
||||
$this->assertNull($cryptoWithPhpseclib->decrypt($encrypted));
|
||||
}
|
||||
}
|
||||
@ -266,6 +266,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'host' => '',
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'hide_connection_errors' => false,
|
||||
];
|
||||
$cfg_ssl = [
|
||||
'user' => 'u',
|
||||
@ -274,6 +275,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'ssl' => true,
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'hide_connection_errors' => false,
|
||||
];
|
||||
$cfg_control_ssl = [
|
||||
'user' => 'u',
|
||||
@ -282,6 +284,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'control_ssl' => true,
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'hide_connection_errors' => false,
|
||||
];
|
||||
return [
|
||||
[
|
||||
@ -301,6 +304,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'compress' => false,
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -317,6 +321,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'port' => 0,
|
||||
'ssl' => false,
|
||||
'compress' => false,
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -337,6 +342,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'compress' => false,
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -353,6 +359,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'port' => 0,
|
||||
'ssl' => true,
|
||||
'compress' => false,
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -374,6 +381,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'controluser' => 'u2',
|
||||
'controlpass' => 'p2',
|
||||
'control_ssl' => true,
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -390,6 +398,7 @@ class DatabaseInterfaceTest extends PmaTestCase
|
||||
'port' => 0,
|
||||
'ssl' => true,
|
||||
'compress' => false,
|
||||
'hide_connection_errors' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@ -46,6 +46,7 @@ class ResultsTest extends PmaTestCase
|
||||
$GLOBALS['PMA_PHP_SELF'] = 'index.php';
|
||||
$this->object = new DisplayResults('as', '', 0, '', '');
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
$GLOBALS['PMA_Config']->enableBc();
|
||||
$GLOBALS['text_dir'] = 'ltr';
|
||||
$_SESSION[' HMAC_secret '] = 'test';
|
||||
@ -427,10 +428,16 @@ class ResultsTest extends PmaTestCase
|
||||
{
|
||||
return [
|
||||
[
|
||||
'tbl_change.php?db=Data&table=customer&where_clause=%60'
|
||||
. 'customer%60.%60id%60+%3D+1&clause_is_unique=1&sql_query='
|
||||
. 'SELECT+%2A+FROM+%60customer%60&goto=sql.php&default_'
|
||||
. 'action=update',
|
||||
'tbl_change.php',
|
||||
[
|
||||
'db' => 'Data',
|
||||
'table' => 'customer',
|
||||
'where_clause' => '`customer`.`id` = 1',
|
||||
'clause_is_unique' => true,
|
||||
'sql_query' => 'SELECT * FROM `customer`',
|
||||
'goto' => 'sql.php',
|
||||
'default_action' => 'update',
|
||||
],
|
||||
'klass edit_row_anchor',
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" alt='
|
||||
. '"Edit" class="icon ic_b_edit"> Edit</span>',
|
||||
@ -441,7 +448,7 @@ class ResultsTest extends PmaTestCase
|
||||
. '<a href="tbl_change.php" data-post="db=Data&table=customer&where_'
|
||||
. 'clause=%60customer%60.%60id%60+%3D+1&clause_is_unique=1&'
|
||||
. 'sql_query=SELECT+%2A+FROM+%60customer%60&goto=sql.php&'
|
||||
. 'default_action=update"'
|
||||
. 'default_action=update&server=0&lang=en"'
|
||||
. '><span class="nowrap"><img src="themes/dot.gif" title="Edit" '
|
||||
. 'alt="Edit" class="icon ic_b_edit"> Edit</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value ="%60customer'
|
||||
@ -466,6 +473,7 @@ class ResultsTest extends PmaTestCase
|
||||
*/
|
||||
public function testGetEditLink(
|
||||
$edit_url,
|
||||
$urlParams,
|
||||
$class,
|
||||
$edit_str,
|
||||
$where_clause,
|
||||
@ -481,6 +489,7 @@ class ResultsTest extends PmaTestCase
|
||||
'_getEditLink',
|
||||
[
|
||||
$edit_url,
|
||||
$urlParams,
|
||||
$class,
|
||||
$edit_str,
|
||||
$where_clause,
|
||||
@ -499,21 +508,27 @@ class ResultsTest extends PmaTestCase
|
||||
{
|
||||
return [
|
||||
[
|
||||
'tbl_change.php?db=Data&table=customer&where_clause=%60cust'
|
||||
. 'omer%60.%60id%60+%3D+1&clause_is_unique=1&sql_query='
|
||||
. 'SELECT+%2A+FROM+%60customer%60&goto=sql.php&default_'
|
||||
. 'action=insert',
|
||||
'tbl_change.php',
|
||||
[
|
||||
'db' => 'Data',
|
||||
'table' => 'customer',
|
||||
'where_clause' => '`customer`.`id` = 1',
|
||||
'clause_is_unique' => true,
|
||||
'sql_query' => 'SELECT * FROM `customer`',
|
||||
'goto' => 'sql.php',
|
||||
'default_action' => 'insert',
|
||||
],
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Copy" alt'
|
||||
. '="Copy" class="icon ic_b_insrow"> Copy</span>',
|
||||
'`customer`.`id` = 1',
|
||||
'%60customer%60.%60id%60+%3D+1',
|
||||
'klass',
|
||||
'<td class="klass center print_ignore"><span class='
|
||||
'<td class="klass center print_ignore" ><span class='
|
||||
. '"nowrap">'
|
||||
. '<a href="tbl_change.php" data-post="db=Data&table=customer&where_'
|
||||
. 'clause=%60customer%60.%60id%60+%3D+1&clause_is_unique=1&'
|
||||
. 'sql_query=SELECT+%2A+FROM+%60customer%60&goto=sql.php&'
|
||||
. 'default_action=insert"'
|
||||
. 'default_action=insert&server=0&lang=en"'
|
||||
. '><span class="nowrap"><img src="themes/dot.gif" title="Copy" '
|
||||
. 'alt="Copy" class="icon ic_b_insrow"> Copy</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value="%60customer%60'
|
||||
@ -538,6 +553,7 @@ class ResultsTest extends PmaTestCase
|
||||
*/
|
||||
public function testGetCopyLink(
|
||||
$copy_url,
|
||||
$urlParams,
|
||||
$copy_str,
|
||||
$where_clause,
|
||||
$where_clause_html,
|
||||
@ -553,6 +569,7 @@ class ResultsTest extends PmaTestCase
|
||||
'_getCopyLink',
|
||||
[
|
||||
$copy_url,
|
||||
$urlParams,
|
||||
$copy_str,
|
||||
$where_clause,
|
||||
$where_clause_html,
|
||||
@ -571,12 +588,14 @@ class ResultsTest extends PmaTestCase
|
||||
{
|
||||
return [
|
||||
[
|
||||
'sql.php?db=Data&table=customer&sql_query=DELETE+FROM+%60'
|
||||
. 'Data%60.%60customer%60+WHERE+%60customer%60.%60id%60+%3D+1&'
|
||||
. 'message_to_show=The+row+has+been+deleted&goto=sql.php%3Fdb'
|
||||
. '%3DData%26table%3Dcustomer%26sql_query%3DSELECT%2B%252A%2BFROM'
|
||||
. '%2B%2560customer%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen'
|
||||
. '%2Bdeleted%26goto%3Dtbl_structure.php',
|
||||
'sql.php',
|
||||
[
|
||||
'db' => 'Data',
|
||||
'table' => 'customer',
|
||||
'sql_query' => 'DELETE FROM `Data`.`customer` WHERE `customer`.`id` = 1',
|
||||
'message_to_show' => 'The row has been deleted.',
|
||||
'goto' => 'tbl_sql.php',
|
||||
],
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
|
||||
. 'alt="Delete" class="icon ic_b_drop"> Delete</span>',
|
||||
'DELETE FROM `Data`.`customer` WHERE `customer`.`id` = 1',
|
||||
@ -584,10 +603,8 @@ class ResultsTest extends PmaTestCase
|
||||
'<td class="klass center print_ignore">'
|
||||
. '<a href="sql.php" data-post="db=Data&table=customer&sql_query=DELETE'
|
||||
. '+FROM+%60Data%60.%60customer%60+WHERE+%60customer%60.%60id%60+%3D'
|
||||
. '+1&message_to_show=The+row+has+been+deleted&goto=sql.php'
|
||||
. '%3Fdb%3DData%26table%3Dcustomer%26sql_query%3DSELECT%2B%252A%2B'
|
||||
. 'FROM%2B%2560customer%2560%26message_to_show%3DThe%2Brow%2Bhas%2B'
|
||||
. 'been%2Bdeleted%26goto%3Dtbl_structure.php" '
|
||||
. '+1&message_to_show=The+row+has+been+deleted.'
|
||||
. '&goto=tbl_sql.php&server=0&lang=en" '
|
||||
. 'class="delete_row requireConfirm"><span class="nowrap"><img src="themes/dot.'
|
||||
. 'gif" title="Delete" alt="Delete" class="icon ic_b_drop"> '
|
||||
. 'Delete</span></a>'
|
||||
@ -612,6 +629,7 @@ class ResultsTest extends PmaTestCase
|
||||
*/
|
||||
public function testGetDeleteLink(
|
||||
$del_url,
|
||||
$delUrlParams,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$class,
|
||||
@ -626,6 +644,7 @@ class ResultsTest extends PmaTestCase
|
||||
'_getDeleteLink',
|
||||
[
|
||||
$del_url,
|
||||
$delUrlParams,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$class,
|
||||
@ -644,12 +663,7 @@ class ResultsTest extends PmaTestCase
|
||||
return [
|
||||
[
|
||||
DisplayResults::POSITION_LEFT,
|
||||
'sql.php?db=data&table=new&sql_query=DELETE+FROM+%60data'
|
||||
. '%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&message_to_show='
|
||||
. 'The+row+has+been+deleted&goto=sql.php%3Fdb%3Ddata%26table%3D'
|
||||
. 'new%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26'
|
||||
. 'message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3D'
|
||||
. 'tbl_structure.php',
|
||||
'sql.php',
|
||||
[
|
||||
'edit_lnk' => 'ur',
|
||||
'del_lnk' => 'dr',
|
||||
@ -665,12 +679,8 @@ class ResultsTest extends PmaTestCase
|
||||
[
|
||||
'`new`.`id`' => '= 1',
|
||||
],
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.'
|
||||
. '%60id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+'
|
||||
. 'FROM+%60new%60&goto=sql.php&default_action=update',
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.'
|
||||
. '%60id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+'
|
||||
. 'FROM+%60new%60&goto=sql.php&default_action=insert',
|
||||
'tbl_change.php',
|
||||
'tbl_change.php',
|
||||
'edit_row_anchor',
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
|
||||
. 'alt="Edit" class="icon ic_b_edit"> Edit</span>',
|
||||
@ -679,6 +689,21 @@ class ResultsTest extends PmaTestCase
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
|
||||
. 'alt="Delete" class="icon ic_b_drop"> Delete</span>',
|
||||
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'where_clause' => '`new`.`id` = 1',
|
||||
'clause_is_unique' => true,
|
||||
'sql_query' => 'SELECT * FROM `new`',
|
||||
'goto' => 'sql.php',
|
||||
],
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
'message_to_show' => 'The row has been deleted.',
|
||||
'goto' => 'tbl_sql.php',
|
||||
],
|
||||
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_delete0_'
|
||||
. 'left" name="rows_to_delete[0]" class="multi_checkbox checkall" '
|
||||
. 'value="%60new%60.%60id%60+%3D+1"><input type="hidden" class='
|
||||
@ -688,26 +713,24 @@ class ResultsTest extends PmaTestCase
|
||||
. '<a href="tbl_change.php" data-post="db=data&table=new&where_'
|
||||
. 'clause=%60new%60.%60id%60+%3D+1&clause_is_unique=1&'
|
||||
. 'sql_query=SELECT+%2A+FROM+%60new%60&goto=sql.php&default'
|
||||
. '_action=update">'
|
||||
. '_action=update&server=0&lang=en">'
|
||||
. '<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
|
||||
. 'alt="Edit" class="icon ic_b_edit"> Edit</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value ="%60new%60.%60'
|
||||
. 'id%60+%3D+1"></span></td><td class="center print_ignore"><span class'
|
||||
. 'id%60+%3D+1"></span></td><td class="center print_ignore" ><span class'
|
||||
. '="nowrap">'
|
||||
. '<a href="tbl_change.php" data-post="db=data&table=new&where_clause'
|
||||
. '=%60new%60.%60id%60+%3D+1&clause_is_unique=1&sql_query='
|
||||
. 'SELECT+%2A+FROM+%60new%60&goto=sql.php&default_action='
|
||||
. 'insert"><span class'
|
||||
. 'insert&server=0&lang=en"><span class'
|
||||
. '="nowrap"><img src="themes/dot.gif" title="Copy" alt="Copy" '
|
||||
. 'class="icon ic_b_insrow"> Copy</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value="%60new%60.%60id'
|
||||
. '%60+%3D+1"></span></td><td class="center print_ignore">'
|
||||
. '<a href="sql.php" data-post="db=data&table=new&sql_query=DELETE+'
|
||||
. 'FROM+%60data%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&'
|
||||
. 'message_to_show=The+row+has+been+deleted&goto=sql.php%3F'
|
||||
. 'db%3Ddata%26table%3Dnew%26sql_query%3DSELECT%2B%252A%2BFROM%2B'
|
||||
. '%2560new%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2B'
|
||||
. 'deleted%26goto%3Dtbl_structure.php" '
|
||||
. 'message_to_show=The+row+has+been+deleted.'
|
||||
. '&goto=tbl_sql.php&server=0&lang=en" '
|
||||
. 'class="delete_row requireConfirm"><span class="nowrap"><img src="themes/dot.'
|
||||
. 'gif" title="Delete" alt="Delete" class="icon ic_b_drop"> '
|
||||
. 'Delete</span></a>'
|
||||
@ -716,12 +739,7 @@ class ResultsTest extends PmaTestCase
|
||||
],
|
||||
[
|
||||
DisplayResults::POSITION_RIGHT,
|
||||
'sql.php?db=data&table=new&sql_query=DELETE+FROM+%60data%60'
|
||||
. '.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&message_to_show='
|
||||
. 'The+row+has+been+deleted&goto=sql.php%3Fdb%3Ddata%26table%3D'
|
||||
. 'new%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26message'
|
||||
. '_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3Dtbl_'
|
||||
. 'structure.php',
|
||||
'sql.php',
|
||||
[
|
||||
'edit_lnk' => 'ur',
|
||||
'del_lnk' => 'dr',
|
||||
@ -737,12 +755,8 @@ class ResultsTest extends PmaTestCase
|
||||
[
|
||||
'`new`.`id`' => '= 1',
|
||||
],
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.'
|
||||
. '%60id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+'
|
||||
. 'FROM+%60new%60&goto=sql.php&default_action=update',
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.'
|
||||
. '%60id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+'
|
||||
. 'FROM+%60new%60&goto=sql.php&default_action=insert',
|
||||
'tbl_change.php',
|
||||
'tbl_change.php',
|
||||
'edit_row_anchor',
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
|
||||
. 'alt="Edit" class="icon ic_b_edit"> Edit</span>',
|
||||
@ -751,21 +765,34 @@ class ResultsTest extends PmaTestCase
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
|
||||
. 'alt="Delete" class="icon ic_b_drop"> Delete</span>',
|
||||
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'where_clause' => '`new`.`id` = 1',
|
||||
'clause_is_unique' => true,
|
||||
'sql_query' => 'SELECT * FROM `new`',
|
||||
'goto' => 'sql.php',
|
||||
],
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
'message_to_show' => 'The row has been deleted.',
|
||||
'goto' => 'tbl_sql.php',
|
||||
],
|
||||
'<td class="center print_ignore">'
|
||||
. '<a href="sql.php" data-post="db=data&table=new&sql_query=DELETE+'
|
||||
. 'FROM+%60data%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&'
|
||||
. 'message_to_show=The+row+has+been+deleted&goto=sql.php%3Fdb'
|
||||
. '%3Ddata%26table%3Dnew%26sql_query%3DSELECT%2B%252A%2BFROM%2B%25'
|
||||
. '60new%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted'
|
||||
. '%26goto%3Dtbl_structure.php" class="delete'
|
||||
. 'message_to_show=The+row+has+been+deleted.&goto=tbl_sql.php'
|
||||
. '&server=0&lang=en" class="delete'
|
||||
. '_row requireConfirm"><span class="nowrap"><img src="themes/dot.gif" title='
|
||||
. '"Delete" alt="Delete" class="icon ic_b_drop"> Delete</span></a>'
|
||||
. '<div class="hide">DELETE FROM `data`.`new` WHERE `new`.'
|
||||
. '`id` = 1</div></td><td class="center print_ignore"><span class="nowrap">'
|
||||
. '`id` = 1</div></td><td class="center print_ignore" ><span class="nowrap">'
|
||||
. '<a href="tbl_change.php" data-post="db=data&table=new&where_'
|
||||
. 'clause=%60new%60.%60id%60+%3D+1&clause_is_unique=1&sql_'
|
||||
. 'query=SELECT+%2A+FROM+%60new%60&goto=sql.php&default_'
|
||||
. 'action=insert"><span '
|
||||
. 'action=insert&server=0&lang=en"><span '
|
||||
. 'class="nowrap"><img src="themes/dot.gif" title="Copy" alt="Copy" '
|
||||
. 'class="icon ic_b_insrow"> Copy</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value="%60new%60.%60id'
|
||||
@ -774,7 +801,7 @@ class ResultsTest extends PmaTestCase
|
||||
. '<a href="tbl_change.php" data-post="db=data&table=new&where_clause'
|
||||
. '=%60new%60.%60id%60+%3D+1&clause_is_unique=1&sql_query='
|
||||
. 'SELECT+%2A+FROM+%60new%60&goto=sql.php&default_action='
|
||||
. 'update"><span class='
|
||||
. 'update&server=0&lang=en"><span class='
|
||||
. '"nowrap"><img src="themes/dot.gif" title="Edit" alt="Edit" class'
|
||||
. '="icon ic_b_edit"> Edit</span></a>'
|
||||
. '<input type="hidden" class="where_clause" value ="%60new%60.%60'
|
||||
@ -786,12 +813,7 @@ class ResultsTest extends PmaTestCase
|
||||
],
|
||||
[
|
||||
DisplayResults::POSITION_NONE,
|
||||
'sql.php?db=data&table=new&sql_query=DELETE+FROM+%60data%60.'
|
||||
. '%60new%60+WHERE+%60new%60.%60id%60+%3D+1&message_to_show=The+'
|
||||
. 'row+has+been+deleted&goto=sql.php%3Fdb%3Ddata%26table%3Dnew'
|
||||
. '%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26message_'
|
||||
. 'to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3Dtbl_structure'
|
||||
. '.php',
|
||||
'sql.php',
|
||||
[
|
||||
'edit_lnk' => 'ur',
|
||||
'del_lnk' => 'dr',
|
||||
@ -807,12 +829,8 @@ class ResultsTest extends PmaTestCase
|
||||
[
|
||||
'`new`.`id`' => '= 1',
|
||||
],
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.%60'
|
||||
. 'id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+FROM+'
|
||||
. '%60new%60&goto=sql.php&default_action=update',
|
||||
'tbl_change.php?db=data&table=new&where_clause=%60new%60.%60'
|
||||
. 'id%60+%3D+1&clause_is_unique=1&sql_query=SELECT+%2A+FROM+'
|
||||
. '%60new%60&goto=sql.php&default_action=insert',
|
||||
'tbl_change.php',
|
||||
'tbl_change.php',
|
||||
'edit_row_anchor',
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
|
||||
. 'alt="Edit" class="icon ic_b_edit"> Edit</span>',
|
||||
@ -821,6 +839,21 @@ class ResultsTest extends PmaTestCase
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
|
||||
. 'alt="Delete" class="icon ic_b_drop"> Delete</span>',
|
||||
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'where_clause' => '`new`.`id` = 1',
|
||||
'clause_is_unique' => true,
|
||||
'sql_query' => 'SELECT * FROM `new`',
|
||||
'goto' => 'sql.php',
|
||||
],
|
||||
[
|
||||
'db' => 'data',
|
||||
'table' => 'new',
|
||||
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
|
||||
'message_to_show' => 'The row has been deleted.',
|
||||
'goto' => 'tbl_sql.php',
|
||||
],
|
||||
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_'
|
||||
. 'delete0_left" name="rows_to_delete[0]" class="multi_checkbox '
|
||||
. 'checkall" value="%60new%60.%60id%60+%3D+1"><input type='
|
||||
@ -869,6 +902,8 @@ class ResultsTest extends PmaTestCase
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams,
|
||||
$output
|
||||
) {
|
||||
$this->assertEquals(
|
||||
@ -890,6 +925,8 @@ class ResultsTest extends PmaTestCase
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams,
|
||||
]
|
||||
)
|
||||
);
|
||||
@ -940,6 +977,8 @@ class ResultsTest extends PmaTestCase
|
||||
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
|
||||
. 'alt="Delete" class="icon ic_b_drop"> Delete</span>',
|
||||
null,
|
||||
[],
|
||||
[],
|
||||
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_'
|
||||
. 'delete0_left" name="rows_to_delete[0]" class="multi_checkbox '
|
||||
. 'checkall" value="%60new%60.%60id%60+%3D+1"><input type='
|
||||
@ -987,6 +1026,8 @@ class ResultsTest extends PmaTestCase
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams,
|
||||
$output
|
||||
) {
|
||||
$this->assertEquals(
|
||||
@ -1008,6 +1049,8 @@ class ResultsTest extends PmaTestCase
|
||||
$copy_str,
|
||||
$del_str,
|
||||
$js_conf,
|
||||
$editCopyUrlParams,
|
||||
$delUrlParams,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
@ -96,6 +96,13 @@ class EncodingTest extends TestCase
|
||||
$this->markTestSkipped('iconv extension missing');
|
||||
}
|
||||
|
||||
// Set PHP native locale
|
||||
if (function_exists('setlocale') && setlocale(0, 'POSIX') === false) {
|
||||
$this->markTestSkipped('native setlocale failed');
|
||||
}
|
||||
|
||||
_setlocale(LC_ALL, 'POSIX');
|
||||
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
$GLOBALS['cfg']['IconvExtraParams'] = '//TRANSLIT';
|
||||
Encoding::setEngine(Encoding::ENGINE_ICONV);
|
||||
|
||||
@ -48,6 +48,7 @@ class FooterTest extends PmaTestCase
|
||||
$GLOBALS['table'] = '';
|
||||
$GLOBALS['text_dir'] = 'ltr';
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
$GLOBALS['PMA_Config']->enableBc();
|
||||
$GLOBALS['cfg']['Server']['DisableIS'] = false;
|
||||
$GLOBALS['cfg']['Server']['verbose'] = 'verbose host';
|
||||
|
||||
@ -65,6 +65,7 @@ class InsertEditTest extends TestCase
|
||||
$GLOBALS['cfg']['LoginCookieValidity'] = 1440;
|
||||
$GLOBALS['cfg']['enable_drag_drop_import'] = true;
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
|
||||
$this->insertEdit = new InsertEdit($GLOBALS['dbi']);
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Navigation\NavigationTree;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Tests\PmaTestCase;
|
||||
use PhpMyAdmin\Theme;
|
||||
use PhpMyAdmin\Url;
|
||||
use ReflectionMethod;
|
||||
|
||||
/**
|
||||
* Tests for PhpMyAdmin\Navigation\NavigationTree class
|
||||
@ -36,6 +39,7 @@ class NavigationTreeTest extends PmaTestCase
|
||||
{
|
||||
$GLOBALS['server'] = 1;
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
$GLOBALS['PMA_Config']->enableBc();
|
||||
$GLOBALS['cfg']['Server']['host'] = 'localhost';
|
||||
$GLOBALS['cfg']['Server']['user'] = 'user';
|
||||
@ -96,4 +100,37 @@ class NavigationTreeTest extends PmaTestCase
|
||||
$result = $this->object->renderDbSelect();
|
||||
$this->assertStringContainsString('pma_navigation_select_database', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptQueryParams()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryption', false);
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$method = new ReflectionMethod($this->object, 'encryptQueryParams');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$link = 'tbl_structure.php?server=1&db=test_db&table=test_table&pos=0';
|
||||
|
||||
$actual = $method->invoke($this->object, $link);
|
||||
$this->assertEquals($link, $actual);
|
||||
|
||||
$PMA_Config->set('URLQueryEncryption', true);
|
||||
|
||||
$actual = $method->invoke($this->object, $link);
|
||||
$this->assertStringStartsWith('tbl_structure.php?server=1&pos=0&eq=', $actual);
|
||||
|
||||
$url = parse_url($actual);
|
||||
parse_str(htmlspecialchars_decode($url['query']), $query);
|
||||
|
||||
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $query['eq']);
|
||||
$decrypted = Url::decryptQuery($query['eq']);
|
||||
$this->assertJson($decrypted);
|
||||
$this->assertSame('{"db":"test_db","table":"test_table"}', $decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ class AuthenticationCookieTest extends PmaTestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
$GLOBALS['PMA_Config'] = new Config();
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
$GLOBALS['PMA_Config']->enableBc();
|
||||
$GLOBALS['server'] = 0;
|
||||
$GLOBALS['text_dir'] = 'ltr';
|
||||
|
||||
@ -40,6 +40,7 @@ class PmaTestCase extends TestCase
|
||||
{
|
||||
require ROOT_PATH . 'libraries/config.default.php';
|
||||
$GLOBALS['cfg'] = $cfg;
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -131,7 +131,7 @@ class UserGroupsTest extends TestCase
|
||||
'viewUsers' => 1,
|
||||
'userGroup' => htmlspecialchars('usergroup'),
|
||||
],
|
||||
''
|
||||
'', false
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
$url_tag,
|
||||
@ -143,7 +143,7 @@ class UserGroupsTest extends TestCase
|
||||
'editUserGroup' => 1,
|
||||
'userGroup' => htmlspecialchars('usergroup'),
|
||||
],
|
||||
''
|
||||
'', false
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
$url_tag,
|
||||
@ -155,7 +155,7 @@ class UserGroupsTest extends TestCase
|
||||
'deleteUserGroup' => 1,
|
||||
'userGroup' => htmlspecialchars('usergroup'),
|
||||
],
|
||||
''
|
||||
'', false
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
$url_tag,
|
||||
|
||||
@ -29,6 +29,7 @@ class UrlTest extends TestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
unset($_COOKIE['pma_lang']);
|
||||
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,4 +115,61 @@ class UrlTest extends TestCase
|
||||
$expected = '?server=x' . htmlentities($separator) . 'lang=en' ;
|
||||
$this->assertEquals($expected, Url::getCommon());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testBuildHttpQueryWithUrlQueryEncryptionDisabled()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$PMA_Config->set('URLQueryEncryption', false);
|
||||
$params = ['db' => 'test_db', 'table' => 'test_table', 'pos' => 0];
|
||||
$this->assertEquals('db=test_db&table=test_table&pos=0', Url::buildHttpQuery($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testBuildHttpQueryWithUrlQueryEncryptionEnabled()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryption', true);
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$params = ['db' => 'test_db', 'table' => 'test_table', 'pos' => 0];
|
||||
$query = Url::buildHttpQuery($params);
|
||||
$this->assertStringStartsWith('pos=0&eq=', $query);
|
||||
parse_str($query, $queryParams);
|
||||
$this->assertCount(2, $queryParams);
|
||||
$this->assertSame('0', $queryParams['pos']);
|
||||
$this->assertTrue(is_string($queryParams['eq']));
|
||||
$this->assertNotSame('', $queryParams['eq']);
|
||||
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $queryParams['eq']);
|
||||
$decrypted = Url::decryptQuery($queryParams['eq']);
|
||||
$this->assertJson($decrypted);
|
||||
$this->assertSame('{"db":"test_db","table":"test_table"}', $decrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testQueryEncryption()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$_SESSION = [];
|
||||
$PMA_Config->set('URLQueryEncryption', true);
|
||||
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
|
||||
|
||||
$query = '{"db":"test_db","table":"test_table"}';
|
||||
$encrypted = Url::encryptQuery($query);
|
||||
$this->assertNotSame($query, $encrypted);
|
||||
$this->assertNotSame('', $encrypted);
|
||||
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $encrypted);
|
||||
$decrypted = Url::decryptQuery($encrypted);
|
||||
$this->assertSame($query, $decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2700,38 +2700,22 @@ class UtilTest extends PmaTestCase
|
||||
{
|
||||
return [
|
||||
[
|
||||
[
|
||||
'index.php',
|
||||
'text',
|
||||
],
|
||||
['index.php', null, 'text'],
|
||||
1000,
|
||||
'<a href="index.php" >text</a>',
|
||||
],
|
||||
[
|
||||
[
|
||||
'index.php?some=parameter',
|
||||
'text',
|
||||
],
|
||||
['index.php', ['some' => 'parameter'], 'text'],
|
||||
20,
|
||||
'<a href="index.php" data-post="some=parameter">text</a>',
|
||||
'<a href="index.php" data-post="some=parameter&lang=en">text</a>',
|
||||
],
|
||||
[
|
||||
[
|
||||
'index.php',
|
||||
'text',
|
||||
[],
|
||||
'target',
|
||||
],
|
||||
['index.php', null, 'text', [], 'target'],
|
||||
1000,
|
||||
'<a href="index.php" target="target">text</a>',
|
||||
],
|
||||
[
|
||||
[
|
||||
'url.php?url=http://phpmyadmin.net/',
|
||||
'text',
|
||||
[],
|
||||
'_blank',
|
||||
],
|
||||
['url.php?url=http://phpmyadmin.net/', null, 'text', [], '_blank'],
|
||||
1000,
|
||||
'<a href="url.php?url=http://phpmyadmin.net/" target="_blank" rel="noopener noreferrer">text</a>',
|
||||
],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user