From a6bd44eeeb1dca803af98a0f7d097473c3385c70 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Sun, 19 Aug 2007 12:02:39 +0000 Subject: [PATCH 01/79] 2.11.0 --- Documentation.html | 4 ++-- README | 4 ++-- libraries/Config.class.php | 2 +- translators.html | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation.html b/Documentation.html index 7ebb8355f..5b2aac4fe 100644 --- a/Documentation.html +++ b/Documentation.html @@ -11,7 +11,7 @@ - phpMyAdmin 2.11.0-rc2 - Documentation + phpMyAdmin 2.11.0 - Documentation @@ -33,7 +33,7 @@
  • Glossary
  • -

    phpMyAdmin 2.11.0-rc2 Documentation

    +

    phpMyAdmin 2.11.0 Documentation

    -

    phpMyAdmin 2.11.0-rc2 official translators list

    +

    phpMyAdmin 2.11.0 official translators list

    Here is the list of the "official translators" of phpMyAdmin.

    From 25b8da6488338e44fd238abccf4e626119116898 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Tue, 21 Aug 2007 20:44:38 +0000 Subject: [PATCH 02/79] 2.11.0 today --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 833dfe157..23ab760f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ phpMyAdmin - ChangeLog $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ -2.11.0.0 (not yet released) +2.11.0.0 (2007-08-21) + [import] support handling of DELIMITER to mimic mysql CLI, thanks to fb1 + improved PHP 6 compatibility From 0a6a8a926662fc6ff6c5ba029d8494bfe0e04484 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Mon, 3 Sep 2007 11:08:58 +0000 Subject: [PATCH 03/79] remove work in progress --- libraries/Sql.class.php | 2978 --------------------------------------- 1 file changed, 2978 deletions(-) delete mode 100644 libraries/Sql.class.php diff --git a/libraries/Sql.class.php b/libraries/Sql.class.php deleted file mode 100644 index 5b037c184..000000000 --- a/libraries/Sql.class.php +++ /dev/null @@ -1,2978 +0,0 @@ -__construct($sql); - } - - /** - * Constructor - * - * @access public - * @uses PMA_Sql::$_raw to set it - * @uses PMA_Sql::$_tokens to set it - * @param string SQL query - */ - function __construct($sql) - { - $this->_raw = $sql; - - $this->_tokens['puncts']['queryend'] = ';'; - $this->_tokens['puncts']['qualifier'] = '.'; - $this->_tokens['puncts']['listsep'] = ','; - //$this->_tokens['puncts']['level_plus'] = '('; - //$this->_tokens['puncts']['level_minus'] = ')'; - $this->_tokens['puncts']['minus'] = '-'; - $this->_tokens['puncts']['colon'] = ':'; - $this->_tokens['puncts']['negator'] = '!'; - $this->_tokens['puncts']['questionmark'] = '?'; - $this->_tokens['puncts']['divisor'] = '/'; - $this->_tokens['puncts']['potenz'] = '^'; - $this->_tokens['puncts']['level_minus'] = '~'; - $this->_tokens['puncts']['escape'] = '\\'; - $this->_tokens['puncts']['m'] = '*'; - $this->_tokens['puncts']['and'] = '&'; - $this->_tokens['puncts']['percent'] = '%'; - $this->_tokens['puncts']['plus'] = '+'; - $this->_tokens['puncts']['less'] = '<'; - $this->_tokens['puncts']['equal'] = '='; - $this->_tokens['puncts']['greater'] = '>'; - $this->_tokens['puncts']['or'] = '|'; - - $this->_tokens['punctpairs']['NEQ'] = '!='; - $this->_tokens['punctpairs']['AND'] = '&&'; - $this->_tokens['punctpairs']['COL'] = ':='; - $this->_tokens['punctpairs']['SHIFTL'] = '<<'; - $this->_tokens['punctpairs']['LTE'] = '<='; - $this->_tokens['punctpairs']['NEQ2'] = '<=>'; - $this->_tokens['punctpairs']['NEQ3'] = '<>'; - $this->_tokens['punctpairs']['GTE'] = '>='; - $this->_tokens['punctpairs']['SHIFTR'] = '>>'; - $this->_tokens['punctpairs']['OR'] = '||'; - - //$this->_tokens['digit']['floatdecimal'] = '.'; - //$this->_tokens['digit']['hexset'] = 'x'; - - $this->_tokens['brackets']['round_open'] = '('; - $this->_tokens['brackets']['round_close'] = ')'; - $this->_tokens['brackets']['square_open'] = '['; - $this->_tokens['brackets']['square_close'] = ']'; - $this->_tokens['brackets']['brace_open'] = '{'; - $this->_tokens['brackets']['brace_close'] = '}'; - - $this->_tokens['quotes']['single'] = "'"; - $this->_tokens['quotes']['double'] = '"'; - $this->_tokens['quotes']['backtick'] = '`'; - } - - /** - * everytime called it adds an array element to the array which holds the parse info - * usally called for every token found in a sql query by PMA_Sql::parse() - * - * @access protected - * @uses PMA_Sql::$_parsed - * @uses PMA_Sql::$_parsed_size - * @uses DEBUG_TIMING - * @uses defined() - * @uses microtime() - * @uses $GLOBALS['timer'] - * @param string $type type of the token - * @param string $data content of this token - */ - function _addParseInfo($type, $data) - { - $this->_parsed[$this->_parsed_size] = array('type' => $type, 'data' => $data); - - if (defined('DEBUG_TIMING')) { - $this->_parsed[$this->_parsed_size]['time'] = $GLOBALS['timer']; - $GLOBALS['timer'] = microtime(); - } - - $this->_parsed_size++; - } // end of the "_addParseInfo()" function - - /** - * Reset the error variable for the SQL parser - * Added, Robbat2 - 13 Janurary 2003, 2:59PM - * - * @access public - * @uses PMA_Sql::$_error_message to set it - */ - function resetError() - { - $this->_error_message = ''; - } - - /** - * Get the contents of the error variable for the SQL parser - * Added, Robbat2 - 13 Janurary 2003, 2:59PM - * - * @return string Error string from SQL parser - * @access public - * @uses PMA_Sql::$_error_message to read it - */ - function getErrorMessage() - { - return $this->_error_message; - } - - /** - * Check if the SQL parser hit an error - * Added, Robbat2 - 13 Janurary 2003, 2:59PM - * - * @access public - * @uses PMA_Sql::$_error_message to check it - * @return boolean error state - */ - function isError() - { - return ! empty($this->_error_message); - } - - /** - * Set an error message for the system - * Added, Robbat2 - 13 Janurary 2003, 2:59PM - * - * @uses PMA_Sql::$_error_message to set it - * @uses PMA_Sql::$_raw to read it - * @uses $GLOBALS['strSQLParserUserError'] - * @uses htmlspecialchars() - * @access protected - * @scope SQL Parser internal - * @param string $message The error message - */ - function _throwError($message) - { - $this->_error_message = '

    '.$GLOBALS['strSQLParserUserError'] . '

    ' . "\n" - . '
    ' . "\n"
    -            . 'ERROR: ' . $message . "\n"
    -            . 'SQL: ' . htmlspecialchars($this->_raw) .  "\n"
    -            . '
    ' . "\n"; - } // end of the "_throwError()" function - - /** - * generate the bug report and ncludes compressed debug info - * - * @access public - * @uses PMA_Sql::$_raw to read it - * @uses PMA_Sql::$_error_message to set it - * @uses PMA_MYSQL_STR_VERSION - * @uses PMA_USR_OS - * @uses PMA_USR_BROWSER_AGENT - * @uses PMA_VERSION - * @uses PMA_PHP_STR_VERSION - * @uses PHP_OS - * @uses $GLOBALS['strSQLParserBugMessage'] - * @uses $GLOBALS['strBeginCut'] - * @uses $GLOBALS['strEndCut'] - * @uses $GLOBALS['strBeginRaw'] - * @uses $GLOBALS['strEndRaw'] - * @uses $GLOBALS['lang'] - * @uses htmlspecialchars() - * @uses function_exists() - * @uses gzcompress() - * @uses preg_replace() - * @uses chunk_split() - * @uses base64_encode() - * @param string $message The error message - */ - function generateBugReport($message) - { - $debugstr = 'ERROR: ' . $message . "\n"; - $debugstr .= 'SVN: $Id$' . "\n"; - $debugstr .= 'MySQL: ' . PMA_MYSQL_STR_VERSION . "\n"; - $debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' ' . PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n"; - $debugstr .= 'PMA: ' . PMA_VERSION . "\n"; - $debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n"; - $debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n"; - $debugstr .= 'SQL: ' . htmlspecialchars($this->_raw); - - $encodedstr = $debugstr; - if (@function_exists('gzcompress')) { - $encodedstr = gzcompress($debugstr, 9); - } - $encodedstr = preg_replace("/(\015\012)|(\015)|(\012)/", '
    ' . "\n", - chunk_split(base64_encode($encodedstr))); - - $this->_error_message .= $GLOBALS['strSQLParserBugMessage'] . '
    ' . "\n" - . '----' . $GLOBALS['strBeginCut'] . '----' . '
    ' . "\n" - . $encodedstr . "\n" - . '----' . $GLOBALS['strEndCut'] . '----' . '
    ' . "\n"; - - $this->_error_message .= '----' . $GLOBALS['strBeginRaw'] . '----
    ' . "\n" - . '
    ' . "\n"
    -             . $debugstr
    -             . '
    ' . "\n" - . '----' . $GLOBALS['strEndRaw'] . '----
    ' . "\n"; - } // end of the "generateBugReport()" function - - /** - * Parses the SQL queries - * - * @todo split into smaller methods - * @access public - * @global array The current PMA configuration - * @global array MySQL column attributes - * @global array MySQL reserved words - * @global array MySQL column types - * @global array MySQL function names - * @global integer MySQL column attributes count - * @global integer MySQL reserved words count - * @global integer MySQL column types count - * @global integer MySQL function names count - * @global array List of available character sets - * @global array List of available collations - * @global integer Character sets count - * @global integer Collations count - * @return mixed Most of times, nothing... - */ - function parse() - { - global - $cfg, - $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, - $PMA_SQPdata_column_type, $PMA_SQPdata_function_name, - $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, - $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt, - $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt, - $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, - $mysql_collations_count; - - $sql = $this->_raw; - - // rabus: Convert all line feeds to Unix style - $sql = str_replace("\r\n", "\n", $sql); - $sql = str_replace("\r", "\n", $sql); - - $this->_parsed = array(); - $this->_parsed_size = 0; - - // there is nothing to do if empty or only spaces - if (PMA_strlen(trim($sql)) === 0) { - return $this->_parsed; - } - // but we will not cut off spaces if there are not only spaces - $sql_len = PMA_strlen($sql); - - $bracket_list = implode($this->_tokens['brackets']); - $allpunct_list = implode($this->_tokens['puncts']); - $quote_list = implode($this->_tokens['quotes']); - - $punctpairs_count = count($this->_tokens['punctpairs']); - - $sql_pos = 0; - while ($sql_pos < $sql_len) { - $c = PMA_substr($sql, $sql_pos, 1); - - // Checks for white space - if (PMA_STR_isSpace($c)) { - $sql_pos++; - continue; - } - - if (($c == "\n")) { - $sql_pos++; - $this->_addParseInfo('white_newline', ''); - continue; - } - - $token_start = $sql_pos; - - // Checks for comment lines. - // MySQL style # - // C style /* */ - // ANSI style -- - if (($c == '#') - || (($sql_pos + 1 < $sql_len) && (PMA_substr($sql, $sql_pos, 2) == '/*')) - || (($sql_pos + 2 == $sql_len) && ($c == '-') && (PMA_substr($sql, $sql_pos + 1, 1) == '-')) - || (($sql_pos + 2 < $sql_len) && ($c == '-') && (PMA_substr($sql, $sql_pos + 1, 1) == '-') && ((PMA_substr($sql, $sql_pos + 2, 1) <= ' ')))) { - $sql_pos++; - $pos = 0; - $type = 'bad'; - switch ($c) { - case '#': - $type = 'mysql'; - case '-': - $type = 'ansi'; - $pos = $GLOBALS['PMA_strpos']($sql, "\n", $sql_pos); - break; - case '/': - $type = 'c'; - $pos = $GLOBALS['PMA_strpos']($sql, '*/', $sql_pos); - $pos += 2; - break; - default: - break; - } // end switch - $sql_pos = ($pos < $sql_pos) ? $sql_len : $pos; - $this->_addParseInfo('comment_' . $type, - PMA_substr($sql, $token_start, $sql_pos - $token_start)); - continue; - } // end if - - // Checks for something inside quotation marks - if (PMA_STR_strInStr($c, $quote_list)) { - // some examples of valid quotes: - // "'" -> ' - // "\"" -> " - // 'blah''blaj' -> blah'blaj - // """" -> " - - $startquotepos = $sql_pos; - $quotetype = $c; - $sql_pos++; - $escaped = FALSE; - $escaped_escaped = FALSE; - $pos = $sql_pos; - $oldpos = 0; - do { - $oldpos = $pos; - $pos = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1; - // ($pos === FALSE) - if ($pos < 0) { - $debugstr = $GLOBALS['strSQPBugUnclosedQuote'] . ' @ ' . $startquotepos. "\n" - . 'STR: ' . htmlspecialchars($quotetype); - $this->_throwError($debugstr); - return array(); - } - - // If the quote is the first character, it can't be - // escaped, so don't do the rest of the code - if ($pos == 0) { - break; - } - - // Checks for MySQL escaping using a \ - // And checks for ANSI escaping using the $quotetype character - if (($pos < $sql_len) && PMA_STR_charIsEscaped($sql, $pos)) { - $pos ++; - continue; - } elseif (($pos + 1 < $sql_len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) { - $pos = $pos + 2; - continue; - } else { - break; - } - } while ($sql_len > $pos); // end do - - $sql_pos = $pos; - $sql_pos++; - $type = 'quote_'; - switch ($quotetype) { - case '\'': - $type .= 'single'; - break; - case '"': - $type .= 'double'; - break; - case '`': - $type .= 'backtick'; - break; - default: - break; - } // end switch - $this->_addParseInfo($type, - PMA_substr($sql, $token_start, $sql_pos - $token_start)); - continue; - } - - // Checks for brackets - if (PMA_STR_strInStr($c, $bracket_list)) { - // All bracket tokens are only one item long - $sql_pos++; - $type = 'punct_bracket_'; - if (PMA_STR_strInStr($c, '([{')) { - $type .= 'open'; - } else { - $type .= 'close'; - } - - if (PMA_STR_strInStr($c, '()')) { - $type .= '_round'; - } elseif (PMA_STR_strInStr($c, '[]')) { - $type .= '_square'; - } else { - $type .= '_curly'; - } - - $this->_addParseInfo($type, $c); - continue; - } - - // Checks for identifier (alpha or numeric) - if (PMA_STR_isSqlIdentifier($c, FALSE) || $c == '@' || $c == '.' && PMA_STR_isDigit(PMA_substr($sql, $sql_pos + 1, 1))) { - $sql_pos ++; - - /** - * @todo a @ can also be present in expressions like - * FROM 'user'@'%' or TO 'user'@'%' - * in this case, the @ is wrongly marked as alpha_variable - */ - - $is_sql_variable = $c == '@'; - $is_digit = !$is_sql_variable && PMA_STR_isDigit($c); - $is_hex_digit = $is_digit && $c == '.' && $c == '0' && $sql_pos < $sql_len && PMA_substr($sql, $sql_pos, 1) == 'x'; - $is_float_digit = $c == '.'; - $is_float_digit_exponent = FALSE; - - // Nijel: Fast skip is especially needed for huge BLOB data, requires PHP at least 4.3.0: - if (PMA_PHP_INT_VERSION >= 40300) { - if ($is_hex_digit) { - $sql_pos++; - $pos = strspn($sql, '0123456789abcdefABCDEF', $sql_pos); - if ($pos > $sql_pos) { - $sql_pos = $pos; - } - unset($pos); - } elseif ($is_digit) { - $pos = strspn($sql, '0123456789', $sql_pos); - if ($pos > $sql_pos) { - $sql_pos = $pos; - } - unset($pos); - } - } - - while (($sql_pos < $sql_len) - && PMA_STR_isSqlIdentifier(PMA_substr($sql, $sql_pos, 1), ($is_sql_variable || $is_digit))) { - $c2 = PMA_substr($sql, $sql_pos, 1); - if ($is_sql_variable && ($c2 == '.')) { - $sql_pos++; - continue; - } - if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) { - $sql_pos++; - if (!$is_float_digit) { - $is_float_digit = TRUE; - continue; - } else { - $debugstr = $GLOBALS['strSQPBugInvalidIdentifer'] . ' @ ' . ($token_start + 1) . "\n" - . 'STR: ' . htmlspecialchars(PMA_substr($sql, $token_start, $sql_pos - $token_start)); - $this->_throwError($debugstr); - return array(); - } - } - if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) { - if (!$is_float_digit_exponent) { - $is_float_digit_exponent = TRUE; - $is_float_digit = TRUE; - $sql_pos++; - continue; - } else { - $is_digit = FALSE; - $is_float_digit = FALSE; - } - } - if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) { - $sql_pos++; - continue; - } else { - $is_digit = FALSE; - $is_hex_digit = FALSE; - } - - $sql_pos++; - } // end while - - if ($is_digit) { - if ($is_float_digit) { - $type = 'digit_float'; - } elseif ($is_hex_digit) { - $type = 'digit_hex'; - } else { - $type = 'digit_integer'; - } - } else { - $type = 'alpha'; - if ($is_sql_variable != FALSE) { - $type .= '_variable'; - } - } // end if... else.... - $this->_addParseInfo($type, - PMA_substr($sql, $token_start, $sql_pos - $token_start)); - - continue; - } - - // Checks for punct - if (PMA_STR_strInStr($c, $allpunct_list)) { - while (($sql_pos < $sql_len) && PMA_STR_strInStr(PMA_substr($sql, $sql_pos, 1), $allpunct_list)) { - $sql_pos++; - } - $l = $sql_pos - $token_start; - if ($l == 1) { - $punct_data = $c; - } else { - $punct_data = PMA_substr($sql, $token_start, $l); - } - - // Special case, sometimes, althought two characters are - // adjectent directly, they ACTUALLY need to be seperate - $t_suffix = ''; - if ($l == 1) { - switch ($punct_data) { - case $this->_tokens['puncts']['queryend']: - $t_suffix = '_queryend'; - break; - case $this->_tokens['puncts']['qualifier']: - $t_suffix = '_qualifier'; - break; - case $this->_tokens['puncts']['listsep']: - $t_suffix = '_listsep'; - break; - default: - break; - } - } elseif (PMA_STR_binarySearchInArr($punct_data, $this->_tokens['punctpairs'], $punctpairs_count)) { - // Ok, we have one of the valid combined punct expressions - } else { - // Bad luck, lets split it up more - $first = $punct_data[0]; - $first2 = $punct_data[0] . $punct_data[1]; - $last2 = $punct_data[$l - 2] . $punct_data[$l - 1]; - $last = $punct_data[$l - 1]; - if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) { - $sql_pos = $token_start + 1; - $punct_data = $first; - } elseif ($last2 == '/*' || ($last2 == '--' && ($sql_pos == $sql_len || PMA_substr($sql, $sql_pos, 1) <= ' '))) { - $sql_pos -= 2; - $punct_data = PMA_substr($sql, $token_start, $sql_pos - $token_start); - } elseif (($last == '-') || ($last == '+') || ($last == '!')) { - $sql_pos--; - $punct_data = PMA_substr($sql, $token_start, $sql_pos - $token_start); - /** - * @todo for negation operator, split in 2 tokens ? - * "select x&~1 from t" - * becomes "select x & ~ 1 from t" ? - */ - - } elseif ($last != '~') { - $debugstr = $GLOBALS['strSQPBugUnknownPunctuation'] . ' @ ' . ($token_start + 1) . "\n" - . 'STR: ' . htmlspecialchars($punct_data); - $this->_throwError($debugstr); - return array(); - } - } // end if... elseif... else - $this->_addParseInfo('punct' . $t_suffix, $punct_data); - continue; - } - - // we reach this point only in case of error - $sql_pos++; - - // DEBUG - $debugstr = 'C1 C2 LEN: ' . $token_start . ' ' . $sql_pos . ' ' . $sql_len . "\n" - . 'STR: ' . PMA_substr($sql, $token_start, $sql_pos - $token_start) . "\n"; - $this->generateBugReport($debugstr); - return array(); - } // end while ($sql_pos < $sql_len) - - - if ($this->_parsed_size > 0) { - $t_next = $this->_parsed[0]['type']; - $t_prev = ''; - $t_bef_prev = ''; - $t_cur = ''; - $d_next = $this->_parsed[0]['data']; - $d_prev = ''; - $d_bef_prev = ''; - $d_cur = ''; - $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; - $d_prev_upper = ''; - $d_bef_prev_upper = ''; - $d_cur_upper = ''; - } - - foreach ($this->_parsed as $pos => $each_parsed) { -// for ($i = 0; $i < $this->_parsed_size; $i++) { - $t_bef_prev = $t_prev; - $t_prev = $t_cur; - $t_cur = $t_next; - $d_bef_prev = $d_prev; - $d_prev = $d_cur; - $d_cur = $d_next; - $d_bef_prev_upper = $d_prev_upper; - $d_prev_upper = $d_cur_upper; - $d_cur_upper = $d_next_upper; - if (($pos + 1) < $this->_parsed_size) { - $t_next = $this->_parsed[$pos + 1]['type']; - $d_next = $this->_parsed[$pos + 1]['data']; - $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; - } else { - $t_next = ''; - $d_next = ''; - $d_next_upper = ''; - } - - //DEBUG echo "[prev: ".$d_prev." ".$t_prev."][cur: ".$d_cur." ".$t_cur."][next: ".$d_next." ".$t_next."]
    "; - - if ($t_cur == 'alpha') { - $t_suffix = '_identifier'; - if (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) { - $t_suffix = '_identifier'; - } elseif (($t_next == 'punct_bracket_open_round') - && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_function_name, $PMA_SQPdata_function_name_cnt)) { - /** - * @todo 2005-10-16: in the case of a CREATE TABLE containing - * a TIMESTAMP, since TIMESTAMP() is also a function, it's - * found here and the token is wrongly marked as alpha_functionName. - * But we compensate for this when analysing for timestamp_not_null - * later in this script. - * - * Same applies to CHAR vs. CHAR() function. - */ - $t_suffix = '_functionName'; - /* There are functions which might be as well column types */ - if (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_type, $PMA_SQPdata_column_type_cnt)) { - } - } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_type, $PMA_SQPdata_column_type_cnt)) { - $t_suffix = '_columnType'; - - /** - * Temporary fix for BUG #621357 - * - * @todo FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER - */ - if ($d_cur_upper == 'SET' && $t_next != 'punct_bracket_open_round') { - $t_suffix = '_reservedWord'; - } - //END OF TEMPORARY FIX - - // CHARACTER is a synonym for CHAR, but can also be meant as - // CHARACTER SET. In this case, we have a reserved word. - if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') { - $t_suffix = '_reservedWord'; - } - - // experimental - // current is a column type, so previous must not be - // a reserved word but an identifier - // CREATE TABLE SG_Persons (first varchar(64)) - - //if ($this->_parsed[$pos-1]['type'] =='alpha_reservedWord') { - // $this->_parsed[$pos-1]['type'] = 'alpha_identifier'; - //} - } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_reserved_word, $PMA_SQPdata_reserved_word_cnt)) { - $t_suffix = '_reservedWord'; - } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_attrib, $PMA_SQPdata_column_attrib_cnt)) { - $t_suffix = '_columnAttrib'; - // INNODB is a MySQL table type, but in "SHOW INNODB STATUS", - // it should be regarded as a reserved word. - if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') { - $t_suffix = '_reservedWord'; - } - - if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') { - $t_suffix = '_reservedWord'; - } - // Binary as character set - if ($d_cur_upper == 'BINARY' && ( - ($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET') - || ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=') - || ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=') - || $d_prev_upper == 'CHARSET' - ) && PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, count($mysql_charsets))) { - $t_suffix = '_charset'; - } - } elseif (PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, $mysql_charsets_count) - || PMA_STR_binarySearchInArr($d_cur, $mysql_collations_flat, $mysql_collations_count) - || ($d_cur{0} == '_' && PMA_STR_binarySearchInArr(substr($d_cur, 1), $mysql_charsets, $mysql_charsets_count))) { - $t_suffix = '_charset'; - } else { - // Do nothing - } - // check if present in the list of forbidden words - if ($t_suffix == '_reservedWord' - && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt)) { - $this->_parsed['forbidden'] = TRUE; - } else { - $this->_parsed['forbidden'] = FALSE; - } - $this->_parsed['type'] .= $t_suffix; - } - } // end for - - // Stores the size of the array inside the array, as count() is a slow - // operation. - //$this->_parsed['len'] = $this->_parsed_size; - - // DEBUG echo 'After parsing
    '; print_r($this->_parsed); echo '
    '; - // Sends the data back - return $this->_parsed; - } // end of the "parse()" function - - /** - * returns SQL query analyzed - * - * @access public - * @uses PMA_Sql::$_analyzed - * @uses PMA_Sql::getAnalyzed() - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql - * @param string $sql the SQL query - * @return array PMA_Sql::$_analyzed - */ - function getAnalyzed($sql = null) - { - if (null !== $sql) { - $pma_sql = new PMA_Sql($sql); - return $pma_sql->getAnalyzed(); - } - - $this->analyzeIfRequired(); - - return $this->_analyzed; - } - - /** - * returns SQL query parsed - * - * @access public - * @uses PMA_Sql::$_parsed - * @uses PMA_Sql::getParsed() - * @uses PMA_Sql::parseIfRequired() - * @uses PMA_Sql - * @param string $sql the SQL query - * @return array PMA_Sql::$_parsed - */ - function getParsed($sql = null) - { - if (null !== $sql) { - $pma_sql = new PMA_Sql($sql); - return $pma_sql->getParsed(); - } - - $this->parseIfRequired(); - - return $this->_parsed; - } - - /** - * checks if the given field/column has attribute ON UPDATE CURRENT_TIMESTAMP - * - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to read - * @param string $field_name name of field/column to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean whether the field has ON UPDATE CURRENT TIMESTAMP - * @todo create a child class espacially for SHOW CREATE TABLE result? - * @todo this function should only be used by class PMA_Table or PMA_Field/Column - */ - function fieldIsOnUpdateCurrentTimestamp($field_name, $subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['create_table_fields'][$field_name]['on_update_current_timestamp'])) { - return true; - } - return false; - } - - /** - * checks if the given field/column is a TIMESTAMP that cannot be NULL - * - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to read - * @param string $field_name name of field/column to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean whether the field is of type TIMESTAMP and NOT NULL - * @todo create a child class espacially for SHOW CREATE TABLE result? - * @todo this function should only be used by class PMA_Table or PMA_Field/Column - */ - function fieldIsTimestampNotNull($field_name, $subquery = 0) - { - $this->analyzeIfRequired(); - - if (! empty($this->_analyzed[$subquery]['create_table_fields'][$field_name]['type']) - && $this->_analyzed[$subquery]['create_table_fields'][$field_name]['type'] == 'TIMESTAMP' - && $this->_analyzed[$subquery]['create_table_fields'][$field_name]['timestamp_not_null']) { - return true; - } - return false; - } - - /** - * checks if the given field/column has CURRENT TIMESTAMP as DEFAULT - * - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to read - * @param string $field_name name of field/column to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean whether field defaults to CURRENT TIMESTAMP - * @todo create a child class espacially for SHOW CREATE TABLE result? - * @todo this function should only be used by class PMA_Table or PMA_Field/Column - */ - function fieldIsDefaultCurrentTimestamp($field_name, $subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['create_table_fields'][$field_name]['default_current_timestamp'])) { - return true; - } - return false; - } - - /** - * returns the name for the given field/column - * - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to read - * @param integer $field_number number of field/column for which to return name - * @param integer $subquery which subquery to check, default 0 - * @return string name for the column - */ - function fieldGetName($field_number, $subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['select_expr'][$field_number]['column'])) { - return $this->_analyzed[$subquery]['select_expr'][$field_number]['column']; - } - - return false; - } - - /** - * check if SQL is SELECT - * - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean whether the SQL is a SELECT or not - */ - function isSelect($subquery = 0) - { - return isset($this->_analyzed[$subquery]['queryflags']['select_from']); - } - - function tableGetTrueName($reference = 0, $subquery = 0) - { - if (isset($this->_analyzed[$subquery]['table_ref'][$reference]['table_true_name'])) { - return $this->_analyzed[$subquery]['table_ref'][$reference]['table_true_name']; - } - - return false; - } - - /** - * analyze only if not already - * - * @uses PMA_Sql::$_analyzed to check if empty - * @uses PMA_Sql::analyze() if PMA_Sql::$_analyzed is empty - */ - function analyzeIfRequired() - { - if (empty($this->_analyzed)) { - $this->analyze(); - } - } - - /** - * parse only if not already - * - * @uses PMA_Sql::$_parsed to check if empty - * @uses PMA_Sql::parse() if PMA_Sql::$_parsed is empty - */ - function parseIfRequired() - { - if (empty($this->_parsed)) { - $this->parse(); - } - } - - /** - * Analyzes SQL queries - * - * db, table, column, alias - * ------------------------ - * - * Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays. - * - * The SELECT syntax (simplified) is - * - * SELECT - * select_expression,... - * [FROM [table_references] - * - * - * ['select_expr'] is filled with each expression, the key represents the - * expression position in the list (0-based) (so we don't lose track of - * multiple occurences of the same column). - * - * ['table_ref'] is filled with each table ref, same thing for the key. - * - * I create all sub-values empty, even if they are - * not present (for example no select_expression alias). - * - * There is a debug section at the end of loop #1, if you want to - * see the exact contents of select_expr and table_ref - * - * queryflags - * ---------- - * - * In $subresult, array 'queryflags' is filled, according to what we - * find in the query. - * - * Currently, those are generated: - * - * ['queryflags']['need_confirm'] = 1; if the query needs confirmation - * ['queryflags']['select_from'] = 1; if this is a real SELECT...FROM - * ['queryflags']['distinct'] = 1; for a DISTINCT - * ['queryflags']['union'] = 1; for a UNION - * ['queryflags']['join'] = 1; for a JOIN - * ['queryflags']['offset'] = 1; for the presence of OFFSET - * - * query clauses - * ------------- - * - * The select is splitted in those clauses: - * ['select_expr_clause'] - * ['from_clause'] - * ['group_by_clause'] - * ['order_by_clause'] - * ['having_clause'] - * ['where_clause'] - * - * The identifiers of the WHERE clause are put into the array - * ['where_clause_identifier'] - * - * For a SELECT, the whole query without the ORDER BY clause is put into - * ['unsorted_query'] - * - * foreign keys - * ------------ - * The CREATE TABLE may contain FOREIGN KEY clauses, so they get - * analyzed and ['foreign_keys'] is an array filled with - * the constraint name, the index list, - * the REFERENCES table name and REFERENCES index list, - * and ON UPDATE | ON DELETE clauses - * - * position_of_first_select - * ------------------------ - * - * The array index of the first SELECT we find. Will be used to - * insert a SQL_CALC_FOUND_ROWS. - * - * create_table_fields - * ------------------- - * - * For now, mostly used to detect the DEFAULT CURRENT_TIMESTAMP and - * ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query. - * An array, each element is the identifier name. - * Note that for now, the timestamp_not_null element is created - * even for non-TIMESTAMP fields. - * - * Sub-elements: ['type'] which contains the column type - * optional (currently they are never false but can be absent): - * ['default_current_timestamp'] boolean - * ['on_update_current_timestamp'] boolean - * ['timestamp_not_null'] boolean - * - * section_before_limit, section_after_limit - * ----------------------------------------- - * - * Marks the point of the query where we can insert a LIMIT clause; - * so the section_before_limit will contain the left part before - * a possible LIMIT clause - * - * @access public - * @param array The SQL queries - * @return array The analyzed SQL queries - */ - function analyze() - { - $this->_analyzed = array(); - $this->parseIfRequired(); - - if (empty($this->_parsed)) { - return $this->_analyzed; - } - - $subresult = array( - 'querytype' => '', - 'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT - 'position_of_first_select' => '', // the array index - 'from_clause'=> '', - 'group_by_clause'=> '', - 'order_by_clause'=> '', - 'having_clause' => '', - 'where_clause' => '', - 'where_clause_identifiers' => array(), - 'unsorted_query' => '', - 'queryflags' => array(), - 'select_expr' => array(), - 'table_ref' => array(), - 'foreign_keys' => array(), - 'create_table_fields' => array() - ); - $subresult_empty = $subresult; - $seek_queryend = FALSE; - $seen_end_of_table_ref = FALSE; - $number_of_brackets_in_extract = 0; - $number_of_brackets_in_group_concat = 0; - - // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE()) - // we must not use CURDATE as a table_ref - // so we track wether we are in the EXTRACT() - $in_extract = FALSE; - - // for GROUP_CONCAT(...) - $in_group_concat = FALSE; - - // must be sorted - // TODO: current logic checks for only one word, so I put only the - // first word of the reserved expressions that end a table ref; - // maybe this is not ok (the first word might mean something else) -// $words_ending_table_ref = array( -// 'FOR UPDATE', -// 'GROUP BY', -// 'HAVING', -// 'LIMIT', -// 'LOCK IN SHARE MODE', -// 'ORDER BY', -// 'PROCEDURE', -// 'UNION', -// 'WHERE' -// ); - $words_ending_table_ref = array( - 'FOR', - 'GROUP', - 'HAVING', - 'LIMIT', - 'LOCK', - 'ORDER', - 'PROCEDURE', - 'UNION', - 'WHERE' - ); - $words_ending_table_ref_cnt = 9; //count($words_ending_table_ref); - - $words_ending_clauses = array( - 'FOR', - 'LIMIT', - 'LOCK', - 'PROCEDURE', - 'UNION' - ); - $words_ending_clauses_cnt = 5; //count($words_ending_clauses); - - // must be sorted - $supported_query_types = array( - 'SELECT' - /* - // Support for these additional query types will come later on. - 'DELETE', - 'INSERT', - 'REPLACE', - 'TRUNCATE', - 'UPDATE' - 'EXPLAIN', - 'DESCRIBE', - 'SHOW', - 'CREATE', - 'SET', - 'ALTER' - */ - ); - $supported_query_types_cnt = count($supported_query_types); - - // loop #1 for each token: select_expr, table_ref for SELECT - - foreach ($this->_parsed as $pos => $each_parsed) { -//DEBUG echo "Loop1 " . $each_parsed['data'] . " (" . $each_parsed['type'] . ")
    "; - - // High speed seek for locating the end of the current query - if ($seek_queryend == TRUE) { - if ($each_parsed['type'] === 'punct_queryend') { - $seek_queryend = FALSE; - } else { - continue; - } // end if (type == punct_queryend) - } // end if ($seek_queryend) - - /** - * Note: do not split if this is a punct_queryend for the first and only query - * @todo when we find a UNION, should we split in another subresult? - */ - if ($each_parsed['type'] == 'punct_queryend' - && ($pos + 1 != $this->_parsed_size)) { - $this->_analyzed[] = $subresult; - $subresult = $subresult_empty; - continue; - } // end if (type == punct_queryend) - -// ============================================================== - if ($each_parsed['type'] == 'punct_bracket_open_round') { - if ($in_extract) { - $number_of_brackets_in_extract++; - } - if ($in_group_concat) { - $number_of_brackets_in_group_concat++; - } - } -// ============================================================== - if ($each_parsed['type'] == 'punct_bracket_close_round') { - if ($in_extract) { - $number_of_brackets_in_extract--; - if ($number_of_brackets_in_extract == 0) { - $in_extract = FALSE; - } - } - if ($in_group_concat) { - $number_of_brackets_in_group_concat--; - if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = FALSE; - } - } - } -// ============================================================== - if ($each_parsed['type'] == 'alpha_functionName') { - $upper_data = strtoupper($each_parsed['data']); - if ($upper_data === 'EXTRACT') { - $in_extract = TRUE; - $number_of_brackets_in_extract = 0; - } - if ($upper_data === 'GROUP_CONCAT') { - $in_group_concat = TRUE; - $number_of_brackets_in_group_concat = 0; - } - } - -// ============================================================== - if ($each_parsed['type'] == 'alpha_reservedWord' -// && $each_parsed['forbidden'] == FALSE) { - ) { - // upper once - $upper_data = strtoupper($each_parsed['data']); - - // We don't know what type of query yet, so run this - if ($subresult['querytype'] === '') { - $subresult['querytype'] = $upper_data; - - // Check if we support this type of query - if (! PMA_STR_binarySearchInArr($subresult['querytype'], - $supported_query_types, $supported_query_types_cnt)) { - // Skip ahead to the next one if we don't - $seek_queryend = TRUE; - continue; - } // end if (query not supported) - } // end if (querytype was empty) - - /** - * @todo reset for each query? - */ - - if ($upper_data == 'SELECT') { - $seen_from = FALSE; - $previous_was_identifier = FALSE; - $current_select_expr = -1; - $seen_end_of_table_ref = FALSE; - } // end if (data == SELECT) - - if ($upper_data =='FROM' && ! $in_extract) { - $current_table_ref = -1; - $seen_from = TRUE; - $previous_was_identifier = FALSE; - $save_table_ref = TRUE; - } // end if (data == FROM) - - // here, do not 'continue' the loop, as we have more work for - // reserved words below - } // end if (type == alpha_reservedWord) - -// ============================== - if ($each_parsed['type'] == 'quote_backtick' - || $each_parsed['type'] == 'quote_double' - || $each_parsed['type'] == 'quote_single' - || $each_parsed['type'] == 'alpha_identifier' - || ($each_parsed['type'] == 'alpha_reservedWord' - && $each_parsed['forbidden'] == FALSE)) { - - switch ($each_parsed['type']) { - case 'alpha_identifier': - case 'alpha_reservedWord': - /** - * this is not a real reservedWord, because it's not - * present in the list of forbidden words, for example - * "storage" which can be used as an identifier - * - * @todo avoid the pretty printing in color in this case - */ - $identifier = $each_parsed['data']; - break; - - case 'quote_backtick': - case 'quote_double': - case 'quote_single': - $identifier = PMA_unQuote($each_parsed['data']); - break; - } // end switch - - if ($subresult['querytype'] == 'SELECT' && ! $in_group_concat) { - if (! $seen_from) { - if ($previous_was_identifier && isset($chain)) { - // found alias for this select_expr, save it - // but only if we got something in $chain - // (for example, SELECT COUNT(*) AS cnt - // puts nothing in $chain, so we avoid - // setting the alias) - $alias_for_select_expr = $identifier; - } else { - $chain[] = $identifier; - $previous_was_identifier = TRUE; - - } // end if !$previous_was_identifier - } else { - // ($seen_from) - if ($save_table_ref && !$seen_end_of_table_ref) { - if ($previous_was_identifier) { - // found alias for table ref - // save it for later - $alias_for_table_ref = $identifier; - } else { - $chain[] = $identifier; - $previous_was_identifier = TRUE; - - } // end if ($previous_was_identifier) - } // end if ($save_table_ref &&!$seen_end_of_table_ref) - } // end if (!$seen_from) - } // end if (querytype SELECT) - } // end if (quote_backtick or double quote or alpha_identifier) - -// =================================== - if ($each_parsed['type'] == 'punct_qualifier') { - // to be able to detect an identifier following another - $previous_was_identifier = FALSE; - continue; - } // end if (punct_qualifier) - - /** - * @todo check if 3 identifiers following one another -> error - */ - - // s a v e a s e l e c t e x p r - // finding a list separator or FROM - // means that we must save the current chain of identifiers - // into a select expression - - // for now, we only save a select expression if it contains - // at least one identifier, as we are interested in checking - // the columns and table names, so in "select * from persons", - // the "*" is not saved - - if (isset($chain) - && !$seen_end_of_table_ref - && ((! $seen_from - && $each_parsed['type'] == 'punct_listsep') - || ($each_parsed['type'] == 'alpha_reservedWord' - && $upper_data == 'FROM'))) { - $size_chain = count($chain); - $current_select_expr++; - $subresult['select_expr'][$current_select_expr] = array( - 'expr' => '', - 'alias' => '', - 'db' => '', - 'table_name' => '', - 'table_true_name' => '', - 'column' => '' - ); - - if (isset($alias_for_select_expr) && strlen($alias_for_select_expr)) { - // we had found an alias for this select expression - $subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr; - unset($alias_for_select_expr); - } - // there is at least a column - $subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1]; - $subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1]; - - // maybe a table - if ($size_chain > 1) { - $subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2]; - // we assume for now that this is also the true name - $subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2]; - $subresult['select_expr'][$current_select_expr]['expr'] - = $subresult['select_expr'][$current_select_expr]['table_name'] - . '.' . $subresult['select_expr'][$current_select_expr]['expr']; - } // end if ($size_chain > 1) - - // maybe a db - if ($size_chain > 2) { - $subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3]; - $subresult['select_expr'][$current_select_expr]['expr'] - = $subresult['select_expr'][$current_select_expr]['db'] - . '.' . $subresult['select_expr'][$current_select_expr]['expr']; - } // end if ($size_chain > 2) - unset($chain); - - /** - * @todo explain this: - * even if this was a reservedWord it is possible this is just an alias - * wihtout using 'AS' - */ - if (($each_parsed['type'] == 'alpha_reservedWord') - && ($upper_data != 'FROM')) { - $previous_was_identifier = TRUE; - } - - } // end if (save a select expr) - - - //====================================== - // s a v e a t a b l e r e f - //====================================== - - // maybe we just saw the end of table refs - // but the last table ref has to be saved - // or we are at the last token - // or we just got a reserved word - /** - * @todo there could be another query after this one - */ - - if (isset($chain) && $seen_from && $save_table_ref - && ($each_parsed['type'] == 'punct_listsep' - || ($each_parsed['type'] == 'alpha_reservedWord' && $upper_data != "AS") - || $seen_end_of_table_ref - || $pos == $this->_parsed_size - 1)) { - - $size_chain = count($chain); - $current_table_ref++; - $subresult['table_ref'][$current_table_ref] = array( - 'expr' => '', - 'db' => '', - 'table_name' => '', - 'table_alias' => '', - 'table_true_name' => '' - ); - if (isset($alias_for_table_ref) && strlen($alias_for_table_ref)) { - $subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref; - unset($alias_for_table_ref); - } - $subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1]; - // we assume for now that this is also the true name - $subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1]; - $subresult['table_ref'][$current_table_ref]['expr'] - = $subresult['table_ref'][$current_table_ref]['table_name']; - // maybe a db - if ($size_chain > 1) { - $subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2]; - $subresult['table_ref'][$current_table_ref]['expr'] - = $subresult['table_ref'][$current_table_ref]['db'] - . '.' . $subresult['table_ref'][$current_table_ref]['expr']; - } // end if ($size_chain > 1) - - // add the table alias into the whole expression - $subresult['table_ref'][$current_table_ref]['expr'] - .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias']; - - unset($chain); - $previous_was_identifier = TRUE; - //continue; - - } // end if (save a table ref) - - - // when we have found all table refs, - // for each table_ref alias, put the true name of the table - // in the corresponding select expressions - - if (isset($current_table_ref) - && ($seen_end_of_table_ref || $pos == $this->_parsed_size - 1) - && $subresult != $subresult_empty) { - for ($tr=0; $tr <= $current_table_ref; $tr++) { - $alias = $subresult['table_ref'][$tr]['table_alias']; - $truename = $subresult['table_ref'][$tr]['table_true_name']; - for ($se=0; $se <= $current_select_expr; $se++) { - if (isset($alias) && strlen($alias) - && $subresult['select_expr'][$se]['table_true_name'] == $alias) { - $subresult['select_expr'][$se]['table_true_name'] = $truename; - } // end if (found the alias) - } // end for (select expressions) - - } // end for (table refs) - } // end if (set the true names) - - - // e n d i n g l o o p #1 - // set the $previous_was_identifier to FALSE if the current - // token is not an identifier - if (($each_parsed['type'] != 'alpha_identifier') - && ($each_parsed['type'] != 'quote_double') - && ($each_parsed['type'] != 'quote_single') - && ($each_parsed['type'] != 'quote_backtick')) { - $previous_was_identifier = FALSE; - } // end if - - // however, if we are on AS, we must keep the $previous_was_identifier - if (($each_parsed['type'] == 'alpha_reservedWord') - && ($upper_data == 'AS')) { - $previous_was_identifier = TRUE; - } - - if (($each_parsed['type'] == 'alpha_reservedWord') - && ($upper_data =='ON' || $upper_data === 'USING')) { - $save_table_ref = FALSE; - } // end if (data == ON) - - if (($each_parsed['type'] == 'alpha_reservedWord') - && ($upper_data =='JOIN' || $upper_data === 'FROM')) { - $save_table_ref = TRUE; - } // end if (data == JOIN) - - /** - * no need to check the end of table ref if we already did - * - * @todo maybe add "&& $seen_from" - */ - if (!$seen_end_of_table_ref) { - // if this is the last token, it implies that we have - // seen the end of table references - // Check for the end of table references - // - // Note: if we are analyzing a GROUP_CONCAT clause, - // we might find a word that seems to indicate that - // we have found the end of table refs (like ORDER) - // but it's a modifier of the GROUP_CONCAT so - // it's not the real end of table refs - if (($pos == $this->_parsed_size - 1) - || ($each_parsed['type'] == 'alpha_reservedWord' - && !$in_group_concat - && PMA_STR_binarySearchInArr($upper_data, $words_ending_table_ref, $words_ending_table_ref_cnt))) { - $seen_end_of_table_ref = TRUE; - // to be able to save the last table ref, but do not - // set it true if we found a word like "ON" that has - // already set it to false - if (isset($save_table_ref) && $save_table_ref != FALSE) { - $save_table_ref = TRUE; - } //end if - - } // end if (check for end of table ref) - } //end if (!$seen_end_of_table_ref) - - if ($seen_end_of_table_ref) { - $save_table_ref = FALSE; - } // end if - } // end for $i (loop #1) - - // ------------------------------------------------------- - // This is a big hunk of debugging code by Marc for this. - // ------------------------------------------------------- - /* - if (isset($current_select_expr)) { - for ($trace=0; $trace<=$current_select_expr; $trace++) { - echo "
    "; - reset ($subresult['select_expr'][$trace]); - while (list ($key, $val) = each ($subresult['select_expr'][$trace])) - echo "sel expr $trace $key => $val
    \n"; - } - } - - if (isset($current_table_ref)) { - echo "current_table_ref = " . $current_table_ref . "
    "; - for ($trace=0; $trace<=$current_table_ref; $trace++) { - - echo "
    "; - reset ($subresult['table_ref'][$trace]); - while (list ($key, $val) = each ($subresult['table_ref'][$trace])) - echo "table ref $trace $key => $val
    \n"; - } - } - */ - // ------------------------------------------------------- - - - // loop #2: - queryflags - // - querytype (for queries != 'SELECT') - // - section_before_limit, section_after_limit - // - // we will also need this queryflag in loop 2 - // so set it here - if (isset($current_table_ref) && $current_table_ref > -1) { - $subresult['queryflags']['select_from'] = 1; - } - - $collect_section_before_limit = TRUE; - $section_before_limit = ''; - $section_after_limit = ''; - $seen_reserved_word = FALSE; - $seen_group = FALSE; - $seen_order = FALSE; - $in_group_by = FALSE; // true when we are inside the GROUP BY clause - $in_order_by = FALSE; // true when we are inside the ORDER BY clause - $in_having = FALSE; // true when we are inside the HAVING clause - $in_select_expr = FALSE; // true when we are inside the select expr clause - $in_where = FALSE; // true when we are inside the WHERE clause - $in_from = FALSE; - $in_group_concat = FALSE; - $unsorted_query = ''; - $first_reserved_word = ''; - $current_identifier = ''; - - foreach ($this->_parsed as $pos => $each_parsed) { -//DEBUG echo "Loop2 " . $each_parsed['data'] . " (" . $each_parsed['type'] . ")
    "; - - // need_confirm - // - // check for reserved words that will have to generate - // a confirmation request later in sql.php - // the cases are: - // DROP TABLE - // DROP DATABASE - // ALTER TABLE... DROP - // DELETE FROM... - // - // this code is not used for confirmations coming from functions.js - - /** - * @todo check for punct_queryend - * @todo verify C-style comments? - */ - if ($each_parsed['type'] == 'comment_ansi') { - $collect_section_before_limit = FALSE; - } - - if ($each_parsed['type'] == 'alpha_reservedWord') { - $upper_data = strtoupper($each_parsed['data']); - if (!$seen_reserved_word) { - $first_reserved_word = $upper_data; - $subresult['querytype'] = $upper_data; - $seen_reserved_word = TRUE; - - // if the first reserved word is DROP or DELETE, - // we know this is a query that needs to be confirmed - if ($first_reserved_word=='DROP' - || $first_reserved_word == 'DELETE' - || $first_reserved_word == 'TRUNCATE') { - $subresult['queryflags']['need_confirm'] = 1; - } - - if ($first_reserved_word=='SELECT'){ - $position_of_first_select = $pos; - } - - } else { - if ($upper_data=='DROP' && $first_reserved_word=='ALTER') { - $subresult['queryflags']['need_confirm'] = 1; - } - } - - if ($upper_data == 'PROCEDURE') { - $collect_section_before_limit = FALSE; - } - /** - * @todo set also to FALSE if we find FOR UPDATE or LOCK IN SHARE MODE - */ - if ($upper_data == 'SELECT') { - $in_select_expr = TRUE; - $select_expr_clause = ''; - } - if ($upper_data == 'DISTINCT' && !$in_group_concat) { - $subresult['queryflags']['distinct'] = 1; - } - - if ($upper_data == 'UNION') { - $subresult['queryflags']['union'] = 1; - } - - if ($upper_data == 'JOIN') { - $subresult['queryflags']['join'] = 1; - } - - if ($upper_data == 'OFFSET') { - $subresult['queryflags']['offset'] = 1; - } - - // if this is a real SELECT...FROM - if ($upper_data == 'FROM' - && isset($subresult['queryflags']['select_from']) - && $subresult['queryflags']['select_from'] == 1) { - $in_from = TRUE; - $from_clause = ''; - $in_select_expr = FALSE; - } - - - // (we could have less resetting of variables to FALSE - // if we trust that the query respects the standard - // MySQL order for clauses) - - // we use $seen_group and $seen_order because we are looking - // for the BY - if ($upper_data == 'GROUP') { - $seen_group = TRUE; - $seen_order = FALSE; - $in_having = FALSE; - $in_order_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; - } - if ($upper_data == 'ORDER' && !$in_group_concat) { - $seen_order = TRUE; - $seen_group = FALSE; - $in_having = FALSE; - $in_group_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; - } - if ($upper_data == 'HAVING') { - $in_having = TRUE; - $having_clause = ''; - $seen_group = FALSE; - $seen_order = FALSE; - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; - } - - if ($upper_data == 'WHERE') { - $in_where = TRUE; - $where_clause = ''; - $where_clause_identifiers = array(); - $seen_group = FALSE; - $seen_order = FALSE; - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_having = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; - } - - if ($upper_data == 'BY') { - if ($seen_group) { - $in_group_by = TRUE; - $group_by_clause = ''; - } - if ($seen_order) { - $in_order_by = TRUE; - $order_by_clause = ''; - } - } - - // if we find one of the words that could end the clause - if (PMA_STR_binarySearchInArr($upper_data, $words_ending_clauses, $words_ending_clauses_cnt)) { - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_having = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; - } - - } // endif (reservedWord) - - - // do not add a space after a function name - /** - * @todo can we combine loop 2 and loop 1? some code is repeated here... - */ - - $sep = ' '; - if ($each_parsed['type'] == 'alpha_functionName') { - $sep=''; - $upper_data = strtoupper($each_parsed['data']); - if ($upper_data =='GROUP_CONCAT') { - $in_group_concat = TRUE; - $number_of_brackets_in_group_concat = 0; - } - } - - if ($each_parsed['type'] == 'punct_bracket_open_round') { - if ($in_group_concat) { - $number_of_brackets_in_group_concat++; - } - } - if ($each_parsed['type'] == 'punct_bracket_close_round') { - if ($in_group_concat) { - $number_of_brackets_in_group_concat--; - if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = FALSE; - } - } - } - - // do not add a space after an identifier if followed by a dot - if ($each_parsed['type'] == 'alpha_identifier' - && $pos < $this->_parsed_size - 1 - && $this->_parsed[$pos + 1]['data'] == '.') { - $sep = ''; - } - - // do not add a space after a dot if followed by an identifier - if ($each_parsed['data'] == '.' - && $pos < $this->_parsed_size - 1 - && $this->_parsed[$pos + 1]['type'] == 'alpha_identifier') { - $sep = ''; - } - - if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') { - $select_expr_clause .= $each_parsed['data'] . $sep; - } - if ($in_from && $upper_data != 'FROM') { - $from_clause .= $each_parsed['data'] . $sep; - } - if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') { - $group_by_clause .= $each_parsed['data'] . $sep; - } - if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') { - // add a space only before ASC or DESC - // not around the dot between dbname and tablename - if ($each_parsed['type'] == 'alpha_reservedWord') { - $order_by_clause .= $sep; - } - $order_by_clause .= $each_parsed['data']; - } - if ($in_having && $upper_data != 'HAVING') { - $having_clause .= $each_parsed['data'] . $sep; - } - if ($in_where && $upper_data != 'WHERE') { - $where_clause .= $each_parsed['data'] . $sep; - - if (($each_parsed['type'] == 'quote_backtick') - || ($each_parsed['type'] == 'alpha_identifier')) { - $where_clause_identifiers[] = $each_parsed['data']; - } - } - - if (isset($subresult['queryflags']['select_from']) - && $subresult['queryflags']['select_from'] == 1 - && !$seen_order) { - $unsorted_query .= $each_parsed['data']; - - if ($each_parsed['type'] != 'punct_bracket_open_round' - && $each_parsed['type'] != 'punct_bracket_close_round' - && $each_parsed['type'] != 'punct') { - $unsorted_query .= $sep; - } - } - - // clear $upper_data for next iteration - $upper_data=''; - - if ($collect_section_before_limit && $each_parsed['type'] != 'punct_queryend') { - $section_before_limit .= $each_parsed['data'] . $sep; - } else { - $section_after_limit .= $each_parsed['data'] . $sep; - } - - - } // end for $i (loop #2) - - - // ----------------------------------------------------- - // loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options - // (for now, check only the first query) - // (for now, identifiers are assumed to be backquoted) - - // If we find that we are dealing with a CREATE TABLE query, - // we look for the next punct_bracket_open_round, which - // introduces the fields list. Then, when we find a - // quote_backtick, it must be a field, so we put it into - // the create_table_fields array. Even if this field is - // not a timestamp, it will be useful when logic has been - // added for complete field attributes analysis. - - $seen_foreign = FALSE; - $seen_references = FALSE; - $seen_constraint = FALSE; - $foreign_key_number = -1; - $seen_create_table = FALSE; - $seen_create = FALSE; - $in_create_table_fields = FALSE; - $brackets_level = 0; - $in_timestamp_options = FALSE; - $seen_default = FALSE; - - foreach ($this->_parsed as $pos => $each_parsed) { - // DEBUG echo "Loop 3 " . $each_parsed['data'] . " " . $each_parsed['type'] . "
    "; - - if ($each_parsed['type'] == 'alpha_reservedWord') { - $upper_data = strtoupper($each_parsed['data']); - - if ($upper_data == 'NOT' && $in_timestamp_options) { - $create_table_fields[$current_identifier]['timestamp_not_null'] = TRUE; - - } - - if ($upper_data == 'CREATE') { - $seen_create = TRUE; - } - - if ($upper_data == 'TABLE' && $seen_create) { - $seen_create_table = TRUE; - $create_table_fields = array(); - } - - if ($upper_data == 'CURRENT_TIMESTAMP') { - if ($in_timestamp_options) { - if ($seen_default) { - $create_table_fields[$current_identifier]['default_current_timestamp'] = TRUE; - } - } - } - - if ($upper_data == 'CONSTRAINT') { - $foreign_key_number++; - $seen_foreign = FALSE; - $seen_references = FALSE; - $seen_constraint = TRUE; - } - if ($upper_data == 'FOREIGN') { - $seen_foreign = TRUE; - $seen_references = FALSE; - $seen_constraint = FALSE; - } - if ($upper_data == 'REFERENCES') { - $seen_foreign = FALSE; - $seen_references = TRUE; - $seen_constraint = FALSE; - } - - - // Cases covered: - - // [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}] - // [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}] - - // but we set ['on_delete'] or ['on_cascade'] to - // CASCADE | SET_NULL | NO_ACTION | RESTRICT - - // ON UPDATE CURRENT_TIMESTAMP - - if ($upper_data == 'ON') { - if ($this->_parsed[$pos + 1]['type'] == 'alpha_reservedWord') { - $second_upper_data = strtoupper($this->_parsed[$pos + 1]['data']); - if ($second_upper_data == 'DELETE') { - $clause = 'on_delete'; - } - if ($second_upper_data == 'UPDATE') { - $clause = 'on_update'; - } - if (isset($clause) - && ($this->_parsed[$pos + 2]['type'] == 'alpha_reservedWord' - - // ugly workaround because currently, NO is not - // in the list of reserved words in sqlparser.data - // (we got a bug report about not being able to use - // 'no' as an identifier) - || ($this->_parsed[$pos + 2]['type'] == 'alpha_identifier' - && strtoupper($this->_parsed[$pos + 2]['data'])=='NO')) - ) { - $third_upper_data = strtoupper($this->_parsed[$pos + 2]['data']); - if ($third_upper_data == 'CASCADE' - || $third_upper_data == 'RESTRICT') { - $value = $third_upper_data; - } elseif ($third_upper_data == 'SET' - || $third_upper_data == 'NO') { - if ($this->_parsed[$pos + 3]['type'] == 'alpha_reservedWord') { - $value = $third_upper_data . '_' - . strtoupper($this->_parsed[$pos + 3]['data']); - } - } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') { - if ($clause == 'on_update' - && $in_timestamp_options) { - $create_table_fields[$current_identifier]['on_update_current_timestamp'] = TRUE; - $seen_default = FALSE; - } - - } else { - $value = ''; - } - if (!empty($value)) { - $foreign[$foreign_key_number][$clause] = $value; - } - unset($clause); - } // endif (isset($clause)) - } - } - - } // end of reserved words analysis - - - if ($each_parsed['type'] == 'punct_bracket_open_round') { - $brackets_level++; - if ($seen_create_table && $brackets_level == 1) { - $in_create_table_fields = TRUE; - } - } - - - if ($each_parsed['type'] == 'punct_bracket_close_round') { - $brackets_level--; - if ($seen_references) { - $seen_references = FALSE; - } - if ($seen_create_table && $brackets_level == 0) { - $in_create_table_fields = FALSE; - } - } - - if (($each_parsed['type'] == 'alpha_columnAttrib')) { - $upper_data = strtoupper($each_parsed['data']); - if ($seen_create_table && $in_create_table_fields) { - if ($upper_data == 'DEFAULT') { - $seen_default = TRUE; - } - } - } - - /** - * @see @todo 2005-10-16 note: the "or" part here is a workaround for a bug - */ - if ($each_parsed['type'] == 'alpha_columnType' - || ($each_parsed['type'] == 'alpha_functionName' - && $seen_create_table)) { - $upper_data = strtoupper($each_parsed['data']); - if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) { - $create_table_fields[$current_identifier]['type'] = $upper_data; - if ($upper_data == 'TIMESTAMP') { - $each_parsed['type'] = 'alpha_columnType'; - $in_timestamp_options = TRUE; - } else { - $in_timestamp_options = FALSE; - if ($upper_data == 'CHAR') { - $each_parsed['type'] = 'alpha_columnType'; - } - } - } - } - - - if ($each_parsed['type'] == 'quote_backtick' - || $each_parsed['type'] == 'alpha_identifier') { - - if ($each_parsed['type'] == 'quote_backtick') { - // remove backquotes - $identifier = PMA_unQuote($each_parsed['data']); - } else { - $identifier = $each_parsed['data']; - } - - if ($seen_create_table && $in_create_table_fields) { - $current_identifier = $identifier; - // warning: we set this one even for non TIMESTAMP type - $create_table_fields[$current_identifier]['timestamp_not_null'] = FALSE; - } - - if ($seen_constraint) { - $foreign[$foreign_key_number]['constraint'] = $identifier; - } - - if ($seen_foreign && $brackets_level > 0) { - $foreign[$foreign_key_number]['index_list'][] = $identifier; - } - - if ($seen_references) { - // here, the first bracket level corresponds to the - // bracket of CREATE TABLE - // so if we are on level 2, it must be the index list - // of the foreign key REFERENCES - if ($brackets_level > 1) { - $foreign[$foreign_key_number]['ref_index_list'][] = $identifier; - } else { - // for MySQL 4.0.18, identifier is - // `table` or `db`.`table` - // the first pass will pick the db name - // the next pass will execute the else and pick the - // db name in $db_table[0] - if ($this->_parsed[$pos + 1]['type'] == 'punct_qualifier') { - $foreign[$foreign_key_number]['ref_db_name'] = $identifier; - } else { - // for MySQL 4.0.16, identifier is - // `table` or `db.table` - $db_table = explode('.', $identifier); - if (isset($db_table[1])) { - $foreign[$foreign_key_number]['ref_db_name'] = $db_table[0]; - $foreign[$foreign_key_number]['ref_table_name'] = $db_table[1]; - } else { - $foreign[$foreign_key_number]['ref_table_name'] = $db_table[0]; - } - } - } - } - } - } // end for $i (loop #3) - - - // Fill the $subresult array - - if (isset($create_table_fields)) { - $subresult['create_table_fields'] = $create_table_fields; - } - - if (isset($foreign)) { - $subresult['foreign_keys'] = $foreign; - } - - if (isset($select_expr_clause)) { - $subresult['select_expr_clause'] = $select_expr_clause; - } - if (isset($from_clause)) { - $subresult['from_clause'] = $from_clause; - } - if (isset($group_by_clause)) { - $subresult['group_by_clause'] = $group_by_clause; - } - if (isset($order_by_clause)) { - $subresult['order_by_clause'] = $order_by_clause; - } - if (isset($having_clause)) { - $subresult['having_clause'] = $having_clause; - } - if (isset($where_clause)) { - $subresult['where_clause'] = $where_clause; - } - if (isset($unsorted_query) && !empty($unsorted_query)) { - $subresult['unsorted_query'] = $unsorted_query; - } - if (isset($where_clause_identifiers)) { - $subresult['where_clause_identifiers'] = $where_clause_identifiers; - } - - if (isset($position_of_first_select)) { - $subresult['position_of_first_select'] = $position_of_first_select; - $subresult['section_before_limit'] = $section_before_limit; - $subresult['section_after_limit'] = $section_after_limit; - } - - // They are naughty and didn't have a trailing semi-colon, - // then still handle it properly - if ($subresult['querytype'] != '') { - $this->_analyzed[] = $subresult; - } - return $this->_analyzed; - } // end of the "analyze()" function - - /** - * Colorizes SQL queries html formatted - * - * @todo check why adding a "\n" after the would cause extra blanks - * to be displayed: SELECT p . person_name - * - * @access public - * @param array The SQL queries html formatted - * @return array The colorized SQL queries - */ - function getFormatedHtmlColored($parsed) - { - $i = $GLOBALS['PMA_strpos']($parsed['type'], '_'); - $class = ''; - if ($i > 0) { - $class = 'syntax_' . PMA_substr($parsed['type'], 0, $i) . ' '; - } - - $class .= 'syntax_' . $parsed['type']; - - return '' . htmlspecialchars($parsed['data']) . ''; - } // end of the "getFormatedHtmlColored()" function - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function isDistinct($subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['queryflags']['distinct'])) { - return true; - } - - return false; - } - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function isUnion($subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['queryflags']['union'])) { - return true; - } - - return false; - } - - function isOnlyOneTable($subquery = 0) - { - if (! isset($this->_analyzed[$subquery]['table_ref'][1]['table_name'])) { - return true; - } - - return false; - } - - function isWhereAlwaysTrue($subquery = 0) - { - if (! $this->hasWhere($subquery) || trim($this->getWhereClause($subquery)) == '1') { - return true; - } - - return false; - } - - function getCountQuery() - { - if (PMA_MYSQL_INT_VERSION < 40000) { - - // detect this case: - // SELECT DISTINCT x AS foo, y AS bar FROM sometable - if ($this->isDistinct()) { - $count_what = 'DISTINCT '; - foreach ($this->_analyzed[0]['select_expr'] as $part) { - $count_what .= $part['expr'] . ', '; - } - $count_what = substr($count_what, 0, -2); - } else { - $count_what = '*'; - } - // this one does not apply to VIEWs - $count_query = 'SELECT COUNT(' . $count_what . ') AS count'; - - // add the remaining of select expression if there is - // a GROUP BY or HAVING clause - if ($count_what === '*' - && ($this->hasGroupBy() || $this->hasHaving())) { - $count_query .= ' ,' . $this->_analyzed[0]['select_expr_clause']; - } - - if ($this->hasFrom()) { - $count_query .= ' FROM ' . $this->getFromClause(); - } - if ($this->hasWhere()) { - $count_query .= ' WHERE ' . $this->getWhereClause(); - } - if ($this->hasGroupBy()) { - $count_query .= ' GROUP BY ' . $this->getGroupByClause(); - } - if ($this->hasHaving()) { - $count_query .= ' HAVING ' . $this->getHavingClause(); - } - } else { // if (PMA_MYSQL_INT_VERSION >= 40000) - // add select expression after the SQL_CALC_FOUND_ROWS - - // for UNION, just adding SQL_CALC_FOUND_ROWS - // after the first SELECT works. - - // take the left part, could be: - // SELECT - // (SELECT - $count_query = $this->getFormatedHtml('query_only', 0, $this->getPositionOfFirstSelect() + 1); - $count_query .= ' SQL_CALC_FOUND_ROWS '; - // add everything that was after the first SELECT - $count_query = $this->getFormatedHtml('query_only', $this->getPositionOfFirstSelect() + 1); - // ensure there is no semicolon at the end of the - // count query because we'll probably add - // a LIMIT 1 clause after it - $count_query = rtrim($count_query); - $count_query = rtrim($count_query, ';'); - - // if using SQL_CALC_FOUND_ROWS, add a LIMIT to avoid - // long delays. Returned count will be complete anyway. - // (but a LIMIT would disrupt results in an UNION) - - if (! $this->isUnion()) { - $count_query .= ' LIMIT 1'; - } - } - - return $count_query; - } - - function isGroup() - { - return preg_match('@(GROUP[[:space:]]+BY|HAVING|SELECT[[:space:]]+DISTINCT)[[:space:]]+@i', $this->_raw); - } - - function getFoundRows() - { - $count_query = $this->getCountQuery(); - - if (PMA_MYSQL_INT_VERSION < 40000) { - if ($cnt_all_result = PMA_DBI_try_query($count_query)) { - if ($this->isGroup() && ! $this->isDistinct()) { - $unlim_num_rows = @PMA_DBI_num_rows($cnt_all_result); - } else { - $unlim_num_rows = PMA_DBI_fetch_assoc($cnt_all_result); - $unlim_num_rows = $unlim_num_rows['count']; - } - PMA_DBI_free_result($cnt_all_result); - } else { - if (PMA_DBI_getError()) { - - // there are some cases where the generated - // count_query (for MySQL 3) is wrong, - // so we get here. - /** - * @todo use a big unlimited query to get the correct - * number of rows (depending on a config variable?) - */ - $unlim_num_rows = 0; - } - } - } else { - PMA_DBI_try_query($count_query); - // if (mysql_error()) { - // void. - // I tried the case - // (SELECT `User`, `Host`, `Db`, `Select_priv` FROM `db`) - // UNION (SELECT `User`, `Host`, "%" AS "Db", - // `Select_priv` - // FROM `user`) ORDER BY `User`, `Host`, `Db`; - // and although the generated count_query is wrong - // the SELECT FOUND_ROWS() work! (maybe it gets the - // count from the latest query that worked) - // - // another case where the count_query is wrong: - // SELECT COUNT(*), f1 from t1 group by f1 - // and you click to sort on count(*) - // } - $unlim_num_rows = PMA_DBI_fetch_value('SELECT FOUND_ROWS();'); - } - - return $unlim_num_rows; - } - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function hasGroupBy($subquery = 0) - { - $this->analyzeIfRequired(); - - if (! empty($this->_analyzed[$subquery]['group_by_clause'])) { - return true; - } - - return false; - } - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function hasFrom($subquery = 0) - { - $this->analyzeIfRequired(); - - if (! empty($this->_analyzed[$subquery]['from_clause'])) { - return true; - } - - return false; - } - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function hasHaving($subquery = 0) - { - $this->analyzeIfRequired(); - - if (! empty($this->_analyzed[$subquery]['having_clause'])) { - return true; - } - - return false; - } - - /** - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::$_analyzed to check - * @param integer $subquery which subquery to check, default 0 - * @return boolean - */ - function hasWhere($subquery = 0) - { - $this->analyzeIfRequired(); - - if (! empty($this->_analyzed[$subquery]['where_clause'])) { - return true; - } - - return false; - } - - /** - * @uses PMA_Sql::hasGroupBy() to check - * @param integer $subquery which subquery to check, default 0 - * @return string or false - */ - function getGroupByClause($subquery = 0) - { - if ($this->hasGroupBy()) { - return $this->_analyzed[$subquery]['group_by_clause']; - } - - return false; - } - - /** - * @uses PMA_Sql::hasHaving() to check - * @param integer $subquery which subquery to check, default 0 - * @return string or false - */ - function getHavingClause($subquery = 0) - { - if ($this->hasHaving()) { - return $this->_analyzed[$subquery]['having_clause']; - } - - return false; - } - - /** - * @uses PMA_Sql::hasWhere() to check - * @param integer $subquery which subquery to check, default 0 - * @return string or false - */ - function getWhereClause($subquery = 0) - { - if ($this->hasWhere()) { - return $this->_analyzed[$subquery]['where_clause']; - } - - return false; - } - - /** - * @uses PMA_Sql::hasFrom() to check - * @param integer $subquery which subquery to check, default 0 - * @return string or false - */ - function getFromClause($subquery = 0) - { - if ($this->hasFrom()) { - return $this->_analyzed[$subquery]['from_clause']; - } - - return false; - } - - /** - * - * @uses PMA_Sql::analyzeIfRequired() - * @uses PMA_Sql::hasFrom() to check - * @param integer $subquery which subquery to check, default 0 - * @return integer or false - */ - function getPositionOfFirstSelect($subquery = 0) - { - $this->analyzeIfRequired(); - - if (isset($this->_analyzed[$subquery]['position_of_first_select'])) { - return $this->_analyzed[$subquery]['position_of_first_select']; - } - - return false; - } - - /** - * Formats SQL queries to html - * - * @access public - * @param array The SQL queries - * @param string mode - * @param integer starting token - * @param integer number of tokens to format, -1 = all - * @return string The formatted SQL queries - */ - function getFormatedHtml($mode = 'color', $start_token = 0, $number_of_tokens = -1) - { - $this->parseIfRequired(); - - //DEBUG echo 'in Format
    '; print_r($this->_parsed); echo '
    '; - // check for parsed data - // check for the SQL parser having hit an error - if (empty($this->_parsed) || $this->isError()) { - return htmlspecialchars($this->_raw); - } - - // else do it properly - switch ($mode) { - case 'color': - $str = ''; - $html_line_break = '
    '; - break; - case 'query_only': - $str = ''; - $html_line_break = "\n"; - break; - case 'text': - $str = ''; - $html_line_break = '
    '; - break; - } // end switch - $indent = 0; - $bracketlevel = 0; - $functionlevel = 0; - $infunction = FALSE; - $space_punct_listsep = ' '; - $space_punct_listsep_function_name = ' '; - // $space_alpha_reserved_word = '
    '."\n"; - $space_alpha_reserved_word = ' '; - - $keywords_with_brackets_1before = array( - 'INDEX', - 'KEY', - 'ON', - 'USING' - ); - $keywords_with_brackets_1before_cnt = 4; - - $keywords_with_brackets_2before = array( - 'IGNORE', - 'INDEX', - 'INTO', - 'KEY', - 'PRIMARY', - 'PROCEDURE', - 'REFERENCES', - 'UNIQUE', - 'USE' - ); - // $keywords_with_brackets_2before_cnt = count($keywords_with_brackets_2before); - $keywords_with_brackets_2before_cnt = 9; - - // These reserved words do NOT get a newline placed near them. - $keywords_no_newline = array( - 'AS', - 'ASC', - 'DESC', - 'DISTINCT', - 'DUPLICATE', - 'HOUR', - 'INTERVAL', - 'IS', - 'LIKE', - 'NOT', - 'NULL', - 'ON', - 'REGEXP' - ); - $keywords_no_newline_cnt = 12; - - // These reserved words introduce a privilege list - $keywords_priv_list = array( - 'GRANT', - 'REVOKE' - ); - $keywords_priv_list_cnt = 2; - - if ($number_of_tokens == -1) { - $number_of_tokens = $this->_parsed_size; - } - $typearr = array(); - if ($number_of_tokens >= 0) { - $typearr[0] = ''; - $typearr[1] = ''; - $typearr[2] = ''; - //$typearr[3] = $this->_parsed[0]['type']; - $typearr[3] = $this->_parsed[$start_token]['type']; - } - - $in_priv_list = FALSE; - for ($i = $start_token; $i < $number_of_tokens; $i++) { - $each_parsed = $this->_parsed[$i]; -// DEBUG echo "Loop format " . $each_parsed['data'] . " " . $each_parsed['type'] . "
    "; - $before = ''; - $after = ''; - $indent = 0; - // array_shift($typearr); - /* - 0 prev2 - 1 prev - 2 current - 3 next - */ - if (($i + 1) < $number_of_tokens) { - // array_push($typearr, $this->_parsed[$i + 1]['type']); - $typearr[4] = $this->_parsed[$i + 1]['type']; - } else { - //array_push($typearr, null); - $typearr[4] = ''; - } - - for ($j = 0; $j < 4; $j++) { - $typearr[$j] = $typearr[$j + 1]; - } - - switch ($typearr[2]) { - case 'white_newline': - $before = ''; - break; - case 'punct_bracket_open_round': - $bracketlevel++; - $infunction = FALSE; - // Make sure this array is sorted! - if ($typearr[1] == 'alpha_functionName' - || $typearr[1] == 'alpha_columnType' - || $typearr[1] == 'punct' - || $typearr[3] == 'digit_integer' - || $typearr[3] == 'digit_hex' - || $typearr[3] == 'digit_float' - || ($typearr[0] == 'alpha_reservedWord' - && PMA_STR_binarySearchInArr(strtoupper($this->_parsed[$i - 2]['data']), $keywords_with_brackets_2before, $keywords_with_brackets_2before_cnt)) - || ($typearr[1] == 'alpha_reservedWord' - && PMA_STR_binarySearchInArr(strtoupper($this->_parsed[$i - 1]['data']), $keywords_with_brackets_1before, $keywords_with_brackets_1before_cnt)) - ) { - $functionlevel++; - $infunction = TRUE; - $after .= ' '; - } else { - $indent++; - $after .= ($mode != 'query_only' ? '
    ' : ' '); - } - break; - case 'alpha_identifier': - if ($typearr[1] == 'punct_qualifier' - || $typearr[3] == 'punct_qualifier') { - $after = ''; - $before = ''; - } - if ($typearr[3] == 'alpha_columnType' - || $typearr[3] == 'alpha_identifier') { - $after .= ' '; - } - break; - case 'punct_qualifier': - $before = ''; - $after = ''; - break; - case 'punct_listsep': - if ($infunction == TRUE) { - $after .= $space_punct_listsep_function_name; - } else { - $after .= $space_punct_listsep; - } - break; - case 'punct_queryend': - if ($typearr[3] != 'comment_mysql' - && $typearr[3] != 'comment_ansi' - && $typearr[3] != 'comment_c') { - $after .= $html_line_break; - $after .= $html_line_break; - } - $space_punct_listsep = ' '; - $space_punct_listsep_function_name = ' '; - $space_alpha_reserved_word = ' '; - $in_priv_list = FALSE; - break; - case 'comment_mysql': - case 'comment_ansi': - $after .= $html_line_break; - break; - case 'punct': - $before .= ' '; - // workaround for - // select * from mytable limit 0,-1 - // (a side effect of this workaround is that - // select 20 - 9 - // becomes - // select 20 -9 - // ) - if ($typearr[3] != 'digit_integer') { - $after .= ' '; - } - break; - case 'punct_bracket_close_round': - $bracketlevel--; - if ($infunction == TRUE) { - $functionlevel--; - $after .= ' '; - $before .= ' '; - } else { - $indent--; - $before .= ($mode != 'query_only' ? '
    ' : ' '); - } - $infunction = ($functionlevel > 0) ? TRUE : FALSE; - break; - case 'alpha_columnType': - if ($typearr[3] == 'alpha_columnAttrib') { - $after .= ' '; - } - if ($typearr[1] == 'alpha_columnType') { - $before .= ' '; - } - break; - case 'alpha_columnAttrib': - - // ALTER TABLE tbl_name AUTO_INCREMENT = 1 - // COLLATE LATIN1_GENERAL_CI DEFAULT - if ($typearr[1] == 'alpha_identifier' - || $typearr[1] == 'alpha_charset') { - $before .= ' '; - } - if ($typearr[3] == 'alpha_columnAttrib' - || $typearr[3] == 'quote_single' - || $typearr[3] == 'digit_integer') { - $after .= ' '; - } - // workaround for - // AUTO_INCREMENT = 31DEFAULT_CHARSET = utf-8 - - if ($typearr[2] == 'alpha_columnAttrib' - && $typearr[3] == 'alpha_reservedWord') { - $before .= ' '; - } - // workaround for - // select * from mysql.user where binary user="root" - // binary is marked as alpha_columnAttrib - // but should be marked as a reserved word - if (strtoupper($each_parsed['data']) == 'BINARY' - && $typearr[3] == 'alpha_identifier') { - $after .= ' '; - } - break; - case 'alpha_reservedWord': - // do not uppercase the reserved word if we are calling - // this function in query_only mode, because we need - // the original query (otherwise we get problems with - // semi-reserved words like "storage" which is legal - // as an identifier name) - - if ($mode != 'query_only') { - $each_parsed['data'] = strtoupper($each_parsed['data']); - } - - if (($typearr[1] != 'alpha_reservedWord' - || ($typearr[1] == 'alpha_reservedWord' - && PMA_STR_binarySearchInArr(strtoupper($this->_parsed[$i - 1]['data']), $keywords_no_newline, $keywords_no_newline_cnt))) - && $typearr[1] != 'punct_level_plus' - && !PMA_STR_binarySearchInArr($each_parsed['data'], $keywords_no_newline, $keywords_no_newline_cnt)) { - // do not put a space before the first token, because - // we use a lot of eregi() checking for the first - // reserved word at beginning of query - // so do not put a newline before - // - // also we must not be inside a privilege list - if ($i > 0) { - // the alpha_identifier exception is there to - // catch cases like - // GRANT SELECT ON mydb.mytable TO myuser@localhost - // (else, we get mydb.mytableTO ) - // - // the quote_single exception is there to - // catch cases like - // GRANT ... TO 'marc'@'domain.com' IDENTIFIED... - /** - * @todo fix all cases and find why this happens - */ - - if (!$in_priv_list - || $typearr[1] == 'alpha_identifier' - || $typearr[1] == 'quote_single' - || $typearr[1] == 'white_newline') { - $before .= $space_alpha_reserved_word; - } - } else { - // on first keyword, check if it introduces a - // privilege list - if (PMA_STR_binarySearchInArr($each_parsed['data'], $keywords_priv_list, $keywords_priv_list_cnt)) { - $in_priv_list = TRUE; - } - } - } else { - $before .= ' '; - } - - switch ($each_parsed['data']) { - case 'CREATE': - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = ' '; - } - break; - case 'EXPLAIN': - case 'DESCRIBE': - case 'SET': - case 'ALTER': - case 'DELETE': - case 'SHOW': - case 'DROP': - case 'UPDATE': - case 'TRUNCATE': - case 'ANALYZE': - case 'ANALYSE': - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = ' '; - } - break; - case 'INSERT': - case 'REPLACE': - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = $html_line_break; - } - break; - case 'VALUES': - $space_punct_listsep = ' '; - $space_alpha_reserved_word = $html_line_break; - break; - case 'SELECT': - $space_punct_listsep = ' '; - $space_alpha_reserved_word = $html_line_break; - break; - default: - break; - } // end switch ($each_parsed['data']) - - $after .= ' '; - break; - case 'digit_integer': - case 'digit_float': - case 'digit_hex': - /** - * @todo could there be other types preceding a digit? - */ - if ($typearr[1] == 'alpha_reservedWord') { - $after .= ' '; - } - if ($infunction && $typearr[3] == 'punct_bracket_close_round') { - $after .= ' '; - } - if ($typearr[1] == 'alpha_columnAttrib') { - $before .= ' '; - } - break; - case 'alpha_variable': - // other workaround for a problem similar to the one - // explained below for quote_single - if (!$in_priv_list && $typearr[3] != 'quote_backtick') { - $after = ' '; - } - break; - case 'quote_double': - case 'quote_single': - // workaround: for the query - // REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%' - // the @ is incorrectly marked as alpha_variable - // in the parser, and here, the '%' gets a blank before, - // which is a syntax error - if ($typearr[1] !='alpha_variable') { - $before .= ' '; - } - if ($infunction && $typearr[3] == 'punct_bracket_close_round') { - $after .= ' '; - } - break; - case 'quote_backtick': - if ($typearr[3] != 'punct_qualifier' - && $typearr[3] != 'alpha_variable') { - $after .= ' '; - } - if ($typearr[1] != 'punct_qualifier' - && $typearr[1] != 'alpha_variable') { - $before .= ' '; - } - break; - default: - break; - } // end switch ($typearr[2]) - - /* - if ($typearr[3] != 'punct_qualifier') { - $after .= ' '; - } - $after .= "\n"; - */ - $str .= $before - . ($mode == 'color' ? $this->getFormatedHtmlColored($each_parsed) : $each_parsed['data']) - . $after; - } // end for - if ($mode == 'color') { - $str .= '
    '; - } - - return $str; - } // end of the "getFormatedHtml()" function - - /** - * Builds a CSS rule used for html formatted SQL queries - * - * @param string The class name - * @param string The property name - * @param string The property value - * @return string The CSS rule - * @access public - * @see PMA_Sql::getCssData() - */ - function getCssRule($classname, $property, $value) - { - $str = '.' . $classname . ' {'; - if ($value != '') { - $str .= $property . ': ' . $value . ';'; - } - $str .= '}' . "\n"; - - return $str; - } // end of the "getCssRule()" function - - /** - * return raw SQL query - * @uses PMA_Sql::$_raw as return value - * @return string SQL query - */ - function getRaw() - { - return $this->_raw; - } - - /** - * Builds CSS rules used for html formatted SQL queries - * - * @return string The CSS rules set - * @access public - * @global array The current PMA configuration - * @see PMA_Sql::getCssRule() - */ - function getCssData() - { - global $cfg; - - $css_string = ''; - foreach ($cfg['SQP']['fmtColor'] as $key => $col) { - $css_string .= $this->getCssRule('syntax_' . $key, 'color', $col); - } - - for ($i = 0; $i < 8; $i++) { - $css_string .= $this->getCssRule('syntax_indent' . $i, 'margin-left', - ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit']); - } - - return $css_string; - } // end of the "getCssData()" function - - /** - * Gets SQL queries with no format - * - * @param array The SQL queries list - * @return string The SQL queries with no format - * @access public - */ - function getFormatedNone() - { - $formatted_sql = htmlspecialchars($this->_raw); - $formatted_sql = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", - $formatted_sql); - - return $formatted_sql; - } // end of the "getFormatedNone()" function - - /** - * Gets SQL queries in text format - * - * @todo WRITE THIS! - * @param array The SQL queries list - * @return string The SQL queries in text format - * @access public - */ - function getFormatedText() - { - return $this->getFormatedNone(); - } // end of the "getFormatedText()" function -} -?> From 5e87087b3d65e990eb8eddfe2a6d39b9e7d6de79 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Sat, 15 Sep 2007 23:16:24 +0000 Subject: [PATCH 04/79] email change --- translators.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translators.html b/translators.html index 27c7a2440..6aa113b43 100644 --- a/translators.html +++ b/translators.html @@ -122,7 +122,7 @@ Catalan - Xavier Navarro (klingonempire@tiscali.es) + Xavier Navarro (xvnavarro@gmail.com) From 7305733c3e2aef0f440431d57740f744ea3538e4 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Tue, 18 Sep 2007 12:10:53 +0000 Subject: [PATCH 05/79] patch goes to 2.11.1 instead of 2.11.2 --- ChangeLog | 1 + libraries/Config.class.php | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 541ea04c4..0c3cd93ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyA - bug #1791568 [core] Undefined cfg, thanks to Christian Schmidt - bug #1782332 [structure] New table form does not overtake data - bug #1793763 [requirements] minimum PHP should be 4.2.0 +- patch #1787915 Avoid CSS reloading on every click, thanks to Juergen Wind 2.11.0.0 (2007-08-21) diff --git a/libraries/Config.class.php b/libraries/Config.class.php index c794ca210..506e8c1e9 100644 --- a/libraries/Config.class.php +++ b/libraries/Config.class.php @@ -538,12 +538,14 @@ class PMA_Config } /** - * returns time of last config change. + * returns a unique value to force a CSS reload if either the config + * or the theme changes * @return int Unix timestamp */ function getMtime() { - return max($this->source_mtime, $this->default_source_mtime, $this->set_mtime); + return $this->source_mtime + $this->default_source_mtime + $_SESSION['PMA_Theme']->mtime_info; + //"max()" most probably would only returns "source" last modified timestamp. } /** From 981b7535ea4dc966e9705dd1cb4bf7ca1602b127 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 20 Sep 2007 16:25:32 +0000 Subject: [PATCH 06/79] bug #1798627 [GUI] Wrong storage engine displayed --- ChangeLog | 1 + libraries/StorageEngine.class.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0c3cd93ce..75edda14d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyA - bug #1782332 [structure] New table form does not overtake data - bug #1793763 [requirements] minimum PHP should be 4.2.0 - patch #1787915 Avoid CSS reloading on every click, thanks to Juergen Wind +- bug #1798627 [GUI] Wrong storage engine displayed 2.11.0.0 (2007-08-21) diff --git a/libraries/StorageEngine.class.php b/libraries/StorageEngine.class.php index ce80ae9e9..012b7fd14 100644 --- a/libraries/StorageEngine.class.php +++ b/libraries/StorageEngine.class.php @@ -105,7 +105,7 @@ class PMA_StorageEngine $output .= ' ' . "\n"; From 31751e330c1aad04a8f1549f70675f19cad9f345 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 20 Sep 2007 16:33:07 +0000 Subject: [PATCH 07/79] 2.11.1 --- ChangeLog | 2 +- Documentation.html | 4 ++-- README | 4 ++-- libraries/Config.class.php | 2 +- translators.html | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 75edda14d..6157a6506 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ phpMyAdmin - ChangeLog $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ -2.11.1.0 (not yet released) +2.11.1.0 (2007-09-20) - bug #1783667 [export] NO_AUTO_VALUE_ON_ZERO and MySQL version - bug #1780098 [GUI] Logout causes CSS loss, thanks to Juergen Wind diff --git a/Documentation.html b/Documentation.html index 6b08a5fcc..635066878 100644 --- a/Documentation.html +++ b/Documentation.html @@ -11,7 +11,7 @@ - phpMyAdmin 2.11.1-rc1 - Documentation + phpMyAdmin 2.11.1 - Documentation @@ -33,7 +33,7 @@
  • Glossary
  • -

    phpMyAdmin 2.11.1-rc1 Documentation

    +

    phpMyAdmin 2.11.1 Documentation

    • phpMyAdmin homepage
    • diff --git a/README b/README index 5f6058878..697b567c9 100644 --- a/README +++ b/README @@ -5,8 +5,8 @@ phpMyAdmin - Readme A set of PHP-scripts to manage MySQL over the web. - Version 2.11.1-rc1 - ------------------ + Version 2.11.1 + -------------- http://www.phpmyadmin.net/ Copyright (C) 1998-2000 Tobias Ratschiller diff --git a/libraries/Config.class.php b/libraries/Config.class.php index 506e8c1e9..fdfcec3f8 100644 --- a/libraries/Config.class.php +++ b/libraries/Config.class.php @@ -85,7 +85,7 @@ class PMA_Config */ function checkSystem() { - $this->set('PMA_VERSION', '2.11.1-rc1'); + $this->set('PMA_VERSION', '2.11.1'); /** * @deprecated */ diff --git a/translators.html b/translators.html index 6aa113b43..1ec0c61e0 100644 --- a/translators.html +++ b/translators.html @@ -8,7 +8,7 @@ - phpMyAdmin 2.11.1-rc1 - Official translators + phpMyAdmin 2.11.1 - Official translators @@ -31,7 +31,7 @@
    • Glossary
    -

    phpMyAdmin 2.11.1-rc1 official translators list

    +

    phpMyAdmin 2.11.1 official translators list

    Here is the list of the "official translators" of phpMyAdmin.

    From 27d5467dc3ba6e594d5e5cd291a908b48464e289 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Wed, 10 Oct 2007 07:30:59 +0000 Subject: [PATCH 08/79] fixed bug #1810629 XSS in setup.php --- ChangeLog | 3 +++ scripts/setup.php | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6157a6506..eec93b71a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ phpMyAdmin - ChangeLog $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ +2.11.1.1 (not yet released) +- bug #1810629 [setup] XSS in setup.php + 2.11.1.0 (2007-09-20) - bug #1783667 [export] NO_AUTO_VALUE_ON_ZERO and MySQL version diff --git a/scripts/setup.php b/scripts/setup.php index 4fe497154..ee723523d 100644 --- a/scripts/setup.php +++ b/scripts/setup.php @@ -1951,7 +1951,10 @@ switch ($action) { if (empty($_SERVER['REQUEST_URI']) || empty($_SERVER['HTTP_HOST'])) { $redir = ''; } else { - $redir = ' If your server is also configured to accept HTTPS request follow this link to use secure connection.'; + $redir = ' If your server is also configured to accept HTTPS request' + . ' follow this link to use secure connection.'; } message('warning', 'You are not using secure connection, all data (including sensitive, like passwords) are transfered unencrypted!' . $redir, 'Not secure connection'); } From 1c9a78764f18c2c3ea5b6f518457395cfebaced5 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Wed, 10 Oct 2007 07:33:32 +0000 Subject: [PATCH 09/79] credits for XSS report in changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index eec93b71a..34a552a9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,7 @@ $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ 2.11.1.1 (not yet released) -- bug #1810629 [setup] XSS in setup.php +- bug #1810629 [setup] XSS in setup.php, thanks to Omer Singer, The DigiTrust Group 2.11.1.0 (2007-09-20) From 6440779a420fbacf927d348f88b7bc6f86e6929c Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Mon, 15 Oct 2007 22:07:35 +0000 Subject: [PATCH 10/79] 2.11.1.1 --- ChangeLog | 2 +- Documentation.html | 4 ++-- README | 4 ++-- libraries/Config.class.php | 2 +- translators.html | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 34a552a9a..319f9abc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ phpMyAdmin - ChangeLog $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ -2.11.1.1 (not yet released) +2.11.1.1 (2007-10-15) - bug #1810629 [setup] XSS in setup.php, thanks to Omer Singer, The DigiTrust Group 2.11.1.0 (2007-09-20) diff --git a/Documentation.html b/Documentation.html index 635066878..8b0b06807 100644 --- a/Documentation.html +++ b/Documentation.html @@ -11,7 +11,7 @@ - phpMyAdmin 2.11.1 - Documentation + phpMyAdmin 2.11.1.1 - Documentation @@ -33,7 +33,7 @@
  • Glossary
  • -

    phpMyAdmin 2.11.1 Documentation

    +

    phpMyAdmin 2.11.1.1 Documentation

    • phpMyAdmin homepage
    • diff --git a/README b/README index 697b567c9..2b0896274 100644 --- a/README +++ b/README @@ -5,8 +5,8 @@ phpMyAdmin - Readme A set of PHP-scripts to manage MySQL over the web. - Version 2.11.1 - -------------- + Version 2.11.1.1 + ---------------- http://www.phpmyadmin.net/ Copyright (C) 1998-2000 Tobias Ratschiller diff --git a/libraries/Config.class.php b/libraries/Config.class.php index fdfcec3f8..9c050d708 100644 --- a/libraries/Config.class.php +++ b/libraries/Config.class.php @@ -85,7 +85,7 @@ class PMA_Config */ function checkSystem() { - $this->set('PMA_VERSION', '2.11.1'); + $this->set('PMA_VERSION', '2.11.1.1'); /** * @deprecated */ diff --git a/translators.html b/translators.html index 1ec0c61e0..81ae7906c 100644 --- a/translators.html +++ b/translators.html @@ -8,7 +8,7 @@ - phpMyAdmin 2.11.1 - Official translators + phpMyAdmin 2.11.1.1 - Official translators @@ -31,7 +31,7 @@
    • Glossary
    -

    phpMyAdmin 2.11.1 official translators list

    +

    phpMyAdmin 2.11.1.1 official translators list

    Here is the list of the "official translators" of phpMyAdmin.

    From 8647be7dd865d53250f937919a9269e267f22ca9 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 16 Oct 2007 07:09:50 +0000 Subject: [PATCH 11/79] - fixed XSS in server_status.php, thanks to Omer Singer, The DigiTrust Group - fixed some possible XSS with PHP_SELF (PATH_INFO) --- ChangeLog | 4 ++++ libraries/common.inc.php | 17 ++++++++++++++++- libraries/common.lib.php | 6 ++++-- libraries/display_change_password.lib.php | 6 ++---- libraries/grab_globals.lib.php | 2 +- server_status.php | 15 ++++++--------- 6 files changed, 33 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 319f9abc1..13a05258d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ phpMyAdmin - ChangeLog $Id$ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyAdmin/ChangeLog $ +2.11.1.2 (not yet released) +- fixed XSS in server_status.php, thanks to Omer Singer, The DigiTrust Group +- fixed some possible XSS with PHP_SELF, PATH_INFO, REQUEST_URI + 2.11.1.1 (2007-10-15) - bug #1810629 [setup] XSS in setup.php, thanks to Omer Singer, The DigiTrust Group diff --git a/libraries/common.inc.php b/libraries/common.inc.php index 9c7a7eb7b..a305f57d3 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -139,6 +139,21 @@ foreach ($GLOBALS as $key => $dummy) { } } +/** + * PATH_INFO could be compromised if set, so remove it from PHP_SELF + * and provide a clean PHP_SELF here + */ +$PMA_PHP_SELF = PMA_getenv('PHP_SELF'); +$_PATH_INFO = PMA_getenv('PATH_INFO'); +if (! empty($_PATH_INFO) && ! empty($PMA_PHP_SELF)) { + $path_info_pos = strrpos($PMA_PHP_SELF, $_PATH_INFO); + if ($path_info_pos + strlen($_PATH_INFO) === strlen($PMA_PHP_SELF)) { + $PMA_PHP_SELF = substr($PMA_PHP_SELF, 0, $path_info_pos); + } +} +$PMA_PHP_SELF = htmlspecialchars($PMA_PHP_SELF); + + /** * just to be sure there was no import (registering) before here * we empty the global space @@ -199,7 +214,7 @@ if (isset($_POST['usesubform'])) { * track this */ if (isset($_POST['redirect']) - && $_POST['redirect'] != basename(PMA_getenv('PHP_SELF'))) { + && $_POST['redirect'] != basename($PMA_PHP_SELF)) { $__redirect = $_POST['redirect']; unset($_POST['redirect']); } diff --git a/libraries/common.lib.php b/libraries/common.lib.php index b7c26e125..67e7db81d 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1449,6 +1449,7 @@ function PMA_localisedDate($timestamp = -1, $format = '') * returns a tab for tabbed navigation. * If the variables $link and $args ar left empty, an inactive tab is created * + * @uses $GLOBALS['PMA_PHP_SELF'] * @uses $GLOBALS['strEmpty'] * @uses $GLOBALS['strDrop'] * @uses $GLOBALS['active_page'] @@ -1492,7 +1493,7 @@ function PMA_getTab($tab) } elseif (!empty($tab['active']) || (isset($GLOBALS['active_page']) && $GLOBALS['active_page'] == $tab['link']) - || (basename(PMA_getenv('PHP_SELF')) == $tab['link'] && empty($tab['warning']))) + || (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link'] && empty($tab['warning']))) { $tab['class'] = 'active'; } @@ -1788,6 +1789,7 @@ function PMA_flipstring($string, $Separator = "
    \n") * @todo use PMA_fatalError() if $die === true? * @uses PMA_getenv() * @uses header_meta_style.inc.php + * @uses $GLOBALS['PMA_PHP_SELF'] * basename * @param array The names of the parameters needed by the calling * script. @@ -1809,7 +1811,7 @@ function PMA_checkParameters($params, $die = true, $request = true) $checked_special = false; } - $reported_script_name = basename(PMA_getenv('PHP_SELF')); + $reported_script_name = basename($GLOBALS['PMA_PHP_SELF']); $found_error = false; $error_message = ''; diff --git a/libraries/display_change_password.lib.php b/libraries/display_change_password.lib.php index 20186af3e..b1fdc3abc 100644 --- a/libraries/display_change_password.lib.php +++ b/libraries/display_change_password.lib.php @@ -12,13 +12,11 @@ $chg_evt_handler = (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER >= 5) ? 'onpropertychange' : 'onchange'; -$calling_script = PMA_getenv('PHP_SELF'); - // Displays the form ?> -
    + ' . "\n" . '' . "\n"; }?> diff --git a/libraries/grab_globals.lib.php b/libraries/grab_globals.lib.php index ccd0ad172..06d983e8e 100644 --- a/libraries/grab_globals.lib.php +++ b/libraries/grab_globals.lib.php @@ -103,7 +103,7 @@ if (! empty($_FILES)) { /** * globalize some environment variables */ -$server_vars = array('PHP_SELF', 'HTTP_ACCEPT_LANGUAGE', 'HTTP_AUTHORIZATION'); +$server_vars = array('HTTP_ACCEPT_LANGUAGE', 'HTTP_AUTHORIZATION'); foreach ($server_vars as $current) { // its not important HOW we detect html tags // its more important to prevent XSS diff --git a/server_status.php b/server_status.php index 75d9137f3..b5de5cdf1 100644 --- a/server_status.php +++ b/server_status.php @@ -267,11 +267,8 @@ $sections = array( // variable or section name => (name => url) $links = array(); -// because of PMA_NO_VARIABLES_IMPORT, the $PHP_SELF globalized by -// grab_globals is not available here when register_globals = Off -// and in some situations, $_SERVER['PHP_SELF'] is not defined $links['table'][$strFlushTables] - = PMA_getenv('PHP_SELF') . '?flush=TABLES&' . PMA_generate_common_url(); + = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); $links['table'][$strShowOpenTables] = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . '&goto=server_status.php&' . PMA_generate_common_url(); @@ -286,7 +283,7 @@ $links['repl']['MySQL - ' . $strDocu] = $cfg['MySQLManualBase'] . '/replication.html'; $links['qcache'][$strFlushQueryCache] - = PMA_getenv('PHP_SELF') . '?flush=' . urlencode('QUERY CACHE') . '&' . + = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . PMA_generate_common_url(); $links['qcache']['MySQL - ' . $strDocu] = $cfg['MySQLManualBase'] . '/query-cache.html'; @@ -345,10 +342,10 @@ $hour_factor = 3600 / $server_status['Uptime']; ?>