Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
commit
eaad8d8a1c
@ -63,6 +63,8 @@ phpMyAdmin - ChangeLog
|
||||
- issue #18454 Fix date field calendar display when changing NULL state
|
||||
- issue #18481 Fix missing pagination when using SELECT DISTINCT
|
||||
- issue #18325 Allow hex representations for integers in the search box validation
|
||||
- issue #14411 Fixed double tap to edit on mobile devices
|
||||
- issue Update documentation to reflect that Node >= 12 is required to compile the JS and CSS files
|
||||
|
||||
5.2.1 (2023-02-07)
|
||||
- issue #17522 Fix case where the routes cache file is invalid
|
||||
|
||||
@ -90,7 +90,7 @@ In order to install from Git, you'll need a few supporting applications:
|
||||
|
||||
* `Git <https://git-scm.com/downloads>`_ to download the source, or you can download the most recent source directly from `Github <https://codeload.github.com/phpmyadmin/phpmyadmin/zip/QA_5_2>`_
|
||||
* `Composer <https://getcomposer.org/download/>`__
|
||||
* `Node.js <https://nodejs.org/en/download/>`_ (version 10 or higher)
|
||||
* `Node.js <https://nodejs.org/en/download/>`_ (version 12 or higher)
|
||||
* `Yarn <https://classic.yarnpkg.com/en/docs/install>`_
|
||||
|
||||
You can clone current phpMyAdmin source from
|
||||
|
||||
@ -2153,8 +2153,8 @@ const makeGrid = function (t, enableResize = undefined, enableReorder = undefine
|
||||
}
|
||||
});
|
||||
|
||||
$(g.t).find('td.data.click2')
|
||||
.on('click', function (e) {
|
||||
$(g.t)
|
||||
.on('click', 'td.data.click2', function (e) {
|
||||
var $cell = $(this);
|
||||
// In the case of relational link, We want single click on the link
|
||||
// to goto the link and double click to start grid-editing.
|
||||
@ -2188,7 +2188,7 @@ const makeGrid = function (t, enableResize = undefined, enableReorder = undefine
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('dblclick', function (e) {
|
||||
.on('dblclick', 'td.data.click2', function (e) {
|
||||
if ($(e.target).is('.grid_edit a')) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
|
||||
@ -1499,8 +1499,9 @@ var ConsoleDebug = {
|
||||
);
|
||||
|
||||
if (url) {
|
||||
var decodedUrl = new URLSearchParams(url.split('?')[1]);
|
||||
$('#debug_console').find('.debug>.welcome').append(
|
||||
$('<span class="script_name">').text(url.split('?')[0])
|
||||
$('<span class="script_name">').text(decodedUrl.has('route') ? decodedUrl.get('route') : url)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -3153,14 +3153,23 @@ function onloadRecentFavoriteTables (): void {
|
||||
return;
|
||||
}
|
||||
|
||||
var favoriteTables = '';
|
||||
if (isStorageSupported('localStorage')
|
||||
&& typeof window.localStorage.favoriteTables !== 'undefined'
|
||||
&& window.localStorage.favoriteTables !== 'undefined') {
|
||||
favoriteTables = window.localStorage.favoriteTables;
|
||||
if (favoriteTables === 'undefined') {
|
||||
// Do not send an invalid value
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: $('#sync_favorite_tables').attr('href'),
|
||||
cache: false,
|
||||
type: 'POST',
|
||||
data: {
|
||||
'favoriteTables': (isStorageSupported('localStorage') && typeof window.localStorage.favoriteTables !== 'undefined')
|
||||
? window.localStorage.favoriteTables
|
||||
: '',
|
||||
'favoriteTables': favoriteTables,
|
||||
'server': CommonParams.get('server'),
|
||||
'no_debug': true
|
||||
},
|
||||
|
||||
@ -186,8 +186,25 @@ function verifyAfterSearchFieldChange (index, searchFormId) {
|
||||
}
|
||||
});
|
||||
|
||||
// validator method for IN(...), NOT IN(...)
|
||||
// BETWEEN and NOT BETWEEN
|
||||
// See all possible syntaxes in tests of https://regexr.com/7h1eq
|
||||
jQuery.validator.addMethod('validationFunctionForMultipleInt', function (value) {
|
||||
return value.match(/^(((0x[0-9a-f]+)|([+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)(e[+-]?[0-9]+)?))(,|$))+$/i) !== null;
|
||||
},
|
||||
window.Messages.strEnterValidNumber
|
||||
);
|
||||
|
||||
validateMultipleIntField($thisInput, true);
|
||||
} else {
|
||||
// validator method for INTs
|
||||
// See all possible syntaxes in tests of https://regexr.com/7h1ci
|
||||
jQuery.validator.addMethod('validationFunctionForInt', function (value) {
|
||||
return value.match(/^(0x[0-9a-f]+$)|([+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)(e[+-]?[0-9]+)?)$/i) !== null;
|
||||
},
|
||||
window.Messages.strEnterValidNumber
|
||||
);
|
||||
|
||||
$(searchFormId).validate({
|
||||
// update errors as we write
|
||||
onkeyup: function (element) {
|
||||
|
||||
@ -10,7 +10,6 @@ use PhpMyAdmin\Dbal\Connection;
|
||||
use PhpMyAdmin\Identifiers\DatabaseName;
|
||||
use PhpMyAdmin\Identifiers\TableName;
|
||||
use PhpMyAdmin\InternalRelations;
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
use PhpMyAdmin\SqlParser\Statements\CreateStatement;
|
||||
use PhpMyAdmin\SqlParser\Utils\Table as TableUtils;
|
||||
@ -1622,32 +1621,13 @@ class Relation
|
||||
}
|
||||
|
||||
$GLOBALS['cfg']['Server']['pmadb'] = $db;
|
||||
|
||||
//NOTE: I am unsure why we do that, as it defeats the purpose of the session cache
|
||||
// Unset the cache
|
||||
unset($_SESSION['relation'][$GLOBALS['server']]);
|
||||
unset(self::$cache[$GLOBALS['server']]);
|
||||
|
||||
$relationParameters = $this->getRelationParameters();
|
||||
if (
|
||||
$relationParameters->recentlyUsedTablesFeature === null
|
||||
&& $relationParameters->favoriteTablesFeature === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since configuration storage is updated, we need to
|
||||
// re-initialize the favorite and recent tables stored in the
|
||||
// session from the current configuration storage.
|
||||
if ($relationParameters->favoriteTablesFeature !== null) {
|
||||
$favTables = RecentFavoriteTable::getInstance('favorite');
|
||||
$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] = $favTables->getFromDb();
|
||||
}
|
||||
|
||||
if ($relationParameters->recentlyUsedTablesFeature !== null) {
|
||||
$recentTables = RecentFavoriteTable::getInstance('recent');
|
||||
$_SESSION['tmpval']['recentTables'][$GLOBALS['server']] = $recentTables->getFromDb();
|
||||
}
|
||||
|
||||
// Reload navi panel to update the recent/favorite lists.
|
||||
$GLOBALS['reload'] = true;
|
||||
// Fill back the cache
|
||||
$this->getRelationParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -44,7 +44,7 @@ final class FavoriteTableController extends AbstractController
|
||||
$GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database');
|
||||
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
|
||||
|
||||
if (! $this->hasDatabase() || ! $this->response->isAjax()) {
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -72,6 +72,10 @@ final class FavoriteTableController extends AbstractController
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$changes = true;
|
||||
$favoriteTable = $parameters['favorite_table'] ?? '';
|
||||
$alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
|
||||
@ -166,10 +170,8 @@ final class FavoriteTableController extends AbstractController
|
||||
*/
|
||||
private function checkFavoriteTable(string $currentTable): bool
|
||||
{
|
||||
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
|
||||
RecentFavoriteTable::getInstance('favorite');
|
||||
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
|
||||
foreach ($favoriteTables as $value) {
|
||||
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
|
||||
foreach ($recentFavoriteTables->getTables() as $value) {
|
||||
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -591,10 +591,8 @@ class StructureController extends AbstractController
|
||||
*/
|
||||
protected function checkFavoriteTable(string $currentTable): bool
|
||||
{
|
||||
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
|
||||
RecentFavoriteTable::getInstance('favorite');
|
||||
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
|
||||
foreach ($favoriteTables as $value) {
|
||||
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
|
||||
foreach ($recentFavoriteTables->getTables() as $value) {
|
||||
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -439,7 +439,7 @@ class Header
|
||||
/**
|
||||
* Re-enable possible disabled XSS filters.
|
||||
*
|
||||
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
|
||||
* @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection
|
||||
*/
|
||||
$headers['X-XSS-Protection'] = '1; mode=block';
|
||||
|
||||
@ -447,21 +447,21 @@ class Header
|
||||
* "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing
|
||||
* a response away from the declared content-type.
|
||||
*
|
||||
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
|
||||
* @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options
|
||||
*/
|
||||
$headers['X-Content-Type-Options'] = 'nosniff';
|
||||
|
||||
/**
|
||||
* Adobe cross-domain-policies.
|
||||
*
|
||||
* @see https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
|
||||
* @see https://www.sentrium.co.uk/labs/application-security-101-http-headers
|
||||
*/
|
||||
$headers['X-Permitted-Cross-Domain-Policies'] = 'none';
|
||||
|
||||
/**
|
||||
* Robots meta tag.
|
||||
*
|
||||
* @see https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
|
||||
* @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
|
||||
*/
|
||||
$headers['X-Robots-Tag'] = 'noindex, nofollow';
|
||||
|
||||
|
||||
@ -59,12 +59,15 @@ class RecentFavoriteTable
|
||||
* Creates a new instance of RecentFavoriteTable
|
||||
*
|
||||
* @param string $type the table type
|
||||
* @phpstan-param 'favorite'|'recent' $type
|
||||
*/
|
||||
private function __construct(public Template $template, string $type)
|
||||
{
|
||||
$this->relation = new Relation($GLOBALS['dbi']);
|
||||
$this->tableType = $type;
|
||||
$serverId = $GLOBALS['server'];
|
||||
// Code search hint: recentTables
|
||||
// Code search hint: favoriteTables
|
||||
if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId])) {
|
||||
$_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId] = $this->getPmaTable()
|
||||
? $this->getFromDb()
|
||||
|
||||
@ -1147,12 +1147,12 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'db' on mixed\\.$#"
|
||||
count: 1
|
||||
count: 2
|
||||
path: libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'table' on mixed\\.$#"
|
||||
count: 1
|
||||
count: 2
|
||||
path: libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
|
||||
|
||||
-
|
||||
@ -1255,6 +1255,16 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'db' on mixed\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'table' on mixed\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$connection of method PhpMyAdmin\\\\Replication\\\\ReplicationInfo\\:\\:load\\(\\) expects string\\|null, mixed given\\.$#"
|
||||
count: 1
|
||||
|
||||
@ -718,10 +718,6 @@
|
||||
</MixedArrayAccess>
|
||||
<MixedArrayAssignment>
|
||||
<code><![CDATA[$_SESSION['sql_history'][]]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['recentTables']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['recentTables'][$GLOBALS['server']]]]></code>
|
||||
</MixedArrayAssignment>
|
||||
<MixedArrayOffset>
|
||||
<code>$foreign[$field]</code>
|
||||
@ -1404,7 +1400,6 @@
|
||||
<code><![CDATA[$value['table']]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
|
||||
<code><![CDATA[$value['db']]]></code>
|
||||
<code><![CDATA[$value['db']]]></code>
|
||||
<code><![CDATA[$value['table']]]></code>
|
||||
@ -1418,7 +1413,6 @@
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$GLOBALS['errorUrl']]]></code>
|
||||
<code>$favoriteTables</code>
|
||||
<code>$favoriteTables</code>
|
||||
<code>$value</code>
|
||||
<code>$value</code>
|
||||
</MixedAssignment>
|
||||
@ -1545,7 +1539,6 @@
|
||||
<code>$updateTimeAll</code>
|
||||
</MixedArgument>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
|
||||
<code><![CDATA[$currentTable['Check_time']]]></code>
|
||||
<code><![CDATA[$currentTable['Collation']]]></code>
|
||||
<code><![CDATA[$currentTable['Create_time']]]></code>
|
||||
@ -1577,7 +1570,6 @@
|
||||
<code>$createTimeAll</code>
|
||||
<code>$currentTable</code>
|
||||
<code>$dbTable</code>
|
||||
<code>$favoriteTables</code>
|
||||
<code>$overheadSize</code>
|
||||
<code>$searchDb</code>
|
||||
<code>$searchDoDBInDB</code>
|
||||
@ -13387,8 +13379,6 @@
|
||||
<code>$sumSize</code>
|
||||
</MixedArrayAccess>
|
||||
<MixedArrayAssignment>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
|
||||
<code><![CDATA[$currentTable['ENGINE']]]></code>
|
||||
<code><![CDATA[$currentTable['ENGINE']]]></code>
|
||||
<code><![CDATA[$currentTable['ENGINE']]]></code>
|
||||
|
||||
@ -1912,15 +1912,6 @@ class RelationTest extends AbstractTestCase
|
||||
|
||||
$dummyDbi->addResult('SELECT NULL FROM `pma__favorite_custom` LIMIT 0', [], ['NULL']);
|
||||
|
||||
$dummyDbi->addResult(
|
||||
'SELECT `tables` FROM `PMA-storage`.`pma__favorite_custom` WHERE `username` = \'\'',
|
||||
[],
|
||||
);
|
||||
$dummyDbi->addResult(
|
||||
'SELECT `tables` FROM `PMA-storage`.`pma__favorite_custom` WHERE `username` = \'\'',
|
||||
[],
|
||||
);
|
||||
|
||||
$_SESSION['relation'] = [];
|
||||
$_SESSION['tmpval'] = [];
|
||||
(new ReflectionClass(Relation::class))->getProperty('cache')->setValue([]);
|
||||
|
||||
@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
use PhpMyAdmin\Replication\Replication;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
@ -249,6 +250,26 @@ class StructureControllerTest extends AbstractTestCase
|
||||
$class = new ReflectionClass(StructureController::class);
|
||||
$method = $class->getMethod('checkFavoriteTable');
|
||||
|
||||
$dbiDummy = $this->createDbiDummy();
|
||||
$dbi = $this->createDatabaseInterface($dbiDummy);
|
||||
|
||||
$GLOBALS['db'] = 'sakila';
|
||||
$GLOBALS['dbi'] = $dbi;
|
||||
|
||||
$dbiDummy->removeDefaultResults();
|
||||
$dbiDummy->addResult(
|
||||
'SHOW COLUMNS FROM `sakila`.`country`',
|
||||
[
|
||||
['country_id', 'smallint(5) unsigned', 'NO', 'PRI', null, 'auto_increment'],
|
||||
],
|
||||
['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'],
|
||||
);
|
||||
$dbiDummy->addResult(
|
||||
'SHOW INDEXES FROM `sakila`.`country`',
|
||||
[],
|
||||
['Table', 'Non_unique', 'Key_name', 'Column_name'],
|
||||
);
|
||||
|
||||
$controller = new StructureController(
|
||||
$this->response,
|
||||
$this->template,
|
||||
@ -259,14 +280,23 @@ class StructureControllerTest extends AbstractTestCase
|
||||
$this->createStub(PageSettings::class),
|
||||
);
|
||||
|
||||
$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] = [['db' => 'db', 'table' => 'table']];
|
||||
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
|
||||
$this->assertSame([], $recentFavoriteTables->getTables());
|
||||
$recentFavoriteTables->remove('sakila', 'country');
|
||||
$recentFavoriteTables->add('sakila', 'country');
|
||||
$this->assertSame([
|
||||
[
|
||||
'db' => 'sakila',
|
||||
'table' => 'country',
|
||||
],
|
||||
], $recentFavoriteTables->getTables());
|
||||
|
||||
$this->assertFalse(
|
||||
$method->invokeArgs($controller, ['']),
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$method->invokeArgs($controller, ['table']),
|
||||
$method->invokeArgs($controller, ['country']),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user