diff --git a/ChangeLog b/ChangeLog index 06745bbc90..7858655aaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -59,6 +59,10 @@ VerboseMultiSubmit, ReplaceHelpImg - [interface] Designer sometimes places tables on the top menu - bug #3546277 [core] Call to undefined function __() when config file has wrong permissions - bug #3540922 [edit] Error searching table with many fields +- bug #3555104 [edit] Cannot copy a DB with table & views + +3.5.2.2 (2012-08-12) +- [security] Fixed XSS vulnerabilities, see PMASA-2012-4 3.5.2.1 (2012-08-03) - [security] Fixed local path disclosure vulnerability, see PMASA-2012-3 @@ -177,6 +181,9 @@ VerboseMultiSubmit, ReplaceHelpImg - bug #3497151 [interface] Duplicate inline query edit box - bug #3504567 [mime] Description of the transformation missing in the tooltip +3.4.11.1 (2012-08-12) +- [security] Fixed XSS vulnerabilities, see PMASA-2012-4 + 3.4.11.0 (2012-04-14) - bug #3486970 [import] Exception on XML import - bug #3488777 [navi] $cfg['ShowTooltipAliasTB'] and blank names in navigation diff --git a/js/db_structure.js b/js/db_structure.js index 8b0629713e..223e02ea12 100644 --- a/js/db_structure.js +++ b/js/db_structure.js @@ -307,7 +307,7 @@ $(function() { */ var question = PMA_messages.strTruncateTableStrongWarning + ' ' - + $.sprintf(PMA_messages.strDoYouReally, 'TRUNCATE ' + curr_table_name); + + $.sprintf(PMA_messages.strDoYouReally, 'TRUNCATE ' + escapeHtml(curr_table_name)); $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function(url) { @@ -366,10 +366,10 @@ $(function() { if (! is_view) { question = PMA_messages.strDropTableStrongWarning + ' ' - + $.sprintf(PMA_messages.strDoYouReally, 'DROP TABLE ' + curr_table_name); + + $.sprintf(PMA_messages.strDoYouReally, 'DROP TABLE ' + escapeHtml(curr_table_name)); } else { question = - $.sprintf(PMA_messages.strDoYouReally, 'DROP VIEW ' + curr_table_name); + $.sprintf(PMA_messages.strDoYouReally, 'DROP VIEW ' + escapeHtml(curr_table_name)); } $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function(url) { diff --git a/js/tbl_gis_visualization.js b/js/tbl_gis_visualization.js index 6ddc14d5ee..6fae5aa148 100644 --- a/js/tbl_gis_visualization.js +++ b/js/tbl_gis_visualization.js @@ -298,7 +298,7 @@ $(function() { */ $('.polygon, .multipolygon, .point, .multipoint, .linestring, .multilinestring, ' + '.geometrycollection').live('mousemove', function(event) { - contents = $.trim($(this).attr('name')); + contents = $.trim(escapeHtml($(this).attr('name'))); $("#tooltip").remove(); if (contents != '') { $('
' + contents + '
').css({ diff --git a/libraries/CommonFunctions.class.php b/libraries/CommonFunctions.class.php index 6ffa509590..6413c30f43 100644 --- a/libraries/CommonFunctions.class.php +++ b/libraries/CommonFunctions.class.php @@ -971,6 +971,58 @@ class PMA_CommonFunctions } // end of the 'backquote()' function + /** + * Adds quotes on both sides of a database, table or field name. + * in compatibility mode + * + * example: + * + * echo backquote('owner`s db'); // `owner``s db` + * + * + * + * @param mixed $a_name the database, table or field name to "backquote" + * or array of it + * @param string $compatibility string compatibility mode (used by dump + * functions) + * @param boolean $do_it a flag to bypass this function (used by dump + * functions) + * @return mixed the "backquoted" database, table or field name + * + * @access public + */ + public function backquote_compat($a_name, $compatibility = 'MSSQL', $do_it = true) + { + + if (is_array($a_name)) { + foreach ($a_name as &$data) { + $data = $this->backquote_compat($data, $compatibility, $do_it); + } + return $a_name; + } + + if (! $do_it) { + global $PMA_SQPdata_forbidden_word; + + if (! in_array(strtoupper($a_name), $PMA_SQPdata_forbidden_word)) { + return $a_name; + } + } + + // @todo add more compatibility cases (ORACLE for example) + switch ($compatibility) { + case 'MSSQL': $quote = '"'; break; + default: (isset($GLOBALS['sql_backquotes'])) ? $quote = "`" : $quote = ''; break; + } + + // '0' is also empty for php :-( + if (strlen($a_name) && $a_name !== '*') { + return $quote . $a_name . $quote; + } else { + return $a_name; + } + + } // end of the 'backquote_compat()' function /** * Defines the value depending on the user OS. diff --git a/libraries/DisplayResults.class.php b/libraries/DisplayResults.class.php index d67237f1a5..1b8eac4fdb 100644 --- a/libraries/DisplayResults.class.php +++ b/libraries/DisplayResults.class.php @@ -183,7 +183,7 @@ class PMA_DisplayResults */ public function __get($property) { - if(array_key_exists($property, $this->_property_array)) { + if (array_key_exists($property, $this->_property_array)) { return $this->_property_array[$property]; } } @@ -193,13 +193,13 @@ class PMA_DisplayResults * Set values for any property of this class * * @param string $property name of the property - * @param $value value to set + * @param any $value value to set * * @return void */ public function __set($property, $value) { - if(array_key_exists($property, $this->_property_array)) { + if (array_key_exists($property, $this->_property_array)) { $this->_property_array[$property] = $value; } } @@ -858,8 +858,8 @@ class PMA_DisplayResults $onsubmit = 'onsubmit="return ' . ($_SESSION['tmp_user_values']['pos'] - + $_SESSION['tmp_user_values']['max_rows'] - < $this->__get('_unlim_num_rows') + + $_SESSION['tmp_user_values']['max_rows'] + < $this->__get('_unlim_num_rows') && $this->__get('_num_rows') >= $_SESSION['tmp_user_values']['max_rows']) ? 'true' : 'false' . '"'; @@ -951,11 +951,12 @@ class PMA_DisplayResults /** * Get the headers of the results table * - * @param array &$is_display which elements to display - * @param array $analyzed_sql the analyzed query - * @param string $sort_expression sort expression - * @param string $sort_expression_nodirection sort expression without direction - * @param string $sort_direction sort direction + * @param array &$is_display which elements to display + * @param array $analyzed_sql the analyzed query + * @param string $sort_expression sort expression + * @param string $sort_expression_nodirection sort expression without direction + * @param string $sort_direction sort direction + * @param boolean $is_limited_display with limited operations or not * * @return string html content * @@ -2438,11 +2439,12 @@ class PMA_DisplayResults /** * Prepare the body of the results table * - * @param integer &$dt_result the link id associated to the query - * which results have to be displayed - * @param array &$is_display which elements to display - * @param array $map the list of relations - * @param array $analyzed_sql the analyzed query + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array &$is_display which elements to display + * @param array $map the list of relations + * @param array $analyzed_sql the analyzed query + * @param boolean $is_limited_display with limited operations or not * * @return string $table_body_html html content * @@ -2795,17 +2797,16 @@ class PMA_DisplayResults ) { $parsed_sql = PMA_SQP_parse($row[$i]); - $row[$i] = PMA_CommonFunctions::getInstance()->formatSql($parsed_sql, $row[$i]); + $row[$i] = PMA_CommonFunctions::getInstance()->formatSql( + $parsed_sql, $row[$i] + ); include_once $this->sytax_highlighting_column_info[strtolower($this->__get('_db'))][strtolower($this->__get('_table'))][strtolower($meta->name)][0]; $transformation_plugin = new $this->sytax_highlighting_column_info[strtolower($this->__get('_db'))][strtolower($this->__get('_table'))][strtolower($meta->name)][1](null); $transform_options = PMA_transformation_getOptions( - isset($mime_map[$meta->name] - ['transformation_options'] - ) - ? $mime_map[$meta->name] - ['transformation_options'] - : '' + isset($mime_map[$meta->name]['transformation_options']) + ? $mime_map[$meta->name]['transformation_options'] + : '' ); $meta->mimetype = str_replace( @@ -2822,7 +2823,9 @@ class PMA_DisplayResults && ($this->_isFieldNeedToLink(strtolower($meta->name))) ) { - $linking_url = $this->_getSpecialLinkUrl($row[$i], $row_info, strtolower($meta->name)); + $linking_url = $this->_getSpecialLinkUrl( + $row[$i], $row_info, strtolower($meta->name) + ); include_once "libraries/plugins/transformations/Text_Plain_Link.class.php"; $transformation_plugin = new Text_Plain_Link(null); @@ -3036,7 +3039,8 @@ class PMA_DisplayResults * * @return boolean */ - private function _isNeedToSytaxHighlight($field) { + private function _isNeedToSytaxHighlight($field) + { if (! empty($this->sytax_highlighting_column_info[strtolower($this->__get('_db'))][strtolower($this->__get('_table'))][strtolower($field)])) { return true; } @@ -3050,7 +3054,8 @@ class PMA_DisplayResults * * @return boolean */ - private function _isFieldNeedToLink($field) { + private function _isFieldNeedToLink($field) + { if (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('_db'))][strtolower($this->__get('_table'))][$field])) { return true; } @@ -3071,14 +3076,19 @@ class PMA_DisplayResults { $linking_url_params = array(); - $link_relations = $GLOBALS['special_schema_links'][strtolower($this->__get('_db'))][strtolower($this->__get('_table'))][$field_name]; + $link_relations = $GLOBALS['special_schema_links'] + [strtolower($this->__get('_db'))] + [strtolower($this->__get('_table'))] + [$field_name]; if (! is_array($link_relations['link_param'])) { $linking_url_params[$link_relations['link_param']] = $column_value; } else { // Consider only the case of creating link for column field // sql query need to be pass as url param - $sql = 'SELECT `'.$column_value.'` FROM `'. $row_info[$link_relations['link_param'][1]] .'`.`'. $row_info[$link_relations['link_param'][2]] .'`'; + $sql = 'SELECT `'.$column_value.'` FROM `' + . $row_info[$link_relations['link_param'][1]] .'`.`' + . $row_info[$link_relations['link_param'][2]] .'`'; $linking_url_params[$link_relations['link_param'][0]] = $sql; } @@ -3090,13 +3100,16 @@ class PMA_DisplayResults // If param_info is an array, set the key and value // from that array if (is_array($new_param['param_info'])) { - $linking_url_params[$new_param['param_info'][0]] = $new_param['param_info'][1]; + $linking_url_params[$new_param['param_info'][0]] + = $new_param['param_info'][1]; } else { - $linking_url_params[$new_param['param_info']] = $row_info[strtolower($new_param['column_name'])]; + + $linking_url_params[$new_param['param_info']] + = $row_info[strtolower($new_param['column_name'])]; // Special case 1 - when executing routines, according // to the type of the routine, url param changes - if (!empty($row_info['routine_type'])){ + if (!empty($row_info['routine_type'])) { if (strtolower($row_info['routine_type']) == self::ROUTINE_PROCEDURE) { $linking_url_params['execute_routine'] = 1; } else if (strtolower($row_info['routine_type']) == self::ROUTINE_FUNCTION) { @@ -3109,7 +3122,8 @@ class PMA_DisplayResults } - return $link_relations['default_page'] . PMA_generate_common_url($linking_url_params); + return $link_relations['default_page'] + . PMA_generate_common_url($linking_url_params); } @@ -3644,7 +3658,6 @@ class PMA_DisplayResults if ((PMA_strlen($column) > $GLOBALS['cfg']['LimitChars']) && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT) && ! $this->_isNeedToSytaxHighlight(strtolower($meta->name)) - ) { $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars']) . '...'; @@ -4434,12 +4447,13 @@ class PMA_DisplayResults * Prepare a table of results returned by a SQL query. * This function is called by the "sql.php" script. * - * @param integer &$dt_result the link id associated to the query - * which results have to be displayed - * @param array &$the_disp_mode the display mode - * @param array $analyzed_sql the analyzed query + * @param integer &$dt_result the link id associated to the query + * which results have to be displayed + * @param array &$the_disp_mode the display mode + * @param array $analyzed_sql the analyzed query + * @param boolean $is_limited_display With limited operations or not * - * @return sting Generated HTML content for resulted table + * @return sting $table_html Generated HTML content for resulted table * * @access public * @@ -5070,7 +5084,8 @@ class PMA_DisplayResults $links_html .= "\n"; $links_html .= '' . "\n"; + .' value="' . htmlspecialchars($this->__get('_sql_query')) . '" />' + . "\n"; if (! empty($url_query)) { $links_html .= 'getProperties(), 'getText')) { + $properties = $plugin->getProperties(); + if ($properties != null) { $text = $plugin->getProperties()->getText(); } $ret .= ' value="' . $plugin_name . '">' @@ -242,8 +243,13 @@ function PMA_pluginGetOneOption( // for main groups $ret .= '
'; - if ($propertyGroup->getText() != null) { - $ret .= '

