home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / phpMyAdmin / libraries / common.lib.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  77.7 KB  |  2,303 lines

  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4.  * Misc functions used all over the scripts.
  5.  *
  6.  * @version $Id: common.lib.php 10941 2007-11-25 12:58:41Z lem9 $
  7.  */
  8.  
  9. /**
  10.  * Exponential expression / raise number into power
  11.  *
  12.  * @uses    function_exists()
  13.  * @uses    bcpow()
  14.  * @uses    gmp_pow()
  15.  * @uses    gmp_strval()
  16.  * @uses    pow()
  17.  * @param   number  $base
  18.  * @param   number  $exp
  19.  * @param   string  pow function use, or false for auto-detect
  20.  * @return  mixed  string or float
  21.  */
  22. function PMA_pow($base, $exp, $use_function = false)
  23. {
  24.     static $pow_function = null;
  25.  
  26.     if ($exp < 0) {
  27.         return false;
  28.     }
  29.  
  30.     if (null == $pow_function) {
  31.         if (function_exists('bcpow')) {
  32.             // BCMath Arbitrary Precision Mathematics Function
  33.             $pow_function = 'bcpow';
  34.         } elseif (function_exists('gmp_pow')) {
  35.             // GMP Function
  36.             $pow_function = 'gmp_pow';
  37.         } else {
  38.             // PHP function
  39.             $pow_function = 'pow';
  40.         }
  41.     }
  42.  
  43.     if (! $use_function) {
  44.         $use_function = $pow_function;
  45.     }
  46.  
  47.     switch ($use_function) {
  48.         case 'bcpow' :
  49.             //bcscale(10);
  50.             $pow = bcpow($base, $exp);
  51.             break;
  52.         case 'gmp_pow' :
  53.              $pow = gmp_strval(gmp_pow($base, $exp));
  54.             break;
  55.         case 'pow' :
  56.             $base = (float) $base;
  57.             $exp = (int) $exp;
  58.             $pow = pow($base, $exp);
  59.             break;
  60.         default:
  61.             $pow = $use_function($base, $exp);
  62.     }
  63.  
  64.     return $pow;
  65. }
  66.  
  67. /**
  68.  * string PMA_getIcon(string $icon)
  69.  *
  70.  * @uses    $GLOBALS['pmaThemeImage']
  71.  * @param   $icon   name of icon
  72.  * @return          html img tag
  73.  */
  74. function PMA_getIcon($icon, $alternate = '')
  75. {
  76.     if ($GLOBALS['cfg']['PropertiesIconic']) {
  77.         return '<img src="' . $GLOBALS['pmaThemeImage'] . $icon . '"'
  78.             . ' title="' . $alternate . '" alt="' . $alternate . '"'
  79.             . ' class="icon" width="16" height="16" />';
  80.     } else {
  81.         return $alternate;
  82.     }
  83. }
  84.  
  85. /**
  86.  * Displays the maximum size for an upload
  87.  *
  88.  * @uses    $GLOBALS['strMaximumSize']
  89.  * @uses    PMA_formatByteDown()
  90.  * @uses    sprintf()
  91.  * @param   integer  the size
  92.  *
  93.  * @return  string   the message
  94.  *
  95.  * @access  public
  96.  */
  97. function PMA_displayMaximumUploadSize($max_upload_size)
  98. {
  99.     list($max_size, $max_unit) = PMA_formatByteDown($max_upload_size);
  100.     return '(' . sprintf($GLOBALS['strMaximumSize'], $max_size, $max_unit) . ')';
  101. }
  102.  
  103. /**
  104.  * Generates a hidden field which should indicate to the browser
  105.  * the maximum size for upload
  106.  *
  107.  * @param   integer  the size
  108.  *
  109.  * @return  string   the INPUT field
  110.  *
  111.  * @access  public
  112.  */
  113.  function PMA_generateHiddenMaxFileSize($max_size)
  114.  {
  115.      return '<input type="hidden" name="MAX_FILE_SIZE" value="' .$max_size . '" />';
  116.  }
  117.  
  118. /**
  119.  * Add slashes before "'" and "\" characters so a value containing them can
  120.  * be used in a sql comparison.
  121.  *
  122.  * @uses    str_replace()
  123.  * @param   string   the string to slash
  124.  * @param   boolean  whether the string will be used in a 'LIKE' clause
  125.  *                   (it then requires two more escaped sequences) or not
  126.  * @param   boolean  whether to treat cr/lfs as escape-worthy entities
  127.  *                   (converts \n to \\n, \r to \\r)
  128.  *
  129.  * @param   boolean  whether this function is used as part of the
  130.  *                   "Create PHP code" dialog
  131.  *
  132.  * @return  string   the slashed string
  133.  *
  134.  * @access  public
  135.  */
  136. function PMA_sqlAddslashes($a_string = '', $is_like = false, $crlf = false, $php_code = false)
  137. {
  138.     if ($is_like) {
  139.         $a_string = str_replace('\\', '\\\\\\\\', $a_string);
  140.     } else {
  141.         $a_string = str_replace('\\', '\\\\', $a_string);
  142.     }
  143.  
  144.     if ($crlf) {
  145.         $a_string = str_replace("\n", '\n', $a_string);
  146.         $a_string = str_replace("\r", '\r', $a_string);
  147.         $a_string = str_replace("\t", '\t', $a_string);
  148.     }
  149.  
  150.     if ($php_code) {
  151.         $a_string = str_replace('\'', '\\\'', $a_string);
  152.     } else {
  153.         $a_string = str_replace('\'', '\'\'', $a_string);
  154.     }
  155.  
  156.     return $a_string;
  157. } // end of the 'PMA_sqlAddslashes()' function
  158.  
  159.  
  160. /**
  161.  * Add slashes before "_" and "%" characters for using them in MySQL
  162.  * database, table and field names.
  163.  * Note: This function does not escape backslashes!
  164.  *
  165.  * @uses    str_replace()
  166.  * @param   string   the string to escape
  167.  *
  168.  * @return  string   the escaped string
  169.  *
  170.  * @access  public
  171.  */
  172. function PMA_escape_mysql_wildcards($name)
  173. {
  174.     $name = str_replace('_', '\\_', $name);
  175.     $name = str_replace('%', '\\%', $name);
  176.  
  177.     return $name;
  178. } // end of the 'PMA_escape_mysql_wildcards()' function
  179.  
  180. /**
  181.  * removes slashes before "_" and "%" characters
  182.  * Note: This function does not unescape backslashes!
  183.  *
  184.  * @uses    str_replace()
  185.  * @param   string   $name  the string to escape
  186.  * @return  string   the escaped string
  187.  * @access  public
  188.  */
  189. function PMA_unescape_mysql_wildcards($name)
  190. {
  191.     $name = str_replace('\\_', '_', $name);
  192.     $name = str_replace('\\%', '%', $name);
  193.  
  194.     return $name;
  195. } // end of the 'PMA_unescape_mysql_wildcards()' function
  196.  
  197. /**
  198.  * removes quotes (',",`) from a quoted string
  199.  *
  200.  * checks if the sting is quoted and removes this quotes
  201.  *
  202.  * @uses    str_replace()
  203.  * @uses    substr()
  204.  * @param   string  $quoted_string  string to remove quotes from
  205.  * @param   string  $quote          type of quote to remove
  206.  * @return  string  unqoted string
  207.  */
  208. function PMA_unQuote($quoted_string, $quote = null)
  209. {
  210.     $quotes = array();
  211.  
  212.     if (null === $quote) {
  213.         $quotes[] = '`';
  214.         $quotes[] = '"';
  215.         $quotes[] = "'";
  216.     } else {
  217.         $quotes[] = $quote;
  218.     }
  219.  
  220.     foreach ($quotes as $quote) {
  221.         if (substr($quoted_string, 0, 1) === $quote
  222.          && substr($quoted_string, -1, 1) === $quote) {
  223.              $unquoted_string = substr($quoted_string, 1, -1);
  224.              // replace escaped quotes
  225.              $unquoted_string = str_replace($quote . $quote, $quote, $unquoted_string);
  226.              return $unquoted_string;
  227.          }
  228.     }
  229.  
  230.     return $quoted_string;
  231. }
  232.  
  233. /**
  234.  * format sql strings
  235.  *
  236.  * @todo    move into PMA_Sql
  237.  * @uses    PMA_SQP_isError()
  238.  * @uses    PMA_SQP_formatHtml()
  239.  * @uses    PMA_SQP_formatNone()
  240.  * @uses    is_array()
  241.  * @param   mixed    pre-parsed SQL structure
  242.  *
  243.  * @return  string   the formatted sql
  244.  *
  245.  * @global  array    the configuration array
  246.  * @global  boolean  whether the current statement is a multiple one or not
  247.  *
  248.  * @access  public
  249.  *
  250.  * @author  Robin Johnson <robbat2@users.sourceforge.net>
  251.  */
  252. function PMA_formatSql($parsed_sql, $unparsed_sql = '')
  253. {
  254.     global $cfg;
  255.  
  256.     // Check that we actually have a valid set of parsed data
  257.     // well, not quite
  258.     // first check for the SQL parser having hit an error
  259.     if (PMA_SQP_isError()) {
  260.         return $parsed_sql;
  261.     }
  262.     // then check for an array
  263.     if (!is_array($parsed_sql)) {
  264.         // We don't so just return the input directly
  265.         // This is intended to be used for when the SQL Parser is turned off
  266.         $formatted_sql = '<pre>' . "\n"
  267.                         . (($cfg['SQP']['fmtType'] == 'none' && $unparsed_sql != '') ? $unparsed_sql : $parsed_sql) . "\n"
  268.                         . '</pre>';
  269.         return $formatted_sql;
  270.     }
  271.  
  272.     $formatted_sql        = '';
  273.  
  274.     switch ($cfg['SQP']['fmtType']) {
  275.         case 'none':
  276.             if ($unparsed_sql != '') {
  277.                 $formatted_sql = "<pre>\n" . PMA_SQP_formatNone(array('raw' => $unparsed_sql)) . "\n</pre>";
  278.             } else {
  279.                 $formatted_sql = PMA_SQP_formatNone($parsed_sql);
  280.             }
  281.             break;
  282.         case 'html':
  283.             $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'color');
  284.             break;
  285.         case 'text':
  286.             //$formatted_sql = PMA_SQP_formatText($parsed_sql);
  287.             $formatted_sql = PMA_SQP_formatHtml($parsed_sql, 'text');
  288.             break;
  289.         default:
  290.             break;
  291.     } // end switch
  292.  
  293.     return $formatted_sql;
  294. } // end of the "PMA_formatSql()" function
  295.  
  296.  
  297. /**
  298.  * Displays a link to the official MySQL documentation
  299.  *
  300.  * @uses    $cfg['MySQLManualType']
  301.  * @uses    $cfg['MySQLManualBase']
  302.  * @uses    $cfg['ReplaceHelpImg']
  303.  * @uses    $GLOBALS['mysql_4_1_doc_lang']
  304.  * @uses    $GLOBALS['mysql_5_1_doc_lang']
  305.  * @uses    $GLOBALS['mysql_5_0_doc_lang']
  306.  * @uses    $GLOBALS['strDocu']
  307.  * @uses    $GLOBALS['pmaThemeImage']
  308.  * @uses    PMA_MYSQL_INT_VERSION
  309.  * @uses    strtolower()
  310.  * @uses    str_replace()
  311.  * @param string  chapter of "HTML, one page per chapter" documentation
  312.  * @param string  contains name of page/anchor that is being linked
  313.  * @param bool    whether to use big icon (like in left frame)
  314.  *
  315.  * @return  string  the html link
  316.  *
  317.  * @access  public
  318.  */
  319. function PMA_showMySQLDocu($chapter, $link, $big_icon = false)
  320. {
  321.     global $cfg;
  322.  
  323.     if ($cfg['MySQLManualType'] == 'none' || empty($cfg['MySQLManualBase'])) {
  324.         return '';
  325.     }
  326.  
  327.     // Fixup for newly used names:
  328.     $chapter = str_replace('_', '-', strtolower($chapter));
  329.     $link = str_replace('_', '-', strtolower($link));
  330.  
  331.     switch ($cfg['MySQLManualType']) {
  332.         case 'chapters':
  333.             if (empty($chapter)) {
  334.                 $chapter = 'index';
  335.             }
  336.             $url = $cfg['MySQLManualBase'] . '/' . $chapter . '.html#' . $link;
  337.             break;
  338.         case 'big':
  339.             $url = $cfg['MySQLManualBase'] . '#' . $link;
  340.             break;
  341.         case 'searchable':
  342.             if (empty($link)) {
  343.                 $link = 'index';
  344.             }
  345.             $url = $cfg['MySQLManualBase'] . '/' . $link . '.html';
  346.             break;
  347.         case 'viewable':
  348.         default:
  349.             if (empty($link)) {
  350.                 $link = 'index';
  351.             }
  352.             $mysql = '5.0';
  353.             $lang = 'en';
  354.             if (defined('PMA_MYSQL_INT_VERSION')) {
  355.                 if (PMA_MYSQL_INT_VERSION < 50000) {
  356.                     $mysql = '4.1';
  357.                     if (!empty($GLOBALS['mysql_4_1_doc_lang'])) {
  358.                         $lang = $GLOBALS['mysql_4_1_doc_lang'];
  359.                     }
  360.                 } elseif (PMA_MYSQL_INT_VERSION >= 50100) {
  361.                     $mysql = '5.1';
  362.                     if (!empty($GLOBALS['mysql_5_1_doc_lang'])) {
  363.                         $lang = $GLOBALS['mysql_5_1_doc_lang'];
  364.                     }
  365.                 } elseif (PMA_MYSQL_INT_VERSION >= 50000) {
  366.                     $mysql = '5.0';
  367.                     if (!empty($GLOBALS['mysql_5_0_doc_lang'])) {
  368.                         $lang = $GLOBALS['mysql_5_0_doc_lang'];
  369.                     }
  370.                 }
  371.             }
  372.             $url = $cfg['MySQLManualBase'] . '/' . $mysql . '/' . $lang . '/' . $link . '.html';
  373.             break;
  374.     }
  375.  
  376.     if ($big_icon) {
  377.         return '<a href="' . $url . '" target="mysql_doc"><img class="icon" src="' . $GLOBALS['pmaThemeImage'] . 'b_sqlhelp.png" width="16" height="16" alt="' . $GLOBALS['strDocu'] . '" title="' . $GLOBALS['strDocu'] . '" /></a>';
  378.     } elseif ($GLOBALS['cfg']['ReplaceHelpImg']) {
  379.         return '<a href="' . $url . '" target="mysql_doc"><img class="icon" src="' . $GLOBALS['pmaThemeImage'] . 'b_help.png" width="11" height="11" alt="' . $GLOBALS['strDocu'] . '" title="' . $GLOBALS['strDocu'] . '" /></a>';
  380.     } else {
  381.         return '[<a href="' . $url . '" target="mysql_doc">' . $GLOBALS['strDocu'] . '</a>]';
  382.     }
  383. } // end of the 'PMA_showMySQLDocu()' function
  384.  
  385. /**
  386.  * Displays a hint icon, on mouse over show the hint
  387.  *
  388.  * @uses    $GLOBALS['pmaThemeImage']
  389.  * @uses    PMA_jsFormat()
  390.  * @param   string   the error message
  391.  *
  392.  * @access  public
  393.  */
  394. function PMA_showHint($hint_message)
  395. {
  396.     //return '<img class="lightbulb" src="' . $GLOBALS['pmaThemeImage'] . 'b_tipp.png" width="16" height="16" border="0" alt="' . $hint_message . '" title="' . $hint_message . '" align="middle" onclick="alert(\'' . PMA_jsFormat($hint_message, false) . '\');" />';
  397.     return '<img class="lightbulb" src="' . $GLOBALS['pmaThemeImage']
  398.         . 'b_tipp.png" width="16" height="16" alt="Tip" title="Tip" onmouseover="pmaTooltip(\''
  399.         .  PMA_jsFormat($hint_message, false) . '\'); return false;" onmouseout="swapTooltip(\'default\'); return false;" />';
  400. }
  401.  
  402. /**
  403.  * Displays a MySQL error message in the right frame.
  404.  *
  405.  * @uses    footer.inc.php
  406.  * @uses    header.inc.php
  407.  * @uses    $GLOBALS['sql_query']
  408.  * @uses    $GLOBALS['strError']
  409.  * @uses    $GLOBALS['strSQLQuery']
  410.  * @uses    $GLOBALS['pmaThemeImage']
  411.  * @uses    $GLOBALS['strEdit']
  412.  * @uses    $GLOBALS['strMySQLSaid']
  413.  * @uses    $cfg['PropertiesIconic']
  414.  * @uses    PMA_backquote()
  415.  * @uses    PMA_DBI_getError()
  416.  * @uses    PMA_formatSql()
  417.  * @uses    PMA_generate_common_hidden_inputs()
  418.  * @uses    PMA_generate_common_url()
  419.  * @uses    PMA_showMySQLDocu()
  420.  * @uses    PMA_sqlAddslashes()
  421.  * @uses    PMA_SQP_isError()
  422.  * @uses    PMA_SQP_parse()
  423.  * @uses    PMA_SQP_getErrorString()
  424.  * @uses    strtolower()
  425.  * @uses    urlencode()
  426.  * @uses    str_replace()
  427.  * @uses    nl2br()
  428.  * @uses    substr()
  429.  * @uses    preg_replace()
  430.  * @uses    preg_match()
  431.  * @uses    explode()
  432.  * @uses    implode()
  433.  * @uses    is_array()
  434.  * @uses    function_exists()
  435.  * @uses    htmlspecialchars()
  436.  * @uses    trim()
  437.  * @uses    strstr()
  438.  * @param   string   the error message
  439.  * @param   string   the sql query that failed
  440.  * @param   boolean  whether to show a "modify" link or not
  441.  * @param   string   the "back" link url (full path is not required)
  442.  * @param   boolean  EXIT the page?
  443.  *
  444.  * @global  string    the curent table
  445.  * @global  string    the current db
  446.  *
  447.  * @access  public
  448.  */
  449. function PMA_mysqlDie($error_message = '', $the_query = '',
  450.                         $is_modify_link = true, $back_url = '', $exit = true)
  451. {
  452.     global $table, $db;
  453.  
  454.     /**
  455.      * start http output, display html headers
  456.      */
  457.     require_once './libraries/header.inc.php';
  458.  
  459.     if (!$error_message) {
  460.         $error_message = PMA_DBI_getError();
  461.     }
  462.     if (!$the_query && !empty($GLOBALS['sql_query'])) {
  463.         $the_query = $GLOBALS['sql_query'];
  464.     }
  465.  
  466.     // --- Added to solve bug #641765
  467.     // Robbat2 - 12 January 2003, 9:46PM
  468.     // Revised, Robbat2 - 13 January 2003, 2:59PM
  469.     if (!function_exists('PMA_SQP_isError') || PMA_SQP_isError()) {
  470.         $formatted_sql = htmlspecialchars($the_query);
  471.     } elseif (empty($the_query) || trim($the_query) == '') {
  472.         $formatted_sql = '';
  473.     } else {
  474.         $formatted_sql = PMA_formatSql(PMA_SQP_parse($the_query), $the_query);
  475.     }
  476.     // ---
  477.     echo "\n" . '<!-- PMA-SQL-ERROR -->' . "\n";
  478.     echo '    <div class="error"><h1>' . $GLOBALS['strError'] . '</h1>' . "\n";
  479.     // if the config password is wrong, or the MySQL server does not
  480.     // respond, do not show the query that would reveal the
  481.     // username/password
  482.     if (!empty($the_query) && !strstr($the_query, 'connect')) {
  483.         // --- Added to solve bug #641765
  484.         // Robbat2 - 12 January 2003, 9:46PM
  485.         // Revised, Robbat2 - 13 January 2003, 2:59PM
  486.         if (function_exists('PMA_SQP_isError') && PMA_SQP_isError()) {
  487.             echo PMA_SQP_getErrorString() . "\n";
  488.             echo '<br />' . "\n";
  489.         }
  490.         // ---
  491.         // modified to show me the help on sql errors (Michael Keck)
  492.         echo '    <p><strong>' . $GLOBALS['strSQLQuery'] . ':</strong>' . "\n";
  493.         if (strstr(strtolower($formatted_sql), 'select')) { // please show me help to the error on select
  494.             echo PMA_showMySQLDocu('SQL-Syntax', 'SELECT');
  495.         }
  496.         if ($is_modify_link && strlen($db)) {
  497.             if (strlen($table)) {
  498.                 $doedit_goto = '<a href="tbl_sql.php?' . PMA_generate_common_url($db, $table) . '&sql_query=' . urlencode($the_query) . '&show_query=1">';
  499.             } else {
  500.                 $doedit_goto = '<a href="db_sql.php?' . PMA_generate_common_url($db) . '&sql_query=' . urlencode($the_query) . '&show_query=1">';
  501.             }
  502.             if ($GLOBALS['cfg']['PropertiesIconic']) {
  503.                 echo $doedit_goto
  504.                    . '<img class="icon" src=" '. $GLOBALS['pmaThemeImage'] . 'b_edit.png" width="16" height="16" alt="' . $GLOBALS['strEdit'] .'" />'
  505.                    . '</a>';
  506.             } else {
  507.                 echo '    ['
  508.                    . $doedit_goto . $GLOBALS['strEdit'] . '</a>'
  509.                    . ']' . "\n";
  510.             }
  511.         } // end if
  512.         echo '    </p>' . "\n"
  513.             .'    <p>' . "\n"
  514.             .'        ' . $formatted_sql . "\n"
  515.             .'    </p>' . "\n";
  516.     } // end if
  517.  
  518.     $tmp_mysql_error = ''; // for saving the original $error_message
  519.     if (!empty($error_message)) {
  520.         $tmp_mysql_error = strtolower($error_message); // save the original $error_message
  521.         $error_message = htmlspecialchars($error_message);
  522.         $error_message = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $error_message);
  523.     }
  524.     // modified to show me the help on error-returns (Michael Keck)
  525.     // (now error-messages-server)
  526.     echo '<p>' . "\n"
  527.             . '    <strong>' . $GLOBALS['strMySQLSaid'] . '</strong>'
  528.             . PMA_showMySQLDocu('Error-messages-server', 'Error-messages-server')
  529.             . "\n"
  530.             . '</p>' . "\n";
  531.  
  532.     // The error message will be displayed within a CODE segment.
  533.     // To preserve original formatting, but allow wordwrapping, we do a couple of replacements
  534.  
  535.     // Replace all non-single blanks with their HTML-counterpart
  536.     $error_message = str_replace('  ', '  ', $error_message);
  537.     // Replace TAB-characters with their HTML-counterpart
  538.     $error_message = str_replace("\t", '    ', $error_message);
  539.     // Replace linebreaks
  540.     $error_message = nl2br($error_message);
  541.  
  542.     echo '<code>' . "\n"
  543.         . $error_message . "\n"
  544.         . '</code><br />' . "\n";
  545.     echo '</div>';
  546.     echo '<fieldset class="tblFooters">';
  547.  
  548.     if (!empty($back_url) && $exit) {
  549.         $goto_back_url='<a href="' . (strstr($back_url, '?') ? $back_url . '&no_history=true' : $back_url . '?no_history=true') . '">';
  550.         echo '[ ' . $goto_back_url . $GLOBALS['strBack'] . '</a> ]';
  551.     }
  552.     echo '    </fieldset>' . "\n\n";
  553.     if ($exit) {
  554.         /**
  555.          * display footer and exit
  556.          */
  557.         require_once './libraries/footer.inc.php';
  558.     }
  559. } // end of the 'PMA_mysqlDie()' function
  560.  
  561. /**
  562.  * Returns a string formatted with CONVERT ... USING
  563.  * if MySQL supports it
  564.  *
  565.  * @uses    PMA_MYSQL_INT_VERSION
  566.  * @uses    $GLOBALS['collation_connection']
  567.  * @uses    explode()
  568.  * @param   string  the string itself
  569.  * @param   string  the mode: quoted or unquoted (this one by default)
  570.  *
  571.  * @return  the formatted string
  572.  *
  573.  * @access  private
  574.  */
  575. function PMA_convert_using($string, $mode='unquoted', $force_utf8 = false)
  576. {
  577.     if ($mode == 'quoted') {
  578.         $possible_quote = "'";
  579.     } else {
  580.         $possible_quote = "";
  581.     }
  582.  
  583.     if (PMA_MYSQL_INT_VERSION >= 40100) {
  584.         if ($force_utf8) {
  585.             $charset = 'utf8';
  586.             $collate = ' COLLATE utf8_bin';
  587.         } else {
  588.             list($charset) = explode('_', $GLOBALS['collation_connection']);
  589.             $collate = '';
  590.         }
  591.         $converted_string = "CONVERT(" . $possible_quote . $string . $possible_quote . " USING " . $charset . ")" . $collate;
  592.     } else {
  593.         $converted_string = $possible_quote . $string . $possible_quote;
  594.     }
  595.     return $converted_string;
  596. } // end function
  597.  
  598. /**
  599.  * Send HTTP header, taking IIS limits into account (600 seems ok)
  600.  *
  601.  * @uses    PMA_IS_IIS
  602.  * @uses    PMA_COMING_FROM_COOKIE_LOGIN
  603.  * @uses    PMA_get_arg_separator()
  604.  * @uses    SID
  605.  * @uses    strlen()
  606.  * @uses    strpos()
  607.  * @uses    header()
  608.  * @uses    session_write_close()
  609.  * @uses    headers_sent()
  610.  * @uses    function_exists()
  611.  * @uses    debug_print_backtrace()
  612.  * @uses    trigger_error()
  613.  * @uses    defined()
  614.  * @param   string   $uri the header to send
  615.  * @return  boolean  always true
  616.  */
  617. function PMA_sendHeaderLocation($uri)
  618. {
  619.     if (PMA_IS_IIS && strlen($uri) > 600) {
  620.  
  621.         echo '<html><head><title>- - -</title>' . "\n";
  622.         echo '<meta http-equiv="expires" content="0">' . "\n";
  623.         echo '<meta http-equiv="Pragma" content="no-cache">' . "\n";
  624.         echo '<meta http-equiv="Cache-Control" content="no-cache">' . "\n";
  625.         echo '<meta http-equiv="Refresh" content="0;url=' .$uri . '">' . "\n";
  626.         echo '<script type="text/javascript">' . "\n";
  627.         echo '//<![CDATA[' . "\n";
  628.         echo 'setTimeout("window.location = unescape(\'"' . $uri . '"\')", 2000);' . "\n";
  629.         echo '//]]>' . "\n";
  630.         echo '</script>' . "\n";
  631.         echo '</head>' . "\n";
  632.         echo '<body>' . "\n";
  633.         echo '<script type="text/javascript">' . "\n";
  634.         echo '//<![CDATA[' . "\n";
  635.         echo 'document.write(\'<p><a href="' . $uri . '">' . $GLOBALS['strGo'] . '</a></p>\');' . "\n";
  636.         echo '//]]>' . "\n";
  637.         echo '</script></body></html>' . "\n";
  638.  
  639.     } else {
  640.         if (SID) {
  641.             if (strpos($uri, '?') === false) {
  642.                 header('Location: ' . $uri . '?' . SID);
  643.             } else {
  644.                 $separator = PMA_get_arg_separator();
  645.                 header('Location: ' . $uri . $separator . SID);
  646.             }
  647.         } else {
  648.             session_write_close();
  649.             if (headers_sent()) {
  650.                 if (function_exists('debug_print_backtrace')) {
  651.                     echo '<pre>';
  652.                     debug_print_backtrace();
  653.                     echo '</pre>';
  654.                 }
  655.                 trigger_error('PMA_sendHeaderLocation called when headers are already sent!', E_USER_ERROR);
  656.             }
  657.             // bug #1523784: IE6 does not like 'Refresh: 0', it
  658.             // results in a blank page
  659.             // but we need it when coming from the cookie login panel)
  660.             if (PMA_IS_IIS && defined('PMA_COMING_FROM_COOKIE_LOGIN')) {
  661.                 header('Refresh: 0; ' . $uri);
  662.             } else {
  663.                 header('Location: ' . $uri);
  664.             }
  665.         }
  666.     }
  667. }
  668.  
  669. /**
  670.  * returns array with tables of given db with extended information and grouped
  671.  *
  672.  * @uses    $cfg['LeftFrameTableSeparator']
  673.  * @uses    $cfg['LeftFrameTableLevel']
  674.  * @uses    $cfg['ShowTooltipAliasTB']
  675.  * @uses    $cfg['NaturalOrder']
  676.  * @uses    PMA_backquote()
  677.  * @uses    count()
  678.  * @uses    array_merge
  679.  * @uses    uksort()
  680.  * @uses    strstr()
  681.  * @uses    explode()
  682.  * @param   string  $db     name of db
  683.  * @param   string  $tables name of tables
  684.  * return   array   (recursive) grouped table list
  685.  */
  686. function PMA_getTableList($db, $tables = null, $limit_offset = 0, $limit_count = false)
  687. {
  688.     $sep = $GLOBALS['cfg']['LeftFrameTableSeparator'];
  689.  
  690.     if (null === $tables) {
  691.         $tables = PMA_DBI_get_tables_full($db, false, false, null, $limit_offset, $limit_count);
  692.         if ($GLOBALS['cfg']['NaturalOrder']) {
  693.             uksort($tables, 'strnatcasecmp');
  694.         }
  695.     }
  696.  
  697.     if (count($tables) < 1) {
  698.         return $tables;
  699.     }
  700.  
  701.     $default = array(
  702.         'Name'      => '',
  703.         'Rows'      => 0,
  704.         'Comment'   => '',
  705.         'disp_name' => '',
  706.     );
  707.  
  708.     $table_groups = array();
  709.  
  710.     foreach ($tables as $table_name => $table) {
  711.  
  712.         // check for correct row count
  713.         if (null === $table['Rows']) {
  714.             // Do not check exact row count here,
  715.             // if row count is invalid possibly the table is defect
  716.             // and this would break left frame;
  717.             // but we can check row count if this is a view,
  718.             // since PMA_Table::countRecords() returns a limited row count
  719.             // in this case.
  720.  
  721.             // set this because PMA_Table::countRecords() can use it
  722.             $tbl_is_view = PMA_Table::isView($db, $table['Name']);
  723.  
  724.             if ($tbl_is_view) {
  725.                 $table['Rows'] = PMA_Table::countRecords($db, $table['Name'],
  726.                     $return = true);
  727.             }
  728.         }
  729.  
  730.         // in $group we save the reference to the place in $table_groups
  731.         // where to store the table info
  732.         if ($GLOBALS['cfg']['LeftFrameDBTree']
  733.             && $sep && strstr($table_name, $sep))
  734.         {
  735.             $parts = explode($sep, $table_name);
  736.  
  737.             $group =& $table_groups;
  738.             $i = 0;
  739.             $group_name_full = '';
  740.             while ($i < count($parts) - 1
  741.               && $i < $GLOBALS['cfg']['LeftFrameTableLevel']) {
  742.                 $group_name = $parts[$i] . $sep;
  743.                 $group_name_full .= $group_name;
  744.  
  745.                 if (!isset($group[$group_name])) {
  746.                     $group[$group_name] = array();
  747.                     $group[$group_name]['is' . $sep . 'group'] = true;
  748.                     $group[$group_name]['tab' . $sep . 'count'] = 1;
  749.                     $group[$group_name]['tab' . $sep . 'group'] = $group_name_full;
  750.                 } elseif (!isset($group[$group_name]['is' . $sep . 'group'])) {
  751.                     $table = $group[$group_name];
  752.                     $group[$group_name] = array();
  753.                     $group[$group_name][$group_name] = $table;
  754.                     unset($table);
  755.                     $group[$group_name]['is' . $sep . 'group'] = true;
  756.                     $group[$group_name]['tab' . $sep . 'count'] = 1;
  757.                     $group[$group_name]['tab' . $sep . 'group'] = $group_name_full;
  758.                 } else {
  759.                     $group[$group_name]['tab' . $sep . 'count']++;
  760.                 }
  761.                 $group =& $group[$group_name];
  762.                 $i++;
  763.             }
  764.         } else {
  765.             if (!isset($table_groups[$table_name])) {
  766.                 $table_groups[$table_name] = array();
  767.             }
  768.             $group =& $table_groups;
  769.         }
  770.  
  771.  
  772.         if ($GLOBALS['cfg']['ShowTooltipAliasTB']
  773.           && $GLOBALS['cfg']['ShowTooltipAliasTB'] !== 'nested') {
  774.             // switch tooltip and name
  775.             $table['Comment'] = $table['Name'];
  776.             $table['disp_name'] = $table['Comment'];
  777.         } else {
  778.             $table['disp_name'] = $table['Name'];
  779.         }
  780.  
  781.         $group[$table_name] = array_merge($default, $table);
  782.     }
  783.  
  784.     return $table_groups;
  785. }
  786.  
  787. /* ----------------------- Set of misc functions ----------------------- */
  788.  
  789.  
  790. /**
  791.  * Adds backquotes on both sides of a database, table or field name.
  792.  * and escapes backquotes inside the name with another backquote
  793.  *
  794.  * example:
  795.  * <code>
  796.  * echo PMA_backquote('owner`s db'); // `owner``s db`
  797.  *
  798.  * </code>
  799.  *
  800.  * @uses    PMA_backquote()
  801.  * @uses    is_array()
  802.  * @uses    strlen()
  803.  * @uses    str_replace()
  804.  * @param   mixed    $a_name    the database, table or field name to "backquote"
  805.  *                              or array of it
  806.  * @param   boolean  $do_it     a flag to bypass this function (used by dump
  807.  *                              functions)
  808.  * @return  mixed    the "backquoted" database, table or field name if the
  809.  *                   current MySQL release is >= 3.23.6, the original one
  810.  *                   else
  811.  * @access  public
  812.  */
  813. function PMA_backquote($a_name, $do_it = true)
  814. {
  815.     if (! $do_it) {
  816.         return $a_name;
  817.     }
  818.  
  819.     if (is_array($a_name)) {
  820.          $result = array();
  821.          foreach ($a_name as $key => $val) {
  822.              $result[$key] = PMA_backquote($val);
  823.          }
  824.          return $result;
  825.     }
  826.  
  827.     // '0' is also empty for php :-(
  828.     if (strlen($a_name) && $a_name !== '*') {
  829.         return '`' . str_replace('`', '``', $a_name) . '`';
  830.     } else {
  831.         return $a_name;
  832.     }
  833. } // end of the 'PMA_backquote()' function
  834.  
  835.  
  836. /**
  837.  * Defines the <CR><LF> value depending on the user OS.
  838.  *
  839.  * @uses    PMA_USR_OS
  840.  * @return  string   the <CR><LF> value to use
  841.  *
  842.  * @access  public
  843.  */
  844. function PMA_whichCrlf()
  845. {
  846.     $the_crlf = "\n";
  847.  
  848.     // The 'PMA_USR_OS' constant is defined in "./libraries/Config.class.php"
  849.     // Win case
  850.     if (PMA_USR_OS == 'Win') {
  851.         $the_crlf = "\r\n";
  852.     }
  853.     // Others
  854.     else {
  855.         $the_crlf = "\n";
  856.     }
  857.  
  858.     return $the_crlf;
  859. } // end of the 'PMA_whichCrlf()' function
  860.  
  861. /**
  862.  * Reloads navigation if needed.
  863.  *
  864.  * @uses    $GLOBALS['reload']
  865.  * @uses    $GLOBALS['db']
  866.  * @uses    PMA_generate_common_url()
  867.  * @global  array  configuration
  868.  *
  869.  * @access  public
  870.  */
  871. function PMA_reloadNavigation()
  872. {
  873.     global $cfg;
  874.  
  875.     // Reloads the navigation frame via JavaScript if required
  876.     if (isset($GLOBALS['reload']) && $GLOBALS['reload']) {
  877.         echo "\n";
  878.         $reload_url = './navigation.php?' . PMA_generate_common_url($GLOBALS['db'], '', '&');
  879.         ?>
  880. <script type="text/javascript">
  881. //<![CDATA[
  882. if (typeof(window.parent) != 'undefined'
  883.     && typeof(window.parent.frame_navigation) != 'undefined') {
  884.     window.parent.goTo('<?php echo $reload_url; ?>');
  885. }
  886. //]]>
  887. </script>
  888.         <?php
  889.         unset($GLOBALS['reload']);
  890.     }
  891. }
  892.  
  893. /**
  894.  * displays the message and the query
  895.  * usually the message is the result of the query executed
  896.  *
  897.  * @param   string  $message    the message to display
  898.  * @param   string  $sql_query  the query to display
  899.  * @global  array   the configuration array
  900.  * @uses    $cfg
  901.  * @access  public
  902.  */
  903. function PMA_showMessage($message, $sql_query = null)
  904. {
  905.     global $cfg;
  906.     $query_too_big = false;
  907.  
  908.     if (null === $sql_query) {
  909.         if (! empty($GLOBALS['display_query'])) {
  910.             $sql_query = $GLOBALS['display_query'];
  911.         } elseif ($cfg['SQP']['fmtType'] == 'none' && ! empty($GLOBALS['unparsed_sql'])) {
  912.             $sql_query = $GLOBALS['unparsed_sql'];
  913.         } elseif (! empty($GLOBALS['sql_query'])) {
  914.             $sql_query = $GLOBALS['sql_query'];
  915.         } else {
  916.             $sql_query = '';
  917.         }
  918.     }
  919.  
  920.     // Corrects the tooltip text via JS if required
  921.     // @todo this is REALLY the wrong place to do this - very unexpected here
  922.     if (strlen($GLOBALS['table']) && $cfg['ShowTooltip']) {
  923.         $result = PMA_DBI_try_query('SHOW TABLE STATUS FROM ' . PMA_backquote($GLOBALS['db']) . ' LIKE \'' . PMA_sqlAddslashes($GLOBALS['table'], true) . '\'');
  924.         if ($result) {
  925.             $tbl_status = PMA_DBI_fetch_assoc($result);
  926.             $tooltip    = (empty($tbl_status['Comment']))
  927.                         ? ''
  928.                         : $tbl_status['Comment'] . ' ';
  929.             $tooltip .= '(' . PMA_formatNumber($tbl_status['Rows'], 0) . ' ' . $GLOBALS['strRows'] . ')';
  930.             PMA_DBI_free_result($result);
  931.             $uni_tbl = PMA_jsFormat($GLOBALS['db'] . '.' . $GLOBALS['table'], false);
  932.             echo "\n";
  933.             echo '<script type="text/javascript">' . "\n";
  934.             echo '//<![CDATA[' . "\n";
  935.             echo "window.parent.updateTableTitle('" . $uni_tbl . "', '" . PMA_jsFormat($tooltip, false) . "');" . "\n";
  936.             echo '//]]>' . "\n";
  937.             echo '</script>' . "\n";
  938.         } // end if
  939.     } // end if ... elseif
  940.  
  941.     // Checks if the table needs to be repaired after a TRUNCATE query.
  942.     // @todo what about $GLOBALS['display_query']???
  943.     // @todo this is REALLY the wrong place to do this - very unexpected here
  944.     if (strlen($GLOBALS['table'])
  945.      && $GLOBALS['sql_query'] == 'TRUNCATE TABLE ' . PMA_backquote($GLOBALS['table'])) {
  946.         if (!isset($tbl_status)) {
  947.             $result = @PMA_DBI_try_query('SHOW TABLE STATUS FROM ' . PMA_backquote($GLOBALS['db']) . ' LIKE \'' . PMA_sqlAddslashes($GLOBALS['table'], true) . '\'');
  948.             if ($result) {
  949.                 $tbl_status = PMA_DBI_fetch_assoc($result);
  950.                 PMA_DBI_free_result($result);
  951.             }
  952.         }
  953.         if (isset($tbl_status) && (int) $tbl_status['Index_length'] > 1024) {
  954.             PMA_DBI_try_query('REPAIR TABLE ' . PMA_backquote($GLOBALS['table']));
  955.         }
  956.     }
  957.     unset($tbl_status);
  958.     echo '<br />' . "\n";
  959.  
  960.     echo '<div align="' . $GLOBALS['cell_align_left'] . '">' . "\n";
  961.     if (!empty($GLOBALS['show_error_header'])) {
  962.         echo '<div class="error">' . "\n";
  963.         echo '<h1>' . $GLOBALS['strError'] . '</h1>' . "\n";
  964.     }
  965.  
  966.     echo '<div class="notice">';
  967.     echo PMA_sanitize($message);
  968.     if (isset($GLOBALS['special_message'])) {
  969.         echo PMA_sanitize($GLOBALS['special_message']);
  970.         unset($GLOBALS['special_message']);
  971.     }
  972.     echo '</div>';
  973.  
  974.     if (!empty($GLOBALS['show_error_header'])) {
  975.         echo '</div>';
  976.     }
  977.  
  978.     if ($cfg['ShowSQL'] == true && ! empty($sql_query)) {
  979.         // Basic url query part
  980.         $url_qpart = '?' . PMA_generate_common_url($GLOBALS['db'], $GLOBALS['table']);
  981.  
  982.         // Html format the query to be displayed
  983.         // The nl2br function isn't used because its result isn't a valid
  984.         // xhtml1.0 statement before php4.0.5 ("<br>" and not "<br />")
  985.         // If we want to show some sql code it is easiest to create it here
  986.          /* SQL-Parser-Analyzer */
  987.  
  988.         if (!empty($GLOBALS['show_as_php'])) {
  989.             $new_line = '\'<br />' . "\n" . '        . \' ';
  990.         }
  991.         if (isset($new_line)) {
  992.              /* SQL-Parser-Analyzer */
  993.             $query_base = PMA_sqlAddslashes(htmlspecialchars($sql_query), false, false, true);
  994.              /* SQL-Parser-Analyzer */
  995.             $query_base = preg_replace("@((\015\012)|(\015)|(\012))+@", $new_line, $query_base);
  996.         } else {
  997.             $query_base = $sql_query;
  998.         }
  999.  
  1000.         if (strlen($query_base) > $cfg['MaxCharactersInDisplayedSQL']) {
  1001.             $query_too_big = true; 
  1002.             $query_base = nl2br(htmlspecialchars($sql_query));
  1003.             unset($GLOBALS['parsed_sql']);
  1004.         }
  1005.  
  1006.         // Parse SQL if needed
  1007.         // (here, use "! empty" because when deleting a bookmark,
  1008.         // $GLOBALS['parsed_sql'] is set but empty
  1009.         if (! empty($GLOBALS['parsed_sql']) && $query_base == $GLOBALS['parsed_sql']['raw']) {
  1010.             $parsed_sql = $GLOBALS['parsed_sql'];
  1011.         } else {
  1012.             // when the query is large (for example an INSERT of binary
  1013.             // data), the parser chokes; so avoid parsing the query
  1014.             if (! $query_too_big) {
  1015.                 $parsed_sql = PMA_SQP_parse($query_base);
  1016.             }
  1017.         }
  1018.  
  1019.         // Analyze it
  1020.         if (isset($parsed_sql)) {
  1021.             $analyzed_display_query = PMA_SQP_analyze($parsed_sql);
  1022.         }
  1023.  
  1024.         // Here we append the LIMIT added for navigation, to
  1025.         // enable its display. Adding it higher in the code
  1026.         // to $sql_query would create a problem when
  1027.         // using the Refresh or Edit links.
  1028.  
  1029.         // Only append it on SELECTs.
  1030.  
  1031.         /**
  1032.          * @todo what would be the best to do when someone hits Refresh:
  1033.          * use the current LIMITs ?
  1034.          */
  1035.  
  1036.         if (isset($analyzed_display_query[0]['queryflags']['select_from'])
  1037.          && isset($GLOBALS['sql_limit_to_append'])) {
  1038.             $query_base  = $analyzed_display_query[0]['section_before_limit'] . "\n" . $GLOBALS['sql_limit_to_append'] . $analyzed_display_query[0]['section_after_limit'];
  1039.             // Need to reparse query
  1040.             $parsed_sql = PMA_SQP_parse($query_base);
  1041.         }
  1042.  
  1043.         if (!empty($GLOBALS['show_as_php'])) {
  1044.             $query_base = '$sql  = \'' . $query_base;
  1045.         } elseif (!empty($GLOBALS['validatequery'])) {
  1046.             $query_base = PMA_validateSQL($query_base);
  1047.         } else {
  1048.             if (isset($parsed_sql)) {
  1049.                 $query_base = PMA_formatSql($parsed_sql, $query_base);
  1050.             }
  1051.         }
  1052.  
  1053.         // Prepares links that may be displayed to edit/explain the query
  1054.         // (don't go to default pages, we must go to the page
  1055.         // where the query box is available)
  1056.  
  1057.         $edit_target = strlen($GLOBALS['db']) ? (strlen($GLOBALS['table']) ? 'tbl_sql.php' : 'db_sql.php') : 'server_sql.php';
  1058.  
  1059.         if (isset($cfg['SQLQuery']['Edit'])
  1060.             && ($cfg['SQLQuery']['Edit'] == true)
  1061.             && (!empty($edit_target))
  1062.             && ! $query_too_big) {
  1063.  
  1064.             if ($cfg['EditInWindow'] == true) {
  1065.                 $onclick = 'window.parent.focus_querywindow(\'' . PMA_jsFormat($sql_query, false) . '\'); return false;';
  1066.             } else {
  1067.                 $onclick = '';
  1068.             }
  1069.  
  1070.             $edit_link = $edit_target
  1071.                        . $url_qpart
  1072.                        . '&sql_query=' . urlencode($sql_query)
  1073.                        . '&show_query=1#querybox';
  1074.             $edit_link = ' [' . PMA_linkOrButton($edit_link, $GLOBALS['strEdit'], array('onclick' => $onclick)) . ']';
  1075.         } else {
  1076.             $edit_link = '';
  1077.         }
  1078.  
  1079.         // Want to have the query explained (Mike Beck 2002-05-22)
  1080.         // but only explain a SELECT (that has not been explained)
  1081.         /* SQL-Parser-Analyzer */
  1082.         if (isset($cfg['SQLQuery']['Explain'])
  1083.             && $cfg['SQLQuery']['Explain'] == true
  1084.             && ! $query_too_big) {
  1085.  
  1086.             // Detect if we are validating as well
  1087.             // To preserve the validate uRL data
  1088.             if (!empty($GLOBALS['validatequery'])) {
  1089.                 $explain_link_validate = '&validatequery=1';
  1090.             } else {
  1091.                 $explain_link_validate = '';
  1092.             }
  1093.  
  1094.             $explain_link = 'import.php'
  1095.                           . $url_qpart
  1096.                           . $explain_link_validate
  1097.                           . '&sql_query=';
  1098.  
  1099.             if (preg_match('@^SELECT[[:space:]]+@i', $sql_query)) {
  1100.                 $explain_link .= urlencode('EXPLAIN ' . $sql_query);
  1101.                 $message = $GLOBALS['strExplain'];
  1102.             } elseif (preg_match('@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i', $sql_query)) {
  1103.                 $explain_link .= urlencode(substr($sql_query, 8));
  1104.                 $message = $GLOBALS['strNoExplain'];
  1105.             } else {
  1106.                 $explain_link = '';
  1107.             }
  1108.             if (!empty($explain_link)) {
  1109.                 $explain_link = ' [' . PMA_linkOrButton($explain_link, $message) . ']';
  1110.             }
  1111.         } else {
  1112.             $explain_link = '';
  1113.         } //show explain
  1114.  
  1115.         // Also we would like to get the SQL formed in some nice
  1116.         // php-code (Mike Beck 2002-05-22)
  1117.         if (isset($cfg['SQLQuery']['ShowAsPHP'])
  1118.             && $cfg['SQLQuery']['ShowAsPHP'] == true
  1119.             && ! $query_too_big) {
  1120.             $php_link = 'import.php'
  1121.                       . $url_qpart
  1122.                       . '&show_query=1'
  1123.                       . '&sql_query=' . urlencode($sql_query)
  1124.                       . '&show_as_php=';
  1125.  
  1126.             if (!empty($GLOBALS['show_as_php'])) {
  1127.                 $php_link .= '0';
  1128.                 $message = $GLOBALS['strNoPhp'];
  1129.             } else {
  1130.                 $php_link .= '1';
  1131.                 $message = $GLOBALS['strPhp'];
  1132.             }
  1133.             $php_link = ' [' . PMA_linkOrButton($php_link, $message) . ']';
  1134.  
  1135.             if (isset($GLOBALS['show_as_php'])) {
  1136.                 $runquery_link
  1137.                      = 'import.php'
  1138.                      . $url_qpart
  1139.                      . '&show_query=1'
  1140.                      . '&sql_query=' . urlencode($sql_query);
  1141.                 $php_link .= ' [' . PMA_linkOrButton($runquery_link, $GLOBALS['strRunQuery']) . ']';
  1142.             }
  1143.  
  1144.         } else {
  1145.             $php_link = '';
  1146.         } //show as php
  1147.  
  1148.         // Refresh query
  1149.         if (isset($cfg['SQLQuery']['Refresh'])
  1150.             && $cfg['SQLQuery']['Refresh']
  1151.             && preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sql_query)) {
  1152.  
  1153.             $refresh_link = 'import.php'
  1154.                       . $url_qpart
  1155.                       . '&show_query=1'
  1156.                       . '&sql_query=' . urlencode($sql_query);
  1157.             $refresh_link = ' [' . PMA_linkOrButton($refresh_link, $GLOBALS['strRefresh']) . ']';
  1158.         } else {
  1159.             $refresh_link = '';
  1160.         } //show as php
  1161.  
  1162.         if (isset($cfg['SQLValidator']['use'])
  1163.             && $cfg['SQLValidator']['use'] == true
  1164.             && isset($cfg['SQLQuery']['Validate'])
  1165.             && $cfg['SQLQuery']['Validate'] == true) {
  1166.             $validate_link = 'import.php'
  1167.                            . $url_qpart
  1168.                            . '&show_query=1'
  1169.                            . '&sql_query=' . urlencode($sql_query)
  1170.                            . '&validatequery=';
  1171.             if (!empty($GLOBALS['validatequery'])) {
  1172.                 $validate_link .= '0';
  1173.                 $validate_message = $GLOBALS['strNoValidateSQL'] ;
  1174.             } else {
  1175.                 $validate_link .= '1';
  1176.                 $validate_message = $GLOBALS['strValidateSQL'] ;
  1177.             }
  1178.             $validate_link = ' [' . PMA_linkOrButton($validate_link, $validate_message) . ']';
  1179.         } else {
  1180.             $validate_link = '';
  1181.         } //validator
  1182.  
  1183.         // why this?
  1184.         //unset($sql_query);
  1185.  
  1186.         // Displays the message
  1187.         echo '<fieldset class="">' . "\n";
  1188.         echo '    <legend>' . $GLOBALS['strSQLQuery'] . ':</legend>';
  1189.         echo '    <div>';
  1190.         // when uploading a 700 Kio binary file into a LONGBLOB,
  1191.         // I get a white page, strlen($query_base) is 2 x 700 Kio
  1192.         // so put a hard limit here (let's say 1000)
  1193.         if ($query_too_big) {
  1194.             echo '    ' . substr($query_base, 0, $cfg['MaxCharactersInDisplayedSQL']) . '[...]';
  1195.         } else {
  1196.             echo '    ' . $query_base;
  1197.         }
  1198.  
  1199.         //Clean up the end of the PHP
  1200.         if (!empty($GLOBALS['show_as_php'])) {
  1201.             echo '\';';
  1202.         }
  1203.         echo '    </div>';
  1204.         echo '</fieldset>' . "\n";
  1205.  
  1206.         if (!empty($edit_target)) {
  1207.             echo '<fieldset class="tblFooters">';
  1208.             PMA_profilingCheckbox($sql_query);
  1209.             echo $edit_link . $explain_link . $php_link . $refresh_link . $validate_link;
  1210.             echo '</fieldset>';
  1211.         }
  1212.     }
  1213.     echo '</div><br />' . "\n";
  1214. } // end of the 'PMA_showMessage()' function
  1215.  
  1216.  
  1217. /**
  1218.  * Verifies if current MySQL server supports profiling 
  1219.  *
  1220.  * @access  public
  1221.  * @return  boolean whether profiling is supported 
  1222.  *
  1223.  * @author   Marc Delisle 
  1224.  */
  1225. function PMA_profilingSupported() {
  1226.     // 5.0.37 has profiling but for example, 5.1.20 does not
  1227.     // (avoid a trip to the server for MySQL before 5.0.37)
  1228.     // and do not set a constant as we might be switching servers
  1229.     if (defined('PMA_MYSQL_INT_VERSION') && PMA_MYSQL_INT_VERSION >= 50037 && PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'profiling'")) {
  1230.         return true;
  1231.     } else {
  1232.         return false;
  1233.     }
  1234. }
  1235.  
  1236. /**
  1237.  * Displays a form with the Profiling checkbox 
  1238.  *
  1239.  * @param   string  $sql_query
  1240.  * @access  public
  1241.  *
  1242.  * @author   Marc Delisle 
  1243.  */
  1244. function PMA_profilingCheckbox($sql_query) {
  1245.     if (PMA_profilingSupported()) {
  1246.         echo '<form action="sql.php" method="post">' . "\n";
  1247.         echo PMA_generate_common_hidden_inputs($GLOBALS['db'], $GLOBALS['table']);
  1248.         echo '<input type="hidden" name="sql_query" value="' . $sql_query . '" />' . "\n";
  1249.         echo '<input type="hidden" name="profiling_form" value="1" />' . "\n";
  1250.         echo '<input type="checkbox" name="profiling" id="profiling"' . (isset($_SESSION['profiling']) ? ' checked="checked"' : '') . ' onclick="this.form.submit();" /><label for="profiling">' . $GLOBALS['strProfiling'] . '</label>' . "\n";
  1251.         echo '<noscript><input type="submit" value="' . $GLOBALS['strGo'] . '" /></noscript>' . "\n";
  1252.         echo '</form>' . "\n";
  1253.     }
  1254. }
  1255.  
  1256. /**
  1257.  * Displays the results of SHOW PROFILE 
  1258.  *
  1259.  * @param    array   the results 
  1260.  * @access  public
  1261.  *
  1262.  * @author   Marc Delisle 
  1263.  */
  1264. function PMA_profilingResults($profiling_results) {
  1265.     echo '<fieldset><legend>' . $GLOBALS['strProfiling'] . '</legend>' . "\n";
  1266.     echo '<table>' . "\n";
  1267.     echo ' <tr>' .  "\n";
  1268.     echo '  <th>' . $GLOBALS['strStatus'] . '</th>' . "\n";
  1269.     echo '  <th>' . $GLOBALS['strTime'] . '</th>' . "\n";
  1270.     echo ' </tr>' .  "\n";
  1271.  
  1272.     foreach($profiling_results as $one_result) {
  1273.         echo ' <tr>' .  "\n";
  1274.         echo '<td>' . $one_result['Status'] . '</td>' .  "\n";
  1275.         echo '<td>' . $one_result['Duration'] . '</td>' .  "\n";
  1276.     }
  1277.     echo '</table>' . "\n";
  1278.     echo '</fieldset>' . "\n";
  1279. }
  1280.  
  1281. /**
  1282.  * Formats $value to byte view
  1283.  *
  1284.  * @param    double   the value to format
  1285.  * @param    integer  the sensitiveness
  1286.  * @param    integer  the number of decimals to retain
  1287.  *
  1288.  * @return   array    the formatted value and its unit
  1289.  *
  1290.  * @access  public
  1291.  *
  1292.  * @author   staybyte
  1293.  * @version  1.2 - 18 July 2002
  1294.  */
  1295. function PMA_formatByteDown($value, $limes = 6, $comma = 0)
  1296. {
  1297.     $dh           = PMA_pow(10, $comma);
  1298.     $li           = PMA_pow(10, $limes);
  1299.     $return_value = $value;
  1300.     $unit         = $GLOBALS['byteUnits'][0];
  1301.  
  1302.     for ($d = 6, $ex = 15; $d >= 1; $d--, $ex-=3) {
  1303.         if (isset($GLOBALS['byteUnits'][$d]) && $value >= $li * PMA_pow(10, $ex)) {
  1304.             // use 1024.0 to avoid integer overflow on 64-bit machines
  1305.             $value = round($value / (PMA_pow(1024, $d) / $dh)) /$dh;
  1306.             $unit = $GLOBALS['byteUnits'][$d];
  1307.             break 1;
  1308.         } // end if
  1309.     } // end for
  1310.  
  1311.     if ($unit != $GLOBALS['byteUnits'][0]) {
  1312.         // if the unit is not bytes (as represented in current language)
  1313.         // reformat with max length of 5
  1314.         // 4th parameter=true means do not reformat if value < 1
  1315.         $return_value = PMA_formatNumber($value, 5, $comma, true);
  1316.     } else {
  1317.         // do not reformat, just handle the locale
  1318.         $return_value = PMA_formatNumber($value, 0);
  1319.     }
  1320.  
  1321.     return array($return_value, $unit);
  1322. } // end of the 'PMA_formatByteDown' function
  1323.  
  1324. /**
  1325.  * Formats $value to the given length and appends SI prefixes
  1326.  * $comma is not substracted from the length
  1327.  * with a $length of 0 no truncation occurs, number is only formated
  1328.  * to the current locale
  1329.  *
  1330.  * examples:
  1331.  * <code>
  1332.  * echo PMA_formatNumber(123456789, 6);     // 123,457 k
  1333.  * echo PMA_formatNumber(-123456789, 4, 2); //    -123.46 M
  1334.  * echo PMA_formatNumber(-0.003, 6);        //      -3 m
  1335.  * echo PMA_formatNumber(0.003, 3, 3);      //       0.003
  1336.  * echo PMA_formatNumber(0.00003, 3, 2);    //       0.03 m
  1337.  * echo PMA_formatNumber(0, 6);             //       0
  1338.  *
  1339.  * </code>
  1340.  * @param   double   $value     the value to format
  1341.  * @param   integer  $length    the max length
  1342.  * @param   integer  $comma     the number of decimals to retain
  1343.  * @param   boolean  $only_down do not reformat numbers below 1
  1344.  *
  1345.  * @return  string   the formatted value and its unit
  1346.  *
  1347.  * @access  public
  1348.  *
  1349.  * @author  staybyte, sebastian mendel
  1350.  * @version 1.1.0 - 2005-10-27
  1351.  */
  1352. function PMA_formatNumber($value, $length = 3, $comma = 0, $only_down = false)
  1353. {
  1354.     //number_format is not multibyte safe, str_replace is safe
  1355.     if ($length === 0) {
  1356.         return str_replace(array(',', '.'),
  1357.                 array($GLOBALS['number_thousands_separator'], $GLOBALS['number_decimal_separator']),
  1358.                 number_format($value, $comma));
  1359.     }
  1360.  
  1361.     // this units needs no translation, ISO
  1362.     $units = array(
  1363.         -8 => 'y',
  1364.         -7 => 'z',
  1365.         -6 => 'a',
  1366.         -5 => 'f',
  1367.         -4 => 'p',
  1368.         -3 => 'n',
  1369.         -2 => 'µ',
  1370.         -1 => 'm',
  1371.         0 => ' ',
  1372.         1 => 'k',
  1373.         2 => 'M',
  1374.         3 => 'G',
  1375.         4 => 'T',
  1376.         5 => 'P',
  1377.         6 => 'E',
  1378.         7 => 'Z',
  1379.         8 => 'Y'
  1380.     );
  1381.  
  1382.     // we need at least 3 digits to be displayed
  1383.     if (3 > $length + $comma) {
  1384.         $length = 3 - $comma;
  1385.     }
  1386.  
  1387.     // check for negative value to retain sign
  1388.     if ($value < 0) {
  1389.         $sign = '-';
  1390.         $value = abs($value);
  1391.     } else {
  1392.         $sign = '';
  1393.     }
  1394.  
  1395.     $dh = PMA_pow(10, $comma);
  1396.     $li = PMA_pow(10, $length);
  1397.     $unit = $units[0];
  1398.  
  1399.     if ($value >= 1) {
  1400.         for ($d = 8; $d >= 0; $d--) {
  1401.             if (isset($units[$d]) && $value >= $li * PMA_pow(1000, $d-1)) {
  1402.                 $value = round($value / (PMA_pow(1000, $d) / $dh)) /$dh;
  1403.                 $unit = $units[$d];
  1404.                 break 1;
  1405.             } // end if
  1406.         } // end for
  1407.     } elseif (!$only_down && (float) $value !== 0.0) {
  1408.         for ($d = -8; $d <= 8; $d++) {
  1409.             if (isset($units[$d]) && $value <= $li * PMA_pow(1000, $d-1)) {
  1410.                 $value = round($value / (PMA_pow(1000, $d) / $dh)) /$dh;
  1411.                 $unit = $units[$d];
  1412.                 break 1;
  1413.             } // end if
  1414.         } // end for
  1415.     } // end if ($value >= 1) elseif (!$only_down && (float) $value !== 0.0)
  1416.  
  1417.     //number_format is not multibyte safe, str_replace is safe
  1418.     $value = str_replace(array(',', '.'),
  1419.                          array($GLOBALS['number_thousands_separator'], $GLOBALS['number_decimal_separator']),
  1420.                          number_format($value, $comma));
  1421.  
  1422.     return $sign . $value . ' ' . $unit;
  1423. } // end of the 'PMA_formatNumber' function
  1424.  
  1425. /**
  1426.  * Extracts ENUM / SET options from a type definition string
  1427.  *
  1428.  * @param   string   The column type definition
  1429.  *
  1430.  * @return  array    The options or
  1431.  *          boolean  false in case of an error.
  1432.  *
  1433.  * @author  rabus
  1434.  */
  1435. function PMA_getEnumSetOptions($type_def)
  1436. {
  1437.     $open = strpos($type_def, '(');
  1438.     $close = strrpos($type_def, ')');
  1439.     if (!$open || !$close) {
  1440.         return false;
  1441.     }
  1442.     $options = substr($type_def, $open + 2, $close - $open - 3);
  1443.     $options = explode('\',\'', $options);
  1444.     return $options;
  1445. } // end of the 'PMA_getEnumSetOptions' function
  1446.  
  1447. /**
  1448.  * Writes localised date
  1449.  *
  1450.  * @param   string   the current timestamp
  1451.  *
  1452.  * @return  string   the formatted date
  1453.  *
  1454.  * @access  public
  1455.  */
  1456. function PMA_localisedDate($timestamp = -1, $format = '')
  1457. {
  1458.     global $datefmt, $month, $day_of_week;
  1459.  
  1460.     if ($format == '') {
  1461.         $format = $datefmt;
  1462.     }
  1463.  
  1464.     if ($timestamp == -1) {
  1465.         $timestamp = time();
  1466.     }
  1467.  
  1468.     $date = preg_replace('@%[aA]@', $day_of_week[(int)strftime('%w', $timestamp)], $format);
  1469.     $date = preg_replace('@%[bB]@', $month[(int)strftime('%m', $timestamp)-1], $date);
  1470.  
  1471.     return strftime($date, $timestamp);
  1472. } // end of the 'PMA_localisedDate()' function
  1473.  
  1474.  
  1475. /**
  1476.  * returns a tab for tabbed navigation.
  1477.  * If the variables $link and $args ar left empty, an inactive tab is created
  1478.  *
  1479.  * @uses    $GLOBALS['PMA_PHP_SELF']
  1480.  * @uses    $GLOBALS['strEmpty']
  1481.  * @uses    $GLOBALS['strDrop']
  1482.  * @uses    $GLOBALS['active_page']
  1483.  * @uses    $GLOBALS['url_query']
  1484.  * @uses    $cfg['MainPageIconic']
  1485.  * @uses    $GLOBALS['pmaThemeImage']
  1486.  * @uses    PMA_generate_common_url()
  1487.  * @uses    E_USER_NOTICE
  1488.  * @uses    htmlentities()
  1489.  * @uses    urlencode()
  1490.  * @uses    sprintf()
  1491.  * @uses    trigger_error()
  1492.  * @uses    array_merge()
  1493.  * @uses    basename()
  1494.  * @param   array   $tab    array with all options
  1495.  * @return  string  html code for one tab, a link if valid otherwise a span
  1496.  * @access  public
  1497.  */
  1498. function PMA_getTab($tab)
  1499. {
  1500.     // default values
  1501.     $defaults = array(
  1502.         'text'      => '',
  1503.         'class'     => '',
  1504.         'active'    => false,
  1505.         'link'      => '',
  1506.         'sep'       => '?',
  1507.         'attr'      => '',
  1508.         'args'      => '',
  1509.         'warning'   => '',
  1510.         'fragment'  => '',
  1511.     );
  1512.  
  1513.     $tab = array_merge($defaults, $tab);
  1514.  
  1515.     // determine additionnal style-class
  1516.     if (empty($tab['class'])) {
  1517.         if ($tab['text'] == $GLOBALS['strEmpty']
  1518.             || $tab['text'] == $GLOBALS['strDrop']) {
  1519.             $tab['class'] = 'caution';
  1520.         } elseif (!empty($tab['active'])
  1521.           || (isset($GLOBALS['active_page'])
  1522.                && $GLOBALS['active_page'] == $tab['link'])
  1523.           || (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link'] && empty($tab['warning'])))
  1524.         {
  1525.             $tab['class'] = 'active';
  1526.         }
  1527.     }
  1528.  
  1529.     if (!empty($tab['warning'])) {
  1530.         $tab['class'] .= ' warning';
  1531.         $tab['attr'] .= ' title="' . htmlspecialchars($tab['warning']) . '"';
  1532.     }
  1533.  
  1534.     // build the link
  1535.     if (!empty($tab['link'])) {
  1536.         $tab['link'] = htmlentities($tab['link']);
  1537.         $tab['link'] = $tab['link'] . $tab['sep']
  1538.             .(empty($GLOBALS['url_query']) ?
  1539.                 PMA_generate_common_url() : $GLOBALS['url_query']);
  1540.         if (!empty($tab['args'])) {
  1541.             foreach ($tab['args'] as $param => $value) {
  1542.                 $tab['link'] .= '&' . urlencode($param) . '='
  1543.                     . urlencode($value);
  1544.             }
  1545.         }
  1546.     }
  1547.  
  1548.     if (! empty($tab['fragment'])) {
  1549.         $tab['link'] .= $tab['fragment'];
  1550.     }
  1551.  
  1552.     // display icon, even if iconic is disabled but the link-text is missing
  1553.     if (($GLOBALS['cfg']['MainPageIconic'] || empty($tab['text']))
  1554.         && isset($tab['icon'])) {
  1555.         $image = '<img class="icon" src="' . htmlentities($GLOBALS['pmaThemeImage'])
  1556.             .'%1$s" width="16" height="16" alt="%2$s" />%2$s';
  1557.         $tab['text'] = sprintf($image, htmlentities($tab['icon']), $tab['text']);
  1558.     }
  1559.     // check to not display an empty link-text
  1560.     elseif (empty($tab['text'])) {
  1561.         $tab['text'] = '?';
  1562.         trigger_error('empty linktext in function ' . __FUNCTION__ . '()',
  1563.             E_USER_NOTICE);
  1564.     }
  1565.  
  1566.     $out = '<li' . ($tab['class'] == 'active' ? ' class="active"' : '') . '>';
  1567.  
  1568.     if (!empty($tab['link'])) {
  1569.         $out .= '<a class="tab' . htmlentities($tab['class']) . '"'
  1570.             .' href="' . $tab['link'] . '" ' . $tab['attr'] . '>'
  1571.             . $tab['text'] . '</a>';
  1572.     } else {
  1573.         $out .= '<span class="tab' . htmlentities($tab['class']) . '">'
  1574.             . $tab['text'] . '</span>';
  1575.     }
  1576.  
  1577.     $out .= '</li>';
  1578.     return $out;
  1579. } // end of the 'PMA_getTab()' function
  1580.  
  1581. /**
  1582.  * returns html-code for a tab navigation
  1583.  *
  1584.  * @uses    PMA_getTab()
  1585.  * @uses    htmlentities()
  1586.  * @param   array   $tabs   one element per tab
  1587.  * @param   string  $tag_id id used for the html-tag
  1588.  * @return  string  html-code for tab-navigation
  1589.  */
  1590. function PMA_getTabs($tabs, $tag_id = 'topmenu')
  1591. {
  1592.     $tab_navigation =
  1593.          '<div id="' . htmlentities($tag_id) . 'container">' . "\n"
  1594.         .'<ul id="' . htmlentities($tag_id) . '">' . "\n";
  1595.  
  1596.     foreach ($tabs as $tab) {
  1597.         $tab_navigation .= PMA_getTab($tab) . "\n";
  1598.     }
  1599.  
  1600.     $tab_navigation .=
  1601.          '</ul>' . "\n"
  1602.         .'<div class="clearfloat"></div>'
  1603.         .'</div>' . "\n";
  1604.  
  1605.     return $tab_navigation;
  1606. }
  1607.  
  1608.  
  1609. /**
  1610.  * Displays a link, or a button if the link's URL is too large, to
  1611.  * accommodate some browsers' limitations
  1612.  *
  1613.  * @param  string  the URL
  1614.  * @param  string  the link message
  1615.  * @param  mixed   $tag_params  string: js confirmation
  1616.  *                              array: additional tag params (f.e. style="")
  1617.  * @param  boolean $new_form    we set this to false when we are already in
  1618.  *                              a  form, to avoid generating nested forms
  1619.  *
  1620.  * @return string  the results to be echoed or saved in an array
  1621.  */
  1622. function PMA_linkOrButton($url, $message, $tag_params = array(),
  1623.     $new_form = true, $strip_img = false, $target = '')
  1624. {
  1625.     if (! is_array($tag_params)) {
  1626.         $tmp = $tag_params;
  1627.         $tag_params = array();
  1628.         if (!empty($tmp)) {
  1629.             $tag_params['onclick'] = 'return confirmLink(this, \'' . $tmp . '\')';
  1630.         }
  1631.         unset($tmp);
  1632.     }
  1633.     if (! empty($target)) {
  1634.         $tag_params['target'] = htmlentities($target);
  1635.     }
  1636.  
  1637.     $tag_params_strings = array();
  1638.     foreach ($tag_params as $par_name => $par_value) {
  1639.         // htmlspecialchars() only on non javascript
  1640.         $par_value = substr($par_name, 0, 2) == 'on'
  1641.             ? $par_value
  1642.             : htmlspecialchars($par_value);
  1643.         $tag_params_strings[] = $par_name . '="' . $par_value . '"';
  1644.     }
  1645.  
  1646.     // previously the limit was set to 2047, it seems 1000 is better
  1647.     if (strlen($url) <= 1000) {
  1648.         // no whitespace within an <a> else Safari will make it part of the link
  1649.         $ret = "\n" . '<a href="' . $url . '" '
  1650.             . implode(' ', $tag_params_strings) . '>'
  1651.             . $message . '</a>' . "\n";
  1652.     } else {
  1653.         // no spaces (linebreaks) at all
  1654.         // or after the hidden fields
  1655.         // IE will display them all
  1656.  
  1657.         // add class=link to submit button
  1658.         if (empty($tag_params['class'])) {
  1659.             $tag_params['class'] = 'link';
  1660.         }
  1661.  
  1662.         // decode encoded url separators
  1663.         $separator   = PMA_get_arg_separator();
  1664.         // on most places separator is still hard coded ...
  1665.         if ($separator !== '&') {
  1666.             // ... so always replace & with $separator
  1667.             $url         = str_replace(htmlentities('&'), $separator, $url);
  1668.             $url         = str_replace('&', $separator, $url);
  1669.         }
  1670.         $url         = str_replace(htmlentities($separator), $separator, $url);
  1671.         // end decode
  1672.  
  1673.         $url_parts   = parse_url($url);
  1674.         $query_parts = explode($separator, $url_parts['query']);
  1675.         if ($new_form) {
  1676.             $ret = '<form action="' . $url_parts['path'] . '" class="link"'
  1677.                  . ' method="post"' . $target . ' style="display: inline;">';
  1678.             $subname_open   = '';
  1679.             $subname_close  = '';
  1680.             $submit_name    = '';
  1681.         } else {
  1682.             $query_parts[] = 'redirect=' . $url_parts['path'];
  1683.             if (empty($GLOBALS['subform_counter'])) {
  1684.                 $GLOBALS['subform_counter'] = 0;
  1685.             }
  1686.             $GLOBALS['subform_counter']++;
  1687.             $ret            = '';
  1688.             $subname_open   = 'subform[' . $GLOBALS['subform_counter'] . '][';
  1689.             $subname_close  = ']';
  1690.             $submit_name    = ' name="usesubform[' . $GLOBALS['subform_counter'] . ']"';
  1691.         }
  1692.         foreach ($query_parts as $query_pair) {
  1693.             list($eachvar, $eachval) = explode('=', $query_pair);
  1694.             $ret .= '<input type="hidden" name="' . $subname_open . $eachvar
  1695.                 . $subname_close . '" value="'
  1696.                 . htmlspecialchars(urldecode($eachval)) . '" />';
  1697.         } // end while
  1698.  
  1699.         if (stristr($message, '<img')) {
  1700.             if ($strip_img) {
  1701.                 $message = trim(strip_tags($message));
  1702.                 $ret .= '<input type="submit"' . $submit_name . ' '
  1703.                     . implode(' ', $tag_params_strings)
  1704.                     . ' value="' . htmlspecialchars($message) . '" />';
  1705.             } else {
  1706.                 $ret .= '<input type="image"' . $submit_name . ' '
  1707.                     . implode(' ', $tag_params_strings)
  1708.                     . ' src="' . preg_replace(
  1709.                         '/^.*\ssrc="([^"]*)".*$/si', '\1', $message) . '"'
  1710.                     . ' value="' . htmlspecialchars(
  1711.                         preg_replace('/^.*\salt="([^"]*)".*$/si', '\1',
  1712.                             $message))
  1713.                     . '" />';
  1714.             }
  1715.         } else {
  1716.             $message = trim(strip_tags($message));
  1717.             $ret .= '<input type="submit"' . $submit_name . ' '
  1718.                 . implode(' ', $tag_params_strings)
  1719.                 . ' value="' . htmlspecialchars($message) . '" />';
  1720.         }
  1721.         if ($new_form) {
  1722.             $ret .= '</form>';
  1723.         }
  1724.     } // end if... else...
  1725.  
  1726.         return $ret;
  1727. } // end of the 'PMA_linkOrButton()' function
  1728.  
  1729.  
  1730. /**
  1731.  * Returns a given timespan value in a readable format.
  1732.  *
  1733.  * @uses    $GLOBALS['timespanfmt']
  1734.  * @uses    sprintf()
  1735.  * @uses    floor()
  1736.  * @param  int     the timespan
  1737.  *
  1738.  * @return string  the formatted value
  1739.  */
  1740. function PMA_timespanFormat($seconds)
  1741. {
  1742.     $return_string = '';
  1743.     $days = floor($seconds / 86400);
  1744.     if ($days > 0) {
  1745.         $seconds -= $days * 86400;
  1746.     }
  1747.     $hours = floor($seconds / 3600);
  1748.     if ($days > 0 || $hours > 0) {
  1749.         $seconds -= $hours * 3600;
  1750.     }
  1751.     $minutes = floor($seconds / 60);
  1752.     if ($days > 0 || $hours > 0 || $minutes > 0) {
  1753.         $seconds -= $minutes * 60;
  1754.     }
  1755.     return sprintf($GLOBALS['timespanfmt'], (string)$days, (string)$hours, (string)$minutes, (string)$seconds);
  1756. }
  1757.  
  1758. /**
  1759.  * Takes a string and outputs each character on a line for itself. Used
  1760.  * mainly for horizontalflipped display mode.
  1761.  * Takes care of special html-characters.
  1762.  * Fulfills todo-item
  1763.  * http://sf.net/tracker/?func=detail&aid=544361&group_id=23067&atid=377411
  1764.  *
  1765.  * @todo    add a multibyte safe function PMA_STR_split()
  1766.  * @uses    strlen
  1767.  * @param   string   The string
  1768.  * @param   string   The Separator (defaults to "<br />\n")
  1769.  *
  1770.  * @access  public
  1771.  * @author  Garvin Hicking <me@supergarv.de>
  1772.  * @return  string      The flipped string
  1773.  */
  1774. function PMA_flipstring($string, $Separator = "<br />\n")
  1775. {
  1776.     $format_string = '';
  1777.     $charbuff = false;
  1778.  
  1779.     for ($i = 0; $i < strlen($string); $i++) {
  1780.         $char = $string{$i};
  1781.         $append = false;
  1782.  
  1783.         if ($char == '&') {
  1784.             $format_string .= $charbuff;
  1785.             $charbuff = $char;
  1786.             $append = true;
  1787.         } elseif (!empty($charbuff)) {
  1788.             $charbuff .= $char;
  1789.         } elseif ($char == ';' && !empty($charbuff)) {
  1790.             $format_string .= $charbuff;
  1791.             $charbuff = false;
  1792.             $append = true;
  1793.         } else {
  1794.             $format_string .= $char;
  1795.             $append = true;
  1796.         }
  1797.  
  1798.         if ($append && ($i != strlen($string))) {
  1799.             $format_string .= $Separator;
  1800.         }
  1801.     }
  1802.  
  1803.     return $format_string;
  1804. }
  1805.  
  1806.  
  1807. /**
  1808.  * Function added to avoid path disclosures.
  1809.  * Called by each script that needs parameters, it displays
  1810.  * an error message and, by default, stops the execution.
  1811.  *
  1812.  * Not sure we could use a strMissingParameter message here,
  1813.  * would have to check if the error message file is always available
  1814.  *
  1815.  * @todo    localize error message
  1816.  * @todo    use PMA_fatalError() if $die === true?
  1817.  * @uses    PMA_getenv()
  1818.  * @uses    header_meta_style.inc.php
  1819.  * @uses    $GLOBALS['PMA_PHP_SELF']
  1820.  * basename
  1821.  * @param   array   The names of the parameters needed by the calling
  1822.  *                  script.
  1823.  * @param   boolean Stop the execution?
  1824.  *                  (Set this manually to false in the calling script
  1825.  *                   until you know all needed parameters to check).
  1826.  * @param   boolean Whether to include this list in checking for special params.
  1827.  * @global  string  path to current script
  1828.  * @global  boolean flag whether any special variable was required
  1829.  *
  1830.  * @access  public
  1831.  * @author  Marc Delisle (lem9@users.sourceforge.net)
  1832.  */
  1833. function PMA_checkParameters($params, $die = true, $request = true)
  1834. {
  1835.     global $checked_special;
  1836.  
  1837.     if (!isset($checked_special)) {
  1838.         $checked_special = false;
  1839.     }
  1840.  
  1841.     $reported_script_name = basename($GLOBALS['PMA_PHP_SELF']);
  1842.     $found_error = false;
  1843.     $error_message = '';
  1844.  
  1845.     foreach ($params as $param) {
  1846.         if ($request && $param != 'db' && $param != 'table') {
  1847.             $checked_special = true;
  1848.         }
  1849.  
  1850.         if (!isset($GLOBALS[$param])) {
  1851.             $error_message .= $reported_script_name
  1852.                 . ': Missing parameter: ' . $param
  1853.                 . ' <a href="./Documentation.html#faqmissingparameters"'
  1854.                 . ' target="documentation"> (FAQ 2.8)</a><br />';
  1855.             $found_error = true;
  1856.         }
  1857.     }
  1858.     if ($found_error) {
  1859.         /**
  1860.          * display html meta tags
  1861.          */
  1862.         require_once './libraries/header_meta_style.inc.php';
  1863.         echo '</head><body><p>' . $error_message . '</p></body></html>';
  1864.         if ($die) {
  1865.             exit();
  1866.         }
  1867.     }
  1868. } // end function
  1869.  
  1870. /**
  1871.  * Function to generate unique condition for specified row.
  1872.  *
  1873.  * @uses    PMA_MYSQL_INT_VERSION
  1874.  * @uses    $GLOBALS['analyzed_sql'][0]
  1875.  * @uses    PMA_DBI_field_flags()
  1876.  * @uses    PMA_backquote()
  1877.  * @uses    PMA_sqlAddslashes()
  1878.  * @uses    stristr()
  1879.  * @uses    bin2hex()
  1880.  * @uses    preg_replace()
  1881.  * @param   resource    $handle         current query result
  1882.  * @param   integer     $fields_cnt     number of fields
  1883.  * @param   array       $fields_meta    meta information about fields
  1884.  * @param   array       $row            current row
  1885.  * @param   boolean     $force_unique   generate condition only on pk or unique
  1886.  *
  1887.  * @access  public
  1888.  * @author  Michal Cihar (michal@cihar.com) and others...
  1889.  * @return  string      calculated condition
  1890.  */
  1891. function PMA_getUniqueCondition($handle, $fields_cnt, $fields_meta, $row, $force_unique=false)
  1892. {
  1893.     $primary_key          = '';
  1894.     $unique_key           = '';
  1895.     $nonprimary_condition = '';
  1896.     $preferred_condition = '';
  1897.  
  1898.     for ($i = 0; $i < $fields_cnt; ++$i) {
  1899.         $condition   = '';
  1900.         $field_flags = PMA_DBI_field_flags($handle, $i);
  1901.         $meta        = $fields_meta[$i];
  1902.  
  1903.         // do not use a column alias in a condition
  1904.         if (! isset($meta->orgname) || ! strlen($meta->orgname)) {
  1905.             $meta->orgname = $meta->name;
  1906.  
  1907.             if (isset($GLOBALS['analyzed_sql'][0]['select_expr'])
  1908.               && is_array($GLOBALS['analyzed_sql'][0]['select_expr'])) {
  1909.                 foreach ($GLOBALS['analyzed_sql'][0]['select_expr']
  1910.                   as $select_expr) {
  1911.                     // need (string) === (string)
  1912.                     // '' !== 0 but '' == 0
  1913.                     if ((string) $select_expr['alias'] === (string) $meta->name) {
  1914.                         $meta->orgname = $select_expr['column'];
  1915.                         break;
  1916.                     } // end if
  1917.                 } // end foreach
  1918.             }
  1919.         }
  1920.  
  1921.         // Do not use a table alias in a condition.
  1922.         // Test case is:
  1923.         // select * from galerie x WHERE
  1924.         //(select count(*) from galerie y where y.datum=x.datum)>1 
  1925.         //
  1926.         // But orgtable is present only with mysqli extension so the
  1927.         // fix is only for mysqli.
  1928.         if (isset($meta->orgtable) && $meta->table != $meta->orgtable) {
  1929.             $meta->table = $meta->orgtable;
  1930.         }
  1931.  
  1932.         // to fix the bug where float fields (primary or not)
  1933.         // can't be matched because of the imprecision of
  1934.         // floating comparison, use CONCAT
  1935.         // (also, the syntax "CONCAT(field) IS NULL"
  1936.         // that we need on the next "if" will work)
  1937.         if ($meta->type == 'real') {
  1938.             $condition = ' CONCAT(' . PMA_backquote($meta->table) . '.'
  1939.                 . PMA_backquote($meta->orgname) . ') ';
  1940.         } else {
  1941.             // string and blob fields have to be converted using
  1942.             // the system character set (always utf8) since
  1943.             // mysql4.1 can use different charset for fields.
  1944.             if (PMA_MYSQL_INT_VERSION >= 40100
  1945.               && ($meta->type == 'string' || $meta->type == 'blob')) {
  1946.                 $condition = ' CONVERT(' . PMA_backquote($meta->table) . '.'
  1947.                     . PMA_backquote($meta->orgname) . ' USING utf8) ';
  1948.             } else {
  1949.                 $condition = ' ' . PMA_backquote($meta->table) . '.'
  1950.                     . PMA_backquote($meta->orgname) . ' ';
  1951.             }
  1952.         } // end if... else...
  1953.  
  1954.         if (!isset($row[$i]) || is_null($row[$i])) {
  1955.             $condition .= 'IS NULL AND';
  1956.         } else {
  1957.             // timestamp is numeric on some MySQL 4.1
  1958.             if ($meta->numeric && $meta->type != 'timestamp') {
  1959.                 $condition .= '= ' . $row[$i] . ' AND';
  1960.             } elseif ($meta->type == 'blob'
  1961.                 // hexify only if this is a true not empty BLOB
  1962.                  && stristr($field_flags, 'BINARY')
  1963.                  && !empty($row[$i])) {
  1964.                     // do not waste memory building a too big condition
  1965.                     if (strlen($row[$i]) < 1000) {
  1966.                         if (PMA_MYSQL_INT_VERSION < 40002) {
  1967.                             $condition .= 'LIKE 0x' . bin2hex($row[$i]) . ' AND';
  1968.                         } else {
  1969.                             // use a CAST if possible, to avoid problems
  1970.                             // if the field contains wildcard characters % or _
  1971.                             $condition .= '= CAST(0x' . bin2hex($row[$i])
  1972.                                 . ' AS BINARY) AND';
  1973.                         }
  1974.                     } else {
  1975.                         // this blob won't be part of the final condition
  1976.                         $condition = '';
  1977.                     }
  1978.             } else {
  1979.                 $condition .= '= \''
  1980.                     . PMA_sqlAddslashes($row[$i], false, true) . '\' AND';
  1981.             }
  1982.         }
  1983.         if ($meta->primary_key > 0) {
  1984.             $primary_key .= $condition;
  1985.         } elseif ($meta->unique_key > 0) {
  1986.             $unique_key  .= $condition;
  1987.         }
  1988.         $nonprimary_condition .= $condition;
  1989.     } // end for
  1990.  
  1991.     // Correction University of Virginia 19991216:
  1992.     // prefer primary or unique keys for condition,
  1993.     // but use conjunction of all values if no primary key
  1994.     if ($primary_key) {
  1995.         $preferred_condition = $primary_key;
  1996.     } elseif ($unique_key) {
  1997.         $preferred_condition = $unique_key;
  1998.     } elseif (! $force_unique) {
  1999.         $preferred_condition = $nonprimary_condition;
  2000.     }
  2001.  
  2002.     return preg_replace('|\s?AND$|', '', $preferred_condition);
  2003. } // end function
  2004.  
  2005. /**
  2006.  * Generate a button or image tag
  2007.  *
  2008.  * @uses    PMA_USR_BROWSER_AGENT
  2009.  * @uses    $GLOBALS['pmaThemeImage']
  2010.  * @uses    $GLOBALS['cfg']['PropertiesIconic']
  2011.  * @param   string      name of button element
  2012.  * @param   string      class of button element
  2013.  * @param   string      name of image element
  2014.  * @param   string      text to display
  2015.  * @param   string      image to display
  2016.  *
  2017.  * @access  public
  2018.  * @author  Michal Cihar (michal@cihar.com)
  2019.  */
  2020. function PMA_buttonOrImage($button_name, $button_class, $image_name, $text,
  2021.     $image)
  2022. {
  2023.     /* Opera has trouble with <input type="image"> */
  2024.     /* IE has trouble with <button> */
  2025.     if (PMA_USR_BROWSER_AGENT != 'IE') {
  2026.         echo '<button class="' . $button_class . '" type="submit"'
  2027.             .' name="' . $button_name . '" value="' . $text . '"'
  2028.             .' title="' . $text . '">' . "\n"
  2029.             .'<img class="icon" src="' . $GLOBALS['pmaThemeImage'] . $image . '"'
  2030.             .' title="' . $text . '" alt="' . $text . '" width="16"'
  2031.             .' height="16" />'
  2032.             .($GLOBALS['cfg']['PropertiesIconic'] === 'both' ? ' ' . $text : '') . "\n"
  2033.             .'</button>' . "\n";
  2034.     } else {
  2035.         echo '<input type="image" name="' . $image_name . '" value="'
  2036.             . $text . '" title="' . $text . '" src="' . $GLOBALS['pmaThemeImage']
  2037.             . $image . '" />'
  2038.             . ($GLOBALS['cfg']['PropertiesIconic'] === 'both' ? ' ' . $text : '') . "\n";
  2039.     }
  2040. } // end function
  2041.  
  2042. /**
  2043.  * Generate a pagination selector for browsing resultsets
  2044.  *
  2045.  * @uses    $GLOBALS['strPageNumber']
  2046.  * @uses    range()
  2047.  * @param   string      URL for the JavaScript
  2048.  * @param   string      Number of rows in the pagination set
  2049.  * @param   string      current page number
  2050.  * @param   string      number of total pages
  2051.  * @param   string      If the number of pages is lower than this
  2052.  *                      variable, no pages will be ommitted in
  2053.  *                      pagination
  2054.  * @param   string      How many rows at the beginning should always
  2055.  *                      be shown?
  2056.  * @param   string      How many rows at the end should always
  2057.  *                      be shown?
  2058.  * @param   string      Percentage of calculation page offsets to
  2059.  *                      hop to a next page
  2060.  * @param   string      Near the current page, how many pages should
  2061.  *                      be considered "nearby" and displayed as
  2062.  *                      well?
  2063.  * @param   string      The prompt to display (sometimes empty)
  2064.  *
  2065.  * @access  public
  2066.  * @author  Garvin Hicking (pma@supergarv.de)
  2067.  */
  2068. function PMA_pageselector($url, $rows, $pageNow = 1, $nbTotalPage = 1,
  2069.     $showAll = 200, $sliceStart = 5, $sliceEnd = 5, $percent = 20,
  2070.     $range = 10, $prompt = '')
  2071. {
  2072.     $gotopage = $prompt 
  2073.               . ' <select name="goToPage" onchange="goToUrl(this, \''
  2074.               . $url . '\');">' . "\n";
  2075.     if ($nbTotalPage < $showAll) {
  2076.         $pages = range(1, $nbTotalPage);
  2077.     } else {
  2078.         $pages = array();
  2079.  
  2080.         // Always show first X pages
  2081.         for ($i = 1; $i <= $sliceStart; $i++) {
  2082.             $pages[] = $i;
  2083.         }
  2084.  
  2085.         // Always show last X pages
  2086.         for ($i = $nbTotalPage - $sliceEnd; $i <= $nbTotalPage; $i++) {
  2087.             $pages[] = $i;
  2088.         }
  2089.  
  2090.         // garvin: Based on the number of results we add the specified
  2091.         // $percent percentate to each page number,
  2092.         // so that we have a representing page number every now and then to
  2093.         // immideately jump to specific pages.
  2094.         // As soon as we get near our currently chosen page ($pageNow -
  2095.         // $range), every page number will be
  2096.         // shown.
  2097.         $i = $sliceStart;
  2098.         $x = $nbTotalPage - $sliceEnd;
  2099.         $met_boundary = false;
  2100.         while ($i <= $x) {
  2101.             if ($i >= ($pageNow - $range) && $i <= ($pageNow + $range)) {
  2102.                 // If our pageselector comes near the current page, we use 1
  2103.                 // counter increments
  2104.                 $i++;
  2105.                 $met_boundary = true;
  2106.             } else {
  2107.                 // We add the percentate increment to our current page to
  2108.                 // hop to the next one in range
  2109.                 $i = $i + floor($nbTotalPage / $percent);
  2110.  
  2111.                 // Make sure that we do not cross our boundaries.
  2112.                 if ($i > ($pageNow - $range) && !$met_boundary) {
  2113.                     $i = $pageNow - $range;
  2114.                 }
  2115.             }
  2116.  
  2117.             if ($i > 0 && $i <= $x) {
  2118.                 $pages[] = $i;
  2119.             }
  2120.         }
  2121.  
  2122.         // Since because of ellipsing of the current page some numbers may be double,
  2123.         // we unify our array:
  2124.         sort($pages);
  2125.         $pages = array_unique($pages);
  2126.     }
  2127.  
  2128.     foreach ($pages as $i) {
  2129.         if ($i == $pageNow) {
  2130.             $selected = 'selected="selected" style="font-weight: bold"';
  2131.         } else {
  2132.             $selected = '';
  2133.         }
  2134.         $gotopage .= '                <option ' . $selected . ' value="' . (($i - 1) * $rows) . '">' . $i . '</option>' . "\n";
  2135.     }
  2136.  
  2137.     $gotopage .= ' </select>';
  2138.  
  2139.     return $gotopage;
  2140. } // end function
  2141.  
  2142.  
  2143. /**
  2144.  * Generate navigation for a list 
  2145.  *
  2146.  * @todo    use $pos from $_url_params 
  2147.  * @uses    $GLOBALS['strPageNumber']
  2148.  * @uses    range()
  2149.  * @param   integer     number of elements in the list 
  2150.  * @param   integer     current position in the list 
  2151.  * @param   array       url parameters 
  2152.  * @param   string      script name for form target 
  2153.  * @param   string      target frame 
  2154.  * @param   integer     maximum number of elements to display from the list 
  2155.  *
  2156.  * @access  public
  2157.  */
  2158. function PMA_listNavigator($count, $pos, $_url_params, $script, $frame, $max_count) {
  2159.  
  2160.     if ($max_count < $count) {
  2161.         echo 'frame_navigation' == $frame ? '<div id="navidbpageselector">' . "\n" : '';
  2162.         echo $GLOBALS['strPageNumber'];
  2163.         echo 'frame_navigation' == $frame ? '<br />' : ' ';
  2164.  
  2165.         // Move to the beginning or to the previous page
  2166.         if ($pos > 0) {
  2167.             // loic1: patch #474210 from Gosha Sakovich - part 1
  2168.             if ($GLOBALS['cfg']['NavigationBarIconic']) {
  2169.                 $caption1 = '<<';
  2170.                 $caption2 = ' < ';
  2171.                 $title1   = ' title="' . $GLOBALS['strPos1'] . '"';
  2172.                 $title2   = ' title="' . $GLOBALS['strPrevious'] . '"';
  2173.             } else {
  2174.                 $caption1 = $GLOBALS['strPos1'] . ' <<';
  2175.                 $caption2 = $GLOBALS['strPrevious'] . ' <';
  2176.                 $title1   = '';
  2177.                 $title2   = '';
  2178.             } // end if... else...
  2179.             $_url_params['pos'] = 0;
  2180.             echo '<a' . $title1 . ' href="' . $script
  2181.                 . PMA_generate_common_url($_url_params) . '" target="' . $frame . '">'
  2182.                 . $caption1 . '</a>';
  2183.             $_url_params['pos'] = $pos - $max_count;
  2184.             echo '<a' . $title2 . ' href="' . $script
  2185.                 . PMA_generate_common_url($_url_params) . '" target="' . $frame . '">'
  2186.                 . $caption2 . '</a>';
  2187.         }
  2188.  
  2189.         echo '<form action="./' . $script . '" method="post">' . "\n";
  2190.         echo PMA_generate_common_hidden_inputs($_url_params);
  2191.         echo PMA_pageselector(
  2192.             $script . PMA_generate_common_url($_url_params) . '&',
  2193.                 $max_count,
  2194.                 floor(($pos + 1) / $max_count) + 1,
  2195.                 ceil($count / $max_count));
  2196.         echo '</form>';
  2197.  
  2198.         if ($pos + $max_count < $count) {
  2199.             if ($GLOBALS['cfg']['NavigationBarIconic']) {
  2200.                 $caption3 = ' > ';
  2201.                 $caption4 = '>>';
  2202.                 $title3   = ' title="' . $GLOBALS['strNext'] . '"';
  2203.                 $title4   = ' title="' . $GLOBALS['strEnd'] . '"';
  2204.             } else {
  2205.                 $caption3 = '> ' . $GLOBALS['strNext'];
  2206.                 $caption4 = '>> ' . $GLOBALS['strEnd'];
  2207.                 $title3   = '';
  2208.                 $title4   = '';
  2209.             } // end if... else...
  2210.             $_url_params['pos'] = $pos + $max_count;
  2211.             echo '<a' . $title3 . ' href="' . $script 
  2212.                 . PMA_generate_common_url($_url_params) . '" target="' . $frame . '">'
  2213.                 . $caption3 . '</a>';
  2214.             $_url_params['pos'] = floor($count / $max_count) * $max_count;
  2215.             if ($_url_params['pos'] == $count) {
  2216.                 $_url_params['pos'] = $count - $max_count;
  2217.             }
  2218.             echo '<a' . $title4 . ' href="' . $script
  2219.                 . PMA_generate_common_url($_url_params) . '" target="' . $frame . '">'
  2220.                 . $caption4 . '</a>';
  2221.         }
  2222.         echo "\n";
  2223.         if ('frame_navigation' == $frame) {
  2224.             echo '</div>' . "\n";
  2225.         }
  2226.     }
  2227. }
  2228.  
  2229. /**
  2230.  * replaces %u in given path with current user name
  2231.  *
  2232.  * example:
  2233.  * <code>
  2234.  * $user_dir = PMA_userDir('/var/pma_tmp/%u/'); // '/var/pma_tmp/root/'
  2235.  *
  2236.  * </code>
  2237.  * @uses    $cfg['Server']['user']
  2238.  * @uses    substr()
  2239.  * @uses    str_replace()
  2240.  * @param   string  $dir with wildcard for user
  2241.  * @return  string  per user directory
  2242.  */
  2243. function PMA_userDir($dir)
  2244. {
  2245.     // add trailing slash
  2246.     if (substr($dir, -1) != '/') {
  2247.         $dir .= '/';
  2248.     }
  2249.  
  2250.     return str_replace('%u', $GLOBALS['cfg']['Server']['user'], $dir);
  2251. }
  2252.  
  2253. /**
  2254.  * returns html code for db link to default db page
  2255.  *
  2256.  * @uses    $cfg['DefaultTabDatabase']
  2257.  * @uses    $GLOBALS['db']
  2258.  * @uses    $GLOBALS['strJumpToDB']
  2259.  * @uses    PMA_generate_common_url()
  2260.  * @uses    PMA_unescape_mysql_wildcards()
  2261.  * @uses    strlen()
  2262.  * @uses    sprintf()
  2263.  * @uses    htmlspecialchars()
  2264.  * @param   string  $database
  2265.  * @return  string  html link to default db page
  2266.  */
  2267. function PMA_getDbLink($database = null)
  2268. {
  2269.     if (!strlen($database)) {
  2270.         if (!strlen($GLOBALS['db'])) {
  2271.             return '';
  2272.         }
  2273.         $database = $GLOBALS['db'];
  2274.     } else {
  2275.         $database = PMA_unescape_mysql_wildcards($database);
  2276.     }
  2277.  
  2278.     return '<a href="' . $GLOBALS['cfg']['DefaultTabDatabase'] . '?' . PMA_generate_common_url($database) . '"'
  2279.         .' title="' . sprintf($GLOBALS['strJumpToDB'], htmlspecialchars($database)) . '">'
  2280.         .htmlspecialchars($database) . '</a>';
  2281. }
  2282.  
  2283. /**
  2284.  * Displays a lightbulb hint explaining a known external bug
  2285.  * that affects a functionality
  2286.  *
  2287.  * @uses    PMA_MYSQL_INT_VERSION
  2288.  * @uses    $GLOBALS['strKnownExternalBug']
  2289.  * @uses    PMA_showHint()
  2290.  * @uses    sprintf()
  2291.  * @param   string  $functionality localized message explaining the func.
  2292.  * @param   string  $component  'mysql' (eventually, 'php')
  2293.  * @param   string  $minimum_version of this component
  2294.  * @param   string  $bugref  bug reference for this component
  2295.  */
  2296. function PMA_externalBug($functionality, $component, $minimum_version, $bugref)
  2297. {
  2298.     if ($component == 'mysql' && PMA_MYSQL_INT_VERSION < $minimum_version) {
  2299.         echo PMA_showHint(sprintf($GLOBALS['strKnownExternalBug'], $functionality, 'http://bugs.mysql.com/' . $bugref));
  2300.     }
  2301. }
  2302. ?>
  2303.