diff --git a/ChangeLog b/ChangeLog index ba203a65c1..2ae6ca654c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,18 @@ phpMyAdmin - ChangeLog ====================== +4.5.5.1 (2016-02-29) +- issue #11971 CREATE UNIQUE INDEX index type is not recognized by parser. +- issue #11982 Row count wrong when grouping joined tables. +- issue #12012 Column definition with default value and comment in CREATE TABLE expoerted faulty. +- issue #12020 New statement but no delimiter and unexpected token with REPLACE. +- issue #12029 Fixed incorrect usage of SQL parser context in SQL export +- issue [security] XSS vulnerability in SQL parser, see PMASA-2016-10. +- issue [security] Multiple XSS vulnerabilities, see PMASA-2016-11. +- issue [security] Multiple XSS vulnerabilities, see PMASA-2016-12. +- issue [security] Vulnerability allowing man-in-the-middle attack on API call to GitHub, see PMASA-2016-13. +- issue #12048 Fixed inclusion of gettext library from SQL parser + 4.5.5.0 (2016-02-22) - issue Undefined index: is_ajax_request - issue #11855 Fix password change on MariaDB 10.1 and newer @@ -70,15 +82,15 @@ phpMyAdmin - ChangeLog - issue #11854 Undefined property: stdClass::$releases at version check when disabled in config - issue #11814 SQL comment and variable stripped from bookmark on save - issue Gracefully handle errors in regex based javascript search -- issue [Security] Multiple full path disclosure vulnerabilities, see PMASA-2016-1 -- issue [Security] Unsafe generation of CSRF token, see PMASA-2016-2 -- issue [Security] Multiple XSS vulnerabilities, see PMASA-2016-3 -- issue [Security] Insecure password generation in JavaScript, see PMASA-2016-4 -- issue [Security] Unsafe comparison of CSRF token, see PMASA-2016-5 -- issue [Security] Multiple full path disclosure vulnerabilities, see PMASA-2016-6 -- issue [Security] XSS vulnerability in normalization page, see PMASA-2016-7 -- issue [Security] Full path disclosure vulnerability in SQL parser, see PMASA-2016-8 -- issue [Security] XSS vulnerability in SQL editor, see PMASA-2016-9 +- issue [security] Multiple full path disclosure vulnerabilities, see PMASA-2016-1 +- issue [security] Unsafe generation of CSRF token, see PMASA-2016-2 +- issue [security] Multiple XSS vulnerabilities, see PMASA-2016-3 +- issue [security] Insecure password generation in JavaScript, see PMASA-2016-4 +- issue [security] Unsafe comparison of CSRF token, see PMASA-2016-5 +- issue [security] Multiple full path disclosure vulnerabilities, see PMASA-2016-6 +- issue [security] XSS vulnerability in normalization page, see PMASA-2016-7 +- issue [security] Full path disclosure vulnerability in SQL parser, see PMASA-2016-8 +- issue [security] XSS vulnerability in SQL editor, see PMASA-2016-9 --- Older ChangeLogs can be found on our project website --- http://www.phpmyadmin.net/old-stuff/ChangeLogs/ diff --git a/README b/README index 52d35d8a75..12c3431601 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ phpMyAdmin - Readme =================== -Version 4.5.5 +Version 4.5.5.1 A set of PHP-scripts to manage MySQL over the web. diff --git a/db_central_columns.php b/db_central_columns.php index 2e9aac73bb..4c78eba255 100644 --- a/db_central_columns.php +++ b/db_central_columns.php @@ -92,7 +92,7 @@ if (isset($_REQUEST['total_rows']) && $_REQUEST['total_rows']) { } else { $total_rows = PMA_getCentralColumnsCount($db); } -if (isset($_REQUEST['pos'])) { +if (PMA_isValid($_REQUEST['pos'], 'integer')) { $pos = $_REQUEST['pos']; } else { $pos = 0; diff --git a/doc/conf.py b/doc/conf.py index 12ea522e99..f40d1c32c2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -51,7 +51,7 @@ copyright = u'2012 - 2014, The phpMyAdmin devel team' # built documents. # # The short X.Y version. -version = '4.5.5' +version = '4.5.5.1' # The full version, including alpha/beta/rc tags. release = version diff --git a/file_echo.php b/file_echo.php index 1f27bb019b..0bc976d44b 100644 --- a/file_echo.php +++ b/file_echo.php @@ -67,12 +67,16 @@ if (isset($_REQUEST['filename']) && isset($_REQUEST['image'])) { } else if (isset($_REQUEST['monitorconfig'])) { /* For monitor chart config export */ - PMA_downloadHeader('monitor.cfg', 'application/force-download'); + PMA_downloadHeader('monitor.cfg', 'application/json; charset=UTF-8'); + header('X-Content-Type-Options: nosniff'); + echo urldecode($_REQUEST['monitorconfig']); } else if (isset($_REQUEST['import'])) { /* For monitor chart config import */ - header('Content-type: text/plain'); + header('Content-Type: application/json; charset=UTF-8'); + header('X-Content-Type-Options: nosniff'); + if (!file_exists($_FILES['file']['tmp_name'])) { exit(); } diff --git a/js/functions.js b/js/functions.js index edf8f457eb..b6a46a39c2 100644 --- a/js/functions.js +++ b/js/functions.js @@ -243,6 +243,24 @@ function escapeHtml(unsafe) { } } +function escapeJsString(unsafe) { + if (typeof(unsafe) != 'undefined') { + return unsafe + .toString() + .replace("\000", '') + .replace('\\', '\\\\') + .replace('\'', '\\\'') + .replace("'", "\\\'") + .replace('"', '\"') + .replace(""", "\"") + .replace("\n", '\n') + .replace("\r", '\r') + .replace(/<\/script/gi, '\' + \'script') + } else { + return false; + } +} + function PMA_sprintf() { return sprintf.apply(this, arguments); } @@ -1840,7 +1858,7 @@ AJAX.registerOnload('functions.js', function () { var $inner_sql = $(this).parent().prev().find('code.sql'); var old_text = $inner_sql.html(); - var new_content = "\n"; + var new_content = "\n"; new_content += getForeignKeyCheckboxLoader(); new_content += "\n"; new_content += "\n"; diff --git a/js/normalization.js b/js/normalization.js index 196e83aed9..5e2b8802f6 100644 --- a/js/normalization.js +++ b/js/normalization.js @@ -82,7 +82,7 @@ function goTo2NFStep1() { $("#mainContent #extra").html(data.extra); $("#mainContent #newCols").html(''); if (data.subText !== '') { - $('.tblFooters').html(''); + $('.tblFooters').html(''); } else { if (normalizeto === '3nf') { $("#mainContent #newCols").html(PMA_messages.strToNextStep); @@ -128,7 +128,7 @@ function goToStep4() $("#mainContent #newCols").html(''); $('.tblFooters').html(''); for(var pk in primary_key) { - $("#extra input[value='" + primary_key[pk] + "']").attr("disabled","disabled"); + $("#extra input[value='" + escapeJsString(primary_key[pk]) + "']").attr("disabled","disabled"); } } ); @@ -153,7 +153,7 @@ function goToStep3() $('.tblFooters').html(''); primary_key = $.parseJSON(data.primary_key); for(var pk in primary_key) { - $("#extra input[value='" + primary_key[pk] + "']").attr("disabled","disabled"); + $("#extra input[value='" + escapeJsString(primary_key[pk]) + "']").attr("disabled","disabled"); } } ); @@ -638,7 +638,7 @@ AJAX.registerOnload('normalization.js', function() { ''; $("#newCols").html(confirmStr); $('.tblFooters').html('' + - ''); + ''); } }); $("#mainContent p").on("click", "#createPrimaryKey", function(event) { diff --git a/libraries/Config.class.php b/libraries/Config.class.php index 5819673249..12844d24a6 100644 --- a/libraries/Config.class.php +++ b/libraries/Config.class.php @@ -114,7 +114,7 @@ class PMA_Config */ public function checkSystem() { - $this->set('PMA_VERSION', '4.5.5'); + $this->set('PMA_VERSION', '4.5.5.1'); /** * @deprecated */ @@ -774,8 +774,8 @@ class PMA_Config PMA_Util::configureCurl($handle); curl_setopt($handle, CURLOPT_FOLLOWLOCATION, 0); curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, '2'); + curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, '1'); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($handle, CURLOPT_TIMEOUT, 5); curl_setopt($handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); @@ -1370,7 +1370,7 @@ class PMA_Config $pma_absolute_uri .= '@'; } // Add hostname - $pma_absolute_uri .= $url['host']; + $pma_absolute_uri .= urlencode($url['host']); // Add port, if it not the default one // (or 80 for https which is most likely a bug) if (! empty($url['port']) diff --git a/libraries/controllers/TableSearchController.class.php b/libraries/controllers/TableSearchController.class.php index 12de6d2367..ddd6d56c4b 100644 --- a/libraries/controllers/TableSearchController.class.php +++ b/libraries/controllers/TableSearchController.class.php @@ -471,7 +471,11 @@ class TableSearchController extends TableController return; } $key = array_search($field, $this->_columnNames); - $properties = $this->getColumnProperties($_REQUEST['it'], $key); + $search_index = 0; + if (PMA_isValid($_REQUEST['it'], 'integer')) { + $search_index = $_REQUEST['it']; + } + $properties = $this->getColumnProperties($search_index, $key); $this->response->addJSON( 'field_type', htmlspecialchars($properties['type']) ); diff --git a/libraries/plugins/export/ExportSql.class.php b/libraries/plugins/export/ExportSql.class.php index 715ad48f92..552a64fe51 100644 --- a/libraries/plugins/export/ExportSql.class.php +++ b/libraries/plugins/export/ExportSql.class.php @@ -1554,7 +1554,7 @@ class ExportSql extends ExportPlugin if (empty($sql_backquotes)) { // Option "Enclose table and column names with backquotes" // was checked. - Context::$MODE |= Context::NO_ENCLOSING_QUOTES; + SqlParser\Context::$MODE |= SqlParser\Context::NO_ENCLOSING_QUOTES; } // Using appropriate quotes. diff --git a/libraries/server_privileges.lib.php b/libraries/server_privileges.lib.php index 9ad749a177..a60c999875 100644 --- a/libraries/server_privileges.lib.php +++ b/libraries/server_privileges.lib.php @@ -3499,7 +3499,7 @@ function PMA_getUsersOverview($result, $db_rights, $pmaThemeImage, $text_dir) __('Export'), 'b_tblexport.png', 'export' ); $html_output .= ''; + . 'value="' . (isset($_GET['initial']) ? htmlspecialchars($_GET['initial']) : '') . '" />'; $html_output .= '' . '
'; diff --git a/libraries/sql-parser/autoload.php b/libraries/sql-parser/autoload.php index 21298b6ced..f12057f211 100644 --- a/libraries/sql-parser/autoload.php +++ b/libraries/sql-parser/autoload.php @@ -67,7 +67,8 @@ class AutoloaderInit // This must be included before any class of the parser is loaded because // if there is no `__` function defined, the library defines a dummy one // in `common.php`. -require_once './libraries/php-gettext/gettext.inc'; +require_once './libraries/vendor_config.php'; +require_once GETTEXT_INC; // Initializing the autoloader. return AutoloaderInit::getLoader( diff --git a/libraries/sql-parser/src/Components/AlterOperation.php b/libraries/sql-parser/src/Components/AlterOperation.php index d0b09f18bd..10c27eac1f 100644 --- a/libraries/sql-parser/src/Components/AlterOperation.php +++ b/libraries/sql-parser/src/Components/AlterOperation.php @@ -26,19 +26,31 @@ class AlterOperation extends Component { /** - * All alter operations. + * All database options * * @var array */ - public static $OPTIONS = array( + public static $DB_OPTIONS = array( + 'CHARACTER SET' => array(1, 'var'), + 'CHARSET' => array(1, 'var'), + 'DEFAULT CHARACTER SET' => array(1, 'var'), + 'DEFAULT CHARSET' => array(1, 'var'), + 'UPGRADE' => array(1, 'var'), + 'COLLATE' => array(2, 'var'), + 'DEFAULT COLLATE' => array(2, 'var'), + ); - // table_options + /** + * All table options + * + * @var array + */ + public static $TABLE_OPTIONS = array( 'ENGINE' => array(1, 'var='), 'AUTO_INCREMENT' => array(1, 'var='), 'AVG_ROW_LENGTH' => array(1, 'var'), 'MAX_ROWS' => array(1, 'var'), 'ROW_FORMAT' => array(1, 'var'), - 'ADD' => 1, 'ALTER' => 1, 'ANALYZE' => 1, @@ -60,6 +72,7 @@ class AlterOperation extends Component 'RENAME' => 1, 'REORGANIZE' => 1, 'REPAIR' => 1, + 'UPGRADE' => 1, 'COLUMN' => 2, 'CONSTRAINT' => 2, @@ -75,11 +88,15 @@ class AlterOperation extends Component 'SPATIAL' => 2, 'TABLESPACE' => 2, 'INDEX' => 2, + ); - 'DEFAULT CHARACTER SET' => array(3, 'var'), - 'DEFAULT CHARSET' => array(3, 'var'), - - 'COLLATE' => array(4, 'var'), + /** + * All view options + * + * @var array + */ + public static $VIEW_OPTIONS = array( + 'AS' => 1, ); /** @@ -165,7 +182,18 @@ class AlterOperation extends Component } if ($state === 0) { - $ret->options = OptionsArray::parse($parser, $list, static::$OPTIONS); + $ret->options = OptionsArray::parse($parser, $list, $options); + + if ($ret->options->has('AS')) { + for (; $list->idx < $list->count; ++$list->idx) { + if ($list->tokens[$list->idx]->type === Token::TYPE_DELIMITER) { + break; + } + $ret->unknown[] = $list->tokens[$list->idx]; + } + break; + } + $state = 1; } elseif ($state === 1) { $ret->field = Expression::parse( diff --git a/libraries/sql-parser/src/Components/ArrayObj.php b/libraries/sql-parser/src/Components/ArrayObj.php index 56c7247e9b..627f8c750e 100644 --- a/libraries/sql-parser/src/Components/ArrayObj.php +++ b/libraries/sql-parser/src/Components/ArrayObj.php @@ -108,7 +108,7 @@ class ArrayObj extends Component || ($token->type === Token::TYPE_COMMENT) ) { $lastRaw .= $token->token; - $lastValue = trim($lastValue) .' '; + $lastValue = trim($lastValue) . ' '; continue; } diff --git a/libraries/sql-parser/src/Components/Condition.php b/libraries/sql-parser/src/Components/Condition.php index f3179ead44..e84ad864ac 100644 --- a/libraries/sql-parser/src/Components/Condition.php +++ b/libraries/sql-parser/src/Components/Condition.php @@ -166,7 +166,10 @@ class Condition extends Component } } - if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED)) { + if (($token->type === Token::TYPE_KEYWORD) + && ($token->flags & Token::FLAG_KEYWORD_RESERVED) + && !($token->flags & Token::FLAG_KEYWORD_FUNCTION) + ) { if ($token->value === 'BETWEEN') { $betweenBefore = true; } diff --git a/libraries/sql-parser/src/Components/CreateDefinition.php b/libraries/sql-parser/src/Components/CreateDefinition.php index 13e5e83a59..79a2745bcc 100644 --- a/libraries/sql-parser/src/Components/CreateDefinition.php +++ b/libraries/sql-parser/src/Components/CreateDefinition.php @@ -43,7 +43,7 @@ class CreateDefinition extends Component 'NOT NULL' => 1, 'NULL' => 1, - 'DEFAULT' => array(2, 'expr'), + 'DEFAULT' => array(2, 'expr', array('breakOnAlias' => true)), 'AUTO_INCREMENT' => 3, 'PRIMARY' => 4, 'PRIMARY KEY' => 4, diff --git a/libraries/sql-parser/src/Components/Expression.php b/libraries/sql-parser/src/Components/Expression.php index f6d3895479..0b9f21513a 100644 --- a/libraries/sql-parser/src/Components/Expression.php +++ b/libraries/sql-parser/src/Components/Expression.php @@ -243,9 +243,9 @@ class Expression extends Component if (!empty($options['breakOnAlias'])) { break; } - if (!empty($ret->alias)) { + if ($alias) { $parser->error( - __('An alias was previously found.'), + __('An alias was expected.'), $token ); break; diff --git a/libraries/sql-parser/src/Components/JoinKeyword.php b/libraries/sql-parser/src/Components/JoinKeyword.php index d8e6ee916b..75ecca6064 100644 --- a/libraries/sql-parser/src/Components/JoinKeyword.php +++ b/libraries/sql-parser/src/Components/JoinKeyword.php @@ -63,6 +63,13 @@ class JoinKeyword extends Component */ public $on; + /** + * Columns in Using clause + * + * @var ArrayObj + */ + public $using; + /** * @param Parser $parser The parser that serves as context. * @param TokensList $list The list of tokens that are being parsed. @@ -86,9 +93,12 @@ class JoinKeyword extends Component * 1 -----------------------[ expr ]----------------------> 2 * * 2 ------------------------[ ON ]-----------------------> 3 + * 2 -----------------------[ USING ]---------------------> 4 * * 3 --------------------[ conditions ]-------------------> 0 * + * 4 ----------------------[ columns ]--------------------> 0 + * * @var int $state */ $state = 0; @@ -131,14 +141,23 @@ class JoinKeyword extends Component $expr->expr = Expression::parse($parser, $list, array('field' => 'table')); $state = 2; } elseif ($state === 2) { - if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'ON')) { - $state = 3; + if ($token->type === Token::TYPE_KEYWORD) { + if ($token->value === 'ON') { + $state = 3; + } elseif ($token->value === 'USING') { + $state = 4; + } } } elseif ($state === 3) { $expr->on = Condition::parse($parser, $list); $ret[] = $expr; $expr = new JoinKeyword(); $state = 0; + } elseif ($state === 4) { + $expr->using = ArrayObj::parse($parser, $list); + $ret[] = $expr; + $expr = new JoinKeyword(); + $state = 0; } } @@ -161,8 +180,10 @@ class JoinKeyword extends Component { $ret = array(); foreach ($component as $c) { - $ret[] = array_search($c->type, static::$JOINS) . ' ' - . $c->expr . ' ON ' . Condition::build($c->on); + $ret[] = array_search($c->type, static::$JOINS) . ' ' . $c->expr + . (!empty($c->on) + ? ' ON ' . Condition::build($c->on) + : ' USING ' . ArrayObj::build($c->using)); } return implode(' ', $ret); } diff --git a/libraries/sql-parser/src/Components/Key.php b/libraries/sql-parser/src/Components/Key.php index 161dfc6153..ef066dd179 100644 --- a/libraries/sql-parser/src/Components/Key.php +++ b/libraries/sql-parser/src/Components/Key.php @@ -93,7 +93,7 @@ class Key extends Component * @param TokensList $list The list of tokens that are being parsed. * @param array $options Parameters for parsing. * - * @return Key[] + * @return Key */ public static function parse(Parser $parser, TokensList $list, array $options = array()) { diff --git a/libraries/sql-parser/src/Components/Limit.php b/libraries/sql-parser/src/Components/Limit.php index c6b3290cab..30881dcbef 100644 --- a/libraries/sql-parser/src/Components/Limit.php +++ b/libraries/sql-parser/src/Components/Limit.php @@ -128,7 +128,7 @@ class Limit extends Component public static function build($component, array $options = array()) { if (empty($component->offset)) { - return $component->rowCount; + return (string) $component->rowCount; } else { return $component->offset . ', ' . $component->rowCount; } diff --git a/libraries/sql-parser/src/Components/OptionsArray.php b/libraries/sql-parser/src/Components/OptionsArray.php index 229b350110..3d2fdedd7e 100644 --- a/libraries/sql-parser/src/Components/OptionsArray.php +++ b/libraries/sql-parser/src/Components/OptionsArray.php @@ -287,10 +287,12 @@ class OptionsArray extends Component public function has($key, $getExpr = false) { foreach ($this->options as $option) { - if ($key === $option) { + if (is_array($option)) { + if (!strcasecmp($key, $option['name'])) { + return $getExpr ? $option['expr'] : $option['value']; + } + } elseif (!strcasecmp($key, $option)) { return true; - } elseif ((is_array($option)) && ($key === $option['name'])) { - return $getExpr ? $option['expr'] : $option['value']; } } return false; @@ -306,9 +308,12 @@ class OptionsArray extends Component public function remove($key) { foreach ($this->options as $idx => $option) { - if (($key === $option) - || ((is_array($option)) && ($key === $option['name'])) - ) { + if (is_array($option)) { + if (!strcasecmp($key, $option['name'])) { + unset($this->options[$idx]); + return true; + } + } elseif (!strcasecmp($key, $option)) { unset($this->options[$idx]); return true; } diff --git a/libraries/sql-parser/src/Components/OrderKeyword.php b/libraries/sql-parser/src/Components/OrderKeyword.php index fc226f0446..7d23013836 100644 --- a/libraries/sql-parser/src/Components/OrderKeyword.php +++ b/libraries/sql-parser/src/Components/OrderKeyword.php @@ -100,9 +100,13 @@ class OrderKeyword extends Component $expr->expr = Expression::parse($parser, $list); $state = 1; } elseif ($state === 1) { - if (($token->type === Token::TYPE_KEYWORD) && (($token->value === 'ASC') || ($token->value === 'DESC'))) { + if (($token->type === Token::TYPE_KEYWORD) + && (($token->value === 'ASC') || ($token->value === 'DESC')) + ) { $expr->type = $token->value; - } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) { + } elseif (($token->type === Token::TYPE_OPERATOR) + && ($token->value === ',') + ) { if (!empty($expr->expr)) { $ret[] = $expr; } diff --git a/libraries/sql-parser/src/Components/SetOperation.php b/libraries/sql-parser/src/Components/SetOperation.php index 9306d43995..ffe754aef5 100644 --- a/libraries/sql-parser/src/Components/SetOperation.php +++ b/libraries/sql-parser/src/Components/SetOperation.php @@ -85,7 +85,10 @@ class SetOperation extends Component } // No keyword is expected. - if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED) && ($state == 0)) { + if (($token->type === Token::TYPE_KEYWORD) + && ($token->flags & Token::FLAG_KEYWORD_RESERVED) + && ($state == 0) + ) { break; } @@ -104,7 +107,6 @@ class SetOperation extends Component ) ); if ($tmp == null) { - $expr = null; break; } $expr->column = trim($expr->column); diff --git a/libraries/sql-parser/src/Parser.php b/libraries/sql-parser/src/Parser.php index e878570b19..3c72a8598e 100644 --- a/libraries/sql-parser/src/Parser.php +++ b/libraries/sql-parser/src/Parser.php @@ -185,6 +185,11 @@ class Parser 'class' => 'SqlParser\\Components\\JoinKeyword', 'field' => 'join', ), + 'ON' => array( + 'class' => 'SqlParser\\Components\\Expression', + 'field' => 'table', + 'options' => array('parseField' => 'table'), + ), 'RIGHT JOIN' => array( 'class' => 'SqlParser\\Components\\JoinKeyword', 'field' => 'join', diff --git a/libraries/sql-parser/src/Statements/AlterStatement.php b/libraries/sql-parser/src/Statements/AlterStatement.php index c8786bd603..e76599958d 100644 --- a/libraries/sql-parser/src/Statements/AlterStatement.php +++ b/libraries/sql-parser/src/Statements/AlterStatement.php @@ -51,6 +51,15 @@ class AlterStatement extends Statement 'ONLINE' => 1, 'OFFLINE' => 1, 'IGNORE' => 2, + + 'DATABASE' => 3, + 'EVENT' => 3, + 'FUNCTION' => 3, + 'PROCEDURE' => 3, + 'SERVER' => 3, + 'TABLE' => 3, + 'TABLESPACE' => 3, + 'VIEW' => 3, ); /** @@ -67,16 +76,14 @@ class AlterStatement extends Statement $list, static::$OPTIONS ); - - // Skipping `TABLE`. - $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'TABLE'); + ++$list->idx; // Parsing affected table. $this->table = Expression::parse( $parser, $list, array( - 'parseField' => 'column', + 'parseField' => 'table', 'breakOnAlias' => true, ) ); @@ -114,7 +121,16 @@ class AlterStatement extends Statement } if ($state === 0) { - $this->altered[] = AlterOperation::parse($parser, $list); + $options = array(); + if ($this->options->has('DATABASE')) { + $options = AlterOperation::$DB_OPTIONS; + } elseif ($this->options->has('TABLE')) { + $options = AlterOperation::$TABLE_OPTIONS; + } elseif ($this->options->has('VIEW')) { + $options = AlterOperation::$VIEW_OPTIONS; + } + + $this->altered[] = AlterOperation::parse($parser, $list, $options); $state = 1; } elseif ($state === 1) { if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) { @@ -135,7 +151,7 @@ class AlterStatement extends Statement } return 'ALTER ' . OptionsArray::build($this->options) - . ' TABLE ' . Expression::build($this->table) + . ' ' . Expression::build($this->table) . ' ' . implode(', ', $tmp); } } diff --git a/libraries/sql-parser/src/Statements/CreateStatement.php b/libraries/sql-parser/src/Statements/CreateStatement.php index d5e23ad421..83c856c352 100644 --- a/libraries/sql-parser/src/Statements/CreateStatement.php +++ b/libraries/sql-parser/src/Statements/CreateStatement.php @@ -53,6 +53,9 @@ class CreateStatement extends Statement 'EVENT' => 6, 'FUNCTION' => 6, 'INDEX' => 6, + 'UNIQUE INDEX' => 6, + 'FULLTEXT INDEX' => 6, + 'SPATIAL INDEX' => 6, 'PROCEDURE' => 6, 'SERVER' => 6, 'TABLE' => 6, @@ -314,13 +317,11 @@ class CreateStatement extends Statement . Expression::build($this->name) . ' ' . ParameterDefinition::build($this->parameters) . ' ' . $tmp . ' ' . TokensList::build($this->body); - } else { - return 'CREATE ' - . OptionsArray::build($this->options) . ' ' - . Expression::build($this->name) . ' ' - . TokensList::build($this->body); } - return ''; + return 'CREATE ' + . OptionsArray::build($this->options) . ' ' + . Expression::build($this->name) . ' ' + . TokensList::build($this->body); } /** diff --git a/libraries/sql-parser/src/Statements/DropStatement.php b/libraries/sql-parser/src/Statements/DropStatement.php index 70583ed83b..5110c9db16 100644 --- a/libraries/sql-parser/src/Statements/DropStatement.php +++ b/libraries/sql-parser/src/Statements/DropStatement.php @@ -59,6 +59,7 @@ class DropStatement extends Statement '_OPTIONS' => array('_OPTIONS', 1), // Used for select expressions. 'DROP_' => array('DROP', 1), + 'ON' => array('ON', 3), ); /** @@ -67,4 +68,11 @@ class DropStatement extends Statement * @var Expression[] */ public $fields; + + /** + * Table of the dropped index. + * + * @var Expression + */ + public $table; } diff --git a/libraries/sql-parser/src/Token.php b/libraries/sql-parser/src/Token.php index 9659672cf1..18ffec76a7 100644 --- a/libraries/sql-parser/src/Token.php +++ b/libraries/sql-parser/src/Token.php @@ -235,17 +235,17 @@ class Token if ($this->flags & Token::FLAG_NUMBER_HEX) { if ($this->flags & Token::FLAG_NUMBER_NEGATIVE) { $ret = str_replace('-', '', $this->token); - sscanf($ret, "%x", $ret); + sscanf($ret, '%x', $ret); $ret = -$ret; } else { - sscanf($ret, "%x", $ret); + sscanf($ret, '%x', $ret); } } elseif (($this->flags & Token::FLAG_NUMBER_APPROXIMATE) || ($this->flags & Token::FLAG_NUMBER_FLOAT) ) { - sscanf($ret, "%f", $ret); + sscanf($ret, '%f', $ret); } else { - sscanf($ret, "%d", $ret); + sscanf($ret, '%d', $ret); } return $ret; case Token::TYPE_STRING: diff --git a/libraries/sql-parser/src/Utils/Error.php b/libraries/sql-parser/src/Utils/Error.php index a9c0814fcf..f0ad5afbb2 100644 --- a/libraries/sql-parser/src/Utils/Error.php +++ b/libraries/sql-parser/src/Utils/Error.php @@ -90,7 +90,7 @@ class Error ++$i, $err[0], $err[1], - $err[2], + htmlspecialchars($err[2]), $err[3] ); } diff --git a/libraries/sql-parser/src/Utils/Formatter.php b/libraries/sql-parser/src/Utils/Formatter.php index 266440bcd6..2ac7e3b4bd 100644 --- a/libraries/sql-parser/src/Utils/Formatter.php +++ b/libraries/sql-parser/src/Utils/Formatter.php @@ -80,7 +80,7 @@ class Formatter * * @var string */ - 'indentation' => " ", + 'indentation' => ' ', /** * Whether comments should be removed or not. @@ -122,49 +122,49 @@ class Formatter 'type' => Token::TYPE_KEYWORD, 'flags' => Token::FLAG_KEYWORD_RESERVED, 'html' => 'class="sql-reserved"', - 'cli' => "\e[35m", + 'cli' => "\e[35m", 'function' => 'strtoupper', ), array( 'type' => Token::TYPE_KEYWORD, 'flags' => 0, 'html' => 'class="sql-keyword"', - 'cli' => "\e[95m", + 'cli' => "\e[95m", 'function' => 'strtoupper', ), array( 'type' => Token::TYPE_COMMENT, 'flags' => 0, 'html' => 'class="sql-comment"', - 'cli' => "\e[37m", + 'cli' => "\e[37m", 'function' => '', ), array( 'type' => Token::TYPE_BOOL, 'flags' => 0, 'html' => 'class="sql-atom"', - 'cli' => "\e[36m", + 'cli' => "\e[36m", 'function' => 'strtoupper', ), array( 'type' => Token::TYPE_NUMBER, 'flags' => 0, 'html' => 'class="sql-number"', - 'cli' => "\e[92m", + 'cli' => "\e[92m", 'function' => 'strtolower', ), array( 'type' => Token::TYPE_STRING, 'flags' => 0, 'html' => 'class="sql-string"', - 'cli' => "\e[91m", + 'cli' => "\e[91m", 'function' => '', ), array( 'type' => Token::TYPE_SYMBOL, 'flags' => 0, 'html' => 'class="sql-variable"', - 'cli' => "\e[36m", + 'cli' => "\e[36m", 'function' => '', ), ) @@ -387,7 +387,8 @@ class Formatter // Also, some tokens do not have spaces before or after them. if (!((($prev->type === Token::TYPE_OPERATOR) && (($prev->value === '.') || ($prev->value === '('))) // No space after . ( - || (($curr->type === Token::TYPE_OPERATOR) && (($curr->value === '.') || ($curr->value === ',') || ($curr->value === '(') || ($curr->value === ')'))) + || (($curr->type === Token::TYPE_OPERATOR) && (($curr->value === '.') || ($curr->value === ',') + || ($curr->value === '(') || ($curr->value === ')'))) // No space before . , ( ) || (($curr->type === Token::TYPE_DELIMITER)) && (mb_strlen($curr->value, 'UTF-8') < 2)) // A space after delimiters that are longer than 2 characters. diff --git a/libraries/sql-parser/src/Utils/Query.php b/libraries/sql-parser/src/Utils/Query.php index d76e6bb723..239cd6f41b 100644 --- a/libraries/sql-parser/src/Utils/Query.php +++ b/libraries/sql-parser/src/Utils/Query.php @@ -57,8 +57,8 @@ class Query /** * Gets an array with flags this statement has. * - * @param Statement $statement The statement to be processed. - * @param bool $all If `false`, false values will not be included. + * @param Statement|null $statement The statement to be processed. + * @param bool $all If `false`, false values will not be included. * * @return array */ @@ -380,7 +380,7 @@ class Query $parser = new Parser($query); if (empty($parser->statements[0])) { - return array(); + return static::getFlags(null, true); } $statement = $parser->statements[0]; diff --git a/libraries/tcpdf/include/tcpdf_static.php b/libraries/tcpdf/include/tcpdf_static.php index 4ab18b6c4d..a1915d640b 100644 --- a/libraries/tcpdf/include/tcpdf_static.php +++ b/libraries/tcpdf/include/tcpdf_static.php @@ -2508,8 +2508,6 @@ class TCPDF_STATIC { } curl_setopt($cs, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($cs, CURLOPT_TIMEOUT, 30); - curl_setopt($cs, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($cs, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($cs, CURLOPT_USERAGENT, 'TCPDF'); $ret = curl_exec($cs); curl_close($cs); diff --git a/normalization.php b/normalization.php index 4cb9569181..069dabbc0f 100644 --- a/normalization.php +++ b/normalization.php @@ -72,7 +72,7 @@ $scripts = $header->getScripts(); $scripts->addFile('normalization.js'); $scripts->addFile('jquery/jquery.uitablefilter.js'); $normalForm = '1nf'; -if (isset($_REQUEST['normalizeTo'])) { +if (PMA_isValid($_REQUEST['normalizeTo'], array('1nf', '2nf', '3nf'))) { $normalForm = $_REQUEST['normalizeTo']; } if (isset($_REQUEST['createNewTables2NF'])) { diff --git a/templates/database/structure/sortable_header.phtml b/templates/database/structure/sortable_header.phtml index d3cec6fd63..044647158d 100644 --- a/templates/database/structure/sortable_header.phtml +++ b/templates/database/structure/sortable_header.phtml @@ -51,16 +51,20 @@ if ($requested_sort == $sort) { } $_url_params = array( 'db' => $_REQUEST['db'], + 'pos' => 0, // We set the position back to 0 every time they sort. + 'sort' => $sort, + 'sort_order' => $future_sort_order, ); -$url = 'db_structure.php' . PMA_URL_getCommon($_url_params); -// We set the position back to 0 every time they sort. -$url .= "&pos=0&sort=$sort&sort_order=$future_sort_order"; -if (! empty($_REQUEST['tbl_type'])) { - $url .= "&tbl_type=" . $_REQUEST['tbl_type']; + +if (PMA_isValid($_REQUEST['tbl_type'], array('view', 'table'))) { + $_url_params['tbl_type'] = $_REQUEST['tbl_type']; } if (! empty($_REQUEST['tbl_group'])) { - $url .= "&tbl_group=" . $_REQUEST['tbl_group']; + $_url_params['tbl_group'] = $_REQUEST['tbl_group']; } + +$url = 'db_structure.php' . PMA_URL_getCommon($_url_params); + echo PMA_Util::linkOrButton( $url, $title . $order_img, $order_link_params -); \ No newline at end of file +); diff --git a/templates/table/search/input_box.phtml b/templates/table/search/input_box.phtml index e9e09b9914..e5bcba1d2c 100644 --- a/templates/table/search/input_box.phtml +++ b/templates/table/search/input_box.phtml @@ -20,7 +20,7 @@ if ($_foreigners - value="" + value="" /> " + - @@ -129,7 +129,7 @@ if ($_foreigners - value="" + value="" /> \ No newline at end of file diff --git a/templates/table/search/rows_zoom.phtml b/templates/table/search/rows_zoom.phtml index 1964eefbd0..fb9d83dfb7 100644 --- a/templates/table/search/rows_zoom.phtml +++ b/templates/table/search/rows_zoom.phtml @@ -68,7 +68,7 @@ for ($i = 0; $i < 4; $i++): ?>