'; if ($include_icon) { $button .= self::getImage($icon, $alternate); } if ($include_icon && $include_text) { $button .= ' '; } if ($include_text) { $button .= $alternate; } $button .= $menu_icon ? '' : ''; return $button; } /** * Returns an HTML IMG tag for a particular image from a theme, * which may be an actual file or an icon from a sprite * * @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 = '', $attributes = array()) { static $sprites; // cached list of available sprites (if any) if (defined('TESTSUITE')) { // prevent caching in testsuite unset($sprites); } $url = ''; $is_sprite = false; $alternate = htmlspecialchars($alternate); // If it's the first time this function is called if (! isset($sprites)) { // Try to load the list of sprites if (is_readable($_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php')) { include_once $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; $sprites = PMA_sprites(); } else { // No sprites are available for this theme $sprites = array(); } } // Check if we have the requested image as a sprite // and set $url accordingly $class = str_replace(array('.gif','.png'), '', $image); if (array_key_exists($class, $sprites)) { $is_sprite = true; $url = (defined('PMA_TEST_THEME') ? '../' : '') . 'themes/dot.gif'; } else { $url = $GLOBALS['pmaThemeImage'] . $image; } // set class attribute if ($is_sprite) { if (isset($attributes['class'])) { $attributes['class'] = "icon ic_$class " . $attributes['class']; } else { $attributes['class'] = "icon ic_$class"; } } // set all other attributes $attr_str = ''; foreach ($attributes as $key => $value) { if (! in_array($key, array('alt', 'title'))) { $attr_str .= " $key=\"$value\""; } } // override the alt attribute if (isset($attributes['alt'])) { $alt = $attributes['alt']; } else { $alt = $alternate; } // override the title attribute if (isset($attributes['title'])) { $title = $attributes['title']; } else { $title = $alternate; } // generate the IMG tag $template = ''; $retval = sprintf($template, $url, $title, $alt, $attr_str); return $retval; } /** * Returns the formatted maximum size for an upload * * @param integer $max_upload_size the size * * @return string the message * * @access public */ public static function getFormattedMaximumUploadSize($max_upload_size) { // I have to reduce the second parameter (sensitiveness) from 6 to 4 // to avoid weird results like 512 kKib list($max_size, $max_unit) = self::formatByteDown($max_upload_size, 4); return '(' . sprintf(__('Max: %s%s'), $max_size, $max_unit) . ')'; } /** * Generates a hidden field which should indicate to the browser * the maximum size for upload * * @param integer $max_size the size * * @return string the INPUT field * * @access public */ public static function generateHiddenMaxFileSize($max_size) { return ''; } /** * Add slashes before "'" and "\" characters so a value containing them can * be used in a sql comparison. * * @param string $a_string the string to slash * @param bool $is_like whether the string will be used in a 'LIKE' clause * (it then requires two more escaped sequences) or not * @param bool $crlf whether to treat cr/lfs as escape-worthy entities * (converts \n to \\n, \r to \\r) * @param bool $php_code whether this function is used as part of the * "Create PHP code" dialog * * @return string the slashed string * * @access public */ public static function sqlAddSlashes( $a_string = '', $is_like = false, $crlf = false, $php_code = false ) { if ($is_like) { $a_string = str_replace('\\', '\\\\\\\\', $a_string); } else { $a_string = str_replace('\\', '\\\\', $a_string); } if ($crlf) { $a_string = strtr( $a_string, array("\n" => '\n', "\r" => '\r', "\t" => '\t') ); } if ($php_code) { $a_string = str_replace('\'', '\\\'', $a_string); } else { $a_string = str_replace('\'', '\'\'', $a_string); } return $a_string; } // end of the 'sqlAddSlashes()' function /** * Add slashes before "_" and "%" characters for using them in MySQL * database, table and field names. * Note: This function does not escape backslashes! * * @param string $name the string to escape * * @return string the escaped string * * @access public */ public static function escapeMysqlWildcards($name) { return strtr($name, array('_' => '\\_', '%' => '\\%')); } // end of the 'escapeMysqlWildcards()' function /** * removes slashes before "_" and "%" characters * Note: This function does not unescape backslashes! * * @param string $name the string to escape * * @return string the escaped string * * @access public */ public static function unescapeMysqlWildcards($name) { return strtr($name, array('\\_' => '_', '\\%' => '%')); } // end of the 'unescapeMysqlWildcards()' function /** * removes quotes (',",`) from a quoted string * * checks if the string is quoted and removes this quotes * * @param string $quoted_string string to remove quotes from * @param string $quote type of quote to remove * * @return string unqoted string */ public static function unQuote($quoted_string, $quote = null) { $quotes = array(); if ($quote === null) { $quotes[] = '`'; $quotes[] = '"'; $quotes[] = "'"; } else { $quotes[] = $quote; } foreach ($quotes as $quote) { if (substr($quoted_string, 0, 1) === $quote && substr($quoted_string, -1, 1) === $quote ) { $unquoted_string = substr($quoted_string, 1, -1); // replace escaped quotes $unquoted_string = str_replace( $quote . $quote, $quote, $unquoted_string ); return $unquoted_string; } } return $quoted_string; } /** * format sql strings * * @param mixed $parsed_sql pre-parsed SQL structure * @param string $unparsed_sql raw SQL string * * @return string the formatted sql * * @global array the configuration array * @global boolean whether the current statement is a multiple one or not * * @access public * @todo move into PMA_Sql */ public static function formatSql($parsed_sql, $unparsed_sql = '') { global $cfg; // Check that we actually have a valid set of parsed data // well, not quite // first check for the SQL parser having hit an error if (PMA_SQP_isError()) { return htmlspecialchars($parsed_sql['raw']); } // then check for an array if (! is_array($parsed_sql)) { // We don't so just return the input directly // This is intended to be used for when the SQL Parser is turned off $formatted_sql = "
\n"; if (($cfg['SQP']['fmtType'] == 'none') && ($unparsed_sql != '')) { $formatted_sql .= $unparsed_sql; } else { $formatted_sql .= $parsed_sql; } $formatted_sql .= "\n"; return $formatted_sql; } $formatted_sql = ''; switch ($cfg['SQP']['fmtType']) { case 'none': if ($unparsed_sql != '') { $formatted_sql = '
' . "\n" . PMA_SQP_formatNone(array('raw' => $unparsed_sql)) . "\n" . ''; } else { $formatted_sql = PMA_SQP_formatNone($parsed_sql); } break; case 'html': $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'color'); break; case 'text': $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'text'); break; default: break; } // end switch return $formatted_sql; } // end of the "formatSql()" function /** * Displays a link to the documentation as an icon * * @param string $link documentation link * @param string $target optional link target * * @return string the html link * * @access public */ public static function showDocLink($link, $target = 'documentation') { return '' . self::getImage('b_help.png', __('Documentation')) . ''; } // end of the 'showDocLink()' function /** * Displays a link to the official MySQL documentation * * @param string $chapter chapter of "HTML, one page per chapter" documentation * @param string $link contains name of page/anchor that is being linked * @param bool $big_icon whether to use big icon (like in left frame) * @param string $anchor anchor to page part * @param bool $just_open whether only the opening tag should be returned * * @return string the html link * * @access public */ public static function showMySQLDocu( $chapter, $link, $big_icon = false, $anchor = '', $just_open = false ) { global $cfg; if (($cfg['MySQLManualType'] == 'none') || empty($cfg['MySQLManualBase'])) { return ''; } // Fixup for newly used names: $chapter = str_replace('_', '-', strtolower($chapter)); $link = str_replace('_', '-', strtolower($link)); switch ($cfg['MySQLManualType']) { case 'chapters': if (empty($chapter)) { $chapter = 'index'; } if (empty($anchor)) { $anchor = $link; } $url = $cfg['MySQLManualBase'] . '/' . $chapter . '.html#' . $anchor; break; case 'big': if (empty($anchor)) { $anchor = $link; } $url = $cfg['MySQLManualBase'] . '#' . $anchor; break; case 'searchable': if (empty($link)) { $link = 'index'; } $url = $cfg['MySQLManualBase'] . '/' . $link . '.html'; if (! empty($anchor)) { $url .= '#' . $anchor; } break; case 'viewable': default: if (empty($link)) { $link = 'index'; } $mysql = '5.5'; $lang = 'en'; if (defined('PMA_MYSQL_INT_VERSION')) { if (PMA_MYSQL_INT_VERSION >= 50600) { $mysql = '5.6'; } else if (PMA_MYSQL_INT_VERSION >= 50500) { $mysql = '5.5'; } else if (PMA_MYSQL_INT_VERSION >= 50100) { $mysql = '5.1'; } else { $mysql = '5.0'; } } $url = $cfg['MySQLManualBase'] . '/' . $mysql . '/' . $lang . '/' . $link . '.html'; if (! empty($anchor)) { $url .= '#' . $anchor; } break; } $open_link = ''; if ($just_open) { return $open_link; } elseif ($big_icon) { return $open_link . self::getImage('b_sqlhelp.png', __('Documentation')) . ''; } else { return self::showDocLink(PMA_linkURL($url), 'mysql_doc'); } } // end of the 'showMySQLDocu()' function /** * Returns link to documentation. * * @param string $page Page in documentation * @param string $anchor Optional anchor in page * * @return string URL */ public static function getDocuLink($page, $anchor = '') { /* Construct base URL */ $url = $page . '.html'; if (!empty($anchor)) { $url .= '#' . $anchor; } /* Check if we have built local documentation */ if (defined('TESTSUITE')) { /* Provide consistent URL for testsuite */ return PMA_linkURL('https://docs.phpmyadmin.net/en/latest/' . $url); } else if (file_exists('doc/html/index.html')) { if (defined('PMA_SETUP')) { return '../doc/html/' . $url; } else { return './doc/html/' . $url; } } else { /* TODO: Should link to correct branch for released versions */ return PMA_linkURL('https://docs.phpmyadmin.net/en/latest/' . $url); } } /** * Displays a link to the phpMyAdmin documentation * * @param string $page Page in documentation * @param string $anchor Optional anchor in page * * @return string the html link * * @access public */ public static function showDocu($page, $anchor = '') { return self::showDocLink(self::getDocuLink($page, $anchor)); } // end of the 'showDocu()' function /** * Displays a link to the PHP documentation * * @param string $target anchor in documentation * * @return string the html link * * @access public */ public static function showPHPDocu($target) { $url = PMA_getPHPDocLink($target); return self::showDocLink($url); } // end of the 'showPHPDocu()' function /** * Returns HTML code for a tooltip * * @param string $message the message for the tooltip * * @return string * * @access public */ public static function showHint($message) { if ($GLOBALS['cfg']['ShowHint']) { $classClause = ' class="pma_hint"'; } else { $classClause = ''; } return '' . self::getImage('b_help.png') . '' . $message . '' . ''; } /** * Displays a MySQL error message in the main panel when $exit is true. * Returns the error message otherwise. * * @param string $error_message the error message * @param string $the_query the sql query that failed * @param bool $is_modify_link whether to show a "modify" link or not * @param string $back_url the "back" link url (full path is not required) * @param bool $exit EXIT the page? * * @return mixed * * @global string the curent table * @global string the current db * * @access public */ public static function mysqlDie( $error_message = '', $the_query = '', $is_modify_link = true, $back_url = '', $exit = true ) { global $table, $db; $error_msg = ''; if (! $error_message) { $error_message = PMA_DBI_getError(); } if (! $the_query && ! empty($GLOBALS['sql_query'])) { $the_query = $GLOBALS['sql_query']; } // --- Added to solve bug #641765 if (! function_exists('PMA_SQP_isError') || PMA_SQP_isError()) { $formatted_sql = htmlspecialchars($the_query); } elseif (empty($the_query) || (trim($the_query) == '')) { $formatted_sql = ''; } else { if (strlen($the_query) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { $formatted_sql = htmlspecialchars( substr( $the_query, 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL'] ) ) . '[...]'; } else { $formatted_sql = self::formatSql( PMA_SQP_parse($the_query), $the_query ); } } // --- $error_msg .= "\n" . '' . "\n"; $error_msg .= '
' . __('SQL query') . ':' . "\n"; if (strstr(strtolower($formatted_sql), 'select')) { // please show me help to the error on select $error_msg .= self::showMySQLDocu('SQL-Syntax', 'SELECT'); } if ($is_modify_link) { $_url_params = array( 'sql_query' => $the_query, 'show_query' => 1, ); if (strlen($table)) { $_url_params['db'] = $db; $_url_params['table'] = $table; $doedit_goto = ''; } elseif (strlen($db)) { $_url_params['db'] = $db; $doedit_goto = ''; } else { $doedit_goto = ''; } $error_msg .= $doedit_goto . self::getIcon('b_edit.png', __('Edit')) . ''; } // end if $error_msg .= '
' . "\n" .'' . "\n" . $formatted_sql . "\n" . '
' . "\n"; } // end if if (! empty($error_message)) { $error_message = preg_replace( "@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $error_message ); } // modified to show the help on error-returns // (now error-messages-server) $error_msg .= '' . "\n" . ' ' . __('MySQL said: ') . '' . self::showMySQLDocu('Error-messages-server', 'Error-messages-server') . "\n" . '
' . "\n"; // The error message will be displayed within a CODE segment. // To preserve original formatting, but allow wordwrapping, // we do a couple of replacements // Replace all non-single blanks with their HTML-counterpart $error_message = str_replace(' ', ' ', $error_message); // Replace TAB-characters with their HTML-counterpart $error_message = str_replace( "\t", ' ', $error_message ); // Replace linebreaks $error_message = nl2br($error_message); $error_msg .= '' . "\n"
. $error_message . "\n"
. '
* echo backquote('owner`s db'); // `owner``s db`
*
*
*
* @param mixed $a_name the database, table or field name to "backquote"
* or array of it
* @param boolean $do_it a flag to bypass this function (used by dump
* functions)
*
* @return mixed the "backquoted" database, table or field name
*
* @access public
*/
public static function backquote($a_name, $do_it = true)
{
if (is_array($a_name)) {
foreach ($a_name as &$data) {
$data = self::backquote($data, $do_it);
}
return $a_name;
}
if (! $do_it) {
global $PMA_SQPdata_forbidden_word;
if (! in_array(strtoupper($a_name), $PMA_SQPdata_forbidden_word)) {
return $a_name;
}
}
// '0' is also empty for php :-(
if (strlen($a_name) && $a_name !== '*') {
return '`' . str_replace('`', '``', $a_name) . '`';
} else {
return $a_name;
}
} // end of the 'backquote()' function
/**
* Adds quotes on both sides of a database, table or field name.
* in compatibility mode
*
* example:
*
* echo backquote('owner`s db'); // `owner``s db`
*
*
*
* @param mixed $a_name the database, table or field name to
* "backquote" or array of it
* @param string $compatibility string compatibility mode (used by dump
* functions)
* @param boolean $do_it a flag to bypass this function (used by dump
* functions)
*
* @return mixed the "backquoted" database, table or field name
*
* @access public
*/
public static function backquoteCompat(
$a_name, $compatibility = 'MSSQL', $do_it = true
) {
if (is_array($a_name)) {
foreach ($a_name as &$data) {
$data = self::backquoteCompat($data, $compatibility, $do_it);
}
return $a_name;
}
if (! $do_it) {
global $PMA_SQPdata_forbidden_word;
if (! in_array(strtoupper($a_name), $PMA_SQPdata_forbidden_word)) {
return $a_name;
}
}
// @todo add more compatibility cases (ORACLE for example)
switch ($compatibility) {
case 'MSSQL':
$quote = '"';
break;
default:
(isset($GLOBALS['sql_backquotes'])) ? $quote = "`" : $quote = '';
break;
}
// '0' is also empty for php :-(
if (strlen($a_name) && $a_name !== '*') {
return $quote . $a_name . $quote;
} else {
return $a_name;
}
} // end of the 'backquoteCompat()' function
/**
* Defines the ';
}
if ($query_too_big) {
$retval .= $shortened_query_base;
} else {
$retval .= $query_base;
}
//Clean up the end of the PHP
if (! empty($GLOBALS['show_as_php'])) {
$retval .= '";';
}
if (! empty($GLOBALS['validatequery'])) {
$retval .= '
* echo formatNumber(123456789, 6); // 123,457 k
* echo formatNumber(-123456789, 4, 2); // -123.46 M
* echo formatNumber(-0.003, 6); // -3 m
* echo formatNumber(0.003, 3, 3); // 0.003
* echo formatNumber(0.00003, 3, 2); // 0.03 m
* echo formatNumber(0, 6); // 0
*
*
* @param double $value the value to format
* @param integer $digits_left number of digits left of the comma
* @param integer $digits_right number of digits right of the comma
* @param boolean $only_down do not reformat numbers below 1
* @param boolean $noTrailingZero removes trailing zeros right of the comma
* (default: true)
*
* @return string the formatted value and its unit
*
* @access public
*/
public static function formatNumber(
$value, $digits_left = 3, $digits_right = 0,
$only_down = false, $noTrailingZero = true
) {
if ($value == 0) {
return '0';
}
$originalValue = $value;
//number_format is not multibyte safe, str_replace is safe
if ($digits_left === 0) {
$value = number_format($value, $digits_right);
if (($originalValue != 0) && (floatval($value) == 0)) {
$value = ' <' . (1 / self::pow(10, $digits_right));
}
return self::localizeNumber($value);
}
// this units needs no translation, ISO
$units = array(
-8 => 'y',
-7 => 'z',
-6 => 'a',
-5 => 'f',
-4 => 'p',
-3 => 'n',
-2 => 'µ',
-1 => 'm',
0 => ' ',
1 => 'k',
2 => 'M',
3 => 'G',
4 => 'T',
5 => 'P',
6 => 'E',
7 => 'Z',
8 => 'Y'
);
// check for negative value to retain sign
if ($value < 0) {
$sign = '-';
$value = abs($value);
} else {
$sign = '';
}
$dh = self::pow(10, $digits_right);
/*
* This gives us the right SI prefix already,
* but $digits_left parameter not incorporated
*/
$d = floor(log10($value) / 3);
/*
* Lowering the SI prefix by 1 gives us an additional 3 zeros
* So if we have 3,6,9,12.. free digits ($digits_left - $cur_digits)
* to use, then lower the SI prefix
*/
$cur_digits = floor(log10($value / self::pow(1000, $d, 'pow'))+1);
if ($digits_left > $cur_digits) {
$d -= floor(($digits_left - $cur_digits)/3);
}
if ($d < 0 && $only_down) {
$d = 0;
}
$value = round($value / (self::pow(1000, $d, 'pow') / $dh)) /$dh;
$unit = $units[$d];
// If we dont want any zeros after the comma just add the thousand separator
if ($noTrailingZero) {
$value = self::localizeNumber(
preg_replace('/(?<=\d)(?=(\d{3})+(?!\d))/', ',', $value)
);
} else {
//number_format is not multibyte safe, str_replace is safe
$value = self::localizeNumber(number_format($value, $digits_right));
}
if ($originalValue != 0 && floatval($value) == 0) {
return ' <' . (1 / self::pow(10, $digits_right)) . ' ' . $unit;
}
return $sign . $value . ' ' . $unit;
} // end of the 'formatNumber' function
/**
* Returns the number of bytes when a formatted size is given
*
* @param string $formatted_size the size expression (for example 8MB)
*
* @return integer The numerical part of the expression (for example 8)
*/
public static function extractValueFromFormattedSize($formatted_size)
{
$return_value = -1;
if (preg_match('/^[0-9]+GB$/', $formatted_size)) {
$return_value = substr($formatted_size, 0, -2) * self::pow(1024, 3);
} elseif (preg_match('/^[0-9]+MB$/', $formatted_size)) {
$return_value = substr($formatted_size, 0, -2) * self::pow(1024, 2);
} elseif (preg_match('/^[0-9]+K$/', $formatted_size)) {
$return_value = substr($formatted_size, 0, -1) * self::pow(1024, 1);
}
return $return_value;
}// end of the 'extractValueFromFormattedSize' function
/**
* Writes localised date
*
* @param string $timestamp the current timestamp
* @param string $format format
*
* @return string the formatted date
*
* @access public
*/
public static function localisedDate($timestamp = -1, $format = '')
{
$month = array(
/* l10n: Short month name */
__('Jan'),
/* l10n: Short month name */
__('Feb'),
/* l10n: Short month name */
__('Mar'),
/* l10n: Short month name */
__('Apr'),
/* l10n: Short month name */
_pgettext('Short month name', 'May'),
/* l10n: Short month name */
__('Jun'),
/* l10n: Short month name */
__('Jul'),
/* l10n: Short month name */
__('Aug'),
/* l10n: Short month name */
__('Sep'),
/* l10n: Short month name */
__('Oct'),
/* l10n: Short month name */
__('Nov'),
/* l10n: Short month name */
__('Dec'));
$day_of_week = array(
/* l10n: Short week day name */
_pgettext('Short week day name', 'Sun'),
/* l10n: Short week day name */
__('Mon'),
/* l10n: Short week day name */
__('Tue'),
/* l10n: Short week day name */
__('Wed'),
/* l10n: Short week day name */
__('Thu'),
/* l10n: Short week day name */
__('Fri'),
/* l10n: Short week day name */
__('Sat'));
if ($format == '') {
/* l10n: See http://www.php.net/manual/en/function.strftime.php */
$format = __('%B %d, %Y at %I:%M %p');
}
if ($timestamp == -1) {
$timestamp = time();
}
$date = preg_replace(
'@%[aA]@',
$day_of_week[(int)strftime('%w', $timestamp)],
$format
);
$date = preg_replace(
'@%[bB]@',
$month[(int)strftime('%m', $timestamp)-1],
$date
);
return strftime($date, $timestamp);
} // end of the 'localisedDate()' function
/**
* returns a tab for tabbed navigation.
* If the variables $link and $args ar left empty, an inactive tab is created
*
* @param array $tab array with all options
* @param array $url_params tab specific URL parameters
*
* @return string html code for one tab, a link if valid otherwise a span
*
* @access public
*/
public static function getHtmlTab($tab, $url_params = array())
{
// default values
$defaults = array(
'text' => '',
'class' => '',
'active' => null,
'link' => '',
'sep' => '?',
'attr' => '',
'args' => '',
'warning' => '',
'fragment' => '',
'id' => '',
);
$tab = array_merge($defaults, $tab);
// determine additionnal style-class
if (empty($tab['class'])) {
if (! empty($tab['active'])
|| PMA_isValid($GLOBALS['active_page'], 'identical', $tab['link'])
) {
$tab['class'] = 'active';
} elseif (is_null($tab['active']) && empty($GLOBALS['active_page'])
&& (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link'])) {
$tab['class'] = 'active';
}
}
// If there are any tab specific URL parameters, merge those with
// the general URL parameters
if (! empty($tab['url_params']) && is_array($tab['url_params'])) {
$url_params = array_merge($url_params, $tab['url_params']);
}
// build the link
if (! empty($tab['link'])) {
$tab['link'] = htmlentities($tab['link']);
$tab['link'] = $tab['link'] . PMA_generate_common_url($url_params);
if (! empty($tab['args'])) {
foreach ($tab['args'] as $param => $value) {
$tab['link'] .= PMA_get_arg_separator('html') . urlencode($param)
. '=' . urlencode($value);
}
}
}
if (! empty($tab['fragment'])) {
$tab['link'] .= $tab['fragment'];
}
// display icon
if (isset($tab['icon'])) {
// avoid generating an alt tag, because it only illustrates
// the text that follows and if browser does not display
// images, the text is duplicated
$tab['text'] = self::getIcon(
$tab['icon'],
$tab['text'],
false,
true,
'TabsMode'
);
} elseif (empty($tab['text'])) {
// check to not display an empty link-text
$tab['text'] = '?';
trigger_error(
'empty linktext in function ' . __FUNCTION__ . '()',
E_USER_NOTICE
);
}
//Set the id for the tab, if set in the params
$id_string = ( empty($tab['id']) ? '' : ' id="'.$tab['id'].'" ' );
$out = '