' . "\n"
. '$sql = "' . $queryBase . '";' . "\n"
. '';
} elseif ($queryTooBig) {
$queryBase = '' . "\n" .
htmlspecialchars($queryBase, ENT_COMPAT) .
'';
} else {
$queryBase = self::formatSql($queryBase);
}
// 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
$urlParams = [];
if (! isset($GLOBALS['db'])) {
$GLOBALS['db'] = '';
}
if (strlen($GLOBALS['db']) > 0) {
$urlParams['db'] = $GLOBALS['db'];
if (strlen($GLOBALS['table']) > 0) {
$urlParams['table'] = $GLOBALS['table'];
$editLink = Url::getFromRoute('/table/sql');
} else {
$editLink = Url::getFromRoute('/database/sql');
}
} else {
$editLink = Url::getFromRoute('/server/sql');
}
// Want to have the query explained
// but only explain a SELECT (that has not been explained)
/* SQL-Parser-Analyzer */
$explainLink = '';
$isSelect = preg_match('@^SELECT[[:space:]]+@i', $sqlQuery);
if (! empty($cfg['SQLQuery']['Explain']) && ! $queryTooBig) {
$explainParams = $urlParams;
if ($isSelect) {
$explainParams['sql_query'] = 'EXPLAIN ' . $sqlQuery;
$explainLink = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $explainParams),
__('Explain SQL')
) . ' ]';
} elseif (
preg_match(
'@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i',
$sqlQuery
)
) {
$explainParams['sql_query'] = mb_substr($sqlQuery, 8);
$explainLink = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $explainParams),
__('Skip Explain SQL')
) . ']';
$url = 'https://mariadb.org/explain_analyzer/analyze/'
. '?client=phpMyAdmin&raw_explain='
. urlencode(self::generateRowQueryOutput($sqlQuery));
$explainLink .= ' ['
. self::linkOrButton(
htmlspecialchars('url.php?url=' . urlencode($url)),
sprintf(__('Analyze Explain at %s'), 'mariadb.org'),
[],
'_blank'
) . ' ]';
}
}
$urlParams['sql_query'] = $sqlQuery;
$urlParams['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'])
) {
$editLink .= Url::getCommon($urlParams, '&');
$editLink = ' [ '
. self::linkOrButton($editLink, __('Edit'))
. ' ]';
} else {
$editLink = '';
}
// Also we would like to get the SQL formed in some nice
// php-code
if (! empty($cfg['SQLQuery']['ShowAsPHP']) && ! $queryTooBig) {
if (! empty($GLOBALS['show_as_php'])) {
$phpLink = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $urlParams),
__('Without PHP code')
)
. ' ]';
$phpLink .= ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $urlParams),
__('Submit query')
)
. ' ]';
} else {
$phpParams = $urlParams;
$phpParams['show_as_php'] = 1;
$phpLink = ' [ '
. self::linkOrButton(
Url::getFromRoute('/import', $phpParams),
__('Create PHP code')
)
. ' ]';
}
} else {
$phpLink = '';
}
// Refresh query
if (
! empty($cfg['SQLQuery']['Refresh'])
&& ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same
&& preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sqlQuery)
) {
$refreshLink = Url::getFromRoute('/sql', $urlParams);
$refreshLink = ' [ '
. self::linkOrButton($refreshLink, __('Refresh')) . ' ]';
} else {
$refreshLink = '';
}
$retval .= '' . __('Static analysis:') . '
'; $errorMessage .= '' . sprintf( __('%d errors were found during analysis.'), count($errors) ) . '
'; $errorMessage .= '' . __('SQL query:') . '' . self::showCopyToClipboard( $sqlQuery ) . "\n"; $formattedSqlToLower = mb_strtolower($formattedSql); // TODO: Show documentation for all statement types. if (mb_strstr($formattedSqlToLower, 'select')) { // please show me help to the error on select $errorMessage .= MySQLDocumentation::show('SELECT'); } if ($isModifyLink) { $urlParams = [ 'sql_query' => $sqlQuery, 'show_query' => 1, ]; if (strlen($table) > 0) { $urlParams['db'] = $db; $urlParams['table'] = $table; $doEditGoto = ''; } elseif (strlen($db) > 0) { $urlParams['db'] = $db; $doEditGoto = ''; } else { $doEditGoto = ''; } $errorMessage .= $doEditGoto . self::getIcon('b_edit', __('Edit')) . ''; } $errorMessage .= '
' . "\n" . '' . "\n" . $formattedSql . "\n" . '
' . "\n"; } // Display server's error. if (! empty($serverMessage)) { $serverMessage = (string) preg_replace( "@((\015\012)|(\015)|(\012)){3,}@", "\n\n", (string) $serverMessage ); // Adds a link to MySQL documentation. $errorMessage .= '' . "\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 $serverMessage = str_replace( [ ' ', "\t", ], [ ' ', ' ', ], $serverMessage ); // Replace line breaks $serverMessage = nl2br($serverMessage); $errorMessage .= '' . $serverMessage . '
';
return sprintf($template, $title, $alt, $attributeString);
}
/**
* Displays a link, or a link with code to trigger POST request.
*
* POST is used in following cases:
*
* - URL is too long
* - 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 $tagParams 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,
$message,
$tagParams = [],
$target = ''
): string {
$urlLength = strlen($url);
if (! is_array($tagParams)) {
$tmp = $tagParams;
$tagParams = [];
if (! empty($tmp)) {
$tagParams['onclick'] = 'return Functions.confirmLink(this, \''
. Sanitize::escapeJsString($tmp) . '\')';
}
unset($tmp);
}
if (! empty($target)) {
$tagParams['target'] = $target;
if ($target === '_blank' && strncmp($url, 'url.php?', 8) == 0) {
$tagParams['rel'] = 'noopener noreferrer';
}
}
// Suhosin: Check that each query parameter is not above maximum
$inSuhosinLimits = true;
if ($urlLength <= $GLOBALS['cfg']['LinkLengthLimit']) {
$suhosinGetMaxValueLength = ini_get('suhosin.get.max_value_length');
if ($suhosinGetMaxValueLength) {
$queryParts = Util::splitURLQuery($url);
foreach ($queryParts as $queryPair) {
if (strpos($queryPair, '=') === false) {
continue;
}
[, $eachValue] = explode('=', $queryPair);
if (strlen($eachValue) > $suhosinGetMaxValueLength) {
$inSuhosinLimits = false;
break;
}
}
}
}
$tagParamsStrings = [];
if (
($urlLength > $GLOBALS['cfg']['LinkLengthLimit'])
|| ! $inSuhosinLimits
// Has as sql_query without a signature
|| (strpos($url, 'sql_query=') !== false && strpos($url, 'sql_signature=') === false)
|| strpos($url, 'view[as]=') !== false
) {
$parts = explode('?', $url, 2);
/*
* The data-post indicates that client should do POST
* this is handled in js/ajax.js
*/
$tagParamsStrings[] = 'data-post="' . ($parts[1] ?? '') . '"';
$url = $parts[0];
if (
array_key_exists('class', $tagParams)
&& strpos($tagParams['class'], 'create_view') !== false
) {
$url .= '?' . explode('&', $parts[1], 2)[0];
}
}
foreach ($tagParams as $paramName => $paramValue) {
$tagParamsStrings[] = $paramName . '="' . htmlspecialchars($paramValue) . '"';
}
// no whitespace within an else Safari will make it part of the link
return ''
. $message . '';
}
/**
* Prepare navigation for a list
*
* @param int $count number of elements in the list
* @param int $pos current position in the list
* @param array $urlParams url parameters
* @param string $script script name for form target
* @param string $frame target frame
* @param int $maxCount maximum number of elements to display from
* the list
* @param string $name the name for the request parameter
* @param string[] $classes additional classes for the container
*
* @return string the html content
*
* @access public
*
* @todo use $pos from $_url_params
*/
public static function getListNavigator(
$count,
$pos,
array $urlParams,
$script,
$frame,
$maxCount,
$name = 'pos',
$classes = []
): string {
// This is often coming from $cfg['MaxTableList'] and
// people sometimes set it to empty string
$maxCount = intval($maxCount);
if ($maxCount <= 0) {
$maxCount = 250;
}
$class = $frame === 'frame_navigation' ? ' class="ajax"' : '';
$listNavigatorHtml = '';
if ($maxCount < $count) {
$classes[] = 'pageselector';
$listNavigatorHtml .= '' . "\n"
. htmlspecialchars($sqlQuery, ENT_COMPAT) . "\n"
. '';
}
/**
* This function processes the datatypes supported by the DB,
* as specified in Types->getColumns() and returns an HTML snippet that
* creates a drop-down list.
*
* @param string $selected The value to mark as selected in HTML mode
*/
public static function getSupportedDatatypes($selected): string
{
global $dbi;
// NOTE: the SELECT tag is not included in this snippet.
$retval = '';
foreach ($dbi->types->getColumns() as $key => $value) {
if (is_array($value)) {
$retval .= '';
} elseif ($selected == $value) {
$retval .= sprintf(
'',
$dbi->types->getTypeDescription($value),
$value
);
} else {
$retval .= sprintf(
'',
$dbi->types->getTypeDescription($value),
$value
);
}
}
return $retval;
}
}