' . "\n";
}
if ($message instanceof Message) {
if (isset($GLOBALS['special_message'])) {
$message->addText($GLOBALS['special_message']);
unset($GLOBALS['special_message']);
}
$retval .= $message->getDisplay();
} else {
$context = 'primary';
if ($type === 'error') {
$context = 'danger';
} elseif ($type === 'success') {
$context = 'success';
}
$retval .= '
';
$retval .= Sanitize::sanitizeMessage($message);
if (isset($GLOBALS['special_message'])) {
$retval .= Sanitize::sanitizeMessage($GLOBALS['special_message']);
unset($GLOBALS['special_message']);
}
$retval .= '
';
}
if ($render_sql) {
$query_too_big = false;
$queryLength = mb_strlen($sql_query);
if ($queryLength > $cfg['MaxCharactersInDisplayedSQL']) {
// when the query is large (for example an INSERT of binary
// data), the parser chokes; so avoid parsing the query
$query_too_big = true;
$query_base = mb_substr(
$sql_query,
0,
$cfg['MaxCharactersInDisplayedSQL']
) . '[...]';
} else {
$query_base = $sql_query;
}
// Html format the query to be displayed
// If we want to show some sql code it is easiest to create it here
/* SQL-Parser-Analyzer */
if (! empty($GLOBALS['show_as_php'])) {
$new_line = '\\n"
' . "\n" . ' . "';
$query_base = htmlspecialchars(addslashes($query_base));
$query_base = preg_replace(
'/((\015\012)|(\015)|(\012))/',
$new_line,
$query_base
);
$query_base = '
' . "\n"
. '$sql = "' . $query_base . '";' . "\n"
. '';
} elseif ($query_too_big) {
$query_base = '
' . "\n" .
htmlspecialchars($query_base, ENT_COMPAT) .
'';
} else {
$query_base = self::formatSql($query_base);
}
// Prepares links that may be displayed to edit/explain the query
// (don't go to default pages, we must go to the page
// where the query box is available)
// Basic url query part
$url_params = [];
if (! isset($GLOBALS['db'])) {
$GLOBALS['db'] = '';
}
if (strlen($GLOBALS['db']) > 0) {
$url_params['db'] = $GLOBALS['db'];
if (strlen($GLOBALS['table']) > 0) {
$url_params['table'] = $GLOBALS['table'];
$edit_link = Url::getFromRoute('/table/sql');
} else {
$edit_link = Url::getFromRoute('/database/sql');
}
} else {
$edit_link = Url::getFromRoute('/server/sql');
}
// Want to have the query explained
// but only explain a SELECT (that has not been explained)
/* SQL-Parser-Analyzer */
$explain_link = '';
$is_select = preg_match('@^SELECT[[:space:]]+@i', $sql_query);
if (! empty($cfg['SQLQuery']['Explain']) && ! $query_too_big) {
$explain_params = $url_params;
if ($is_select) {
$explain_params['sql_query'] = 'EXPLAIN ' . $sql_query;
$explain_link = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $explain_params),
__('Explain SQL')
) . ' ]';
} elseif (preg_match(
'@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i',
$sql_query
)) {
$explain_params['sql_query']
= mb_substr($sql_query, 8);
$explain_link = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $explain_params),
__('Skip Explain SQL')
) . ']';
$url = 'https://mariadb.org/explain_analyzer/analyze/'
. '?client=phpMyAdmin&raw_explain='
. urlencode(self::generateRowQueryOutput($sql_query));
$explain_link .= ' ['
. self::linkOrButton(
htmlspecialchars('url.php?url=' . urlencode($url)),
sprintf(__('Analyze Explain at %s'), 'mariadb.org'),
[],
'_blank'
) . ' ]';
}
}
$url_params['sql_query'] = $sql_query;
$url_params['show_query'] = 1;
// even if the query is big and was truncated, offer the chance
// to edit it (unless it's enormous, see linkOrButton() )
if (! empty($cfg['SQLQuery']['Edit'])
&& empty($GLOBALS['show_as_php'])
) {
$edit_link .= Url::getCommon($url_params, '&');
$edit_link = ' [ '
. self::linkOrButton($edit_link, __('Edit'))
. ' ]';
} else {
$edit_link = '';
}
// Also we would like to get the SQL formed in some nice
// php-code
if (! empty($cfg['SQLQuery']['ShowAsPHP']) && ! $query_too_big) {
if (! empty($GLOBALS['show_as_php'])) {
$php_link = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $url_params),
__('Without PHP code')
)
. ' ]';
$php_link .= ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $url_params),
__('Submit query')
)
. ' ]';
} else {
$php_params = $url_params;
$php_params['show_as_php'] = 1;
$php_link = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $php_params),
__('Create PHP code')
)
. ' ]';
}
} else {
$php_link = '';
}
// Refresh query
if (! empty($cfg['SQLQuery']['Refresh'])
&& ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same
&& preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sql_query)
) {
$refresh_link = Url::getFromRoute('/sql', $url_params);
$refresh_link = ' [ '
. self::linkOrButton($refresh_link, __('Refresh')) . ' ]';
} else {
$refresh_link = '';
}
$retval .= '
';
$retval .= $query_base;
$retval .= '
';
$retval .= '
';
$retval .= '';
/**
* TODO: Should we have $cfg['SQLQuery']['InlineEdit']?
*/
if (! empty($cfg['SQLQuery']['Edit'])
&& ! $query_too_big
&& empty($GLOBALS['show_as_php'])
) {
$inline_edit_link = ' [ '
. self::linkOrButton(
'#',
_pgettext('Inline edit query', 'Edit inline'),
['class' => 'inline_edit_sql']
)
. ' ]';
} else {
$inline_edit_link = '';
}
$retval .= $inline_edit_link . $edit_link . $explain_link . $php_link
. $refresh_link;
$retval .= '
';
$retval .= '
';
}
return $retval;
}
/**
* Displays a link to the PHP documentation
*
* @param string $target anchor in documentation
*
* @return string the html link
*
* @access public
*/
public static function showPHPDocumentation($target): string
{
return self::showDocumentationLink(Core::getPHPDocLink($target));
}
/**
* Displays a link to the documentation as an icon
*
* @param string $link documentation link
* @param string $target optional link target
* @param bool $bbcode optional flag indicating whether to output bbcode
*
* @return string the html link
*
* @access public
*/
public static function showDocumentationLink($link, $target = 'documentation', $bbcode = false): string
{
if ($bbcode) {
return '[a@' . $link . '@' . $target . '][dochelpicon][/a]';
}
return '' . __('Error') . '
';
// For security reasons, if the MySQL refuses the connection, the query
// is hidden so no details are revealed.
if (! empty($sql_query) && ! mb_strstr($sql_query, 'connect')) {
// Static analysis errors.
if (! empty($errors)) {
$error_msg .= '
' . __('Static analysis:')
. '
';
$error_msg .= '
' . sprintf(
__('%d errors were found during analysis.'),
count($errors)
) . '
';
$error_msg .= '
';
$error_msg .= implode(
ParserError::format(
$errors,
'- %2$s (near "%4$s" at position %5$d)
'
)
);
$error_msg .= '
';
}
// Display the SQL query and link to MySQL documentation.
$error_msg .= '
' . __('SQL query:') . '' . self::showCopyToClipboard(
$sql_query
) . "\n";
$formattedSqlToLower = mb_strtolower($formatted_sql);
// TODO: Show documentation for all statement types.
if (mb_strstr($formattedSqlToLower, 'select')) {
// please show me help to the error on select
$error_msg .= MySQLDocumentation::show('SELECT');
}
if ($is_modify_link) {
$_url_params = [
'sql_query' => $sql_query,
'show_query' => 1,
];
if (strlen($table) > 0) {
$_url_params['db'] = $db;
$_url_params['table'] = $table;
$doedit_goto = '';
} elseif (strlen($db) > 0) {
$_url_params['db'] = $db;
$doedit_goto = '';
} else {
$doedit_goto = '';
}
$error_msg .= $doedit_goto
. self::getIcon('b_edit', __('Edit'))
. '';
}
$error_msg .= '
' . "\n"
. '
' . "\n"
. $formatted_sql . "\n"
. '
' . "\n";
}
// Display server's error.
if (! empty($server_msg)) {
$server_msg = (string) preg_replace(
"@((\015\012)|(\015)|(\012)){3,}@",
"\n\n",
(string) $server_msg
);
// Adds a link to MySQL documentation.
$error_msg .= '
' . "\n"
. ' ' . __('MySQL said: ') . ''
. MySQLDocumentation::show('server-error-reference')
. "\n"
. '
' . "\n";
// The error message will be displayed within a CODE segment.
// To preserve original formatting, but allow word-wrapping,
// a couple of replacements are done.
// All non-single blanks and TAB-characters are replaced with their
// HTML-counterpart
$server_msg = str_replace(
[
' ',
"\t",
],
[
' ',
' ',
],
$server_msg
);
// Replace line breaks
$server_msg = nl2br($server_msg);
$error_msg .= '
' . $server_msg . '';
}
$error_msg .= '
';
$_SESSION['Import_message']['message'] = $error_msg;
if (! $exit) {
return $error_msg;
}
/**
* If this is an AJAX request, there is no "Back" link and
* `Response()` is used to send the response.
*/
$response = Response::getInstance();
if ($response->isAjax()) {
$response->setRequestStatus(false);
$response->addJSON('message', $error_msg);
exit;
}
if (! empty($back_url)) {
if (mb_strstr($back_url, '?')) {
$back_url .= '&no_history=true';
} else {
$back_url .= '?no_history=true';
}
$_SESSION['Import_message']['go_back_url'] = $back_url;
$error_msg .= '' . "\n\n";
}
exit($error_msg);
}
/**
* Returns an HTML IMG tag for a particular image from a theme
*
* The image name should match CSS class defined in icons.css.php
*
* @param string $image The name of the file to get
* @param string $alternate Used to set 'alt' and 'title' attributes
* of the image
* @param array $attributes An associative array of other attributes
*
* @return string an html IMG tag
*/
public static function getImage($image, $alternate = '', array $attributes = []): string
{
$alternate = htmlspecialchars($alternate);
if (isset($attributes['class'])) {
$attributes['class'] = 'icon ic_' . $image . ' ' . $attributes['class'];
} else {
$attributes['class'] = 'icon ic_' . $image;
}
// set all other attributes
$attr_str = '';
foreach ($attributes as $key => $value) {
if (in_array($key, ['alt', 'title'])) {
continue;
}
$attr_str .= ' ' . $key . '="' . $value . '"';
}
// override the alt attribute
$alt = $attributes['alt'] ?? $alternate;
// override the title attribute
$title = $attributes['title'] ?? $alternate;
// generate the IMG tag
$template = '';
if ($frame !== 'frame_navigation') {
$list_navigator_html .= __('Page number:');
}
// Move to the beginning or to the previous page
if ($pos > 0) {
$caption1 = '';
$caption2 = '';
if (Util::showIcons('TableNavigationLinksMode')) {
$caption1 .= '<< ';
$caption2 .= '< ';
}
if (Util::showText('TableNavigationLinksMode')) {
$caption1 .= _pgettext('First page', 'Begin');
$caption2 .= _pgettext('Previous page', 'Previous');
}
$title1 = ' title="' . _pgettext('First page', 'Begin') . '"';
$title2 = ' title="' . _pgettext('Previous page', 'Previous') . '"';
$_url_params[$name] = 0;
$list_navigator_html .= '
' . $caption1
. '';
$_url_params[$name] = $pos - $max_count;
$list_navigator_html .= '
'
. $caption2 . '';
}
$list_navigator_html .= '
';
if ($pos + $max_count < $count) {
$caption3 = '';
$caption4 = '';
if (Util::showText('TableNavigationLinksMode')) {
$caption3 .= _pgettext('Next page', 'Next');
$caption4 .= _pgettext('Last page', 'End');
}
if (Util::showIcons('TableNavigationLinksMode')) {
$caption3 .= ' >';
$caption4 .= ' >>';
}
$title3 = ' title="' . _pgettext('Next page', 'Next') . '"';
$title4 = ' title="' . _pgettext('Last page', 'End') . '"';
$_url_params[$name] = $pos + $max_count;
$list_navigator_html .= '
' . $caption3
. '';
$_url_params[$name] = floor($count / $max_count) * $max_count;
if ($_url_params[$name] == $count) {
$_url_params[$name] = $count - $max_count;
}
$list_navigator_html .= '
'
. $caption4 . '';
}
$list_navigator_html .= '
' . "\n";
}
return $list_navigator_html;
}
/**
* format sql strings
*
* @param string $sqlQuery raw SQL string
* @param bool $truncate truncate the query if it is too long
*
* @return string the formatted sql
*
* @global array $cfg the configuration array
*
* @access public
*/
public static function formatSql($sqlQuery, $truncate = false): string
{
global $cfg;
if ($truncate
&& mb_strlen($sqlQuery) > $cfg['MaxCharactersInDisplayedSQL']
) {
$sqlQuery = mb_substr(
$sqlQuery,
0,
$cfg['MaxCharactersInDisplayedSQL']
) . '[...]';
}
return '