' . PMA_getString($propertyGroup->getText()) . '

'; + + if (method_exists($propertyGroup, 'getText')) { + $text = $propertyGroup->getText(); + } + + if ($text != null) { + $ret .= '

' . PMA_getString($text) . '

'; } $ret .= '
    '; } @@ -447,17 +453,20 @@ function PMA_pluginGetOptions($section, &$list) $default = PMA_pluginGetDefault('Export', 'format'); // Options for plugins that support them foreach ($list as $plugin) { + $properties = $plugin->getProperties(); + if ($properties != null) { + $text = $properties->getText(); + $options = $properties->getOptions(); + } + $plugin_name = strtolower(substr(get_class($plugin), strlen($section))); $ret .= '
    '; - $ret .= '

    ' . PMA_getString($plugin->getProperties()->getText()) - . '

    '; + $ret .= '

    ' . PMA_getString($text) . '

    '; $no_options = true; - if ($plugin->getProperties()->getOptions() != null - && count($plugin->getProperties()->getOptions()) > 0 - ) { - foreach ($plugin->getProperties()->getOptions()->getProperties() + if ($options != null && count($options) > 0) { + foreach ($options->getProperties() as $propertyMainGroup ) { // check for hidden properties diff --git a/libraries/plugins/export/ExportSql.class.php b/libraries/plugins/export/ExportSql.class.php index 9a0a38add6..305a830100 100644 --- a/libraries/plugins/export/ExportSql.class.php +++ b/libraries/plugins/export/ExportSql.class.php @@ -693,20 +693,24 @@ class ExportSql extends ExportPlugin global $crlf; $common_functions = PMA_CommonFunctions::getInstance(); - + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } if (isset($GLOBALS['sql_drop_database'])) { if (! PMA_exportOutputHandler( 'DROP DATABASE ' . (isset($GLOBALS['sql_backquotes']) - ? $common_functions->backquote($db) : $db) + ? $common_functions->backquote_compat($db, $compat) : $db) . ';' . $crlf )) { return false; } } $create_query = 'CREATE DATABASE ' - . (isset($GLOBALS['sql_backquotes']) - ? $common_functions->backquote($db) : $db); + . (isset($GLOBALS['sql_backquotes']) + ? $common_functions->backquote_compat($db, $compat) : $db); $collation = PMA_getDbCollation($db); if (PMA_DRIZZLE) { $create_query .= ' COLLATE ' . $collation; @@ -729,7 +733,8 @@ class ExportSql extends ExportPlugin || PMA_DRIZZLE) ) { $result = PMA_exportOutputHandler( - 'USE ' . $common_functions->backquote($db) . ';' . $crlf + 'USE ' . $common_functions->backquote_compat($db, $compat) + . ';' . $crlf ); } else { $result = PMA_exportOutputHandler('USE ' . $db . ';' . $crlf); @@ -747,11 +752,16 @@ class ExportSql extends ExportPlugin */ public function exportDBHeader($db) { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } $head = $this->_exportComment() . $this->_exportComment( __('Database') . ': ' . (isset($GLOBALS['sql_backquotes']) - ? PMA_CommonFunctions::getInstance()->backquote($db) + ? PMA_CommonFunctions::getInstance()->backquote_compat($db, $compat) : '\'' . $db . '\'') ) . $this->_exportComment(); @@ -893,6 +903,12 @@ class ExportSql extends ExportPlugin $auto_increment = ''; $new_crlf = $crlf; + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli $result = PMA_DBI_query( 'SHOW TABLE STATUS FROM ' . $common_functions->backquote($db) @@ -1040,7 +1056,8 @@ class ExportSql extends ExportPlugin } // Should we use IF NOT EXISTS? - if (isset($GLOBALS['sql_if_not_exists'])) { + // It always must be OFF for MSSQL compatibility mode + if (isset($GLOBALS['sql_if_not_exists']) && $compat != 'MSSQL') { $create_query = preg_replace( '/^CREATE TABLE/', 'CREATE TABLE IF NOT EXISTS', @@ -1048,6 +1065,95 @@ class ExportSql extends ExportPlugin ); } + // In MSSQL + // 1. DATE field doesn't exists, we will use DATETIME instead + // 2. UNSIGNED attribute doesn't exist + // 3. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on + // FLOAT fields + // 4. No KEY and INDEX inside CREATE TABLE + // 5. DOUBLE field doesn't exists, we will use FLOAT instead + if ($compat == 'MSSQL') { + // first we need to replace all lines ended with '" DATE ...,\n' + // last preg_replace preserve us from situation with date text + // inside DEFAULT field value + $create_query = preg_replace( + "/\" date DEFAULT NULL(,)?\n/", + '" datetime DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\" date NOT NULL(,)?\n/", + '" datetime NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" date NOT NULL DEFAULT \'([^\'])/', + '" datetime NOT NULL DEFAULT \'$1', + $create_query + ); + + // next we need to replace all lines ended with ') UNSIGNED ...,' + // last preg_replace preserve us from situation with unsigned text + // inside DEFAULT field value + $create_query = preg_replace( + "/\) unsigned NOT NULL(,)?\n/", + ') NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\) unsigned DEFAULT NULL(,)?\n/", + ') DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/\) unsigned NOT NULL DEFAULT \'([^\'])/', + ') NOT NULL DEFAULT \'$1', + $create_query + ); + + // we need to replace all lines ended with + // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us + // from situation with int([0-9]{1,}) text inside DEFAULT field + // value + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/', + '" $1 DEFAULT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/', + '" $1 NOT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/', + '" $1 NOT NULL DEFAULT \'$2', + $create_query + ); + + // we need to replace all lines ended with + // '" FLOAT|DOUBLE([0-9,]{1,}) ...,' + // last preg_replace preserve us from situation with + // float([0-9,]{1,}) text inside DEFAULT field value + $create_query = preg_replace( + '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/', + '" float DEFAULT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/', + '" float NOT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/', + '" float NOT NULL DEFAULT \'$3', + $create_query + ); + + // @todo remove indexes from CREATE TABLE + } + // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded // with quotes, which is not accepted by parser if (PMA_DRIZZLE) { @@ -1107,19 +1213,22 @@ class ExportSql extends ExportPlugin . $this->_exportComment( __('Constraints for table') . ' ' - . $common_functions->backquote($table) + . $common_functions->backquote_compat($table, $compat) ) . $this->_exportComment(); } // let's do the work $sql_constraints_query .= 'ALTER TABLE ' - . $common_functions->backquote($table) . $crlf; + . $common_functions->backquote_compat($table, $compat) + . $crlf; $sql_constraints .= 'ALTER TABLE ' - . $common_functions->backquote($table) . $crlf; + . $common_functions->backquote_compat($table, $compat) + . $crlf; $sql_drop_foreign_keys .= 'ALTER TABLE ' - . $common_functions->backquote($db) . '.' - . $common_functions->backquote($table) . $crlf; + . $common_functions->backquote_compat($db, $compat) . '.' + . $common_functions->backquote_compat($table, $compat) + . $crlf; $first = true; for ($j = $i; $j < $sql_count; $j++) { @@ -1190,7 +1299,7 @@ class ExportSql extends ExportPlugin $schema_create ); - $schema_create .= $auto_increment; + $schema_create .= ($compat != 'MSSQL') ? $auto_increment : ''; PMA_DBI_free_result($result); return $schema_create . ($add_semicolon ? ';' . $crlf : ''); @@ -1335,9 +1444,14 @@ class ExportSql extends ExportPlugin ) { $common_functions = PMA_CommonFunctions::getInstance(); + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) - ? $common_functions->backquote($table) : '\'' . $table . '\''; + ? $common_functions->backquote_compat($table, $compat) : '\'' . $table . '\''; $dump = $this->_possibleCRLF() . $this->_exportComment(str_repeat('-', 56)) . $this->_possibleCRLF() @@ -1395,7 +1509,7 @@ class ExportSql extends ExportPlugin ) . $this->_exportComment(); // export a stand-in definition to resolve view dependencies - $dump .= getTableDefStandIn($db, $table, $crlf); + $dump .= $this->getTableDefStandIn($db, $table, $crlf); } // end switch // this one is built by getTableDef() to use in table copy/move @@ -1420,9 +1534,15 @@ class ExportSql extends ExportPlugin { global $current_row, $sql_backquotes; + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + $common_functions = PMA_CommonFunctions::getInstance(); $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) - ? $common_functions->backquote($table) + ? $common_functions->backquote_compat($table, $compat) : '\'' . $table . '\''; // Do not export data for a VIEW @@ -1469,13 +1589,15 @@ class ExportSql extends ExportPlugin for ($j = 0; $j < $fields_cnt; $j++) { if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) { - $field_set[$j] = $common_functions->backquote( + $field_set[$j] = $common_functions->backquote_compat( $analyzed_sql[0]['select_expr'][$j]['column'], + $compat, $sql_backquotes ); } else { - $field_set[$j] = $common_functions->backquote( + $field_set[$j] = $common_functions->backquote_compat( $fields_meta[$j]->name, + $compat, $sql_backquotes ); } @@ -1490,8 +1612,9 @@ class ExportSql extends ExportPlugin $schema_insert .= 'IGNORE '; } // avoid EOL blank - $schema_insert .= $common_functions->backquote( + $schema_insert .= $common_functions->backquote_compat( $table, + $compat, $sql_backquotes ) . ' SET'; } else { @@ -1524,8 +1647,9 @@ class ExportSql extends ExportPlugin && $sql_command == 'INSERT' ) { $truncate = 'TRUNCATE TABLE ' - . $common_functions->backquote( + . $common_functions->backquote_compat( $table, + $compat, $sql_backquotes ) . ";"; $truncatehead = $this->_possibleCRLF() @@ -1541,18 +1665,19 @@ class ExportSql extends ExportPlugin } else { $truncate = ''; } + // scheme for inserting fields if ($GLOBALS['sql_insert_syntax'] == 'complete' || $GLOBALS['sql_insert_syntax'] == 'both' ) { $fields = implode(', ', $field_set); $schema_insert = $sql_command . $insert_delayed .' INTO ' - . $common_functions->backquote($table, $sql_backquotes) + . $common_functions->backquote_compat($table, $compat, $sql_backquotes) // avoid EOL blank . ' (' . $fields . ') VALUES'; } else { $schema_insert = $sql_command . $insert_delayed .' INTO ' - . $common_functions->backquote($table, $sql_backquotes) + . $common_functions->backquote_compat($table, $compat, $sql_backquotes) . ' VALUES'; } } @@ -1586,6 +1711,18 @@ class ExportSql extends ExportPlugin if (! PMA_exportOutputHandler($head)) { return false; } + } + // We need to SET IDENTITY_INSERT ON for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row == 0) { + if (! PMA_exportOutputHandler('SET IDENTITY_INSERT ' + . $common_functions->backquote_compat( + $table, + $compat) + . ' ON ;'.$crlf)) { + return false; + } } $current_row++; for ($j = 0; $j < $fields_cnt; $j++) { @@ -1707,14 +1844,30 @@ class ExportSql extends ExportPlugin } } // end while + if ($current_row > 0) { if (! PMA_exportOutputHandler(';' . $crlf)) { return false; } } + + // We need to SET IDENTITY_INSERT OFF for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row > 0) + if (! PMA_exportOutputHandler( + $crlf . 'SET IDENTITY_INSERT ' + . $common_functions->backquote_compat( + $table, + $compat) + . ' OFF;' . $crlf + )) { + return false; + } + } // end if ($result != false) PMA_DBI_free_result($result); return true; } // end of the 'exportData()' function -} \ No newline at end of file +} diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index c47554a673..29290a67f8 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -100,8 +100,12 @@ function PMA_TRI_handleEditor() // 'Add a new item' mode $result = PMA_DBI_try_query($item_query); if (! $result) { - $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '

    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '

    ' + . __('MySQL said: ') . PMA_DBI_getError(null); } else { $message = PMA_Message::success(__('Trigger %1$s has been created.')); $message->addParam(PMA_CommonFunctions::getInstance()->backquote($_REQUEST['item_name'])); @@ -325,7 +329,9 @@ function PMA_TRI_getEditorForm($mode, $item) } else if ($mode == 'edit' && $value == $item['item_table']) { $selected = " selected='selected'"; } - $retval .= " $value\n"; + $retval .= ""; + $retval .= htmlspecialchars($value); + $retval .= "\n"; } $retval .= " \n"; $retval .= " \n"; diff --git a/po/fa.po b/po/fa.po index ba20af2b15..a9cfaaa97f 100644 --- a/po/fa.po +++ b/po/fa.po @@ -4,10 +4,10 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.0.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2012-08-10 12:59+0200\n" -"PO-Revision-Date: 2012-08-03 00:13+0200\n" +"PO-Revision-Date: 2012-08-11 04:26+0200\n" "Last-Translator: Ashiyane Digital Security Team \n" -"Language-Team: Persian \n" +"Language-Team: Persian " +"\n" "Language: fa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2839,7 +2839,7 @@ msgstr "" #: libraries/File.class.php:279 msgid "The uploaded file was only partially uploaded." -msgstr "" +msgstr "فایل آپلود شده کاملا آپلود نشده." #: libraries/File.class.php:282 msgid "Missing a temporary folder." @@ -2865,7 +2865,7 @@ msgstr "" #: libraries/File.class.php:485 msgid "Error while moving uploaded file." -msgstr "" +msgstr "خطا در موقع جابجا کردن فایل آپلود شده." #: libraries/File.class.php:493 msgid "Cannot read (moved) upload file." @@ -3059,11 +3059,11 @@ msgstr[1] "" #: libraries/PDF.class.php:88 msgid "Error while creating PDF:" -msgstr "" +msgstr " PDF خطا در موقع درست کردن " #: libraries/RecentTable.class.php:112 msgid "Could not save recent table" -msgstr "" +msgstr "جدول اخیر ذخیره نشد" #: libraries/RecentTable.class.php:147 msgid "Recent tables" @@ -3071,7 +3071,7 @@ msgstr "جدول های اخیر" #: libraries/RecentTable.class.php:154 msgid "There are no recent tables" -msgstr "" +msgstr "جدول های اخیری وجود ندارد." #: libraries/StorageEngine.class.php:214 msgid "" @@ -3095,7 +3095,7 @@ msgstr "" #: libraries/Table.class.php:345 msgid "unknown table status: " -msgstr "" +msgstr " :وضعیت جدول ناشناس" #: libraries/Table.class.php:756 #, fuzzy, php-format @@ -3109,7 +3109,7 @@ msgstr "جستجو در پايگاه‌داده" #: libraries/Table.class.php:1191 msgid "Invalid database" -msgstr "" +msgstr " پایگاه داده نامعتبر " #: libraries/Table.class.php:1205 tbl_get_field.php:31 msgid "Invalid table name" diff --git a/po/pt_BR.po b/po/pt_BR.po index cec8c31bec..cf04e9ab61 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4,15 +4,16 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.0.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2012-08-10 12:59+0200\n" -"PO-Revision-Date: 2012-07-16 22:05+0200\n" -"Last-Translator: Bruno Rafael \n" -"Language-Team: brazilian_portuguese \n" +"PO-Revision-Date: 2012-08-10 22:16+0200\n" +"Last-Translator: gilberto dos santos alves \n" +"Language-Team: Portuguese (Brazil) " +"\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Weblate 1.1\n" +"X-Generator: Weblate 1.2\n" #: browse_foreigners.php:36 browse_foreigners.php:60 js/messages.php:354 #: libraries/DisplayResults.class.php:816 @@ -2175,7 +2176,7 @@ msgstr "Segundo" #: libraries/Advisor.class.php:67 #, php-format msgid "PHP threw following error: %s" -msgstr "" +msgstr "PHP apresentou o seguinte erro: %s" #: libraries/Advisor.class.php:89 #, php-format @@ -2185,7 +2186,7 @@ msgstr "" #: libraries/Advisor.class.php:106 #, php-format msgid "Failed calculating value for rule '%s'" -msgstr "" +msgstr "O Cálculo para a regra '%s' falhou" #: libraries/Advisor.class.php:125 #, php-format diff --git a/po/th.po b/po/th.po index a42436fc43..684eb90cb4 100644 --- a/po/th.po +++ b/po/th.po @@ -3371,17 +3371,24 @@ msgid "" msgstr "" #: libraries/Types.class.php:331 libraries/Types.class.php:729 -#, php-format +#, php-format, fuzzy msgid "" "A variable-length (%s) string, the effective maximum length is subject to " "the maximum row size" msgstr "" +"คุณคงไม่ได้สร้างแฟ้มการกำหนดค่า คุณอาจต้องการใช้ %1$ssetup script%2$s " +"เพื่อสร้างอย่างใดอย่างหนึ่ง" #: libraries/Types.class.php:333 +#, fuzzy msgid "" "A TEXT column with a maximum length of 255 (2^8 - 1) characters, stored with " "a one-byte prefix indicating the length of the value in bytes" msgstr "" +"phpMyAdmin พยายามเชื่อมต่อไปยังเซิร์ฟเวอร์ MySQL " +"และเซิร์ฟเวอร์ได้ปฏิเสธการเชื่อมต่อดังกล่าว คุณควรตรวจสอบโฮสต์ " +"ชื่อผู้ใช้และรหัสผ่านในการกำหนดค่าของคุณ และให้แน่ใจว่าค่าต่างๆ " +"สอดคล้องกับข้อมูลที่กำหนดไว้ โดยผู้ดูแลระบบของเซิร์ฟเวอร์ MySQL แล้ว" #: libraries/Types.class.php:335 libraries/Types.class.php:731 msgid "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 086163c645..676fdff124 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -4,10 +4,10 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.0.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2012-08-10 12:59+0200\n" -"PO-Revision-Date: 2012-08-04 06:39+0200\n" +"PO-Revision-Date: 2012-08-13 12:11+0200\n" "Last-Translator: shanyan baishui \n" -"Language-Team: Chinese (China) \n" +"Language-Team: Chinese (China) " +"\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1367,17 +1367,15 @@ msgid "Total time:" msgstr "总时间:" #: js/messages.php:188 -#, fuzzy #| msgid "Profiling" msgid "Profiling results" -msgstr "概要" +msgstr "性能分析结果" #: js/messages.php:189 -#, fuzzy #| msgid "Table" msgctxt "Display format" msgid "Table" -msgstr "表" +msgstr "表格" #: js/messages.php:190 msgid "Chart" @@ -2255,11 +2253,11 @@ msgstr "连接到 SQL 校验器失败!" #: libraries/CommonFunctions.class.php:1256 #: libraries/config/messages.inc.php:491 msgid "Explain SQL" -msgstr "解释 SQL" +msgstr "解析 SQL" #: libraries/CommonFunctions.class.php:1264 msgid "Skip Explain SQL" -msgstr "略过解释 SQL" +msgstr "略过解析 SQL" #: libraries/CommonFunctions.class.php:1303 msgid "Without PHP Code" @@ -2300,7 +2298,7 @@ msgstr "快速编辑" #: libraries/CommonFunctions.class.php:1480 sql.php:1067 msgid "Profiling" -msgstr "概要" +msgstr "性能分析" #. l10n: Short week day name #: libraries/CommonFunctions.class.php:1750 diff --git a/server_status.php b/server_status.php index da775b9d3f..f0cfe15b16 100644 --- a/server_status.php +++ b/server_status.php @@ -1257,6 +1257,45 @@ function printServerTraffic() } else { $full_text_link = 'server_status.php' . PMA_generate_common_url(array('full' => 1)); } + + // This array contains display name and real column name of each + // sortable column in the table + $sortable_columns = array( + array( + 'column_name' => __('ID'), + 'order_by_field' => 'Id' + ), + array( + 'column_name' => __('User'), + 'order_by_field' => 'User' + ), + array( + 'column_name' => __('Host'), + 'order_by_field' => 'Host' + ), + array( + 'column_name' => __('Database'), + 'order_by_field' => 'db' + ), + array( + 'column_name' => __('Command'), + 'order_by_field' => 'Command' + ), + array( + 'column_name' => __('Time'), + 'order_by_field' => 'Time' + ), + array( + 'column_name' => __('Status'), + 'order_by_field' => 'State' + ), + array( + 'column_name' => __('SQL query'), + 'order_by_field' => 'Info' + ) + ); + $sortable_columns_count = count($sortable_columns); + if (PMA_DRIZZLE) { $sql_query = "SELECT p.id AS Id, @@ -1269,47 +1308,102 @@ function printServerTraffic() " . ($show_full_sql ? 's.query' : 'left(p.info, ' . (int)$GLOBALS['cfg']['MaxCharactersInDisplayedSQL'] . ')') . " AS Info FROM data_dictionary.PROCESSLIST p " . ($show_full_sql ? 'LEFT JOIN data_dictionary.SESSIONS s ON s.session_id = p.id' : ''); + if (!empty($_REQUEST['order_by_field']) + && !empty($_REQUEST['sort_order']) + ) { + $sql_query .= ' ORDER BY p.' . $_REQUEST['order_by_field'] . ' ' . $_REQUEST['sort_order']; + } } else { $sql_query = $show_full_sql ? 'SHOW FULL PROCESSLIST' : 'SHOW PROCESSLIST'; + if (!empty($_REQUEST['order_by_field']) + && !empty($_REQUEST['sort_order']) + ) { + $sql_query = 'SELECT * FROM `INFORMATION_SCHEMA`.`PROCESSLIST` ORDER BY `' + . $_REQUEST['order_by_field'] . '` ' . $_REQUEST['sort_order']; + } } + $result = PMA_DBI_query($sql_query); /** * Displays the page */ ?> - +
    - - - - - - - - - - + + + - - <?php echo $show_full_sql ? __('Truncate Shown Queries') : __('Show Full Queries'); ?> - - - - + + + + + diff --git a/setup/styles.css b/setup/styles.css index c6798c74e2..9f2d2ec943 100644 --- a/setup/styles.css +++ b/setup/styles.css @@ -176,7 +176,7 @@ div.notice { .error { border: 1px solid maroon !important; color: #000; - background: #fcf; + background: pink; } h1.error, diff --git a/tbl_create.php b/tbl_create.php index c202d8bb9f..3ffd2dd223 100644 --- a/tbl_create.php +++ b/tbl_create.php @@ -277,7 +277,9 @@ if (isset($_REQUEST['do_save_data'])) { $new_table_string .= '' . "\n"; $new_table_string .= '
    +
    + + onmouseout="$('.soimg').toggle()" onmouseover="$('.soimg').toggle()" + + > + + + + + Descending + Ascending + + + + + + + <?php echo $show_full_sql ? __('Truncate Shown Queries') : __('Show Full Queries'); ?> + + + +
    '; - $new_table_string .= ''. $table . ''; + $new_table_string .= '' + . htmlspecialchars($table) . ''; if (PMA_Tracker::isActive()) { $truename = str_replace(' ', ' ', htmlspecialchars($table)); diff --git a/test/classes/PMA_DisplayResults_test.php b/test/classes/PMA_DisplayResults_test.php index d47c2e5ffc..f259e879ba 100644 --- a/test/classes/PMA_DisplayResults_test.php +++ b/test/classes/PMA_DisplayResults_test.php @@ -1397,6 +1397,261 @@ class PMA_DisplayResults_test extends PHPUnit_Framework_TestCase ) ); } + + + /** + * Data provider for testIsNeedToSytaxHighlight + * + * @return array parameters and output + */ + public function dataProviderForTestIsNeedToSytaxHighlight() + { + return array( + array( + 'information_schema', + 'processlist', + array( + 'information_schema' => array( + 'processlist' => array( + 'info' => array( + 'libraries/plugins/transformations/Text_Plain_Formatted.class.php', + 'Text_Plain_Formatted', + 'Text_Plain' + ) + ) + ) + ), + 'info', + true + ), + array( + 'incorrect_database', + 'processlist', + array( + 'information_schema' => array( + 'processlist' => array( + 'info' => array( + 'libraries/plugins/transformations/Text_Plain_Formatted.class.php', + 'Text_Plain_Formatted', + 'Text_Plain' + ) + ) + ) + ), + 'info', + false + ) + ); + } + + + /** + * Test _isNeedToSytaxHighlight + * + * @param string $db the database name + * @param string $table the table name + * @param array $data predifined data of columns need to sytax highlighted + * @param string $field the field name + * @param boolean $output output of _isNeedToSytaxHighlight + * + * @dataProvider dataProviderForTestIsNeedToSytaxHighlight + */ + public function testIsNeedToSytaxHighlight($db, $table, $data, $field, $output) + { + $this->object->__set('_db', $db); + $this->object->__set('_table', $table); + $this->object->__set('sytax_highlighting_column_info', $data); + + + $this->assertEquals( + $output, + $this->_callPrivateFunction( + '_isNeedToSytaxHighlight', + array($field) + ) + ); + + } + + + /** + * Data provider for testIsFieldNeedToLink + * + * @return array parameters and output + */ + public function dataProviderForTestIsFieldNeedToLink() + { + return array( + array( + 'mysql', + 'proc', + 'db', + true + ), + array( + 'incorrect_database', + 'processlist', + 'info', + false + ) + ); + } + + + /** + * Test _isFieldNeedToLink + * + * @param string $db the database name + * @param string $table the table name + * @param string $field the field name + * @param boolean $output output of _isFieldNeedToLink + * + * @dataProvider dataProviderForTestIsFieldNeedToLink + */ + public function testIsFieldNeedToLink($db, $table, $field, $output) + { + + $GLOBALS['special_schema_links'] = array( + 'mysql' => array( + 'proc' => array( + 'db' => array( + 'link_param' => 'db', + 'default_page' => 'index.php' + ) - + ) + ) + ); + + $this->object->__set('_db', $db); + $this->object->__set('_table', $table); + + $this->assertEquals( + $output, + $this->_callPrivateFunction( + '_isFieldNeedToLink', + array($field) + ) + ); + + } + + + /** + * Data provider for testGetSpecialLinkUrl + * + * @return array parameters and output + */ + public function dataProviderForTestGetSpecialLinkUrl() + { + return array( + array( + 'information_schema', + 'routines', + 'circumference', + array( + 'routine_name' => 'circumference', + 'routine_schema' => 'data', + 'routine_type' => 'FUNCTION' + ), + 'routine_name', + 'db_routines.php?item_name=circumference&db=data&execute_dialog=1&item_type=FUNCTION&lang=en&token=token' + ), + array( + 'information_schema', + 'routines', + 'area', + array( + 'routine_name' => 'area', + 'routine_schema' => 'data', + 'routine_type' => 'PROCEDURE' + ), + 'routine_name', + 'db_routines.php?item_name=area&db=data&execute_routine=1&item_type=PROCEDURE&lang=en&token=token' + ), + array( + 'information_schema', + 'columns', + 'CHARACTER_SET_NAME', + array( + 'table_schema' => 'information_schema', + 'table_name' => 'CHARACTER_SETS' + ), + 'column_name', + 'index.php?sql_query=SELECT+%60CHARACTER_SET_NAME%60+FROM+%60information_schema%60.%60CHARACTER_SETS%60&db=information_schema&test_name=value&lang=en&token=token' + ) + ); + } + + + /** + * Test _getSpecialLinkUrl + * + * @param string $db the database name + * @param string $table the table name + * @param string $column_value column value + * @param array $row_info information about row + * @param string $field_name column name + * @param boolean $output output of _getSpecialLinkUrl + * + * @dataProvider dataProviderForTestGetSpecialLinkUrl + */ + public function testGetSpecialLinkUrl( + $db, $table, $column_value, $row_info, $field_name, $output + ) { + + $GLOBALS['special_schema_links'] = array( + 'information_schema' => array( + 'routines' => array( + 'routine_name' => array( + 'link_param' => 'item_name', + 'link_dependancy_params' => array( + 0 => array( + 'param_info' => 'db', + 'column_name' => 'routine_schema' + ), + 1 => array( + 'param_info' => 'item_type', + 'column_name' => 'routine_type' + ) + ), + 'default_page' => 'db_routines.php' + ) + ), + 'columns' => array( + 'column_name' => array( + 'link_param' => array( + 'sql_query', + 'table_schema', + 'table_name' + ), + 'link_dependancy_params' => array( + 0 => array( + 'param_info' => 'db', + 'column_name' => 'table_schema' + ), + 1 => array( + 'param_info' => array('test_name', 'value') + ) + ), + 'default_page' => 'index.php' + ) + ) + ) + ); + + $this->object->__set('_db', $db); + $this->object->__set('_table', $table); + + $this->assertEquals( + $output, + $this->_callPrivateFunction( + '_getSpecialLinkUrl', + array($column_value, $row_info, $field_name) + ) + ); + + } + + } diff --git a/test/libraries/common/PMA_quoting_slashing_test.php b/test/libraries/common/PMA_quoting_slashing_test.php index 151273a1c4..2c69693827 100644 --- a/test/libraries/common/PMA_quoting_slashing_test.php +++ b/test/libraries/common/PMA_quoting_slashing_test.php @@ -114,6 +114,41 @@ class PMA_quoting_slashing_test extends PHPUnit_Framework_TestCase $this->assertEquals($b, PMA_CommonFunctions::getInstance()->backquote($a)); } + /** + * data provider for backquote_compat test + * + * @return array + */ + public function backquote_compatDataProvider() + { + return array( + array('0', '"0"'), + array('test', '"test"'), + array('te`st', '"te`st"'), + array(array('test', 'te`st', '', '*'), array('"test"', '"te`st"', '', '*')) + ); + } + + /** + * backquote_compat test with different param $compatibility (NONE, MSSQL) + * @dataProvider backquote_compatDataProvider + */ + public function testBackquote_compat($a, $b) + { + // Test bypass quoting (used by dump functions) + $this->assertEquals($a, PMA_CommonFunctions::getInstance()->backquote_compat($a, 'NONE', false)); + + // Test backquote (backquoting will be enabled only if isset $GLOBALS['sql_backquotes'] + $this->assertEquals($a, PMA_CommonFunctions::getInstance()->backquote_compat($a, 'NONE')); + + // Run tests in MSSQL compatibility mode + // Test bypass quoting (used by dump functions) + $this->assertEquals($a, PMA_CommonFunctions::getInstance()->backquote_compat($a, 'MSSQL', false)); + + // Test backquote + $this->assertEquals($b, PMA_CommonFunctions::getInstance()->backquote_compat($a, 'MSSQL')); + } + public function testBackquoteForbidenWords() { global $PMA_SQPdata_forbidden_word; diff --git a/themes/pmahomme/jquery/jquery-ui-1.8.16.custom.css b/themes/pmahomme/jquery/jquery-ui-1.8.16.custom.css index a087015598..4abfd610b0 100644 --- a/themes/pmahomme/jquery/jquery-ui-1.8.16.custom.css +++ b/themes/pmahomme/jquery/jquery-ui-1.8.16.custom.css @@ -60,7 +60,7 @@ .ui-widget .ui-widget { font-size: 1em; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } -.ui-widget-content a { color: #222222; } +.ui-widget-content a { color: #235A81; } .ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } .ui-widget-header a { color: #222222; }