' . __('Copy') . '';
}
/**
* Get a link to variable documentation
*
* @param string $name The variable name
* @param bool $useMariaDB Use only MariaDB documentation
* @param string $text (optional) The text for the link
*
* @return string link or empty string
*/
public static function linkToVarDocumentation(
string $name,
bool $useMariaDB = false,
string $text = null
): string {
$html = '';
try {
$type = KBSearch::MYSQL;
if ($useMariaDB) {
$type = KBSearch::MARIADB;
}
$docLink = KBSearch::getByName($name, $type);
$html = MySQLDocumentation::show(
$name,
false,
$docLink,
$text
);
} catch (KBException $e) {
unset($e);// phpstan workaround
}
return $html;
}
/**
* Returns HTML code for a tooltip
*
* @param string $message the message for the tooltip
*
* @access public
*/
public static function showHint($message): string
{
if ($GLOBALS['cfg']['ShowHint']) {
$classClause = ' class="pma_hint"';
} else {
$classClause = '';
}
return ''
. self::getImage('b_help')
. '' . $message . ''
. '';
}
/**
* 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
*
* @throws Throwable
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*
* @access public
*/
public static function getHtmlTab(array $tab, array $url_params = []): string
{
$template = new Template();
// default values
$defaults = [
'text' => '',
'class' => '',
'active' => null,
'link' => '',
'sep' => '?',
'attr' => '',
'args' => '',
'warning' => '',
'fragment' => '',
'id' => '',
];
$tab = array_merge($defaults, $tab);
// determine additional style-class
if (empty($tab['class'])) {
if (! empty($tab['active'])
|| Core::isValid($GLOBALS['active_page'], 'identical', $tab['link'])
) {
$tab['class'] = 'active';
} elseif ($tab['active'] === null && empty($GLOBALS['active_page'])
&& (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link'])
) {
$tab['class'] = 'active';
}
}
// build the link
if (! empty($tab['link'])) {
// If there are any tab specific URL parameters, merge those with
// the general URL parameters
if (! empty($tab['args']) && is_array($tab['args'])) {
$url_params = array_merge($url_params, $tab['args']);
}
if (strpos($tab['link'], '?') === false) {
$tab['link'] = htmlentities($tab['link']) . Url::getCommon($url_params);
} else {
$tab['link'] = htmlentities($tab['link']) . Url::getCommon($url_params, '&');
}
}
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
$tabId = (empty($tab['id']) ? null : $tab['id']);
$item = [];
if (! empty($tab['link'])) {
$item = [
'content' => $tab['text'],
'url' => [
'href' => empty($tab['link']) ? null : $tab['link'],
'id' => $tabId,
'class' => 'tab' . htmlentities($tab['class']),
],
];
} else {
$item['content'] = '' . $tab['text'] . '';
}
$item['class'] = $tab['class'] === 'active' ? 'active' : '';
return $template->render('list/item', $item);
}
/**
* Generate a button or image tag
*
* @param string $button_name name of button element
* @param string $button_class class of button or image element
* @param string $text text to display
* @param string $image image to display
* @param string $value value
*
* @return string html content
*
* @access public
*/
public static function getButtonOrImage(
$button_name,
$button_class,
$text,
$image,
$value = ''
): string {
return Factory::build($GLOBALS['cfg']['ActionLinksMode'])
->generate($button_name, $button_class, $text, $image, $value);
}
/**
* returns html code for db link to default db page
*
* @param string $database database
*
* @return string html link to default db page
*/
public static function getDbLink($database = ''): string
{
if ((string) $database === '') {
if ((string) $GLOBALS['db'] === '') {
return '';
}
$database = $GLOBALS['db'];
} else {
$database = Util::unescapeMysqlWildcards($database);
}
$scriptName = Util::getScriptNameForOption(
$GLOBALS['cfg']['DefaultTabDatabase'],
'database'
);
return '' . htmlspecialchars($database) . '';
}
/**
* Prepare a lightbulb hint explaining a known external bug
* that affects a functionality
*
* @param string $functionality localized message explaining the func.
* @param string $component 'mysql' (eventually, 'php')
* @param string $minimum_version of this component
* @param string $bugref bug reference for this component
*/
public static function getExternalBug(
$functionality,
$component,
$minimum_version,
$bugref
): string {
$ext_but_html = '';
if (($component === 'mysql') && ($GLOBALS['dbi']->getVersion() < $minimum_version)) {
$ext_but_html .= self::showHint(
sprintf(
__('The %s functionality is affected by a known bug, see %s'),
$functionality,
Core::linkURL('https://bugs.mysql.com/') . $bugref
)
);
}
return $ext_but_html;
}
/**
* Generates a slider effect (jQjuery)
* Takes care of generating the initial
and the link
* controlling the slider; you have to generate the
yourself
* after the sliding section.
*
* @param string $id the id of the
on which to apply the effect
* @param string $message the message to show as a link
* @param string|null $overrideDefault override InitialSlidersState config
*
* @return string html div element
*
* @throws Throwable
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
public static function getDivForSliderEffect($id = '', $message = '', $overrideDefault = null): string
{
$template = new Template();
return $template->render(
'div_for_slider_effect',
[
'id' => $id,
'initial_sliders_state' => $overrideDefault != null ? $overrideDefault
: $GLOBALS['cfg']['InitialSlidersState'],
'message' => $message,
]
);
}
/**
* Creates an AJAX sliding toggle button
* (or and equivalent form when AJAX is disabled)
*
* @param string $action The URL for the request to be executed
* @param string $select_name The name for the dropdown box
* @param array $options An array of options (see PhpMyAdmin\Rte\Footer)
* @param string $callback A JS snippet to execute when the request is
* successfully processed
*
* @return string HTML code for the toggle button
*
* @throws Throwable
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
public static function toggleButton($action, $select_name, array $options, $callback): string
{
$template = new Template();
// Do the logic first
$link = $action . '&' . urlencode($select_name) . '=';
$link_on = $link . urlencode($options[1]['value']);
$link_off = $link . urlencode($options[0]['value']);
if ($options[1]['selected'] == true) {
$state = 'on';
} elseif ($options[0]['selected'] == true) {
$state = 'off';
} else {
$state = 'on';
}
return $template->render(
'toggle_button',
[
'pma_theme_image' => $GLOBALS['pmaThemeImage'],
'text_dir' => $GLOBALS['text_dir'],
'link_on' => $link_on,
'link_off' => $link_off,
'toggle_on' => $options[1]['label'],
'toggle_off' => $options[0]['label'],
'callback' => $callback,
'state' => $state,
]
);
}
/**
* Returns an HTML IMG tag for a particular icon from a theme,
* which may be an actual file or an icon from a sprite.
* This function takes into account the ActionLinksMode
* configuration setting and wraps the image tag in a span tag.
*
* @param string $icon name of icon file
* @param string $alternate alternate text
* @param bool $force_text whether to force alternate text to be displayed
* @param bool $menu_icon whether this icon is for the menu bar or not
* @param string $control_param which directive controls the display
*
* @return string an html snippet
*/
public static function getIcon(
$icon,
$alternate = '',
$force_text = false,
$menu_icon = false,
$control_param = 'ActionLinksMode'
): string {
$include_icon = $include_text = false;
if (Util::showIcons($control_param)) {
$include_icon = true;
}
if ($force_text
|| Util::showText($control_param)
) {
$include_text = true;
}
// Sometimes use a span (we rely on this in js/sql.js). But for menu bar
// we don't need a span
$button = $menu_icon ? '' : '';
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 information about SSL status for current connection
*/
public static function getServerSSL(): string
{
$server = $GLOBALS['cfg']['Server'];
$class = 'caution';
if (! $server['ssl']) {
$message = __('SSL is not being used');
if (! empty($server['socket']) || $server['host'] === '127.0.0.1' || $server['host'] === 'localhost') {
$class = '';
}
} elseif (! $server['ssl_verify']) {
$message = __('SSL is used with disabled verification');
} elseif (empty($server['ssl_ca'])) {
$message = __('SSL is used without certification authority');
} else {
$class = '';
$message = __('SSL is used');
}
return '' . $message . ' ' . MySQLDocumentation::showDocumentation(
'setup',
'ssl'
);
}
/**
* Returns default function for a particular column.
*
* @param array $field Data about the column for which
* to generate the dropdown
* @param bool $insert_mode Whether the operation is 'insert'
*
* @return string An HTML snippet of a dropdown list with function
* names appropriate for the requested column.
*
* @global mixed $data data of currently edited row
* (used to detect whether to choose defaults)
* @global array $cfg PMA configuration
*/
public static function getDefaultFunctionForField(array $field, $insert_mode): string
{
/*
* @todo Except for $cfg, no longer use globals but pass as parameters
* from higher levels
*/
global $cfg, $data;
$default_function = '';
// Can we get field class based values?
$current_class = $GLOBALS['dbi']->types->getTypeClass($field['True_Type']);
if (! empty($current_class) && isset($cfg['DefaultFunctions']['FUNC_' . $current_class])) {
$default_function = $cfg['DefaultFunctions']['FUNC_' . $current_class];
}
// what function defined as default?
// for the first timestamp we don't set the default function
// if there is a default value for the timestamp
// (not including CURRENT_TIMESTAMP)
// and the column does not have the
// ON UPDATE DEFAULT TIMESTAMP attribute.
if (($field['True_Type'] === 'timestamp')
&& $field['first_timestamp']
&& empty($field['Default'])
&& empty($data)
&& $field['Extra'] !== 'on update CURRENT_TIMESTAMP'
&& $field['Null'] === 'NO'
) {
$default_function = $cfg['DefaultFunctions']['first_timestamp'];
}
// For primary keys of type char(36) or varchar(36) UUID if the default
// function
// Only applies to insert mode, as it would silently trash data on updates.
if ($insert_mode
&& $field['Key'] === 'PRI'
&& ($field['Type'] === 'char(36)' || $field['Type'] === 'varchar(36)')
) {
$default_function = $cfg['DefaultFunctions']['FUNC_UUID'];
}
return $default_function;
}
/**
* Creates a dropdown box with MySQL functions for a particular column.
*
* @param array $field Data about the column for which
* to generate the dropdown
* @param bool $insert_mode Whether the operation is 'insert'
* @param array $foreignData Foreign data
*
* @return string An HTML snippet of a dropdown list with function
* names appropriate for the requested column.
*/
public static function getFunctionsForField(array $field, $insert_mode, array $foreignData): string
{
$default_function = self::getDefaultFunctionForField($field, $insert_mode);
$dropdown_built = [];
// Create the output
$retval = '' . "\n";
// loop on the dropdown array and print all available options for that
// field.
$functions = $GLOBALS['dbi']->types->getFunctions($field['True_Type']);
foreach ($functions as $function) {
$retval .= ''
. "\n";
}
// For compatibility's sake, do not let out all other functions. Instead
// print a separator (blank) and then show ALL functions which weren't
// shown yet.
$functions = $GLOBALS['dbi']->types->getAllFunctions();
foreach ($functions as $function) {
// Skip already included functions
if (isset($dropdown_built[$function])) {
continue;
}
$retval .= '';
} elseif ($selected == $value) {
$retval .= sprintf(
'',
$GLOBALS['dbi']->types->getTypeDescription($value),
$value
);
} else {
$retval .= sprintf(
'',
$GLOBALS['dbi']->types->getTypeDescription($value),
$value
);
}
}
return $retval;
}
}