Merge pull request #19569 from kamil-tekiela/Replace-trigger_error-in-mysqli

Add an error instead of triggering warning
This commit is contained in:
Maurício Meneghini Fauth 2025-02-19 20:28:57 -03:00 committed by GitHub
commit 65cd15d10d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 119 additions and 145 deletions

View File

@ -6867,12 +6867,6 @@ parameters:
count: 1
path: src/Error/ErrorHandler.php
-
message: '#^Loose comparison via "\!\=" is not allowed\.$#'
identifier: notEqual.notAllowed
count: 1
path: src/Error/ErrorHandler.php
-
message: '#^Parameter \#1 \$value of function count expects array\|Countable, mixed given\.$#'
identifier: argument.type

View File

@ -5,7 +5,7 @@
{{ message|raw }}
{%- if not is_user_error -%}
{%- if not is_user_error and formatted_backtrace is not empty -%}
<p class="mt-3"><strong>Backtrace</strong></p>
{{- formatted_backtrace|raw -}}
{%- endif -%}

View File

@ -16,6 +16,7 @@ namespace PhpMyAdmin\Config;
use PhpMyAdmin\Config;
use PhpMyAdmin\Config\Forms\User\UserFormList;
use PhpMyAdmin\Error\ErrorHandler;
use PhpMyAdmin\Html\MySQLDocumentation;
use PhpMyAdmin\Util;
@ -37,11 +38,8 @@ use function sprintf;
use function str_ends_with;
use function str_replace;
use function str_starts_with;
use function trigger_error;
use function trim;
use const E_USER_WARNING;
/**
* Form management class, displays and processes forms
*/
@ -391,7 +389,7 @@ class FormDisplay
return $htmlOutput;
case 'NULL':
trigger_error('Field ' . $systemPath . ' has no type', E_USER_WARNING);
ErrorHandler::getInstance()->addUserError('Field ' . $systemPath . ' has no type');
return null;
}

View File

@ -45,7 +45,6 @@ use function unserialize;
use function urldecode;
use const DATE_RFC1123;
use const E_USER_WARNING;
use const FILTER_VALIDATE_IP;
/**
@ -115,7 +114,7 @@ class Core
throw new MissingExtensionException(Sanitize::convertBBCode($message));
}
ErrorHandler::getInstance()->addError($message, E_USER_WARNING, '', 0, false);
ErrorHandler::getInstance()->addUserError($message, false);
}
/**

View File

@ -60,12 +60,10 @@ use function strtoupper;
use function strtr;
use function substr;
use function syslog;
use function trigger_error;
use function uasort;
use function uksort;
use function usort;
use const E_USER_WARNING;
use const LOG_INFO;
use const LOG_NDELAY;
use const LOG_PID;
@ -1049,20 +1047,21 @@ class DatabaseInterface
. $this->quoteString($currentServer->sessionTimeZone);
if (! $this->tryQuery($sqlQueryTz)) {
$errorMessageTz = sprintf(
__(
'Unable to use timezone "%1$s" for server %2$d. '
. 'Please check your configuration setting for '
. '[em]$cfg[\'Servers\'][%3$d][\'SessionTimeZone\'][/em]. '
. 'phpMyAdmin is currently using the default time zone '
. 'of the database server.',
$errorHandler = ErrorHandler::getInstance();
$errorHandler->addUserError(
sprintf(
__(
'Unable to use timezone "%1$s" for server %2$d. '
. 'Please check your configuration setting for '
. '[em]$cfg[\'Servers\'][%3$d][\'SessionTimeZone\'][/em]. '
. 'phpMyAdmin is currently using the default time zone '
. 'of the database server.',
),
$currentServer->sessionTimeZone,
Current::$server,
Current::$server,
),
$currentServer->sessionTimeZone,
Current::$server,
Current::$server,
);
trigger_error($errorMessageTz, E_USER_WARNING);
}
}
@ -1092,10 +1091,8 @@ class DatabaseInterface
);
if ($result === false) {
trigger_error(
__('Failed to set configured collation connection!'),
E_USER_WARNING,
);
$errorHandler = ErrorHandler::getInstance();
$errorHandler->addUserError(__('Failed to set configured collation connection!'));
return;
}
@ -1606,33 +1603,20 @@ class DatabaseInterface
try {
$result = $this->extension->connect($server);
} catch (ConnectionException $exception) {
trigger_error($exception->getMessage(), E_USER_WARNING);
$errorHandler->addUserError($exception->getMessage());
return null;
}
$errorHandler->setHideLocation(false);
if ($result !== null) {
$this->connections[$target->value] = $result;
/* Run post connect for user connections */
if ($target === ConnectionType::User) {
$this->postConnect($currentServer);
}
return $result;
$this->connections[$target->value] = $result;
/* Run post connect for user connections */
if ($target === ConnectionType::User) {
$this->postConnect($currentServer);
}
if ($connectionType === ConnectionType::ControlUser) {
trigger_error(
__(
'Connection for controluser as defined in your configuration failed.',
),
E_USER_WARNING,
);
}
return null;
return $result;
}
/**
@ -1702,6 +1686,11 @@ class DatabaseInterface
return $this->extension->getError($this->connections[$connectionType->value]);
}
public function getConnectionErrorNumber(): int
{
return $this->extension->getConnectionErrorNumber();
}
/**
* returns last inserted auto_increment id for given $link
*/

