sorry, wrong version checked in
[phpmyadmin/arisferyanto.git] / libraries / common.lib.php
blob23297e81b6f6aa226f56ecbda72e39de216c8ed7
1 <?php
2 /* $Id$ */
3 // vim: expandtab sw=4 ts=4 sts=4:
5 /**
6 * Misc stuff and functions used by almost all the scripts.
7 * Among other things, it contains the advanced authentification work.
8 */
10 /**
11 * Order of sections for common.lib.php:
13 * some functions need the constants of libraries/defines.lib.php
14 * and defines_mysql.lib.php
16 * the PMA_setFontSizes() function must be before the call to the
17 * libraries/auth/cookie.auth.lib.php library
19 * the include of libraries/defines_mysql.lib.php must be after the connection
20 * to db to get the MySql version
22 * the PMA_sqlAddslashes() function must be before the connection to db
24 * the authentication libraries must be before the connection to db but
25 * after the PMA_isInto() function
27 * the PMA_mysqlDie() function must be before the connection to db but
28 * after mysql extension has been loaded
30 * the PMA_mysqlDie() function needs the PMA_format_sql() Function
32 * ... so the required order is:
34 * - parsing of the configuration file
35 * - load of the libraries/defines.lib.php library
36 * - load of mysql extension (if necessary)
37 * - definition of PMA_sqlAddslashes()
38 * - definition of PMA_format_sql()
39 * - definition of PMA_mysqlDie()
40 * - definition of PMA_isInto()
41 * - definition of PMA_setFontSizes()
42 * - loading of an authentication library
43 * - db connection
44 * - authentication work
45 * - load of the libraries/defines_mysql.lib.php library to get the MySQL
46 * release number
47 * - other functions, respecting dependencies
50 // grab_globals.lib.php should really go before common.lib.php
51 require_once('./libraries/grab_globals.lib.php');
53 /**
54 * @var array $GLOBALS['PMA_errors'] holds errors
56 $GLOBALS['PMA_errors'] = array();
58 /**
59 * Avoids undefined variables
61 if (!isset($use_backquotes)) {
62 $use_backquotes = 0;
64 if (!isset($pos)) {
65 $pos = 0;
68 /**
69 * 2004-06-30 rabus: Ensure, that $cfg variables are not set somwhere else
70 * before including the config file.
72 unset($cfg);
74 /**
75 * Added messages while developing:
77 if (file_exists('./lang/added_messages.php')) {
78 include('./lang/added_messages.php');
81 /**
82 * Set default configuration values.
84 include './config.default.php';
86 // Remember default server config
87 $default_server = $cfg['Servers'][1];
89 // Drop all server, as they have to be configured by user
90 unset($cfg['Servers']);
92 /**
93 * Parses the configuration file and gets some constants used to define
94 * versions of phpMyAdmin/php/mysql...
96 $old_error_reporting = error_reporting(0);
97 // We can not use include as it fails on parse error
98 if (file_exists('./config.inc.php')) {
99 $config_fd = fopen('./config.inc.php', 'r');
100 $result = eval('?>' . fread($config_fd, filesize('./config.inc.php')));
101 fclose( $config_fd );
102 unset( $config_fd );
104 // Eval failed
105 if ($result === FALSE || !isset($cfg['Servers'])) {
106 // Creates fake settings
107 $cfg = array('DefaultLang' => 'en-iso-8859-1',
108 'AllowAnywhereRecoding' => FALSE);
109 // Loads the language file
110 require_once('./libraries/select_lang.lib.php');
111 // Displays the error message
112 // (do not use &amp; for parameters sent by header)
113 header( 'Location: error.php'
114 . '?lang=' . urlencode( $available_languages[$lang][2] )
115 . '&char=' . urlencode( $charset )
116 . '&dir=' . urlencode( $text_dir )
117 . '&type=' . urlencode( $strError )
118 . '&error=' . urlencode(
119 strtr( $strConfigFileError, array( '<br />' => '[br]' ) )
120 . '[br][br]' . '[a@./config.inc.php@_blank]config.inc.php[/a]' )
121 . '&' . SID
123 exit();
125 error_reporting($old_error_reporting);
126 unset( $old_error_reporting, $result );
130 * Includes the language file if it hasn't been included yet
132 require_once('./libraries/select_lang.lib.php');
135 * Servers array fixups.
137 // Do we have some server?
138 if (!isset($cfg['Servers']) || count($cfg['Servers']) == 0) {
139 // No server => create one with defaults
140 $cfg['Servers'] = array(1 => $default_server);
141 } else {
142 // We have server(s) => apply default config
143 $new_servers = array();
144 foreach($cfg['Servers'] as $key => $val) {
145 if (!is_int($key) || $key < 1) {
146 // Show error
147 header( 'Location: error.php'
148 . '?lang=' . urlencode( $available_languages[$lang][2] )
149 . '&char=' . urlencode( $charset )
150 . '&dir=' . urlencode( $text_dir )
151 . '&type=' . urlencode( $strError )
152 . '&error=' . urlencode(
153 // FIXME: We could translate this message, however it's translations freeze right now:
154 sprintf( 'Invalid server index: "%s"', $key))
155 . '&' . SID
158 $new_servers[$key] = array_merge($default_server, $val);
160 $cfg['Servers'] = $new_servers;
161 unset( $new_servers, $key, $val );
164 // Cleanup
165 unset($default_server);
168 * We really need this one!
170 if (!function_exists('preg_replace')) {
171 header( 'Location: error.php'
172 . '?lang=' . urlencode( $available_languages[$lang][2] )
173 . '&char=' . urlencode( $charset )
174 . '&dir=' . urlencode( $text_dir )
175 . '&type=' . urlencode( $strError )
176 . '&error=' . urlencode(
177 strtr( sprintf( $strCantLoad, 'pcre' ),
178 array('<br />' => '[br]') ) )
179 . '&' . SID
181 exit();
185 * Gets constants that defines the PHP version number.
186 * This include must be located physically before any code that needs to
187 * reference the constants, else PHP 3.0.16 won't be happy.
189 require_once('./libraries/defines.lib.php');
191 /* Input sanitizing */
192 require_once('./libraries/sanitizing.lib.php');
194 // XSS
195 if (isset($convcharset)) {
196 $convcharset = PMA_sanitize($convcharset);
199 if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) {
201 * Define $is_upload
204 $is_upload = TRUE;
205 if (strtolower(@ini_get('file_uploads')) == 'off'
206 || @ini_get('file_uploads') == 0) {
207 $is_upload = FALSE;
211 * Maximum upload size as limited by PHP
212 * Used with permission from Moodle (http://moodle.org) by Martin Dougiamas
214 * this section generates $max_upload_size in bytes
217 function get_real_size($size=0) {
218 /// Converts numbers like 10M into bytes
219 if (!$size) {
220 return 0;
222 $scan['MB'] = 1048576;
223 $scan['Mb'] = 1048576;
224 $scan['M'] = 1048576;
225 $scan['m'] = 1048576;
226 $scan['KB'] = 1024;
227 $scan['Kb'] = 1024;
228 $scan['K'] = 1024;
229 $scan['k'] = 1024;
231 while (list($key) = each($scan)) {
232 if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
233 $size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
234 break;
237 return $size;
238 } // end function
241 if (!$filesize = ini_get('upload_max_filesize')) {
242 $filesize = "5M";
244 $max_upload_size = get_real_size($filesize);
246 if ($postsize = ini_get('post_max_size')) {
247 $postsize = get_real_size($postsize);
248 if ($postsize < $max_upload_size) {
249 $max_upload_size = $postsize;
252 unset($filesize);
253 unset($postsize);
256 * other functions for maximum upload work
260 * Displays the maximum size for an upload
262 * @param integer the size
264 * @return string the message
266 * @access public
268 function PMA_displayMaximumUploadSize($max_upload_size) {
269 list($max_size, $max_unit) = PMA_formatByteDown($max_upload_size);
270 return '(' . sprintf($GLOBALS['strMaximumSize'], $max_size, $max_unit) . ')';
274 * Generates a hidden field which should indicate to the browser
275 * the maximum size for upload
277 * @param integer the size
279 * @return string the INPUT field
281 * @access public
283 function PMA_generateHiddenMaxFileSize($max_size){
284 return '<input type="hidden" name="MAX_FILE_SIZE" value="' .$max_size . '" />';
288 * Charset conversion.
290 require_once('./libraries/charset_conversion.lib.php');
293 * String handling
295 require_once('./libraries/string.lib.php');
299 * Removes insecure parts in a path; used before include() or
300 * require() when a part of the path comes from an insecure source
301 * like a cookie or form.
303 * @param string The path to check
305 * @return string The secured path
307 * @access public
308 * @author Marc Delisle (lem9@users.sourceforge.net)
310 function PMA_securePath($path) {
312 // change .. to .
313 $path = preg_replace('@\.\.*@','.',$path);
315 return $path;
316 } // end function
318 // If zlib output compression is set in the php configuration file, no
319 // output buffering should be run
320 if (@ini_get('zlib.output_compression')) {
321 $cfg['OBGzip'] = FALSE;
324 // disable output-buffering (if set to 'auto') for IE6, else enable it.
325 if (strtolower($cfg['OBGzip']) == 'auto') {
326 if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER >= 6 && PMA_USR_BROWSER_VER < 7) {
327 $cfg['OBGzip'] = FALSE;
328 } else {
329 $cfg['OBGzip'] = TRUE;
334 /* Theme Manager
335 * 2004-05-20 Michael Keck (mail_at_michaelkeck_dot_de)
336 * This little script checks if there're themes available
337 * and if the directory $ThemePath/$theme/img/ exists
338 * If not, it will use default images
340 // Allow different theme per server
341 $theme_cookie_name = 'pma_theme';
342 if ($GLOBALS['cfg']['ThemePerServer'] && isset($server)) {
343 $theme_cookie_name .= '-' . $server;
345 //echo $theme_cookie_name;
346 // Theme Manager
347 if (!$cfg['ThemeManager'] || !isset($_COOKIE[$theme_cookie_name]) || empty($_COOKIE[$theme_cookie_name])){
348 $GLOBALS['theme'] = $cfg['ThemeDefault'];
349 $ThemeDefaultOk = FALSE;
350 if ($cfg['ThemePath']!='' && $cfg['ThemePath'] != FALSE) {
351 $tmp_theme_mainpath = $cfg['ThemePath'];
352 $tmp_theme_fullpath = $cfg['ThemePath'] . '/' .$cfg['ThemeDefault'];
353 if (@is_dir($tmp_theme_mainpath)) {
354 if (isset($cfg['ThemeDefault']) && @is_dir($tmp_theme_fullpath)) {
355 $ThemeDefaultOk = TRUE;
359 if ($ThemeDefaultOk == TRUE){
360 $GLOBALS['theme'] = $cfg['ThemeDefault'];
361 } else {
362 $GLOBALS['theme'] = 'original';
364 } else {
365 // if we just changed theme, we must take the new one so that
366 // index.php takes the correct one for height computing
367 if (isset($_POST['set_theme'])) {
368 $GLOBALS['theme'] = PMA_securePath($_POST['set_theme']);
369 } else {
370 $GLOBALS['theme'] = PMA_securePath($_COOKIE[$theme_cookie_name]);
374 // check for theme requires/name
375 unset($theme_name, $theme_generation, $theme_version);
376 @include($cfg['ThemePath'] . '/' . $GLOBALS['theme'] . '/info.inc.php');
378 // did it set correctly?
379 if (!isset($theme_name, $theme_generation, $theme_version)) {
380 $GLOBALS['theme'] = 'original'; // invalid theme
381 } elseif ($theme_generation != PMA_THEME_GENERATION) {
382 $GLOBALS['theme'] = 'original'; // different generation
383 } elseif ($theme_version < PMA_THEME_VERSION) {
384 $GLOBALS['theme'] = 'original'; // too old version
387 $pmaThemeImage = $cfg['ThemePath'] . '/' . $GLOBALS['theme'] . '/img/';
388 $tmp_layout_file = $cfg['ThemePath'] . '/' . $GLOBALS['theme'] . '/layout.inc.php';
389 if (@file_exists($tmp_layout_file)) {
390 include($tmp_layout_file);
392 unset( $tmp_layout_file );
393 if (!is_dir($pmaThemeImage)) {
394 $pmaThemeImage = $cfg['ThemePath'] . '/original/img/';
396 // end theme manager
399 * collation_connection
401 // (could be improved by executing it after the MySQL connection only if
402 // PMA_MYSQL_INT_VERSION >= 40100 )
403 if (isset($_COOKIE) && !empty($_COOKIE['pma_collation_connection']) && empty($_POST['collation_connection'])) {
404 $collation_connection = $_COOKIE['pma_collation_connection'];
408 if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) {
410 * Include URL/hidden inputs generating.
412 require_once('./libraries/url_generating.lib.php');
415 * Add slashes before "'" and "\" characters so a value containing them can
416 * be used in a sql comparison.
418 * @param string the string to slash
419 * @param boolean whether the string will be used in a 'LIKE' clause
420 * (it then requires two more escaped sequences) or not
421 * @param boolean whether to treat cr/lfs as escape-worthy entities
422 * (converts \n to \\n, \r to \\r)
424 * @param boolean whether this function is used as part of the
425 * "Create PHP code" dialog
427 * @return string the slashed string
429 * @access public
431 function PMA_sqlAddslashes($a_string = '', $is_like = FALSE, $crlf = FALSE, $php_code = FALSE)
433 if ($is_like) {
434 $a_string = str_replace('\\', '\\\\\\\\', $a_string);
435 } else {
436 $a_string = str_replace('\\', '\\\\', $a_string);
439 if ($crlf) {
440 $a_string = str_replace("\n", '\n', $a_string);
441 $a_string = str_replace("\r", '\r', $a_string);
442 $a_string = str_replace("\t", '\t', $a_string);
445 if ($php_code) {
446 $a_string = str_replace('\'', '\\\'', $a_string);
447 } else {
448 $a_string = str_replace('\'', '\'\'', $a_string);
451 return $a_string;
452 } // end of the 'PMA_sqlAddslashes()' function
456 * Add slashes before "_" and "%" characters for using them in MySQL
457 * database, table and field names.
458 * Note: This function does not escape backslashes!
460 * @param string the string to escape
462 * @return string the escaped string
464 * @access public
466 function PMA_escape_mysql_wildcards($name)
468 $name = str_replace('_', '\\_', $name);
469 $name = str_replace('%', '\\%', $name);
471 return $name;
472 } // end of the 'PMA_escape_mysql_wildcards()' function
475 * removes slashes before "_" and "%" characters
476 * Note: This function does not unescape backslashes!
478 * @param string $name the string to escape
479 * @return string the escaped string
480 * @access public
482 function PMA_unescape_mysql_wildcards( $name )
484 $name = str_replace('\\_', '_', $name);
485 $name = str_replace('\\%', '%', $name);
487 return $name;
488 } // end of the 'PMA_unescape_mysql_wildcards()' function
491 * format sql strings
493 * @param mixed pre-parsed SQL structure
495 * @return string the formatted sql
497 * @global array the configuration array
498 * @global boolean whether the current statement is a multiple one or not
500 * @access public
502 * @author Robin Johnson <robbat2@users.sourceforge.net>
504 function PMA_formatSql($parsed_sql, $unparsed_sql = '')
506 global $cfg;
508 // Check that we actually have a valid set of parsed data
509 // well, not quite
510 // first check for the SQL parser having hit an error
511 if (PMA_SQP_isError()) {
512 return $parsed_sql;
514 // then check for an array
515 if (!is_array($parsed_sql)) {
516 // We don't so just return the input directly
517 // This is intended to be used for when the SQL Parser is turned off
518 $formatted_sql = '<pre>' . "\n"
519 . (($cfg['SQP']['fmtType'] == 'none' && $unparsed_sql != '') ? $unparsed_sql : $parsed_sql) . "\n"
520 . '</pre>';
521 return $formatted_sql;
524 $formatted_sql = '';
526 switch ($cfg['SQP']['fmtType']) {
527 case 'none':
528 if ($unparsed_sql != '') {
529 $formatted_sql = "<pre>\n" . PMA_SQP_formatNone(array('raw' => $unparsed_sql)) . "\n</pre>";
530 } else {
531 $formatted_sql = PMA_SQP_formatNone($parsed_sql);
533 break;
534 case 'html':
535 $formatted_sql = PMA_SQP_formatHtml($parsed_sql,'color');
536 break;
537 case 'text':
538 //$formatted_sql = PMA_SQP_formatText($parsed_sql);
539 $formatted_sql = PMA_SQP_formatHtml($parsed_sql,'text');
540 break;
541 default:
542 break;
543 } // end switch
545 return $formatted_sql;
546 } // end of the "PMA_formatSql()" function
550 * Displays a link to the official MySQL documentation
552 * @param string chapter of "HTML, one page per chapter" documentation
553 * @param string contains name of page/anchor that is being linked
554 * @param bool whether to use big icon (like in left frame)
556 * @return string the html link
558 * @access public
560 function PMA_showMySQLDocu($chapter, $link, $big_icon = FALSE)
562 global $cfg;
564 if ($cfg['MySQLManualType'] == 'none' || empty($cfg['MySQLManualBase'])) return '';
566 // Fixup for newly used names:
567 $chapter = str_replace('_', '-', strtolower($chapter));
568 $link = str_replace('_', '-', strtolower($link));
570 switch ($cfg['MySQLManualType']) {
571 case 'chapters':
572 if (empty($chapter)) $chapter = 'index';
573 $url = $cfg['MySQLManualBase'] . '/' . $chapter . '.html#' . $link;
574 break;
575 case 'big':
576 $url = $cfg['MySQLManualBase'] . '#' . $link;
577 break;
578 case 'searchable':
579 if (empty($link)) $link = 'index';
580 $url = $cfg['MySQLManualBase'] . '/' . $link . '.html';
581 break;
582 case 'viewable':
583 default:
584 if (empty($link)) $link = 'index';
585 $mysql = '4.1';
586 if ( ! defined( 'PMA_MYSQL_INT_VERSION' )
587 || PMA_MYSQL_INT_VERSION < 50000 ) {
588 $mysql = '4.1';
589 } elseif (PMA_MYSQL_INT_VERSION >= 50100) {
590 $mysql = '5.1';
591 } elseif (PMA_MYSQL_INT_VERSION >= 50000) {
592 $mysql = '5.0';
594 $url = $cfg['MySQLManualBase'] . '/' . $mysql . '/en/' . $link . '.html';
595 break;
598 if ($big_icon) {
599 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>';
600 } elseif ($GLOBALS['cfg']['ReplaceHelpImg']) {
601 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>';
602 }else{
603 return '[<a href="' . $url . '" target="mysql_doc">' . $GLOBALS['strDocu'] . '</a>]';
605 } // end of the 'PMA_showMySQLDocu()' function
608 * Displays a hint icon, on mouse over show the hint
610 * @param string the error message
612 * @access public
614 function PMA_showHint($hint_message)
616 //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) . '\');" />';
617 return '<img class="lightbulb" src="' . $GLOBALS['pmaThemeImage'] . 'b_tipp.png" width="16" height="16" alt="Tip" title="Tip" onmouseover="pmaTooltip(\'' . PMA_jsFormat($hint_message, FALSE) . '\'); return false;" onmouseout="swapTooltip(\'default\'); return false;" />';
621 * Displays a MySQL error message in the right frame.
623 * @param string the error message
624 * @param string the sql query that failed
625 * @param boolean whether to show a "modify" link or not
626 * @param string the "back" link url (full path is not required)
627 * @param boolean EXIT the page?
629 * @global array the configuration array
631 * @access public
633 function PMA_mysqlDie($error_message = '', $the_query = '',
634 $is_modify_link = TRUE, $back_url = '',
635 $exit = TRUE)
637 global $cfg, $table, $db, $sql_query;
639 require_once('./header.inc.php');
641 if (!$error_message) {
642 $error_message = PMA_DBI_getError();
644 if (!$the_query && !empty($GLOBALS['sql_query'])) {
645 $the_query = $GLOBALS['sql_query'];
648 // --- Added to solve bug #641765
649 // Robbat2 - 12 January 2003, 9:46PM
650 // Revised, Robbat2 - 13 January 2003, 2:59PM
651 if (!function_exists('PMA_SQP_isError') || PMA_SQP_isError()) {
652 $formatted_sql = htmlspecialchars($the_query);
653 } elseif (empty($the_query) || trim($the_query) == '') {
654 $formatted_sql = '';
655 } else {
656 $formatted_sql = PMA_formatSql(PMA_SQP_parse($the_query), $the_query);
658 // ---
659 echo "\n" . '<!-- PMA-SQL-ERROR -->' . "\n";
660 echo ' <div class="error"><h1>' . $GLOBALS['strError'] . '</h1>' . "\n";
661 // if the config password is wrong, or the MySQL server does not
662 // respond, do not show the query that would reveal the
663 // username/password
664 if (!empty($the_query) && !strstr($the_query, 'connect')) {
665 // --- Added to solve bug #641765
666 // Robbat2 - 12 January 2003, 9:46PM
667 // Revised, Robbat2 - 13 January 2003, 2:59PM
668 if (function_exists('PMA_SQP_isError') && PMA_SQP_isError()) {
669 echo PMA_SQP_getErrorString() . "\n";
670 echo '<br />' . "\n";
672 // ---
673 // modified to show me the help on sql errors (Michael Keck)
674 echo ' <p><strong>' . $GLOBALS['strSQLQuery'] . ':</strong>' . "\n";
675 if (strstr(strtolower($formatted_sql),'select')) { // please show me help to the error on select
676 echo PMA_showMySQLDocu('SQL-Syntax', 'SELECT');
678 if ($is_modify_link && isset($db)) {
679 if (isset($table)) {
680 $doedit_goto = '<a href="tbl_properties.php?' . PMA_generate_common_url($db, $table) . '&amp;sql_query=' . urlencode($the_query) . '&amp;show_query=1">';
681 } else {
682 $doedit_goto = '<a href="db_details.php?' . PMA_generate_common_url($db) . '&amp;sql_query=' . urlencode($the_query) . '&amp;show_query=1">';
684 if ($GLOBALS['cfg']['PropertiesIconic']) {
685 echo $doedit_goto
686 . '<img class="icon" src=" '. $GLOBALS['pmaThemeImage'] . 'b_edit.png" width="16" height="16" alt="' . $GLOBALS['strEdit'] .'" />'
687 . '</a>';
688 } else {
689 echo ' ['
690 . $doedit_goto . $GLOBALS['strEdit'] . '</a>'
691 . ']' . "\n";
693 } // end if
694 echo ' </p>' . "\n"
695 .' <p>' . "\n"
696 .' ' . $formatted_sql . "\n"
697 .' </p>' . "\n";
698 } // end if
700 $tmp_mysql_error = ''; // for saving the original $error_message
701 if (!empty($error_message)) {
702 $tmp_mysql_error = strtolower($error_message); // save the original $error_message
703 $error_message = htmlspecialchars($error_message);
704 $error_message = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $error_message);
706 // modified to show me the help on error-returns (Michael Keck)
707 echo '<p>' . "\n"
708 . ' <strong>' . $GLOBALS['strMySQLSaid'] . '</strong>'
709 . PMA_showMySQLDocu('Error-returns', 'Error-returns')
710 . "\n"
711 . '</p>' . "\n";
713 // The error message will be displayed within a CODE segment.
714 // To preserve original formatting, but allow wordwrapping, we do a couple of replacements
716 // Replace all non-single blanks with their HTML-counterpart
717 $error_message = str_replace(' ', '&nbsp;&nbsp;', $error_message);
718 // Replace TAB-characters with their HTML-counterpart
719 $error_message = str_replace("\t", '&nbsp;&nbsp;&nbsp;&nbsp;', $error_message);
720 // Replace linebreaks
721 $error_message = nl2br($error_message);
723 echo '<code>' . "\n"
724 . $error_message . "\n"
725 . '</code><br />' . "\n";
727 // feature request #1036254:
728 // Add a link by MySQL-Error #1062 - Duplicate entry
729 // 2004-10-20 by mkkeck
730 // 2005-01-17 modified by mkkeck bugfix
731 if (substr($error_message, 1, 4) == '1062') {
732 // get the duplicate entry
734 // get table name
735 preg_match( '°ALTER\sTABLE\s\`([^\`]+)\`°iu', $the_query, $error_table = array() );
736 $error_table = $error_table[1];
738 // get fields
739 preg_match( '°\(([^\)]+)\)°i', $the_query, $error_fields = array() );
740 $error_fields = explode( ',', $error_fields[1] );
742 // duplicate value
743 preg_match( '°\'([^\']+)\'°i', $tmp_mysql_error, $duplicate_value = array() );
744 $duplicate_value = $duplicate_value[1];
746 $sql = '
747 SELECT *
748 FROM ' . PMA_backquote( $error_table ) . '
749 WHERE CONCAT_WS( "-", ' . implode( ', ', $error_fields ) . ' )
750 = "' . PMA_sqlAddslashes( $duplicate_value ) . '"
751 ORDER BY ' . implode( ', ', $error_fields );
752 unset( $error_table, $error_fields, $duplicate_value );
754 echo ' <form method="post" action="import.php" style="padding: 0; margin: 0">' ."\n"
755 .' <input type="hidden" name="sql_query" value="' . htmlentities( $sql ) . '" />' . "\n"
756 .' ' . PMA_generate_common_hidden_inputs($db, $table) . "\n"
757 .' <input type="submit" name="submit" value="' . $GLOBALS['strBrowse'] . '" />' . "\n"
758 .' </form>' . "\n";
759 unset( $sql );
760 } // end of show duplicate entry
762 echo '</div>';
763 echo '<fieldset class="tblFooters">';
765 if (!empty($back_url) && $exit) {
766 $goto_back_url='<a href="' . (strstr($back_url, '?') ? $back_url . '&amp;no_history=true' : $back_url . '?no_history=true') . '">';
767 echo '[ ' . $goto_back_url . $GLOBALS['strBack'] . '</a> ]';
769 echo ' </fieldset>' . "\n\n";
770 if ($exit) {
771 require_once('./footer.inc.php');
773 } // end of the 'PMA_mysqlDie()' function
777 * Defines whether a string exists inside an array or not
779 * @param string string to search for
780 * @param mixed array to search into
782 * @return integer the rank of the $toFind string in the array or '-1' if
783 * it hasn't been found
785 * @access public
787 function PMA_isInto($toFind = '', &$in)
789 $max = count($in);
790 for ($i = 0; $i < $max && ($toFind != $in[$i]); $i++) {
791 // void();
794 return ($i < $max) ? $i : -1;
795 } // end of the 'PMA_isInto()' function
799 * Returns a string formatted with CONVERT ... USING
800 * if MySQL supports it
802 * @param string the string itself
803 * @param string the mode: quoted or unquoted (this one by default)
805 * @return the formatted string
807 * @access private
809 function PMA_convert_using($string, $mode='unquoted') {
811 if ($mode == 'quoted') {
812 $possible_quote = "'";
813 } else {
814 $possible_quote = "";
817 if (PMA_MYSQL_INT_VERSION >= 40100) {
818 list($conn_charset) = explode('_', $GLOBALS['collation_connection']);
819 $converted_string = "CONVERT(" . $possible_quote . $string . $possible_quote . " USING " . $conn_charset . ")";
820 } else {
821 $converted_string = $possible_quote . $string . $possible_quote;
823 return $converted_string;
824 } // end function
829 * returns array with dbs grouped with extended infos
831 * @uses $GLOBALS['dblist'] from PMA_availableDatabases()
832 * @uses $GLOBALS['num_dbs'] from PMA_availableDatabases()
833 * @uses $GLOBALS['cfgRelation']['commwork']
834 * @uses $GLOBALS['cfg']['ShowTooltip']
835 * @uses $GLOBALS['cfg']['LeftFrameDBTree']
836 * @uses $GLOBALS['cfg']['LeftFrameDBSeparator']
837 * @uses $GLOBALS['cfg']['ShowTooltipAliasDB']
838 * @uses PMA_availableDatabases()
839 * @uses PMA_getTableCount()
840 * @uses PMA_getComments()
841 * @uses PMA_availableDatabases()
842 * @uses is_array()
843 * @uses implode()
844 * @uses strstr()
845 * @uses explode()
846 * @return array db list
848 function PMA_getDbList() {
849 if ( empty( $GLOBALS['dblist'] ) ) {
850 PMA_availableDatabases();
852 $dblist = $GLOBALS['dblist'];
853 $dbgroups = array();
854 $parts = array();
855 foreach ( $dblist as $key => $db ) {
856 // garvin: Get comments from PMA comments table
857 $db_tooltip = '';
858 if ( $GLOBALS['cfg']['ShowTooltip']
859 && $GLOBALS['cfgRelation']['commwork'] ) {
860 $_db_tooltip = PMA_getComments( $db );
861 if ( is_array( $_db_tooltip ) ) {
862 $db_tooltip = implode( ' ', $_db_tooltip );
866 if ( $GLOBALS['cfg']['LeftFrameDBTree']
867 && $GLOBALS['cfg']['LeftFrameDBSeparator']
868 && strstr( $db, $GLOBALS['cfg']['LeftFrameDBSeparator'] ) )
870 $pos = strrpos($db, $GLOBALS['cfg']['LeftFrameDBSeparator']);
871 $group = substr($db, 0, $pos);
872 $disp_name_cut = substr($db, $pos);
873 } else {
874 $group = $db;
875 $disp_name_cut = $db;
878 $disp_name = $db;
879 if ( $db_tooltip && $GLOBALS['cfg']['ShowTooltipAliasDB'] ) {
880 $disp_name = $db_tooltip;
881 $disp_name_cut = $db_tooltip;
882 $db_tooltip = $db;
885 $dbgroups[$group][$db] = array(
886 'name' => $db,
887 'disp_name_cut' => $disp_name_cut,
888 'disp_name' => $disp_name,
889 'comment' => $db_tooltip,
890 'num_tables' => PMA_getTableCount( $db ),
892 } // end foreach ( $dblist as $db )
893 return $dbgroups;
897 * returns html code for select form element with dbs
899 * @return string html code select
901 function PMA_getHtmlSelectDb( $selected = '' ) {
902 $dblist = PMA_getDbList();
903 // TODO: IE can not handle different text directions in select boxes
904 // so, as mostly names will be in english, we set the whole selectbox to LTR
905 // and EN
906 $return = '<select name="db" id="lightm_db" xml:lang="en" dir="ltr"'
907 .' onchange="window.parent.openDb( this.value );">' . "\n"
908 .'<option value="" dir="' . $GLOBALS['text_dir'] . '">(' . $GLOBALS['strDatabases'] . ') ...</option>'
909 ."\n";
910 foreach( $dblist as $group => $dbs ) {
911 if ( count( $dbs ) > 1 ) {
912 $return .= '<optgroup label="' . htmlspecialchars( $group )
913 . '">' . "\n";
914 // wether display db_name cuted by the group part
915 $cut = true;
916 } else {
917 // .. or full
918 $cut = false;
920 foreach( $dbs as $db ) {
921 $return .= '<option value="' . $db['name'] . '"'
922 .' title="' . $db['comment'] . '"';
923 if ( $db['name'] == $selected ) {
924 $return .= ' selected="selected"';
926 $return .= '>' . ( $cut ? $db['disp_name_cut'] : $db['disp_name'] )
927 .' (' . $db['num_tables'] . ')</option>' . "\n";
929 if ( count( $dbs ) > 1 ) {
930 $return .= '</optgroup>' . "\n";
933 $return .= '</select>';
935 return $return;
939 * returns count of tables in given db
941 * @param string $db database to count tables for
942 * @return integer count of tables in $db
944 function PMA_getTableCount( $db ) {
945 $tables = PMA_DBI_try_query(
946 'SHOW TABLES FROM ' . PMA_backquote( $db ) . ';',
947 NULL, PMA_DBI_QUERY_STORE);
948 if ( $tables ) {
949 $num_tables = PMA_DBI_num_rows( $tables );
950 PMA_DBI_free_result( $tables );
951 } else {
952 $num_tables = 0;
955 return $num_tables;
960 * Get the complete list of Databases a user can access
962 * @param boolean whether to include check on failed 'only_db' operations
963 * @param resource database handle (superuser)
964 * @param integer amount of databases inside the 'only_db' container
965 * @param resource possible resource from a failed previous query
966 * @param resource database handle (user)
967 * @param array configuration
968 * @param array previous list of databases
970 * @return array all databases a user has access to
972 * @access private
974 function PMA_safe_db_list($only_db_check, $dbh, $dblist_cnt, $rs, $userlink, $cfg, $dblist) {
975 if ($only_db_check == FALSE) {
976 // try to get the available dbs list
977 // use userlink by default
978 $dblist = PMA_DBI_get_dblist();
979 $dblist_cnt = count($dblist);
981 // did not work so check for available databases in the "mysql" db;
982 // I don't think we can fall here now...
983 if (!$dblist_cnt) {
984 $auth_query = 'SELECT User, Select_priv '
985 . 'FROM mysql.user '
986 . 'WHERE User = \'' . PMA_sqlAddslashes($cfg['Server']['user']) . '\'';
987 $rs = PMA_DBI_try_query($auth_query, $dbh);
988 } // end
991 // Access to "mysql" db allowed and dblist still empty -> gets the
992 // usable db list
993 if (!$dblist_cnt
994 && ($rs && @PMA_DBI_num_rows($rs))) {
995 $row = PMA_DBI_fetch_assoc($rs);
996 PMA_DBI_free_result($rs);
997 // Correction uva 19991215
998 // Previous code assumed database "mysql" admin table "db" column
999 // "db" contains literal name of user database, and works if so.
1000 // Mysql usage generally (and uva usage specifically) allows this
1001 // column to contain regular expressions (we have all databases
1002 // owned by a given student/faculty/staff beginning with user i.d.
1003 // and governed by default by a single set of privileges with
1004 // regular expression as key). This breaks previous code.
1005 // This maintenance is to fix code to work correctly for regular
1006 // expressions.
1007 if ($row['Select_priv'] != 'Y') {
1009 // 1. get allowed dbs from the "mysql.db" table
1010 // lem9: User can be blank (anonymous user)
1011 $local_query = 'SELECT DISTINCT Db FROM mysql.db WHERE Select_priv = \'Y\' AND (User = \'' . PMA_sqlAddslashes($cfg['Server']['user']) . '\' OR User = \'\')';
1012 $rs = PMA_DBI_try_query($local_query, $dbh);
1013 if ($rs && @PMA_DBI_num_rows($rs)) {
1014 // Will use as associative array of the following 2 code
1015 // lines:
1016 // the 1st is the only line intact from before
1017 // correction,
1018 // the 2nd replaces $dblist[] = $row['Db'];
1019 $uva_mydbs = array();
1020 // Code following those 2 lines in correction continues
1021 // populating $dblist[], as previous code did. But it is
1022 // now populated with actual database names instead of
1023 // with regular expressions.
1024 while ($row = PMA_DBI_fetch_assoc($rs)) {
1025 // loic1: all databases cases - part 1
1026 if (empty($row['Db']) || $row['Db'] == '%') {
1027 $uva_mydbs['%'] = 1;
1028 break;
1030 // loic1: avoid multiple entries for dbs
1031 if (!isset($uva_mydbs[$row['Db']])) {
1032 $uva_mydbs[$row['Db']] = 1;
1034 } // end while
1035 PMA_DBI_free_result($rs);
1036 $uva_alldbs = PMA_DBI_query('SHOW DATABASES;', $GLOBALS['dbh']);
1037 // loic1: all databases cases - part 2
1038 if (isset($uva_mydbs['%'])) {
1039 while ($uva_row = PMA_DBI_fetch_row($uva_alldbs)) {
1040 $dblist[] = $uva_row[0];
1041 } // end while
1042 } // end if
1043 else {
1044 while ($uva_row = PMA_DBI_fetch_row($uva_alldbs)) {
1045 $uva_db = $uva_row[0];
1046 if (isset($uva_mydbs[$uva_db]) && $uva_mydbs[$uva_db] == 1) {
1047 $dblist[] = $uva_db;
1048 $uva_mydbs[$uva_db] = 0;
1049 } else if (!isset($dblist[$uva_db])) {
1050 foreach ($uva_mydbs AS $uva_matchpattern => $uva_value) {
1051 // loic1: fixed bad regexp
1052 // TODO: db names may contain characters
1053 // that are regexp instructions
1054 $re = '(^|(\\\\\\\\)+|[^\])';
1055 $uva_regex = ereg_replace($re . '%', '\\1.*', ereg_replace($re . '_', '\\1.{1}', $uva_matchpattern));
1056 // Fixed db name matching
1057 // 2000-08-28 -- Benjamin Gandon
1058 if (ereg('^' . $uva_regex . '$', $uva_db)) {
1059 $dblist[] = $uva_db;
1060 break;
1062 } // end while
1063 } // end if ... else if....
1064 } // end while
1065 } // end else
1066 PMA_DBI_free_result($uva_alldbs);
1067 unset($uva_mydbs);
1068 } // end if
1070 // 2. get allowed dbs from the "mysql.tables_priv" table
1071 $local_query = 'SELECT DISTINCT Db FROM mysql.tables_priv WHERE Table_priv LIKE \'%Select%\' AND User = \'' . PMA_sqlAddslashes($cfg['Server']['user']) . '\'';
1072 $rs = PMA_DBI_try_query($local_query, $dbh);
1073 if ($rs && @PMA_DBI_num_rows($rs)) {
1074 while ($row = PMA_DBI_fetch_assoc($rs)) {
1075 if (PMA_isInto($row['Db'], $dblist) == -1) {
1076 $dblist[] = $row['Db'];
1078 } // end while
1079 PMA_DBI_free_result($rs);
1080 } // end if
1081 } // end if
1082 } // end building available dbs from the "mysql" db
1084 return $dblist;
1088 * Determines the font sizes to use depending on the os and browser of the
1089 * user.
1091 * This function is based on an article from phpBuilder (see
1092 * http://www.phpbuilder.net/columns/tim20000821.php).
1094 * @return boolean always true
1096 * @global string the standard font size
1097 * @global string the font size for titles
1098 * @global string the small font size
1099 * @global string the smallest font size
1101 * @access public
1103 * @version 1.1
1105 function PMA_setFontSizes()
1107 global $font_size, $font_biggest, $font_bigger, $font_smaller, $font_smallest;
1109 // IE (<7)/Opera (<7) for win case: needs smaller fonts than anyone else
1110 if (PMA_USR_OS == 'Win'
1111 && ((PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 7)
1112 || (PMA_USR_BROWSER_AGENT == 'OPERA' && PMA_USR_BROWSER_VER < 7))) {
1113 $font_size = 'x-small';
1114 $font_biggest = 'large';
1115 $font_bigger = 'medium';
1116 $font_smaller = '90%';
1117 $font_smallest = '7pt';
1119 // IE6 and other browsers for win case
1120 else if (PMA_USR_OS == 'Win') {
1121 $font_size = 'small';
1122 $font_biggest = 'large';
1123 $font_bigger = 'medium';
1124 $font_smaller = (PMA_USR_BROWSER_AGENT == 'IE')
1125 ? '90%'
1126 : 'x-small';
1127 $font_smallest = 'x-small';
1129 // Some mac browsers need also smaller default fonts size (OmniWeb &
1130 // Opera)...
1131 // and a beta version of Safari did also, but not the final 1.0 version
1132 // so I remove || PMA_USR_BROWSER_AGENT == 'SAFARI'
1133 // but we got a report that Safari 1.0 build 85.5 needs it!
1135 else if (PMA_USR_OS == 'Mac'
1136 && (PMA_USR_BROWSER_AGENT == 'OMNIWEB' || PMA_USR_BROWSER_AGENT == 'OPERA' || PMA_USR_BROWSER_AGENT == 'SAFARI')) {
1137 $font_size = 'x-small';
1138 $font_biggest = 'large';
1139 $font_bigger = 'medium';
1140 $font_smaller = '90%';
1141 $font_smallest = '7pt';
1143 // ... but most of them (except IE 5+ & NS 6+) need bigger fonts
1144 else if ((PMA_USR_OS == 'Mac'
1145 && ((PMA_USR_BROWSER_AGENT != 'IE' && PMA_USR_BROWSER_AGENT != 'MOZILLA')
1146 || PMA_USR_BROWSER_VER < 5))
1147 || PMA_USR_BROWSER_AGENT == 'KONQUEROR'
1148 || PMA_USR_BROWSER_AGENT == 'MOZILLA') {
1149 $font_size = 'medium';
1150 $font_biggest = 'x-large';
1151 $font_bigger = 'large';
1152 $font_smaller = 'small';
1153 $font_smallest = 'x-small';
1155 // OS/2 browser
1156 else if (PMA_USR_OS == 'OS/2'
1157 && PMA_USR_BROWSER_AGENT == 'OPERA') {
1158 $font_size = 'small';
1159 $font_biggest = 'medium';
1160 $font_bigger = 'medium';
1161 $font_smaller = 'x-small';
1162 $font_smallest = 'x-small';
1164 else {
1165 $font_size = 'small';
1166 $font_biggest = 'large';
1167 $font_bigger = 'medium';
1168 $font_smaller = 'x-small';
1169 $font_smallest = 'x-small';
1172 return TRUE;
1173 } // end of the 'PMA_setFontSizes()' function
1176 if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) {
1178 * $cfg['PmaAbsoluteUri'] is a required directive else cookies won't be
1179 * set properly and, depending on browsers, inserting or updating a
1180 * record might fail
1183 // Setup a default value to let the people and lazy syadmins work anyway,
1184 // they'll get an error if the autodetect code doesn't work
1185 if (empty($cfg['PmaAbsoluteUri'])) {
1187 $url = array();
1189 // At first we try to parse REQUEST_URI, it might contain full URI
1190 if (!empty($_SERVER['REQUEST_URI'])) {
1191 $url = parse_url($_SERVER['REQUEST_URI']);
1194 // If we don't have scheme, we didn't have full URL so we need to dig deeper
1195 if (empty($url['scheme'])) {
1196 // Scheme
1197 if (!empty($_SERVER['HTTP_SCHEME'])) {
1198 $url['scheme'] = $_SERVER['HTTP_SCHEME'];
1199 } else {
1200 $url['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http';
1203 // Host and port
1204 if (!empty($_SERVER['HTTP_HOST'])) {
1205 if (strpos($_SERVER['HTTP_HOST'], ':') > 0) {
1206 list($url['host'], $url['port']) = explode(':', $_SERVER['HTTP_HOST']);
1207 } else {
1208 $url['host'] = $_SERVER['HTTP_HOST'];
1210 } else if (!empty($_SERVER['SERVER_NAME'])) {
1211 $url['host'] = $_SERVER['SERVER_NAME'];
1212 } else {
1213 // Displays the error message
1214 header( 'Location: error.php'
1215 . '?lang=' . urlencode( $available_languages[$lang][2] )
1216 . '&char=' . urlencode( $charset )
1217 . '&dir=' . urlencode( $text_dir )
1218 . '&type=' . urlencode( $strError )
1219 . '&error=' . urlencode(
1220 strtr( $strPmaUriError,
1221 array( '<tt>' => '[tt]', '</tt>' => '[/tt]' ) ) )
1222 . '&' . SID
1224 exit();
1227 // If we didn't set port yet...
1228 if (empty($url['port']) && !empty($_SERVER['SERVER_PORT'])) {
1229 $url['port'] = $_SERVER['SERVER_PORT'];
1232 // And finally the path could be already set from REQUEST_URI
1233 if (empty($url['path'])) {
1234 if (!empty($_SERVER['PATH_INFO'])) {
1235 $path = parse_url($_SERVER['PATH_INFO']);
1236 } else {
1237 // PHP_SELF in CGI often points to cgi executable, so use it as last choice
1238 $path = parse_url($_SERVER['PHP_SELF']);
1240 $url['path'] = $path['path'];
1241 unset($path);
1245 // Make url from parts we have
1246 $cfg['PmaAbsoluteUri'] = $url['scheme'] . '://';
1247 // Was there user information?
1248 if (!empty($url['user'])) {
1249 $cfg['PmaAbsoluteUri'] .= $url['user'];
1250 if (!empty($url['pass'])) {
1251 $cfg['PmaAbsoluteUri'] .= ':' . $url['pass'];
1253 $cfg['PmaAbsoluteUri'] .= '@';
1255 // Add hostname
1256 $cfg['PmaAbsoluteUri'] .= $url['host'];
1257 // Add port, if it not the default one
1258 if (!empty($url['port']) && (($url['scheme'] == 'http' && $url['port'] != 80) || ($url['scheme'] == 'https' && $url['port'] != 443))) {
1259 $cfg['PmaAbsoluteUri'] .= ':' . $url['port'];
1261 // And finally path, without script name, the 'a' is there not to
1262 // strip our directory, when path is only /pmadir/ without filename
1263 $path = dirname($url['path'] . 'a');
1264 // To work correctly within transformations overview:
1265 if (defined('PMA_PATH_TO_BASEDIR') && PMA_PATH_TO_BASEDIR == '../../') {
1266 $path = dirname(dirname($path));
1268 $cfg['PmaAbsoluteUri'] .= $path . '/';
1270 unset($url);
1272 // We used to display a warning if PmaAbsoluteUri wasn't set, but now
1273 // the autodetect code works well enough that we don't display the
1274 // warning at all. The user can still set PmaAbsoluteUri manually.
1275 // See https://sourceforge.net/tracker/index.php?func=detail&aid=1257134&group_id=23067&atid=377411
1277 } else {
1278 // The URI is specified, however users do often specify this
1279 // wrongly, so we try to fix this.
1281 // Adds a trailing slash et the end of the phpMyAdmin uri if it
1282 // does not exist.
1283 if (substr($cfg['PmaAbsoluteUri'], -1) != '/') {
1284 $cfg['PmaAbsoluteUri'] .= '/';
1287 // If URI doesn't start with http:// or https://, we will add
1288 // this.
1289 if (substr($cfg['PmaAbsoluteUri'], 0, 7) != 'http://' && substr($cfg['PmaAbsoluteUri'], 0, 8) != 'https://') {
1290 $cfg['PmaAbsoluteUri'] = ((!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http') . ':'
1291 . (substr($cfg['PmaAbsoluteUri'], 0, 2) == '//' ? '' : '//')
1292 . $cfg['PmaAbsoluteUri'];
1296 // some variables used mostly for cookies:
1297 $pma_uri_parts = parse_url($cfg['PmaAbsoluteUri']);
1298 $cookie_path = substr($pma_uri_parts['path'], 0, strrpos($pma_uri_parts['path'], '/')) . '/';
1299 $is_https = (isset($pma_uri_parts['scheme']) && $pma_uri_parts['scheme'] == 'https') ? 1 : 0;
1302 if ($cfg['ForceSLL'] && !$is_https) {
1303 header(
1304 'Location: ' . preg_replace(
1305 '/^http/', 'https', $cfg['PmaAbsoluteUri'] )
1306 . ( isset( $_SERVER['REQUEST_URI'] )
1307 ? preg_replace( '@' . $pma_uri_parts['path'] . '@',
1308 '', $_SERVER['REQUEST_URI'] )
1309 : '' )
1310 . '&' . SID );
1311 exit;
1315 $dblist = array();
1318 * Gets the valid servers list and parameters
1321 foreach ($cfg['Servers'] AS $key => $val) {
1322 // Don't use servers with no hostname
1323 if ( isset($val['connect_type']) && ($val['connect_type'] == 'tcp') && empty($val['host'])) {
1324 unset($cfg['Servers'][$key]);
1327 // Final solution to bug #582890
1328 // If we are using a socket connection
1329 // and there is nothing in the verbose server name
1330 // or the host field, then generate a name for the server
1331 // in the form of "Server 2", localized of course!
1332 if ( isset($val['connect_type']) && $val['connect_type'] == 'socket' && empty($val['host']) && empty($val['verbose']) ) {
1333 $cfg['Servers'][$key]['verbose'] = $GLOBALS['strServer'] . $key;
1334 $val['verbose'] = $GLOBALS['strServer'] . $key;
1337 unset( $key, $val );
1339 if (empty($server) || !isset($cfg['Servers'][$server]) || !is_array($cfg['Servers'][$server])) {
1340 $server = $cfg['ServerDefault'];
1345 * If no server is selected, make sure that $cfg['Server'] is empty (so
1346 * that nothing will work), and skip server authentication.
1347 * We do NOT exit here, but continue on without logging into any server.
1348 * This way, the welcome page will still come up (with no server info) and
1349 * present a choice of servers in the case that there are multiple servers
1350 * and '$cfg['ServerDefault'] = 0' is set.
1352 if ($server == 0) {
1353 $cfg['Server'] = array();
1357 * Otherwise, set up $cfg['Server'] and do the usual login stuff.
1359 else if (isset($cfg['Servers'][$server])) {
1360 $cfg['Server'] = $cfg['Servers'][$server];
1363 * Loads the proper database interface for this server
1365 require_once('./libraries/database_interface.lib.php');
1367 // Gets the authentication library that fits the $cfg['Server'] settings
1368 // and run authentication
1370 // (for a quick check of path disclosure in auth/cookies:)
1371 $coming_from_common = TRUE;
1373 if (!file_exists('./libraries/auth/' . $cfg['Server']['auth_type'] . '.auth.lib.php')) {
1374 header( 'Location: error.php'
1375 . '?lang=' . urlencode( $available_languages[$lang][2] )
1376 . '&char=' . urlencode( $charset )
1377 . '&dir=' . urlencode( $text_dir )
1378 . '&type=' . urlencode( $strError )
1379 . '&error=' . urlencode(
1380 $strInvalidAuthMethod . ' '
1381 . $cfg['Server']['auth_type'] )
1382 . '&' . SID
1384 exit();
1386 require_once('./libraries/auth/' . $cfg['Server']['auth_type'] . '.auth.lib.php');
1387 if (!PMA_auth_check()) {
1388 PMA_auth();
1389 } else {
1390 PMA_auth_set_user();
1393 // Check IP-based Allow/Deny rules as soon as possible to reject the
1394 // user
1395 // Based on mod_access in Apache:
1396 // http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/aaa/mod_access.c?rev=1.37&content-type=text/vnd.viewcvs-markup
1397 // Look at: "static int check_dir_access(request_rec *r)"
1398 // Robbat2 - May 10, 2002
1399 if (isset($cfg['Server']['AllowDeny']) && isset($cfg['Server']['AllowDeny']['order'])) {
1400 require_once('./libraries/ip_allow_deny.lib.php');
1402 $allowDeny_forbidden = FALSE; // default
1403 if ($cfg['Server']['AllowDeny']['order'] == 'allow,deny') {
1404 $allowDeny_forbidden = TRUE;
1405 if (PMA_allowDeny('allow')) {
1406 $allowDeny_forbidden = FALSE;
1408 if (PMA_allowDeny('deny')) {
1409 $allowDeny_forbidden = TRUE;
1411 } else if ($cfg['Server']['AllowDeny']['order'] == 'deny,allow') {
1412 if (PMA_allowDeny('deny')) {
1413 $allowDeny_forbidden = TRUE;
1415 if (PMA_allowDeny('allow')) {
1416 $allowDeny_forbidden = FALSE;
1418 } else if ($cfg['Server']['AllowDeny']['order'] == 'explicit') {
1419 if (PMA_allowDeny('allow')
1420 && !PMA_allowDeny('deny')) {
1421 $allowDeny_forbidden = FALSE;
1422 } else {
1423 $allowDeny_forbidden = TRUE;
1425 } // end if... else if... else if
1427 // Ejects the user if banished
1428 if ($allowDeny_forbidden) {
1429 PMA_auth_fails();
1431 unset($allowDeny_forbidden); //Clean up after you!
1432 } // end if
1434 // is root allowed?
1435 if (!$cfg['Server']['AllowRoot'] && $cfg['Server']['user'] == 'root') {
1436 $allowDeny_forbidden = TRUE;
1437 PMA_auth_fails();
1438 unset($allowDeny_forbidden); //Clean up after you!
1441 // The user can work with only some databases
1442 if (isset($cfg['Server']['only_db']) && $cfg['Server']['only_db'] != '') {
1443 if (is_array($cfg['Server']['only_db'])) {
1444 $dblist = $cfg['Server']['only_db'];
1445 } else {
1446 $dblist[] = $cfg['Server']['only_db'];
1448 } // end if
1450 $bkp_track_err = @ini_set('track_errors', 1);
1452 // Try to connect MySQL with the control user profile (will be used to
1453 // get the privileges list for the current user but the true user link
1454 // must be open after this one so it would be default one for all the
1455 // scripts)
1456 if ($cfg['Server']['controluser'] != '') {
1457 $dbh = PMA_DBI_connect($cfg['Server']['controluser'], $cfg['Server']['controlpass'], TRUE);
1458 } else {
1459 $dbh = PMA_DBI_connect($cfg['Server']['user'], $cfg['Server']['password'], TRUE);
1460 } // end if ... else
1462 // Pass #1 of DB-Config to read in master level DB-Config will go here
1463 // Robbat2 - May 11, 2002
1465 // Connects to the server (validates user's login)
1466 $userlink = PMA_DBI_connect($cfg['Server']['user'], $cfg['Server']['password'], FALSE);
1468 // Pass #2 of DB-Config to read in user level DB-Config will go here
1469 // Robbat2 - May 11, 2002
1471 @ini_set('track_errors', $bkp_track_err);
1472 unset($bkp_track_err);
1475 * SQL Parser code
1477 require_once('./libraries/sqlparser.lib.php');
1480 * SQL Validator interface code
1482 require_once('./libraries/sqlvalidator.lib.php');
1484 // if 'only_db' is set for the current user, there is no need to check for
1485 // available databases in the "mysql" db
1486 $dblist_cnt = count($dblist);
1487 if ($dblist_cnt) {
1488 $true_dblist = array();
1489 $is_show_dbs = TRUE;
1491 $dblist_asterisk_bool = FALSE;
1492 for ($i = 0; $i < $dblist_cnt; $i++) {
1494 // The current position
1495 if ($dblist[$i] == '*' && $dblist_asterisk_bool == FALSE) {
1496 $dblist_asterisk_bool = TRUE;
1497 $dblist_full = PMA_safe_db_list(FALSE, $dbh, FALSE, $rs, $userlink, $cfg, $dblist);
1498 foreach ($dblist_full as $dbl_val) {
1499 if (!in_array($dbl_val, $dblist)) {
1500 $true_dblist[] = $dbl_val;
1504 continue;
1505 } elseif ($dblist[$i] == '*') {
1506 // We don't want more than one asterisk inside our 'only_db'.
1507 continue;
1509 if ($is_show_dbs && ereg('(^|[^\])(_|%)', $dblist[$i])) {
1510 $local_query = 'SHOW DATABASES LIKE \'' . $dblist[$i] . '\'';
1511 // here, a PMA_DBI_query() could fail silently
1512 // if SHOW DATABASES is disabled
1513 $rs = PMA_DBI_try_query($local_query, $dbh);
1515 if ($i == 0
1516 && (substr(PMA_DBI_getError($dbh), 1, 4) == 1045)) {
1517 // "SHOW DATABASES" statement is disabled
1518 $true_dblist[] = str_replace('\\_', '_', str_replace('\\%', '%', $dblist[$i]));
1519 $is_show_dbs = FALSE;
1521 // Debug
1522 // else if (PMA_DBI_getError($dbh)) {
1523 // PMA_mysqlDie(PMA_DBI_getError($dbh), $local_query, FALSE);
1524 // }
1525 while ($row = @PMA_DBI_fetch_row($rs)) {
1526 $true_dblist[] = $row[0];
1527 } // end while
1528 if ($rs) {
1529 PMA_DBI_free_result($rs);
1531 } else {
1532 $true_dblist[] = str_replace('\\_', '_', str_replace('\\%', '%', $dblist[$i]));
1533 } // end if... else...
1534 } // end for
1535 $dblist = $true_dblist;
1536 unset( $true_dblist, $i, $dbl_val );
1537 $only_db_check = TRUE;
1538 } // end if
1540 // 'only_db' is empty for the current user...
1541 else {
1542 $only_db_check = FALSE;
1543 } // end if (!$dblist_cnt)
1545 if (isset($dblist_full) && !count($dblist_full)) {
1546 $dblist = PMA_safe_db_list($only_db_check, $dbh, $dblist_cnt, $rs, $userlink, $cfg, $dblist);
1549 } // end server connecting
1551 * Missing server hostname
1553 else {
1554 echo $strHostEmpty;
1558 * Send HTTP header, taking IIS limits into account
1559 * ( 600 seems ok)
1561 * @param string the header to send
1563 * @return boolean always true
1565 function PMA_sendHeaderLocation($uri)
1567 if (PMA_IS_IIS && strlen($uri) > 600) {
1569 echo '<html><head><title>- - -</title>' . "\n";
1570 echo '<meta http-equiv="expires" content="0">' . "\n";
1571 echo '<meta http-equiv="Pragma" content="no-cache">' . "\n";
1572 echo '<meta http-equiv="Cache-Control" content="no-cache">' . "\n";
1573 echo '<meta http-equiv="Refresh" content="0;url=' .$uri . '">' . "\n";
1574 echo '<script language="JavaScript">' . "\n";
1575 echo 'setTimeout ("window.location = unescape(\'"' . $uri . '"\')",2000); </script>' . "\n";
1576 echo '</head>' . "\n";
1577 echo '<body> <script language="JavaScript">' . "\n";
1578 echo 'document.write (\'<p><a href="' . $uri . '">' . $GLOBALS['strGo'] . '</a></p>\');' . "\n";
1579 echo '</script></body></html>' . "\n";
1581 } else {
1582 header( 'Location: ' . $uri . '&' . SID );
1588 * Get the list and number of available databases.
1590 * @param string the url to go back to in case of error
1592 * @return boolean always true
1594 * @global array the list of available databases
1595 * @global integer the number of available databases
1596 * @global array current configuration
1598 function PMA_availableDatabases($error_url = '')
1600 global $dblist;
1601 global $num_dbs;
1602 global $cfg;
1604 // 1. A list of allowed databases has already been defined by the
1605 // authentification process -> gets the available databases list
1606 if ( count( $dblist ) ) {
1607 foreach ( $dblist as $key => $db ) {
1608 if ( ! @PMA_DBI_select_db( $db ) ) {
1609 unset( $dblist[$key] );
1610 } // end if
1611 } // end for
1612 } // end if
1613 // 2. Allowed database list is empty -> gets the list of all databases
1614 // on the server
1615 elseif ( empty( $cfg['Server']['only_db'] ) ) {
1616 $dblist = PMA_DBI_get_dblist(); // needed? or PMA_mysqlDie('', 'SHOW DATABASES;', FALSE, $error_url);
1617 } // end else
1619 $num_dbs = count( $dblist );
1621 // natural order for db list; but do not sort if user asked
1622 // for a specific order with the 'only_db' mechanism
1623 if ( ! is_array( $GLOBALS['cfg']['Server']['only_db'] )
1624 && $GLOBALS['cfg']['NaturalOrder'] ) {
1625 natsort( $dblist );
1628 return TRUE;
1629 } // end of the 'PMA_availableDatabases()' function
1632 * returns array with tables of given db with extended infomation and grouped
1634 * @uses $GLOBALS['cfg']['LeftFrameTableSeparator']
1635 * @uses $GLOBALS['cfg']['LeftFrameTableLevel']
1636 * @uses $GLOBALS['cfg']['ShowTooltipAliasTB']
1637 * @uses $GLOBALS['cfg']['NaturalOrder']
1638 * @uses PMA_DBI_fetch_result()
1639 * @uses PMA_backquote()
1640 * @uses count()
1641 * @uses array_merge
1642 * @uses uksort()
1643 * @uses strstr()
1644 * @uses explode()
1645 * @param string $db name of db
1646 * return array (rekursive) grouped table list
1648 function PMA_getTableList( $db ) {
1649 $sep = $GLOBALS['cfg']['LeftFrameTableSeparator'];
1651 $tables = PMA_DBI_get_tables_full($db);
1652 if ( count( $tables ) < 1 ) {
1653 return $tables;
1656 if ( $GLOBALS['cfg']['NaturalOrder'] ) {
1657 uksort( $tables, 'strcmp' );
1660 $default = array(
1661 'Name' => '',
1662 'Rows' => 0,
1663 'Comment' => '',
1664 'disp_name' => '',
1667 $table_groups = array();
1669 foreach ( $tables as $table_name => $table ) {
1671 // check for correct row count
1672 if ( NULL === $table['Rows'] ) {
1673 $table['Rows'] = PMA_countRecords( $db, $table['Name'],
1674 $return = true, $force_exact = true );
1677 // in $group we save the reference to the place in $table_groups
1678 // where to store the table info
1679 if ( $GLOBALS['cfg']['LeftFrameDBTree']
1680 && $sep && strstr( $table_name, $sep ) )
1682 $parts = explode( $sep, $table_name );
1684 $group =& $table_groups;
1685 $i = 0;
1686 $group_name_full = '';
1687 while ( $i < count( $parts ) - 1
1688 && $i < $GLOBALS['cfg']['LeftFrameTableLevel'] ) {
1689 $group_name = $parts[$i] . $sep;
1690 $group_name_full .= $group_name;
1692 if ( ! isset( $group[$group_name] ) ) {
1693 $group[$group_name] = array();
1694 $group[$group_name]['is' . $sep . 'group'] = true;
1695 $group[$group_name]['tab' . $sep . 'count'] = 1;
1696 $group[$group_name]['tab' . $sep . 'group'] = $group_name_full;
1697 } elseif ( ! isset( $group[$group_name]['is' . $sep . 'group'] ) ) {
1698 $table = $group[$group_name];
1699 $group[$group_name] = array();
1700 $group[$group_name][$group_name] = $table;
1701 unset( $table );
1702 $group[$group_name]['is' . $sep . 'group'] = true;
1703 $group[$group_name]['tab' . $sep . 'count'] = 1;
1704 $group[$group_name]['tab' . $sep . 'group'] = $group_name_full;
1705 } else {
1706 $group[$group_name]['tab_count']++;
1708 $group =& $group[$group_name];
1709 $i++;
1711 } else {
1712 if ( ! isset( $table_groups[$table_name] ) ) {
1713 $table_groups[$table_name] = array();
1715 $group =& $table_groups;
1719 if ( $GLOBALS['cfg']['ShowTooltipAliasTB']
1720 && $GLOBALS['cfg']['ShowTooltipAliasTB'] !== 'nested' ) {
1721 // switch tooltip and name
1722 $table['Comment'] = $table['Name'];
1723 $table['disp_name'] = $table['Comment'];
1724 } else {
1725 $table['disp_name'] = $table['Name'];
1728 $group[$table_name] = array_merge( $default, $table );
1731 return $table_groups;
1734 /* ----------------------- Set of misc functions ----------------------- */
1738 * Adds backquotes on both sides of a database, table or field name.
1739 * Since MySQL 3.23.6 this allows to use non-alphanumeric characters in
1740 * these names.
1742 * @param mixed the database, table or field name to "backquote" or
1743 * array of it
1744 * @param boolean a flag to bypass this function (used by dump
1745 * functions)
1747 * @return mixed the "backquoted" database, table or field name if the
1748 * current MySQL release is >= 3.23.6, the original one
1749 * else
1751 * @access public
1753 function PMA_backquote($a_name, $do_it = TRUE)
1755 // '0' is also empty for php :-(
1756 if ($do_it
1757 && (!empty($a_name) || $a_name == '0') && $a_name != '*') {
1759 if (is_array($a_name)) {
1760 $result = array();
1761 foreach ($a_name AS $key => $val) {
1762 $result[$key] = '`' . $val . '`';
1764 return $result;
1765 } else {
1766 return '`' . $a_name . '`';
1768 } else {
1769 return $a_name;
1771 } // end of the 'PMA_backquote()' function
1775 * Format a string so it can be passed to a javascript function.
1776 * This function is used to displays a javascript confirmation box for
1777 * "DROP/DELETE/ALTER" queries.
1779 * @param string the string to format
1780 * @param boolean whether to add backquotes to the string or not
1782 * @return string the formated string
1784 * @access public
1786 function PMA_jsFormat($a_string = '', $add_backquotes = TRUE)
1788 if (is_string($a_string)) {
1789 $a_string = htmlspecialchars($a_string);
1790 $a_string = str_replace('\\', '\\\\', $a_string);
1791 $a_string = str_replace('\'', '\\\'', $a_string);
1792 $a_string = str_replace('#', '\\#', $a_string);
1793 $a_string = str_replace("\012", '\\\\n', $a_string);
1794 $a_string = str_replace("\015", '\\\\r', $a_string);
1797 return (($add_backquotes) ? PMA_backquote($a_string) : $a_string);
1798 } // end of the 'PMA_jsFormat()' function
1802 * Defines the <CR><LF> value depending on the user OS.
1804 * @return string the <CR><LF> value to use
1806 * @access public
1808 function PMA_whichCrlf()
1810 $the_crlf = "\n";
1812 // The 'PMA_USR_OS' constant is defined in "./libraries/defines.lib.php"
1813 // Win case
1814 if (PMA_USR_OS == 'Win') {
1815 $the_crlf = "\r\n";
1817 // Mac case
1818 else if (PMA_USR_OS == 'Mac') {
1819 $the_crlf = "\r";
1821 // Others
1822 else {
1823 $the_crlf = "\n";
1826 return $the_crlf;
1827 } // end of the 'PMA_whichCrlf()' function
1831 * Counts and displays the number of records in a table
1833 * Last revision 13 July 2001: Patch for limiting dump size from
1834 * vinay@sanisoft.com & girish@sanisoft.com
1836 * @param string the current database name
1837 * @param string the current table name
1838 * @param boolean whether to retain or to displays the result
1839 * @param boolean whether to force an exact count
1841 * @return mixed the number of records if retain is required, true else
1843 * @access public
1845 function PMA_countRecords($db, $table, $ret = FALSE, $force_exact = FALSE)
1847 global $err_url, $cfg;
1848 if (!$force_exact) {
1849 $result = PMA_DBI_query('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \'' . PMA_sqlAddslashes($table, TRUE) . '\';');
1850 $showtable = PMA_DBI_fetch_assoc($result);
1851 $num = (isset($showtable['Rows']) ? $showtable['Rows'] : 0);
1852 if ($num < $cfg['MaxExactCount']) {
1853 unset($num);
1855 PMA_DBI_free_result($result);
1858 if (!isset($num)) {
1859 $result = PMA_DBI_query('SELECT COUNT(*) AS num FROM ' . PMA_backquote($db) . '.' . PMA_backquote($table));
1860 list($num) = ($result) ? PMA_DBI_fetch_row($result) : array(0);
1861 PMA_DBI_free_result($result);
1863 if ($ret) {
1864 return $num;
1865 } else {
1866 echo number_format($num, 0, $GLOBALS['number_decimal_separator'], $GLOBALS['number_thousands_separator']);
1867 return TRUE;
1869 } // end of the 'PMA_countRecords()' function
1872 * Reloads navigation if needed.
1874 * @global mixed configuration
1875 * @global bool whether to reload
1877 * @access public
1879 function PMA_reloadNavigation() {
1880 global $cfg;
1882 // Reloads the navigation frame via JavaScript if required
1883 if (isset($GLOBALS['reload']) && $GLOBALS['reload']) {
1884 echo "\n";
1885 $reload_url = './left.php?' . PMA_generate_common_url((isset($GLOBALS['db']) ? $GLOBALS['db'] : ''), '', '&');
1887 <script type="text/javascript">
1888 //<![CDATA[
1889 if (typeof(window.parent) != 'undefined'
1890 && typeof(window.parent.frames[0]) != 'undefined') {
1891 window.parent.goTo('<?php echo $reload_url; ?>');
1893 //]]>
1894 </script>
1895 <?php
1896 unset($GLOBALS['reload']);
1901 * Displays a message at the top of the "main" (right) frame
1903 * @param string the message to display
1905 * @global array the configuration array
1907 * @access public
1909 function PMA_showMessage($message)
1911 global $cfg;
1913 // Sanitizes $message
1914 $message = PMA_sanitize($message);
1916 // Corrects the tooltip text via JS if required
1917 if (!empty($GLOBALS['table']) && $cfg['ShowTooltip']) {
1918 $result = PMA_DBI_try_query('SHOW TABLE STATUS FROM ' . PMA_backquote($GLOBALS['db']) . ' LIKE \'' . PMA_sqlAddslashes($GLOBALS['table'], TRUE) . '\'');
1919 if ($result) {
1920 $tbl_status = PMA_DBI_fetch_assoc($result);
1921 $tooltip = (empty($tbl_status['Comment']))
1922 ? ''
1923 : $tbl_status['Comment'] . ' ';
1924 $tooltip .= '(' . PMA_formatNumber( $tbl_status['Rows'], 0 ) . ' ' . $GLOBALS['strRows'] . ')';
1925 PMA_DBI_free_result($result);
1926 $uni_tbl = PMA_jsFormat( $GLOBALS['db'] . '.' . $GLOBALS['table'], false );
1927 echo "\n";
1929 <script type="text/javascript">
1930 //<![CDATA[
1931 window.parent.updateTableTitle( '<?php echo $uni_tbl; ?>', '<?php echo PMA_jsFormat($tooltip, false); ?>' );
1932 //]]>
1933 </script>
1934 <?php
1935 } // end if
1936 } // end if... else if
1938 // Checks if the table needs to be repaired after a TRUNCATE query.
1939 if (isset($GLOBALS['table']) && isset($GLOBALS['sql_query'])
1940 && $GLOBALS['sql_query'] == 'TRUNCATE TABLE ' . PMA_backquote($GLOBALS['table'])) {
1941 if (!isset($tbl_status)) {
1942 $result = @PMA_DBI_try_query('SHOW TABLE STATUS FROM ' . PMA_backquote($GLOBALS['db']) . ' LIKE \'' . PMA_sqlAddslashes($GLOBALS['table'], TRUE) . '\'');
1943 if ($result) {
1944 $tbl_status = PMA_DBI_fetch_assoc($result);
1945 PMA_DBI_free_result($result);
1948 if (isset($tbl_status) && (int) $tbl_status['Index_length'] > 1024) {
1949 PMA_DBI_try_query('REPAIR TABLE ' . PMA_backquote($GLOBALS['table']));
1952 unset($tbl_status);
1954 <br />
1955 <div align="<?php echo $GLOBALS['cell_align_left']; ?>">
1956 <?php
1957 if ( ! empty( $GLOBALS['show_error_header'] ) ) {
1959 <div class="error">
1960 <h1><?php echo $GLOBALS['strError']; ?></h1>
1961 <?php
1964 echo $message;
1965 if (isset($GLOBALS['special_message'])) {
1966 echo PMA_sanitize($GLOBALS['special_message']);
1967 unset($GLOBALS['special_message']);
1970 if ( ! empty( $GLOBALS['show_error_header'] ) ) {
1971 echo '</div>';
1974 if ( $cfg['ShowSQL'] == TRUE
1975 && ( !empty($GLOBALS['sql_query']) || !empty($GLOBALS['display_query']) ) ) {
1976 $local_query = !empty($GLOBALS['display_query']) ? $GLOBALS['display_query'] : (($cfg['SQP']['fmtType'] == 'none' && isset($GLOBALS['unparsed_sql']) && $GLOBALS['unparsed_sql'] != '') ? $GLOBALS['unparsed_sql'] : $GLOBALS['sql_query']);
1977 // Basic url query part
1978 $url_qpart = '?' . PMA_generate_common_url(isset($GLOBALS['db']) ? $GLOBALS['db'] : '', isset($GLOBALS['table']) ? $GLOBALS['table'] : '');
1980 // Html format the query to be displayed
1981 // The nl2br function isn't used because its result isn't a valid
1982 // xhtml1.0 statement before php4.0.5 ("<br>" and not "<br />")
1983 // If we want to show some sql code it is easiest to create it here
1984 /* SQL-Parser-Analyzer */
1986 if (!empty($GLOBALS['show_as_php'])) {
1987 $new_line = '\'<br />' . "\n" . '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. \' ';
1989 if (isset($new_line)) {
1990 /* SQL-Parser-Analyzer */
1991 $query_base = PMA_sqlAddslashes(htmlspecialchars($local_query), FALSE, FALSE, TRUE);
1992 /* SQL-Parser-Analyzer */
1993 $query_base = preg_replace("@((\015\012)|(\015)|(\012))+@", $new_line, $query_base);
1994 } else {
1995 $query_base = $local_query;
1998 // Parse SQL if needed
1999 if (isset($GLOBALS['parsed_sql']) && $query_base == $GLOBALS['parsed_sql']['raw']) {
2000 $parsed_sql = $GLOBALS['parsed_sql'];
2001 } else {
2002 $parsed_sql = PMA_SQP_parse($query_base);
2005 // Analyze it
2006 $analyzed_display_query = PMA_SQP_analyze($parsed_sql);
2008 // Here we append the LIMIT added for navigation, to
2009 // enable its display. Adding it higher in the code
2010 // to $local_query would create a problem when
2011 // using the Refresh or Edit links.
2013 // Only append it on SELECTs.
2015 // FIXME: what would be the best to do when someone
2016 // hits Refresh: use the current LIMITs ?
2018 if (isset($analyzed_display_query[0]['queryflags']['select_from'])
2019 && isset($GLOBALS['sql_limit_to_append'])) {
2020 $query_base = $analyzed_display_query[0]['section_before_limit'] . "\n" . $GLOBALS['sql_limit_to_append'] . $analyzed_display_query[0]['section_after_limit'];
2021 // Need to reparse query
2022 $parsed_sql = PMA_SQP_parse($query_base);
2025 if (!empty($GLOBALS['show_as_php'])) {
2026 $query_base = '$sql = \'' . $query_base;
2027 } else if (!empty($GLOBALS['validatequery'])) {
2028 $query_base = PMA_validateSQL($query_base);
2029 } else {
2030 $query_base = PMA_formatSql($parsed_sql, $query_base);
2033 // Prepares links that may be displayed to edit/explain the query
2034 // (don't go to default pages, we must go to the page
2035 // where the query box is available)
2036 // (also, I don't see why we should check the goto variable)
2038 //if (!isset($GLOBALS['goto'])) {
2039 //$edit_target = (isset($GLOBALS['table'])) ? $cfg['DefaultTabTable'] : $cfg['DefaultTabDatabase'];
2040 $edit_target = isset($GLOBALS['db']) ? (isset($GLOBALS['table']) ? 'tbl_properties.php' : 'db_details.php') : 'server_sql.php';
2041 //} else if ($GLOBALS['goto'] != 'main.php') {
2042 // $edit_target = $GLOBALS['goto'];
2043 //} else {
2044 // $edit_target = '';
2047 if (isset($cfg['SQLQuery']['Edit'])
2048 && ($cfg['SQLQuery']['Edit'] == TRUE )
2049 && (!empty($edit_target))) {
2051 if ($cfg['EditInWindow'] == TRUE) {
2052 $onclick = 'window.parent.focus_querywindow(\'' . urlencode($local_query) . '\'); return false;';
2053 } else {
2054 $onclick = '';
2057 $edit_link = $edit_target
2058 . $url_qpart
2059 . '&amp;sql_query=' . urlencode($local_query)
2060 . '&amp;show_query=1#querybox"';
2061 $edit_link = ' [' . PMA_linkOrButton( $edit_link, $GLOBALS['strEdit'], array( 'onclick' => $onclick ) ) . ']';
2062 } else {
2063 $edit_link = '';
2066 // Want to have the query explained (Mike Beck 2002-05-22)
2067 // but only explain a SELECT (that has not been explained)
2068 /* SQL-Parser-Analyzer */
2069 if (isset($cfg['SQLQuery']['Explain'])
2070 && $cfg['SQLQuery']['Explain'] == TRUE) {
2072 // Detect if we are validating as well
2073 // To preserve the validate uRL data
2074 if (!empty($GLOBALS['validatequery'])) {
2075 $explain_link_validate = '&amp;validatequery=1';
2076 } else {
2077 $explain_link_validate = '';
2080 $explain_link = 'import.php'
2081 . $url_qpart
2082 . $explain_link_validate
2083 . '&amp;sql_query=';
2085 if (preg_match('@^SELECT[[:space:]]+@i', $local_query)) {
2086 $explain_link .= urlencode('EXPLAIN ' . $local_query);
2087 $message = $GLOBALS['strExplain'];
2088 } else if (preg_match('@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i', $local_query)) {
2089 $explain_link .= urlencode(substr($local_query, 8));
2090 $message = $GLOBALS['strNoExplain'];
2091 } else {
2092 $explain_link = '';
2094 if (!empty($explain_link)) {
2095 $explain_link = ' [' . PMA_linkOrButton( $explain_link, $message ) . ']';
2097 } else {
2098 $explain_link = '';
2099 } //show explain
2101 // Also we would like to get the SQL formed in some nice
2102 // php-code (Mike Beck 2002-05-22)
2103 if (isset($cfg['SQLQuery']['ShowAsPHP'])
2104 && $cfg['SQLQuery']['ShowAsPHP'] == TRUE) {
2105 $php_link = 'import.php'
2106 . $url_qpart
2107 . '&amp;show_query=1'
2108 . '&amp;sql_query=' . urlencode($local_query)
2109 . '&amp;show_as_php=';
2111 if (!empty($GLOBALS['show_as_php'])) {
2112 $php_link .= '0';
2113 $message = $GLOBALS['strNoPhp'];
2114 } else {
2115 $php_link .= '1';
2116 $message = $GLOBALS['strPhp'];
2118 $php_link = ' [' . PMA_linkOrButton( $php_link, $message ) . ']';
2120 if (isset($GLOBALS['show_as_php']) && $GLOBALS['show_as_php'] == '1') {
2121 $runquery_link
2122 = 'import.php'
2123 . $url_qpart
2124 . '&amp;show_query=1'
2125 . '&amp;sql_query=' . urlencode($local_query);
2126 $php_link .= ' [' . PMA_linkOrButton( $runquery_link, $GLOBALS['strRunQuery'] ) . ']';
2129 } else {
2130 $php_link = '';
2131 } //show as php
2133 // Refresh query
2134 if (isset($cfg['SQLQuery']['Refresh'])
2135 && $cfg['SQLQuery']['Refresh']
2136 && preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $local_query)) {
2138 $refresh_link = 'import.php'
2139 . $url_qpart
2140 . '&amp;show_query=1'
2141 . '&amp;sql_query=' . urlencode($local_query);
2142 $refresh_link = ' [' . PMA_linkOrButton( $refresh_link, $GLOBALS['strRefresh'] ) . ']';
2143 } else {
2144 $refresh_link = '';
2145 } //show as php
2147 if (isset($cfg['SQLValidator']['use'])
2148 && $cfg['SQLValidator']['use'] == TRUE
2149 && isset($cfg['SQLQuery']['Validate'])
2150 && $cfg['SQLQuery']['Validate'] == TRUE) {
2151 $validate_link = 'import.php'
2152 . $url_qpart
2153 . '&amp;show_query=1'
2154 . '&amp;sql_query=' . urlencode($local_query)
2155 . '&amp;validatequery=';
2156 if (!empty($GLOBALS['validatequery'])) {
2157 $validate_link .= '0';
2158 $validate_message = $GLOBALS['strNoValidateSQL'] ;
2159 } else {
2160 $validate_link .= '1';
2161 $validate_message = $GLOBALS['strValidateSQL'] ;
2163 $validate_link = ' [' . PMA_linkOrButton( $validate_link, $validate_message ) . ']';
2164 } else {
2165 $validate_link = '';
2166 } //validator
2167 unset($local_query);
2169 // Displays the message
2170 echo '<fieldset class="">' . "\n";
2171 echo ' <legend>' . $GLOBALS['strSQLQuery'] . ':</legend>';
2172 echo ' ' . $query_base;
2174 //Clean up the end of the PHP
2175 if (!empty($GLOBALS['show_as_php'])) {
2176 echo '\';';
2178 echo '</fieldset>' . "\n";
2180 if ( ! empty( $edit_target ) ) {
2181 echo '<fieldset class="tblFooters">';
2182 echo $edit_link . $explain_link . $php_link . $refresh_link . $validate_link;
2183 echo '</fieldset>';
2187 </div><br />
2188 <?php
2189 } // end of the 'PMA_showMessage()' function
2193 * Formats $value to byte view
2195 * @param double the value to format
2196 * @param integer the sensitiveness
2197 * @param integer the number of decimals to retain
2199 * @return array the formatted value and its unit
2201 * @access public
2203 * @author staybyte
2204 * @version 1.2 - 18 July 2002
2206 function PMA_formatByteDown($value, $limes = 6, $comma = 0)
2208 $dh = pow(10, $comma);
2209 $li = pow(10, $limes);
2210 $return_value = $value;
2211 $unit = $GLOBALS['byteUnits'][0];
2213 for ( $d = 6, $ex = 15; $d >= 1; $d--, $ex-=3 ) {
2214 if (isset($GLOBALS['byteUnits'][$d]) && $value >= $li * pow(10, $ex)) {
2215 $value = round($value / ( pow(1024, $d) / $dh) ) /$dh;
2216 $unit = $GLOBALS['byteUnits'][$d];
2217 break 1;
2218 } // end if
2219 } // end for
2221 if ($unit != $GLOBALS['byteUnits'][0]) {
2222 $return_value = number_format($value, $comma, $GLOBALS['number_decimal_separator'], $GLOBALS['number_thousands_separator']);
2223 } else {
2224 $return_value = number_format($value, 0, $GLOBALS['number_decimal_separator'], $GLOBALS['number_thousands_separator']);
2227 return array($return_value, $unit);
2228 } // end of the 'PMA_formatByteDown' function
2231 * Formats $value to the given length and appends SI prefixes
2232 * $comma is not substracted from the length
2233 * with a $length of 0 no truncation occurs, number is only formated
2234 * to the current locale
2235 * <code>
2236 * echo PMA_formatNumber( 123456789, 6 ); // 123,457 k
2237 * echo PMA_formatNumber( -123456789, 4, 2 ); // -123.46 M
2238 * echo PMA_formatNumber( -0.003, 6 ); // -3 m
2239 * echo PMA_formatNumber( 0.003, 3, 3 ); // 0.003
2240 * echo PMA_formatNumber( 0.00003, 3, 2 ); // 0.03 m
2241 * echo PMA_formatNumber( 0, 6 ); // 0
2242 * </code>
2243 * @param double $value the value to format
2244 * @param integer $length the max length
2245 * @param integer $comma the number of decimals to retain
2246 * @param boolean $only_down do not reformat numbers below 1
2248 * @return string the formatted value and its unit
2250 * @access public
2252 * @author staybyte, sebastian mendel
2253 * @version 1.1.0 - 2005-10-27
2255 function PMA_formatNumber( $value, $length = 3, $comma = 0, $only_down = false ) {
2256 if ( $length === 0 ) {
2257 return number_format( $value,
2258 $comma,
2259 $GLOBALS['number_decimal_separator'],
2260 $GLOBALS['number_thousands_separator'] );
2263 // this units needs no translation, ISO
2264 $units = array(
2265 -8 => 'y',
2266 -7 => 'z',
2267 -6 => 'a',
2268 -5 => 'f',
2269 -4 => 'p',
2270 -3 => 'n',
2271 -2 => '&micro;',
2272 -1 => 'm',
2273 0 => ' ',
2274 1 => 'k',
2275 2 => 'M',
2276 3 => 'G',
2277 4 => 'T',
2278 5 => 'P',
2279 6 => 'E',
2280 7 => 'Z',
2281 8 => 'Y'
2284 // we need at least 3 digits to be displayed
2285 if ( 3 > $length + $comma ) {
2286 $length = 3 - $comma;
2289 // check for negativ value to retain sign
2290 if ( $value < 0 ) {
2291 $sign = '-';
2292 $value = abs( $value );
2293 } else {
2294 $sign = '';
2297 $dh = pow(10, $comma);
2298 $li = pow(10, $length);
2299 $unit = $units[0];
2301 if ( $value >= 1 ) {
2302 for ( $d = 8; $d >= 0; $d-- ) {
2303 if (isset($units[$d]) && $value >= $li * pow(1000, $d-1)) {
2304 $value = round($value / ( pow(1000, $d) / $dh) ) /$dh;
2305 $unit = $units[$d];
2306 break 1;
2307 } // end if
2308 } // end for
2309 } elseif ( ! $only_down && (float) $value !== 0.0 ) {
2310 for ( $d = -8; $d <= 8; $d++ ) {
2311 if (isset($units[$d]) && $value <= $li * pow(1000, $d-1)) {
2312 $value = round($value / ( pow(1000, $d) / $dh) ) /$dh;
2313 $unit = $units[$d];
2314 break 1;
2315 } // end if
2316 } // end for
2317 } // end if ( $value >= 1 ) elseif ( ! $only_down && (float) $value !== 0.0 )
2319 $value = number_format( $value,
2320 $comma,
2321 $GLOBALS['number_decimal_separator'],
2322 $GLOBALS['number_thousands_separator'] );
2324 return $sign . $value . ' ' . $unit;
2325 } // end of the 'PMA_formatNumber' function
2328 * Extracts ENUM / SET options from a type definition string
2330 * @param string The column type definition
2332 * @return array The options or
2333 * boolean FALSE in case of an error.
2335 * @author rabus
2337 function PMA_getEnumSetOptions($type_def) {
2338 $open = strpos($type_def, '(');
2339 $close = strrpos($type_def, ')');
2340 if (!$open || !$close) {
2341 return FALSE;
2343 $options = substr($type_def, $open + 2, $close - $open - 3);
2344 $options = explode('\',\'', $options);
2345 return $options;
2346 } // end of the 'PMA_getEnumSetOptions' function
2349 * Writes localised date
2351 * @param string the current timestamp
2353 * @return string the formatted date
2355 * @access public
2357 function PMA_localisedDate($timestamp = -1, $format = '')
2359 global $datefmt, $month, $day_of_week;
2361 if ($format == '') {
2362 $format = $datefmt;
2365 if ($timestamp == -1) {
2366 $timestamp = time();
2369 $date = preg_replace('@%[aA]@', $day_of_week[(int)strftime('%w', $timestamp)], $format);
2370 $date = preg_replace('@%[bB]@', $month[(int)strftime('%m', $timestamp)-1], $date);
2372 return strftime($date, $timestamp);
2373 } // end of the 'PMA_localisedDate()' function
2377 * returns a tab for tabbed navigation.
2378 * If the variables $link and $args ar left empty, an inactive tab is created
2380 * @uses array_merge()
2381 * basename()
2382 * $GLOBALS['strEmpty']
2383 * $GLOBALS['strDrop']
2384 * $GLOBALS['active_page']
2385 * $GLOBALS['PHP_SELF']
2386 * htmlentities()
2387 * PMA_generate_common_url()
2388 * $GLOBALS['url_query']
2389 * urlencode()
2390 * $GLOBALS['cfg']['MainPageIconic']
2391 * $GLOBALS['pmaThemeImage']
2392 * sprintf()
2393 * trigger_error()
2394 * E_USER_NOTICE
2395 * @param array $tab array with all options
2396 * @return string html code for one tab, a link if valid otherwise a span
2397 * @access public
2399 function PMA_getTab( $tab )
2401 // default values
2402 $defaults = array(
2403 'text' => '',
2404 'class' => '',
2405 'active' => false,
2406 'link' => '',
2407 'sep' => '?',
2408 'attr' => '',
2409 'args' => '',
2412 $tab = array_merge( $defaults, $tab );
2414 // determine aditional style-class
2415 if ( empty( $tab['class'] ) ) {
2416 if ( $tab['text'] == $GLOBALS['strEmpty']
2417 || $tab['text'] == $GLOBALS['strDrop'] ) {
2418 $tab['class'] = 'caution';
2420 elseif ( isset( $tab['active'] ) && $tab['active']
2421 || isset( $GLOBALS['active_page'] )
2422 && $GLOBALS['active_page'] == $tab['link']
2423 || basename( $GLOBALS['PHP_SELF'] ) == $tab['link'] )
2425 $tab['class'] = 'active';
2429 // build the link
2430 if ( ! empty( $tab['link'] ) ) {
2431 $tab['link'] = htmlentities( $tab['link'] );
2432 $tab['link'] = $tab['link'] . $tab['sep']
2433 .( empty( $GLOBALS['url_query'] ) ?
2434 PMA_generate_common_url() : $GLOBALS['url_query'] );
2435 if ( ! empty( $tab['args'] ) ) {
2436 foreach( $tab['args'] as $param => $value ) {
2437 $tab['link'] .= '&amp;' . urlencode( $param ) . '='
2438 . urlencode( $value );
2443 // display icon, even if iconic is disabled but the link-text is missing
2444 if ( ( $GLOBALS['cfg']['MainPageIconic'] || empty( $tab['text'] ) )
2445 && isset( $tab['icon'] ) ) {
2446 $image = '<img class="icon" src="' . htmlentities( $GLOBALS['pmaThemeImage'] )
2447 .'%1$s" width="16" height="16" alt="%2$s" />%2$s';
2448 $tab['text'] = sprintf( $image, htmlentities( $tab['icon'] ), $tab['text'] );
2450 // check to not display an empty link-text
2451 elseif ( empty( $tab['text'] ) ) {
2452 $tab['text'] = '?';
2453 trigger_error( __FILE__ . '(' . __LINE__ . '): '
2454 . 'empty linktext in function ' . __FUNCTION__ . '()',
2455 E_USER_NOTICE );
2458 if ( ! empty( $tab['link'] ) ) {
2459 $out = '<a class="tab' . htmlentities( $tab['class'] ) . '"'
2460 .' href="' . $tab['link'] . '" ' . $tab['attr'] . '>'
2461 . $tab['text'] . '</a>';
2462 } else {
2463 $out = '<span class="tab' . htmlentities( $tab['class'] ) . '">'
2464 . $tab['text'] . '</span>';
2467 return $out;
2468 } // end of the 'PMA_printTab()' function
2471 * returns html-code for a tab navigation
2473 * @uses PMA_getTab()
2474 * @uses htmlentities()
2475 * @param array $tabs one element per tab
2476 * @param string $tag_id id used for the html-tag
2477 * @return string html-code for tab-navigation
2479 function PMA_getTabs( $tabs, $tag_id = 'topmenu' ) {
2480 $tab_navigation =
2481 '<div id="' . htmlentities( $tag_id ) . 'container">' . "\n"
2482 .'<ul id="' . htmlentities( $tag_id ) . '">' . "\n";
2484 foreach ( $tabs as $tab ) {
2485 $tab_navigation .= '<li>' . PMA_getTab( $tab ) . '</li>' . "\n";
2488 $tab_navigation .=
2489 '</ul>' . "\n"
2490 .'<div class="clearfloat"></div>'
2491 .'</div>' . "\n";
2493 return $tab_navigation;
2498 * Displays a link, or a button if the link's URL is too large, to
2499 * accommodate some browsers' limitations
2501 * @param string the URL
2502 * @param string the link message
2503 * @param mixed $tag_params string: js confirmation
2504 * array: additional tag params (f.e. style="")
2505 * @param boolean $new_form we set this to FALSE when we are already in
2506 * a form, to avoid generating nested forms
2508 * @return string the results to be echoed or saved in an array
2510 function PMA_linkOrButton($url, $message, $tag_params = array(), $new_form = TRUE, $strip_img = FALSE, $target = '')
2512 if ( ! is_array( $tag_params ) )
2514 $tmp = $tag_params;
2515 $tag_params = array();
2516 if ( ! empty( $tmp ) )
2518 $tag_params['onclick'] = 'return confirmLink(this, \'' . $tmp . '\')';
2520 unset( $tmp );
2522 if ( ! empty( $target ) ) {
2523 $tag_params['target'] = htmlentities( $target );
2526 $tag_params_strings = array();
2527 foreach( $tag_params as $par_name => $par_value ) {
2528 // htmlentities() only on non javascript
2529 $par_value = substr( $par_name,0 ,2 ) == 'on' ? $par_value : htmlentities( $par_value );
2530 $tag_params_strings[] = $par_name . '="' . $par_value . '"';
2533 // previously the limit was set to 2047, it seems 1000 is better
2534 if (strlen($url) <= 1000) {
2535 $ret = '<a href="' . $url . '" ' . implode( ' ', $tag_params_strings ) . '>' . "\n"
2536 . ' ' . $message . '</a>' . "\n";
2538 else {
2539 // no spaces (linebreaks) at all
2540 // or after the hidden fields
2541 // IE will display them all
2543 // add class=link to submit button
2544 if ( empty( $tag_params['class'] ) ) {
2545 $tag_params['class'] = 'link';
2547 $url = str_replace('&amp;', '&', $url);
2548 $url_parts = parse_url($url);
2549 $query_parts = explode('&', $url_parts['query']);
2550 if ($new_form) {
2551 $ret = '<form action="' . $url_parts['path'] . '" class="link"'
2552 . ' method="post"' . $target . ' style="display: inline;">';
2553 $subname_open = '';
2554 $subname_close = '';
2555 $submit_name = '';
2556 } else {
2557 $query_parts[] = 'redirect=' . $url_parts['path'];
2558 if ( empty( $GLOBALS['subform_counter'] ) ) {
2559 $GLOBALS['subform_counter'] = 0;
2561 $GLOBALS['subform_counter']++;
2562 $ret = '';
2563 $subname_open = 'subform[' . $GLOBALS['subform_counter'] . '][';
2564 $subname_close = ']';
2565 $submit_name = ' name="usesubform[' . $GLOBALS['subform_counter'] . ']"';
2567 foreach ($query_parts AS $query_pair) {
2568 list($eachvar, $eachval) = explode('=', $query_pair);
2569 $ret .= '<input type="hidden" name="' . $subname_open . $eachvar . $subname_close . '" value="' . htmlspecialchars(urldecode($eachval)) . '" />';
2570 } // end while
2572 if (stristr($message, '<img')) {
2573 if ($strip_img) {
2574 $message = trim( strip_tags( $message ) );
2575 $ret .= '<input type="submit"' . $submit_name . ' ' . implode( ' ', $tag_params_strings )
2576 . ' value="' . htmlspecialchars($message) . '" />';
2577 } else {
2578 $ret .= '<input type="image"' . $submit_name . ' ' . implode( ' ', $tag_params_strings )
2579 . ' src="' . preg_replace('°^.*\ssrc="([^"]*)".*$°si', '\1', $message) . '"'
2580 . ' value="' . htmlspecialchars(preg_replace('°^.*\salt="([^"]*)".*$°si', '\1', $message)) . '" />';
2582 } else {
2583 $message = trim( strip_tags( $message ) );
2584 $ret .= '<input type="submit"' . $submit_name . ' ' . implode( ' ', $tag_params_strings )
2585 . ' value="' . htmlspecialchars($message) . '" />';
2587 if ($new_form) {
2588 $ret .= '</form>';
2590 } // end if... else...
2592 return $ret;
2593 } // end of the 'PMA_linkOrButton()' function
2597 * Returns a given timespan value in a readable format.
2599 * @param int the timespan
2601 * @return string the formatted value
2603 function PMA_timespanFormat($seconds)
2605 $return_string = '';
2606 $days = floor($seconds / 86400);
2607 if ($days > 0) {
2608 $seconds -= $days * 86400;
2610 $hours = floor($seconds / 3600);
2611 if ($days > 0 || $hours > 0) {
2612 $seconds -= $hours * 3600;
2614 $minutes = floor($seconds / 60);
2615 if ($days > 0 || $hours > 0 || $minutes > 0) {
2616 $seconds -= $minutes * 60;
2618 return sprintf($GLOBALS['timespanfmt'], (string)$days, (string)$hours, (string)$minutes, (string)$seconds);
2622 * Takes a string and outputs each character on a line for itself. Used mainly for horizontalflipped display mode.
2623 * Takes care of special html-characters.
2624 * Fulfills todo-item http://sourceforge.net/tracker/index.php?func=detail&aid=544361&group_id=23067&atid=377411
2626 * @param string The string
2627 * @param string The Separator (defaults to "<br />\n")
2629 * @access public
2630 * @author Garvin Hicking <me@supergarv.de>
2631 * @return string The flipped string
2633 function PMA_flipstring($string, $Separator = "<br />\n") {
2634 $format_string = '';
2635 $charbuff = false;
2637 for ($i = 0; $i < strlen($string); $i++) {
2638 $char = $string{$i};
2639 $append = false;
2641 if ($char == '&') {
2642 $format_string .= $charbuff;
2643 $charbuff = $char;
2644 $append = true;
2645 } elseif (!empty($charbuff)) {
2646 $charbuff .= $char;
2647 } elseif ($char == ';' && !empty($charbuff)) {
2648 $format_string .= $charbuff;
2649 $charbuff = false;
2650 $append = true;
2651 } else {
2652 $format_string .= $char;
2653 $append = true;
2656 if ($append && ($i != strlen($string))) {
2657 $format_string .= $Separator;
2661 return $format_string;
2666 * Function added to avoid path disclosures.
2667 * Called by each script that needs parameters, it displays
2668 * an error message and, by default, stops the execution.
2670 * Not sure we could use a strMissingParameter message here,
2671 * would have to check if the error message file is always available
2673 * @param array The names of the parameters needed by the calling
2674 * script.
2675 * @param boolean Stop the execution?
2676 * (Set this manually to FALSE in the calling script
2677 * until you know all needed parameters to check).
2679 * @access public
2680 * @author Marc Delisle (lem9@users.sourceforge.net)
2682 function PMA_checkParameters($params, $die = TRUE) {
2683 global $PHP_SELF;
2685 $reported_script_name = basename($PHP_SELF);
2686 $found_error = FALSE;
2687 $error_message = '';
2689 foreach ($params AS $param) {
2690 if (!isset($GLOBALS[$param])) {
2691 $error_message .= $reported_script_name . ': Missing parameter: ' . $param . ' <a href="./Documentation.html#faqmissingparameters" target="documentation"> (FAQ 2.8)</a><br />';
2692 $found_error = TRUE;
2695 if ($found_error) {
2696 require_once('./libraries/header_meta_style.inc.php');
2697 echo '</head><body><p>' . $error_message . '</p></body></html>';
2698 if ($die) {
2699 exit();
2702 } // end function
2704 // Kanji encoding convert feature appended by Y.Kawada (2002/2/20)
2705 if (@function_exists('mb_convert_encoding')
2706 && strpos(' ' . $lang, 'ja-')
2707 && file_exists('./libraries/kanji-encoding.lib.php')) {
2708 require_once('./libraries/kanji-encoding.lib.php');
2709 define('PMA_MULTIBYTE_ENCODING', 1);
2710 } // end if
2713 * Function to generate unique condition for specified row.
2715 * @param resource handle for current query
2716 * @param integer number of fields
2717 * @param array meta information about fields
2718 * @param array current row
2720 * @access public
2721 * @author Michal Cihar (michal@cihar.com)
2722 * @return string calculated condition
2724 function PMA_getUvaCondition($handle, $fields_cnt, $fields_meta, $row) {
2726 $primary_key = '';
2727 $unique_key = '';
2728 $uva_nonprimary_condition = '';
2730 for ($i = 0; $i < $fields_cnt; ++$i) {
2731 $field_flags = PMA_DBI_field_flags($handle, $i);
2732 $meta = $fields_meta[$i];
2733 // do not use an alias in a condition
2734 $column_for_condition = $meta->name;
2735 if (isset($analyzed_sql[0]['select_expr']) && is_array($analyzed_sql[0]['select_expr'])) {
2736 foreach ($analyzed_sql[0]['select_expr'] AS $select_expr_position => $select_expr) {
2737 $alias = $analyzed_sql[0]['select_expr'][$select_expr_position]['alias'];
2738 if (!empty($alias)) {
2739 $true_column = $analyzed_sql[0]['select_expr'][$select_expr_position]['column'];
2740 if ($alias == $meta->name) {
2741 $column_for_condition = $true_column;
2742 } // end if
2743 } // end if
2744 } // end while
2747 // to fix the bug where float fields (primary or not)
2748 // can't be matched because of the imprecision of
2749 // floating comparison, use CONCAT
2750 // (also, the syntax "CONCAT(field) IS NULL"
2751 // that we need on the next "if" will work)
2752 if ($meta->type == 'real') {
2753 $condition = ' CONCAT(' . PMA_backquote($column_for_condition) . ') ';
2754 } else {
2755 // string and blob fields have to be converted using
2756 // the system character set (always utf8) since
2757 // mysql4.1 can use different charset for fields.
2758 if (PMA_MYSQL_INT_VERSION >= 40100 && ($meta->type == 'string' || $meta->type == 'blob')) {
2759 $condition = ' CONVERT(' . PMA_backquote($column_for_condition) . ' USING utf8) ';
2760 } else {
2761 $condition = ' ' . PMA_backquote($column_for_condition) . ' ';
2763 } // end if... else...
2765 if (!isset($row[$i]) || is_null($row[$i])) {
2766 $condition .= 'IS NULL AND';
2767 } else {
2768 // timestamp is numeric on some MySQL 4.1
2769 if ($meta->numeric && $meta->type != 'timestamp') {
2770 $condition .= '= ' . $row[$i] . ' AND';
2771 } elseif ($meta->type == 'blob'
2772 // hexify only if this is a true not empty BLOB
2773 && stristr($field_flags, 'BINARY')
2774 && !empty($row[$i])) {
2775 // use a CAST if possible, to avoid problems
2776 // if the field contains wildcard characters % or _
2777 if (PMA_MYSQL_INT_VERSION < 40002) {
2778 $condition .= 'LIKE 0x' . bin2hex($row[$i]). ' AND';
2779 } else {
2780 $condition .= '= CAST(0x' . bin2hex($row[$i]). ' AS BINARY) AND';
2782 } else {
2783 $condition .= '= \'' . PMA_sqlAddslashes($row[$i], FALSE, TRUE) . '\' AND';
2786 if ($meta->primary_key > 0) {
2787 $primary_key .= $condition;
2788 } else if ($meta->unique_key > 0) {
2789 $unique_key .= $condition;
2791 $uva_nonprimary_condition .= $condition;
2792 } // end for
2794 // Correction uva 19991216: prefer primary or unique keys
2795 // for condition, but use conjunction of all values if no
2796 // primary key
2797 if ($primary_key) {
2798 $uva_condition = $primary_key;
2799 } else if ($unique_key) {
2800 $uva_condition = $unique_key;
2801 } else {
2802 $uva_condition = $uva_nonprimary_condition;
2805 return preg_replace('|\s?AND$|', '', $uva_condition);
2806 } // end function
2809 * Function to generate unique condition for specified row.
2811 * @param string name of button element
2812 * @param string class of button element
2813 * @param string name of image element
2814 * @param string text to display
2815 * @param string image to display
2817 * @access public
2818 * @author Michal Cihar (michal@cihar.com)
2820 function PMA_buttonOrImage($button_name, $button_class, $image_name, $text, $image) {
2821 global $pmaThemeImage, $propicon;
2823 /* Opera has trouble with <input type="image"> */
2824 /* IE has trouble with <button> */
2825 if (PMA_USR_BROWSER_AGENT != 'IE') {
2826 echo '<button class="' . $button_class . '" type="submit" name="' . $button_name . '" value="' . $text . '" title="' . $text . '">' . "\n"
2827 . '<img class="icon" src="' . $pmaThemeImage . $image . '" title="' . $text . '" alt="' . $text . '" width="16" height="16" />' . (($propicon == 'both') ? '&nbsp;' . $text : '') . "\n"
2828 . '</button>' . "\n";
2829 } else {
2830 echo '<input type="image" name="' . $image_name . '" value="' .$text . '" title="' . $text . '" src="' . $pmaThemeImage . $image . '" />' . (($propicon == 'both') ? '&nbsp;' . $text : '') . "\n";
2832 } // end function
2835 * Generate a pagination selector for browsing resultsets
2837 * @param string URL for the JavaScript
2838 * @param string Number of rows in the pagination set
2839 * @param string current page number
2840 * @param string number of total pages
2841 * @param string If the number of pages is lower than this
2842 * variable, no pages will be ommitted in
2843 * pagination
2844 * @param string How many rows at the beginning should always
2845 * be shown?
2846 * @param string How many rows at the end should always
2847 * be shown?
2848 * @param string Percentage of calculation page offsets to
2849 * hop to a next page
2850 * @param string Near the current page, how many pages should
2851 * be considered "nearby" and displayed as
2852 * well?
2854 * @access public
2855 * @author Garvin Hicking (pma@supergarv.de)
2857 function PMA_pageselector($url, $rows, $pageNow = 1, $nbTotalPage = 1, $showAll = 200, $sliceStart = 5, $sliceEnd = 5, $percent = 20, $range = 10) {
2858 $gotopage = $GLOBALS['strPageNumber']
2859 . ' <select name="goToPage" onchange="goToUrl(this, \'' . $url . '\');">' . "\n";
2860 if ($nbTotalPage < $showAll) {
2861 $pages = range(1, $nbTotalPage);
2862 } else {
2863 $pages = array();
2865 // Always show first X pages
2866 for ($i = 1; $i <= $sliceStart; $i++) {
2867 $pages[] = $i;
2870 // Always show last X pages
2871 for ($i = $nbTotalPage - $sliceEnd; $i <= $nbTotalPage; $i++) {
2872 $pages[] = $i;
2875 // garvin: Based on the number of results we add the specified $percent percentate to each page number,
2876 // so that we have a representing page number every now and then to immideately jump to specific pages.
2877 // As soon as we get near our currently chosen page ($pageNow - $range), every page number will be
2878 // shown.
2879 $i = $sliceStart;
2880 $x = $nbTotalPage - $sliceEnd;
2881 $met_boundary = false;
2882 while($i <= $x) {
2883 if ($i >= ($pageNow - $range) && $i <= ($pageNow + $range)) {
2884 // If our pageselector comes near the current page, we use 1 counter increments
2885 $i++;
2886 $met_boundary = true;
2887 } else {
2888 // We add the percentate increment to our current page to hop to the next one in range
2889 $i = $i + floor($nbTotalPage / $percent);
2891 // Make sure that we do not cross our boundaries.
2892 if ($i > ($pageNow - $range) && !$met_boundary) {
2893 $i = $pageNow - $range;
2897 if ($i > 0 && $i <= $x) {
2898 $pages[] = $i;
2902 // Since because of ellipsing of the current page some numbers may be double,
2903 // we unify our array:
2904 sort($pages);
2905 $pages = array_unique($pages);
2908 foreach($pages AS $i) {
2909 if ($i == $pageNow) {
2910 $selected = 'selected="selected" style="font-weight: bold"';
2911 } else {
2912 $selected = '';
2914 $gotopage .= ' <option ' . $selected . ' value="' . (($i - 1) * $rows) . '">' . $i . '</option>' . "\n";
2917 $gotopage .= ' </select>';
2919 return $gotopage;
2920 } // end function
2923 function PMA_generateFieldSpec($name, $type, $length, $attribute, $collation, $null, $default, $default_current_timestamp, $extra, $comment='', &$field_primary, $index, $default_orig = FALSE) {
2925 // $default_current_timestamp has priority over $default
2926 // TODO: on the interface, some js to clear the default value
2927 // when the default current_timestamp is checked
2929 $query = PMA_backquote($name) . ' ' . $type;
2931 if ($length != ''
2932 && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT)$@i', $type)) {
2933 $query .= '(' . $length . ')';
2936 if ($attribute != '') {
2937 $query .= ' ' . $attribute;
2940 if (PMA_MYSQL_INT_VERSION >= 40100 && !empty($collation) && $collation != 'NULL' && preg_match('@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', $type)) {
2941 $query .= PMA_generateCharsetQueryPart($collation);
2944 if (!($null === FALSE)) {
2945 if (!empty($null)) {
2946 $query .= ' NOT NULL';
2947 } else {
2948 $query .= ' NULL';
2952 if ($default_current_timestamp && strpos(' ' . strtoupper($type),'TIMESTAMP') == 1) {
2953 $query .= ' DEFAULT CURRENT_TIMESTAMP';
2954 // 0 is empty in PHP
2955 } elseif (!empty($default) || $default == '0' || $default != $default_orig) {
2956 if (strtoupper($default) == 'NULL') {
2957 $query .= ' DEFAULT NULL';
2958 } else {
2959 $query .= ' DEFAULT \'' . PMA_sqlAddslashes($default) . '\'';
2963 if (!empty($extra)) {
2964 $query .= ' ' . $extra;
2965 // An auto_increment field must be use as a primary key
2966 if ($extra == 'AUTO_INCREMENT' && isset($field_primary)) {
2967 $primary_cnt = count($field_primary);
2968 for ($j = 0; $j < $primary_cnt && $field_primary[$j] != $index; $j++) {
2969 // void
2970 } // end for
2971 if (isset($field_primary[$j]) && $field_primary[$j] == $index) {
2972 $query .= ' PRIMARY KEY';
2973 unset($field_primary[$j]);
2974 } // end if
2975 } // end if (auto_increment)
2977 if (PMA_MYSQL_INT_VERSION >= 40100 && !empty($comment)) {
2978 $query .= " COMMENT '" . PMA_sqlAddslashes($comment) . "'";
2980 return $query;
2981 } // end function
2983 function PMA_generateAlterTable($oldcol, $newcol, $type, $length, $attribute, $collation, $null, $default, $default_current_timestamp, $extra, $comment='', $default_orig) {
2984 $empty_a = array();
2985 return PMA_backquote($oldcol) . ' ' . PMA_generateFieldSpec($newcol, $type, $length, $attribute, $collation, $null, $default, $default_current_timestamp, $extra, $comment, $empty_a, -1, $default_orig);
2986 } // end function
2988 function PMA_userDir($dir) {
2989 global $cfg;
2991 if (substr($dir, -1) != '/') {
2992 $dir .= '/';
2995 return str_replace('%u', $cfg['Server']['user'], $dir);
2999 * returns html code for db link to default db page
3001 * @uses $GLOBALS['cfg']['DefaultTabDatabase']
3002 * @uses $GLOBALS['db']
3003 * @uses $GLOBALS['strJumpToDB']
3004 * @uses PMA_generate_common_url()
3005 * @param string $database
3006 * @return string html link to default db page
3008 function PMA_getDbLink( $database = NULL ) {
3010 if ( empty( $database ) ) {
3011 if ( empty( $GLOBALS['db'] ) ) {
3012 return '';
3014 $database = $GLOBALS['db'];
3017 return '<a href="' . $GLOBALS['cfg']['DefaultTabDatabase'] . '?' . PMA_generate_common_url( $database ) . '"'
3018 .' title="' . sprintf( $GLOBALS['strJumpToDB'], htmlspecialchars( $database ) ) . '">'
3019 .htmlspecialchars( $database ) . '</a>';
3022 } // end if: minimal common.lib needed?