View File

@ -20,7 +20,7 @@ interface DbiExtension
*
* @throws ConnectionException
*/
public function connect(Server $server): Connection|null;
public function connect(Server $server): Connection;
/**
* selects given database
@ -74,6 +74,11 @@ interface DbiExtension
*/
public function getError(Connection $connection): string;
/**
* Returns the error code for the most recent connection attempt.
*/
public function getConnectionErrorNumber(): int;
/**
* returns the number of rows affected by last query
*

View File

@ -16,8 +16,8 @@ use PhpMyAdmin\Query\Utilities;
use function __;
use function defined;
use function mysqli_connect_errno;
use function mysqli_get_client_info;
use function mysqli_init;
use function mysqli_report;
use function sprintf;
use function str_contains;
@ -39,15 +39,11 @@ use const MYSQLI_USE_RESULT;
*/
class DbiMysqli implements DbiExtension
{
public function connect(Server $server): Connection|null
public function connect(Server $server): Connection
{
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_init();
if ($mysqli === false) {
return null;
}
$mysqli = new mysqli();
$clientFlags = 0;
@ -254,6 +250,14 @@ class DbiMysqli implements DbiExtension
return Utilities::formatError($errorNumber, $errorMessage);
}
/**
* Returns the error code for the most recent connection attempt.
*/
public function getConnectionErrorNumber(): int
{
return mysqli_connect_errno();
}
/**
* returns the number of rows affected by last query
*

View File

@ -326,6 +326,10 @@ class Error extends Message
*/
public static function formatBacktrace(array $backtrace): string
{
if ($backtrace === []) {
return '';
}
$retval = '<ol class="list-group">';
foreach ($backtrace as $step) {

View File

@ -197,34 +197,24 @@ class ErrorHandler
string $errfile,
int $errline,
): bool {
if (function_exists('error_reporting')) {
/**
* Check if Error Control Operator (@) was used, but still show
* user errors even in this case.
* See: https://github.com/phpmyadmin/phpmyadmin/issues/16729
*/
$isSilenced = (error_reporting() & $errno) === 0;
$config = Config::getInstance();
if (
$config->config->environment === 'development'
&& ! $isSilenced
) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
if (
$isSilenced &&
$this->errorReporting != 0 &&
($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE | E_USER_DEPRECATED)) === 0
) {
return false;
}
} elseif (($errno & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE | E_USER_DEPRECATED)) === 0) {
if (! function_exists('error_reporting')) {
return false;
}
$this->addError($errstr, $errno, $errfile, $errline);
/**
* Check if Error Control Operator (@) was used.
* See: https://github.com/phpmyadmin/phpmyadmin/issues/16729
*/
$isSilenced = (error_reporting() & $errno) === 0;
$config = Config::getInstance();
if ($config->config->environment === 'development' && ! $isSilenced) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
if (! $isSilenced || $this->errorReporting === 0) {
$this->addError($errstr, $errno, $errfile, $errline);
}
return false;
}
@ -314,6 +304,30 @@ class ErrorHandler
}
}
public function addUserError(string $message, bool $escape = true): void
{
// The file name and line number are not relevant for user errors
$error = new Error(
E_USER_WARNING,
$escape ? htmlspecialchars($message) : $message,
__FILE__,
__LINE__,
);
$this->errors[$error->getHash()] = $error;
}
public function addNotice(string $message, bool $escape = true): void
{
// The file name and line number are not relevant for user errors
$error = new Error(
E_USER_NOTICE,
$escape ? htmlspecialchars($message) : $message,
__FILE__,
__LINE__,
);
$this->errors[$error->getHash()] = $error;
}
/**
* display fatal error and exit
*

View File

@ -12,6 +12,7 @@ use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\Current;
use PhpMyAdmin\Dbal\DatabaseInterface;
use PhpMyAdmin\Error\ErrorHandler;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Html\Generator;
@ -67,12 +68,9 @@ use function strnatcasecmp;
use function strrpos;
use function strstr;
use function substr;
use function trigger_error;
use function trim;
use function usort;
use const E_USER_WARNING;
/**
* Displays a collapsible of database objects in the navigation frame
*/
@ -739,13 +737,12 @@ class NavigationTree
foreach ($prefixes as $key => $value) {
// warn about large groups
if ($value > 500 && ! $this->largeGroupWarning) {
trigger_error(
ErrorHandler::getInstance()->addUserError(
__(
'There are large item groups in navigation panel which '
. 'may affect the performance. Consider disabling item '
. 'grouping in the navigation panel.',
),
E_USER_WARNING,
);
$this->largeGroupWarning = true;
}

View File

@ -11,7 +11,6 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\Dbal\DatabaseInterface;
use PhpMyAdmin\Error\ErrorHandler;
use PhpMyAdmin\Exceptions\AuthenticationFailure;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Http\Response;
use PhpMyAdmin\Plugins\AuthenticationPlugin;
use PhpMyAdmin\ResponseRenderer;
@ -23,10 +22,6 @@ use function count;
use function ob_get_clean;
use function ob_start;
use function sprintf;
use function trigger_error;
use const E_USER_NOTICE;
use const E_USER_WARNING;
/**
* Handles the config authentication method
@ -70,11 +65,8 @@ class AuthenticationConfig extends AuthenticationPlugin
public function showFailure(AuthenticationFailure $failure): Response
{
$this->logFailure($failure);
$connError = DatabaseInterface::getInstance()->getError();
if ($connError === '' || $connError === '0') {
$connError = __('Cannot connect: invalid settings.');
}
$dbi = DatabaseInterface::getInstance();
$errorHandler = ErrorHandler::getInstance();
/* HTML header */
$responseRenderer = ResponseRenderer::getInstance();
@ -97,7 +89,7 @@ class AuthenticationConfig extends AuthenticationPlugin
<td>';
$config = Config::getInstance();
if ($failure->failureType === AuthenticationFailure::ALLOW_DENIED) {
trigger_error($failure->getMessage(), E_USER_NOTICE);
$errorHandler->addNotice($failure->getMessage());
} else {
// Check whether user has configured something
if ($config->sourceMtime == 0) {
@ -110,11 +102,7 @@ class AuthenticationConfig extends AuthenticationPlugin
'<a href="setup/">',
'</a>',
) , '</p>' , "\n";
} elseif (
DatabaseInterface::$errorNumber === null
|| DatabaseInterface::$errorNumber !== 2002
&& DatabaseInterface::$errorNumber !== 2003
) {
} elseif ($dbi->getConnectionErrorNumber() !== 2002 && $dbi->getConnectionErrorNumber() !== 2003) {
// if we display the "Server not responding" error, do not confuse
// users by telling them they have a settings problem
// (note: it's true that they could have a badly typed host name,
@ -122,7 +110,7 @@ class AuthenticationConfig extends AuthenticationPlugin
// rejected the connection, which is not really what happened)
// 2002 is the error given by mysqli
// 2003 is the error given by mysql
trigger_error(
$errorHandler->addUserError(
__(
'phpMyAdmin tried to connect to the MySQL server, and the'
. ' server rejected the connection. You should check the'
@ -130,14 +118,11 @@ class AuthenticationConfig extends AuthenticationPlugin
. ' make sure that they correspond to the information given'
. ' by the administrator of the MySQL server.',
),
E_USER_WARNING,
);
}
echo Generator::mysqlDie($connError, '', true, '', false);
}
ErrorHandler::getInstance()->dispUserErrors();
$errorHandler->dispUserErrors();
echo '</td>
</tr>
<tr>

View File

@ -15,6 +15,7 @@ use PhpMyAdmin\Database\Events;
use PhpMyAdmin\Database\Routines;
use PhpMyAdmin\Dbal\ConnectionType;
use PhpMyAdmin\Dbal\DatabaseInterface;
use PhpMyAdmin\Exceptions\ExportException;
use PhpMyAdmin\Export\Export;
use PhpMyAdmin\Export\StructureOrData;
use PhpMyAdmin\Http\ServerRequest;
@ -44,7 +45,6 @@ use PhpMyAdmin\Version;
use function __;
use function array_keys;
use function bin2hex;
use function defined;
use function explode;
use function implode;
use function in_array;
@ -62,9 +62,7 @@ use function str_contains;
use function str_repeat;
use function str_replace;
use function strtoupper;
use function trigger_error;
use const E_USER_ERROR;
use const PHP_VERSION;
/**
@ -1420,11 +1418,8 @@ class ExportSql extends ExportPlugin
if ($tmpError !== '') {
$message = sprintf(__('Error reading structure for table %s:'), $db . '.' . $table);
$message .= ' ' . $tmpError;
if (! defined('TESTSUITE')) {
trigger_error($message, E_USER_ERROR);
}
return $this->exportComment($message);
throw new ExportException($message);
}
// Old mode is stored so it can be restored once exporting is done.
@ -2053,13 +2048,8 @@ class ExportSql extends ExportPlugin
if ($tmpError !== '') {
$message = sprintf(__('Error reading data for table %s:'), $db . '.' . $table);
$message .= ' ' . $tmpError;
if (! defined('TESTSUITE')) {
trigger_error($message, E_USER_ERROR);
}
return $this->export->outputHandler(
$this->exportComment($message),
);
throw new ExportException($message);
}
if ($result === false) {

View File

@ -18,6 +18,7 @@ use PhpMyAdmin\Controllers\Setup\ShowConfigController;
use PhpMyAdmin\Controllers\Setup\ValidateController;
use PhpMyAdmin\Core;
use PhpMyAdmin\Current;
use PhpMyAdmin\Error\ErrorHandler;
use PhpMyAdmin\Http\Factory\ResponseFactory;
use PhpMyAdmin\Http\Response;
use PhpMyAdmin\Http\ServerRequest;
@ -42,12 +43,10 @@ use function mb_strrpos;
use function mb_substr;
use function rawurldecode;
use function sprintf;
use function trigger_error;
use function urldecode;
use function var_export;
use const CACHE_DIR;
use const E_USER_WARNING;
/**
* Class used to warm up the routing cache and manage routing.
@ -119,7 +118,7 @@ class Routing
&& ! self::writeCache(sprintf('<?php return %s;', var_export($dispatchData, true)))
) {
$_SESSION['isRoutesCacheFileValid'] = false;
trigger_error(
ErrorHandler::getInstance()->addUserError(
sprintf(
__(
'The routing cache could not be written, '
@ -127,7 +126,6 @@ class Routing
),
self::ROUTES_CACHE_FILE,
),
E_USER_WARNING,
);
}
}

View File

@ -108,17 +108,6 @@ class AuthenticationConfigTest extends AbstractTestCase
$html,
);
self::assertStringContainsString(
'<strong>MySQL said: </strong><a href="index.php?route=/url&url=https%3A%2F%2F' .
'dev.mysql.com%2Fdoc%2Frefman%2F5.5%2Fen%2Fserver-error-reference.html"' .
' target="mysql_doc">' .
'<img src="themes/dot.gif" title="Documentation" alt="Documentation" ' .
'class="icon ic_b_help"></a>',
$html,
);
self::assertStringContainsString('Cannot connect: invalid settings.', $html);
self::assertStringContainsString(
'<a href="index.php?route=/&server=2&lang=en" '
. 'class="btn btn-primary mt-1 mb-1 disableAjax">Retry to connect</a>',

View File

@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\Current;
use PhpMyAdmin\Dbal\ConnectionType;
use PhpMyAdmin\Dbal\DatabaseInterface;
use PhpMyAdmin\Exceptions\ExportException;
use PhpMyAdmin\Export\Export;
use PhpMyAdmin\Http\Factory\ServerRequestFactory;
use PhpMyAdmin\Plugins\Export\ExportSql;
@ -855,11 +856,13 @@ SQL;
$this->object->setExportOptions($request, []);
$result = $this->object->getTableDef('db', 'table', true, false);
$this->expectException(ExportException::class);
$this->expectExceptionMessage('Error reading structure for table db.table: error occurred');
$this->object->getTableDef('db', 'table', true, false);
$dbiDummy->assertAllQueriesConsumed();
$dbiDummy->assertAllErrorCodesConsumed();
self::assertStringContainsString('-- Error reading structure for table db.table: error occurred', $result);
}
public function testGetTableComments(): void
@ -1257,15 +1260,12 @@ SQL;
$this->object->setExportOptions($request, []);
ob_start();
$this->expectException(ExportException::class);
$this->expectExceptionMessage('Error reading data for table db.table: err');
self::assertTrue(
$this->object->exportData('db', 'table', 'SELECT'),
);
$result = ob_get_clean();
self::assertIsString($result);
self::assertStringContainsString('-- Error reading data for table db.table: err', $result);
}
public function testMakeCreateTableMSSQLCompatible(): void

View File

@ -253,6 +253,14 @@ class DbiDummy implements DbiExtension
return array_shift($this->fifoErrorCodes) ?? '';
}
/**
* Returns the error code for the most recent connection attempt.
*/
public function getConnectionErrorNumber(): int
{
return 0;
}
/**
* returns the number of rows affected by last query
*