diff --git a/ChangeLog b/ChangeLog index b35579bbdefe..d45ccd61c205 100644 --- a/ChangeLog +++ b/ChangeLog @@ -59,6 +59,14 @@ phpMyAdmin - ChangeLog - issue #12473 Code can throw unhandled exception - issue #12550 Do not try to keep alive session even after expiry - issue #12512 Fixed rendering BBCode links in setup +- issue #12518 Fixed copy of table with generated columns +- issue #12221 Fixed export of table with generated columns +- issue #12320 Copying a user does not copy usergroup +- issue #12272 Adding a new row with default enum goes to no selection when you want to add more then 2 rows +- issue #12487 Drag and drop import prevents file dropping to blob column file selector on the insert tab +- issue #12554 Absence of scrolling makes it impossible to read longer text values in grid editing +- issue #12530 "Edit routine" crashes when the current user is not the definer, even if privileges are adequate +- issue #12300 Export selective tables by-default dumps Events also 4.6.4 (2016-08-16) - issue [security] Weaknesses with cookie encryption, see PMASA-2016-29 diff --git a/doc/setup.rst b/doc/setup.rst index 4336ffe1cd04..5c73b3f1d7bd 100644 --- a/doc/setup.rst +++ b/doc/setup.rst @@ -852,6 +852,7 @@ are always ways to make your installation more secure: * Ensure your PHP setup follows recommendations for production sites, for example `display_errors `_ should be disabled. +* Remove the ``test`` directory from phpMyAdmin, unless you are developing and need test suite. * Remove the ``setup`` directory from phpMyAdmin, you will probably not use it after the initial setup. * Properly choose an authentication method - :ref:`cookie` diff --git a/js/common.js b/js/common.js index 83733bf3eb9c..c4331627153e 100644 --- a/js/common.js +++ b/js/common.js @@ -298,6 +298,13 @@ PMA_DROP_IMPORT = { * @return void */ _dragenter : function (event) { + + // We don't want to prevent users from using + // browser's default drag-drop feature on some page(s) + if ($(".noDragDrop").length !== 0) { + return; + } + event.stopPropagation(); event.preventDefault(); if (!PMA_DROP_IMPORT._hasFiles(event)) { @@ -333,6 +340,12 @@ PMA_DROP_IMPORT = { * @return void */ _dragover: function (event) { + // We don't want to prevent users from using + // browser's default drag-drop feature on some page(s) + if ($(".noDragDrop").length !== 0) { + return; + } + event.stopPropagation(); event.preventDefault(); if (!PMA_DROP_IMPORT._hasFiles(event)) { @@ -348,6 +361,11 @@ PMA_DROP_IMPORT = { * @return void */ _dragleave: function (event) { + // We don't want to prevent users from using + // browser's default drag-drop feature on some page(s) + if ($(".noDragDrop").length !== 0) { + return; + } event.stopPropagation(); event.preventDefault(); var $pma_drop_handler = $(".pma_drop_handler"); @@ -408,6 +426,12 @@ PMA_DROP_IMPORT = { * @return void */ _drop: function (event) { + // We don't want to prevent users from using + // browser's default drag-drop feature on some page(s) + if ($(".noDragDrop").length !== 0) { + return; + } + var dbname = PMA_commonParams.get('db'); var server = PMA_commonParams.get('server'); diff --git a/js/export.js b/js/export.js index 8d59c6e6d02c..a0da0f251e64 100644 --- a/js/export.js +++ b/js/export.js @@ -545,6 +545,16 @@ function toggle_table_select(row) { } } +function handleAddProcCheckbox() { + if ($('#table_structure_all').is(':checked') === true + && $('#table_data_all').is(':checked') === true + ) { + $('#checkbox_sql_procedure_function').prop('checked', true); + } else { + $('#checkbox_sql_procedure_function').prop('checked', false); + } +} + AJAX.registerOnload('export.js', function () { /** * For SQL plugin, if "CREATE TABLE options" is checked/unchecked, check/uncheck each of its sub-options @@ -584,26 +594,31 @@ AJAX.registerOnload('export.js', function () { $('input[name="table_select[]"]').on('change', function() { toggle_table_select($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('input[name="table_structure[]"]').on('change', function() { check_table_selected($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('input[name="table_data[]"]').on('change', function() { check_table_selected($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('#table_structure_all').on('change', function() { toggle_table_select_all_str(); check_selected_tables(); + handleAddProcCheckbox(); }); $('#table_data_all').on('change', function() { toggle_table_select_all_data(); check_selected_tables(); + handleAddProcCheckbox(); }); if ($("input[name='export_type']").val() == 'database') { @@ -810,6 +825,8 @@ AJAX.registerOnload('export.js', function () { toggle_quick_or_custom(); toggle_structure_data_opts(); toggle_sql_include_comments(); + check_table_select_all(); + handleAddProcCheckbox(); /** * Initially disables the "Dump some row(s)" sub-options diff --git a/js/functions.js b/js/functions.js index 31b2776ff686..ad365db589e5 100644 --- a/js/functions.js +++ b/js/functions.js @@ -906,7 +906,7 @@ AJAX.registerOnload('functions.js', function () { var remaining = PMA_commonParams.get('LoginCookieValidity') - _idleSecondsCounter; if (remaining > 5) { // max value for setInterval() function - var interval = min(remaining * 1000, Math.pow(2, 31) - 1); + var interval = Math.min(remaining * 1000, Math.pow(2, 31) - 1); updateTimeout = window.setTimeout(UpdateIdleTime, interval); } else if (remaining > 0) { // We're close to session expiry diff --git a/js/messages.php b/js/messages.php index 75a296fd3430..17ea572c8e64 100644 --- a/js/messages.php +++ b/js/messages.php @@ -390,6 +390,8 @@ function () { $js_messages['MissingReturn'] = __('The definition of a stored function must contain a RETURN statement!'); $js_messages['strExport'] = __('Export'); +$js_messages['NoExportable'] + = __('No routine is exportable. Required privileges may be lacking.'); /* For ENUM/SET editor*/ $js_messages['enum_editor'] = __('ENUM/SET editor'); diff --git a/js/rte.js b/js/rte.js index 73e3964b2a5d..0d082154e26b 100644 --- a/js/rte.js +++ b/js/rte.js @@ -128,6 +128,11 @@ RTE.COMMON = { var count = export_anchors.length; var returnCount = 0; + // No routine is exportable (due to privilege issues) + if (count === 0) { + PMA_ajaxShowMessage(PMA_messages.NoExportable); + } + export_anchors.each(function () { $.get($(this).attr('href'), {'ajax_request': true}, function (data) { returnCount++; @@ -149,6 +154,7 @@ RTE.COMMON = { } else { $.get($this.attr('href'), {'ajax_request': true}, showExport); } + PMA_ajaxRemoveMessage($msg); function showExport(data) { if (data.success === true) { diff --git a/js/tbl_change.js b/js/tbl_change.js index eeba3b51d71b..6ae5948aa6a2 100644 --- a/js/tbl_change.js +++ b/js/tbl_change.js @@ -553,6 +553,7 @@ AJAX.registerOnload('tbl_change.js', function () { // handle input text fields and textareas if ($this_element.is('.textfield') || $this_element.is('.char')) { // do not remove the 'value' attribute for ENUM columns + // special handling for radio fields after updating ids to unique - see below if ($this_element.closest('tr').find('span.column_type').html() != 'enum') { $this_element.val($this_element.closest('tr').find('span.default_value').html()); } @@ -675,6 +676,15 @@ AJAX.registerOnload('tbl_change.js', function () { $(this).attr('tabindex', tabindex); // update the IDs of textfields to ensure that they are unique $(this).attr('id', "field_" + tabindex + "_3"); + + // special handling for radio fields after updating ids to unique + if ($(this).closest('tr').find('span.column_type').html() === 'enum') { + if ($(this).val() === $(this).closest('tr').find('span.default_value').html()) { + $(this).prop('checked', true); + } else { + $(this).prop('checked', false); + } + } }); $('.control_at_footer') .each(function () { diff --git a/libraries/DatabaseInterface.php b/libraries/DatabaseInterface.php index 4d02f6e4219c..6e8b44c90be4 100644 --- a/libraries/DatabaseInterface.php +++ b/libraries/DatabaseInterface.php @@ -1748,10 +1748,11 @@ public function getProceduresOrFunctions($db, $which, $link = null) * @param string $db db name * @param string $which PROCEDURE | FUNCTION | EVENT | VIEW * @param string $name the procedure|function|event|view name + * @param object $link MySQL link * * @return string the definition */ - public function getDefinition($db, $which, $name) + public function getDefinition($db, $which, $name, $link = null) { $returned_field = array( 'PROCEDURE' => 'Create Procedure', @@ -1762,7 +1763,7 @@ public function getDefinition($db, $which, $name) $query = 'SHOW CREATE ' . $which . ' ' . Util::backquote($db) . '.' . Util::backquote($name); - return($this->fetchValue($query, 0, $returned_field[$which])); + return($this->fetchValue($query, 0, $returned_field[$which], $link)); } /** diff --git a/libraries/OpenDocument.php b/libraries/OpenDocument.php new file mode 100644 index 000000000000..d649fa92280d --- /dev/null +++ b/libraries/OpenDocument.php @@ -0,0 +1,176 @@ + addFile($mime, 'mimetype'); + $zipfile -> addFile($data, 'content.xml'); + $zipfile -> addFile( + '' + . '' + . '' + . 'phpMyAdmin ' . PMA_VERSION . '' + . 'phpMyAdmin ' . PMA_VERSION + . '' + . '' . strftime('%Y-%m-%dT%H:%M:%S') + . '' + . '' + . '', + 'meta.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '', + 'styles.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' + . '', + 'META-INF/manifest.xml' + ); + return $zipfile -> file(); + } +} diff --git a/libraries/Table.php b/libraries/Table.php index 59ac3fcde13e..95a8a2ebef69 100644 --- a/libraries/Table.php +++ b/libraries/Table.php @@ -971,10 +971,17 @@ static public function moveCopy($source_db, $source_table, $target_db, $GLOBALS['dbi']->query($sql_set_mode); $GLOBALS['sql_query'] .= "\n\n" . $sql_set_mode . ';'; - $sql_insert_data = 'INSERT INTO ' . $target - . ' SELECT * FROM ' . $source; - $GLOBALS['dbi']->query($sql_insert_data); - $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';'; + $_old_table = new Table($source_table, $source_db); + $nonGeneratedCols = $_old_table->getNonGeneratedColumns(true); + if (count($nonGeneratedCols) > 0) { + $sql_insert_data = 'INSERT INTO ' . $target . '(' + . implode(', ', $nonGeneratedCols) + . ') SELECT ' . implode(', ', $nonGeneratedCols) + . ' FROM ' . $source; + + $GLOBALS['dbi']->query($sql_insert_data); + $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';'; + } } PMA_getRelationsParam(); @@ -1450,6 +1457,40 @@ public function getColumnsMeta() } } + /** + * Get non-generated columns in table + * + * @param bool $backquoted whether to quote name with backticks `` + * + * @return array + */ + public function getNonGeneratedColumns($backquoted = true) + { + $columns_meta_query = 'SHOW COLUMNS FROM ' . $this->getFullName(true); + $ret = array(); + + $columns_meta_query_result = $this->_dbi->fetchResult( + $columns_meta_query + ); + + if ($columns_meta_query_result + && $columns_meta_query_result !== false + ) { + foreach ($columns_meta_query_result as $column) { + $value = $column['Field']; + if ($backquoted === true) { + $value = Util::backquote($value); + } + + if (strpos($column['Extra'], 'GENERATED') === false) { + array_push($ret, $value); + } + } + } + + return $ret; + } + /** * Return UI preferences for this table from phpMyAdmin database. * diff --git a/libraries/export.lib.php b/libraries/export.lib.php index b90fb6f5d622..da26e47c524d 100644 --- a/libraries/export.lib.php +++ b/libraries/export.lib.php @@ -684,8 +684,13 @@ function PMA_exportDatabase( && in_array($table, $table_data) && ! ($is_view) ) { - $local_query = 'SELECT * FROM ' . PMA\libraries\Util::backquote($db) + $tableObj = new PMA\libraries\Table($table, $db); + $nonGeneratedCols = $tableObj->getNonGeneratedColumns(true); + + $local_query = 'SELECT ' . implode(', ', $nonGeneratedCols) + . ' FROM ' . PMA\libraries\Util::backquote($db) . '.' . PMA\libraries\Util::backquote($table); + if (! $export_plugin->exportData( $db, $table, $crlf, $err_url, $local_query, $aliases )) { @@ -864,7 +869,12 @@ function PMA_exportTable( $local_query = $sql_query . $add_query; $GLOBALS['dbi']->selectDb($db); } else { - $local_query = 'SELECT * FROM ' . PMA\libraries\Util::backquote($db) + // Data is exported only for Non-generated columns + $tableObj = new PMA\libraries\Table($table, $db); + $nonGeneratedCols = $tableObj->getNonGeneratedColumns(true); + + $local_query = 'SELECT ' . implode(', ', $nonGeneratedCols) + . ' FROM ' . PMA\libraries\Util::backquote($db) . '.' . PMA\libraries\Util::backquote($table) . $add_query; } if (! $export_plugin->exportData( diff --git a/libraries/insert_edit.lib.php b/libraries/insert_edit.lib.php index 0c821e453eff..84fc0454d2da 100644 --- a/libraries/insert_edit.lib.php +++ b/libraries/insert_edit.lib.php @@ -1128,10 +1128,13 @@ function PMA_getBinaryAndBlobColumn( $html_output .= sprintf($fields_type_html, $fields_type_val); if ($is_upload && $column['is_blob'] && !$readOnly) { + // We don't want to prevent users from using + // browser's default drag-drop feature on some page(s), + // so we add noDragDrop class to the input $html_output .= '
' . ' '; list($html_out,) = PMA_getMaxUploadSize( $column, $biggest_max_file_size diff --git a/libraries/opendocument.lib.php b/libraries/opendocument.lib.php deleted file mode 100644 index 71305d86dff2..000000000000 --- a/libraries/opendocument.lib.php +++ /dev/null @@ -1,167 +0,0 @@ - addFile($mime, 'mimetype'); - $zipfile -> addFile($data, 'content.xml'); - $zipfile -> addFile( - '' - . '' - . '' - . 'phpMyAdmin ' . PMA_VERSION . '' - . 'phpMyAdmin ' . PMA_VERSION - . '' - . '' . strftime('%Y-%m-%dT%H:%M:%S') - . '' - . '' - . '', - 'meta.xml' - ); - $zipfile -> addFile( - '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '', - 'styles.xml' - ); - $zipfile -> addFile( - '' - . '' - . '' - . '' - . '' - . '' - . '', - 'META-INF/manifest.xml' - ); - return $zipfile -> file(); -} diff --git a/libraries/plugins/export/ExportOds.php b/libraries/plugins/export/ExportOds.php index 8ee621c515b1..86c873d6678d 100644 --- a/libraries/plugins/export/ExportOds.php +++ b/libraries/plugins/export/ExportOds.php @@ -16,9 +16,9 @@ use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup; use PMA\libraries\DatabaseInterface; use PMA\libraries\properties\options\items\TextPropertyItem; +use PMA\libraries\OpenDocument; $GLOBALS['ods_buffer'] = ''; -require_once 'libraries/opendocument.lib.php'; /** * Handles the export for the ODS class @@ -91,7 +91,7 @@ public function exportHeader() { $GLOBALS['ods_buffer'] .= '' . '' + . OpenDocument::NS . 'office:version="1.0">' . '' . '' @@ -149,7 +149,7 @@ public function exportFooter() . '' . ''; if (!PMA_exportOutputHandler( - PMA_createOpenDocument( + OpenDocument::create( 'application/vnd.oasis.opendocument.spreadsheet', $GLOBALS['ods_buffer'] ) diff --git a/libraries/plugins/export/ExportOdt.php b/libraries/plugins/export/ExportOdt.php index 152619cecda3..3c51b5beec91 100644 --- a/libraries/plugins/export/ExportOdt.php +++ b/libraries/plugins/export/ExportOdt.php @@ -17,9 +17,9 @@ use PMA\libraries\Util; use PMA\libraries\properties\options\items\RadioPropertyItem; use PMA\libraries\properties\options\items\TextPropertyItem; +use PMA\libraries\OpenDocument; $GLOBALS['odt_buffer'] = ''; -require_once 'libraries/opendocument.lib.php'; /** * Handles the export for the ODT class @@ -148,7 +148,7 @@ public function exportHeader() { $GLOBALS['odt_buffer'] .= '' . '' + . OpenDocument::NS . 'office:version="1.0">' . '' . ''; @@ -166,7 +166,7 @@ public function exportFooter() . '' . ''; if (!PMA_exportOutputHandler( - PMA_createOpenDocument( + OpenDocument::create( 'application/vnd.oasis.opendocument.text', $GLOBALS['odt_buffer'] ) diff --git a/libraries/rte/rte_export.lib.php b/libraries/rte/rte_export.lib.php index 55f9c2da57eb..94b59ff5aaa6 100644 --- a/libraries/rte/rte_export.lib.php +++ b/libraries/rte/rte_export.lib.php @@ -44,15 +44,16 @@ function PMA_RTE_handleExport($export_data) } else { $_db = htmlspecialchars(PMA\libraries\Util::backquote($db)); $message = __('Error in processing request:') . ' ' - . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db); - $response = Message::error($message); + . sprintf(PMA_RTE_getWord('no_view'), $item_name, $_db); + $message = Message::error($message); + if ($GLOBALS['is_ajax_request'] == true) { $response = PMA\libraries\Response::getInstance(); $response->setRequestStatus(false); $response->addJSON('message', $message); exit; } else { - $response->display(); + $message->display(); } } } // end PMA_RTE_handleExport() @@ -70,6 +71,9 @@ function PMA_EVN_handleExport() if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { $item_name = $_GET['item_name']; $export_data = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $item_name); + if (! $export_data) { + $export_data = false; + } PMA_RTE_handleExport($export_data); } } // end PMA_EVN_handleExport() @@ -89,13 +93,20 @@ function PMA_RTN_handleExport() && ! empty($_GET['item_type']) ) { if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { - $export_data = "DELIMITER $$\n" - . $GLOBALS['dbi']->getDefinition( + $rtn_definition + = $GLOBALS['dbi']->getDefinition( $db, $_GET['item_type'], $_GET['item_name'] - ) - . "$$\nDELIMITER ;\n"; + ); + if (! $rtn_definition) { + $export_data = false; + } else { + $export_data = "DELIMITER $$\n" + . $rtn_definition + . "$$\nDELIMITER ;\n"; + } + PMA_RTE_handleExport($export_data); } } diff --git a/libraries/rte/rte_list.lib.php b/libraries/rte/rte_list.lib.php index 11b403d76598..fe33e17d8c34 100644 --- a/libraries/rte/rte_list.lib.php +++ b/libraries/rte/rte_list.lib.php @@ -204,9 +204,24 @@ function PMA_RTN_getRowForList($routine, $rowclass = '') $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + + // this is for our purpose to decide whether to + // show the edit link or not, so we need the DEFINER for the routine + $where = "ROUTINE_SCHEMA " . PMA\libraries\Util::getCollateForIS() . "=" + . "'" . PMA\libraries\Util::sqlAddSlashes($db) . "' " + . "AND SPECIFIC_NAME='" . PMA\libraries\Util::sqlAddSlashes($routine['name']) . "'" + . "AND ROUTINE_TYPE='" . PMA\libraries\Util::sqlAddSlashes($routine['type']) . "'"; + $query = "SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; + $routine_definer = $GLOBALS['dbi']->fetchValue($query, 0, 0, $GLOBALS['controllink']); + + $curr_user = $GLOBALS['dbi']->getCurrentUser(); + // Since editing a procedure involved dropping and recreating, check also for // CREATE ROUTINE privilege to avoid lost procedures. - if (PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db)) { + if ((PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { $retval .= ' \n"; $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; + if ((PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { + $retval .= ' ' . $titles['Export'] . "\n"; + } else { + $retval .= " {$titles['NoExport']}\n"; + } $retval .= " \n"; $retval .= " \n"; $retval .= ' fetchSingleRow($query); + $routine = $GLOBALS['dbi']->fetchSingleRow($query, 'ASSOC', $link); if (! $routine) { return false; @@ -597,13 +605,19 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) $retval['item_name'] = $routine['SPECIFIC_NAME']; $retval['item_type'] = $routine['ROUTINE_TYPE']; - $parser = new SqlParser\Parser( - $GLOBALS['dbi']->getDefinition( + $definition + = $GLOBALS['dbi']->getDefinition( $db, $routine['ROUTINE_TYPE'], - $routine['SPECIFIC_NAME'] - ) - ); + $routine['SPECIFIC_NAME'], + $link + ); + + if ($definition == NULL) { + return false; + } + + $parser = new SqlParser\Parser($definition); /** * @var CreateStatement $stmt @@ -1283,7 +1297,7 @@ function PMA_RTN_handleExecute() if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) { // Build the queries $routine = PMA_RTN_getDataFromName( - $_REQUEST['item_name'], $_REQUEST['item_type'], false + $_REQUEST['item_name'], $_REQUEST['item_type'], false, true ); if ($routine === false) { $message = __('Error in processing request:') . ' '; @@ -1481,7 +1495,7 @@ function PMA_RTN_handleExecute() * Display the execute form for a routine. */ $routine = PMA_RTN_getDataFromName( - $_GET['item_name'], $_GET['item_type'], true + $_GET['item_name'], $_GET['item_type'], true, true ); if ($routine !== false) { $form = PMA_RTN_getExecuteForm($routine); diff --git a/libraries/rte/rte_words.lib.php b/libraries/rte/rte_words.lib.php index 18d757d25218..3205c2e7fb1e 100644 --- a/libraries/rte/rte_words.lib.php +++ b/libraries/rte/rte_words.lib.php @@ -31,6 +31,14 @@ function PMA_RTE_getWord($index) 'no_create' => __( 'You do not have the necessary privileges to create a routine' ), + 'no_edit' => __( + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to edit this routine' + ), + 'no_view' => __( + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to view/export this routine' + ), 'not_found' => __('No routine with name %1$s found in database %2$s'), 'nothing' => __('There are no routines to display.'), 'title' => __('Routines'), diff --git a/libraries/server_privileges.lib.php b/libraries/server_privileges.lib.php index 810e7031e442..4d49401e0993 100644 --- a/libraries/server_privileges.lib.php +++ b/libraries/server_privileges.lib.php @@ -2949,6 +2949,33 @@ function PMA_getUserGroupCount() return $user_group_count; } +/** + * Returns name of user group that user is part of + * + * @param string $username User name + * + * @return mixed usergroup if found or null if not found + */ +function PMA_getUserGroupForUser($username) +{ + $cfgRelation = PMA_getRelationsParam(); + $user_table = Util::backquote($cfgRelation['db']) + . '.' . Util::backquote($cfgRelation['users']); + $sql_query = 'SELECT `usergroup` FROM ' . $user_table + . ' WHERE `username` = \'' . $username . '\'' + . ' LIMIT 1'; + + $usergroup = $GLOBALS['dbi']->fetchValue( + $sql_query, 0, 0, $GLOBALS['controllink'] + ); + + if ($usergroup === false) { + return null; + } + + return $usergroup; +} + /** * This function return the extra data array for the ajax behavior * @@ -3127,8 +3154,15 @@ function PMA_getChangeLoginInformationHtmlForm($username, $hostname) . '' . "\n" . '' . "\n" - . '
' . "\n" + . 'value="' . htmlspecialchars($hostname) . '" />' . "\n"; + + $usergroup = PMA_getUserGroupForUser($username); + if ($usergroup !== null) { + $html_output .= '' . "\n"; + } + + $html_output .= '
' . "\n" . '' . "\n" . __('Change login information / Copy user account') . '' . "\n" @@ -4304,6 +4338,12 @@ function PMA_addUser( ); } + // Copy the user group while copying a user + $old_usergroup = + $_REQUEST['old_usergroup'] ? $_REQUEST['old_usergroup'] : null; + PMA_setUserGroup($_REQUEST['username'], $old_usergroup); + + if (isset($create_user_real)) { $queries[] = $create_user_real; } diff --git a/libraries/tbl_info.inc.php b/libraries/tbl_info.inc.php index 8bb730b18727..09db3b692ef8 100644 --- a/libraries/tbl_info.inc.php +++ b/libraries/tbl_info.inc.php @@ -85,25 +85,26 @@ ? $showtable['Auto_increment'] : ''; - $create_options = isset($showtable['Create_options']) + $create_options_tmp = isset($showtable['Create_options']) ? explode(' ', $showtable['Create_options']) : array(); + $create_options = array(); // export create options by its name as variables into global namespace // f.e. pack_keys=1 becomes available as $pack_keys with value of '1' unset($pack_keys); - foreach ($create_options as $each_create_option) { + foreach ($create_options_tmp as $each_create_option) { $each_create_option = explode('=', $each_create_option); if (isset($each_create_option[1])) { // ensure there is no ambiguity for PHP 5 and 7 - ${$each_create_option[0]} = $each_create_option[1]; + $create_options[$each_create_option[0]] = $each_create_option[1]; } } // we need explicit DEFAULT value here (different from '0') - $pack_keys = (! isset($pack_keys) || strlen($pack_keys) === 0) + $create_options['pack_keys'] = (! isset($create_options['pack_keys']) || strlen($create_options['pack_keys']) == 0) ? 'DEFAULT' - : $pack_keys; - unset($create_options, $each_create_option); + : $create_options['pack_keys']; + unset($create_options_tmp, $each_create_option); } else { $pack_keys = $row_format = null; }// end if diff --git a/po/de.po b/po/de.po index 32194a272690..b58c5d6d7b10 100644 --- a/po/de.po +++ b/po/de.po @@ -4,16 +4,16 @@ msgstr "" "Project-Id-Version: phpMyAdmin-docs 4.0.0-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2016-08-17 11:28+0200\n" -"PO-Revision-Date: 2016-08-16 18:53+0000\n" -"Last-Translator: Axel Rindle \n" -"Language-Team: German \n" +"PO-Revision-Date: 2016-09-18 15:45+0000\n" +"Last-Translator: Deven Bansod \n" +"Language-Team: German " +"\n" "Language: de\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 2.8-dev\n" +"X-Generator: Weblate 2.9-dev\n" #: changelog.php:38 license.php:33 #, fuzzy, php-format @@ -11375,7 +11375,7 @@ msgid "" "This server is not configured as master in a replication process. Would you " "like to configure it?" msgstr "" -"Dieser Server ist als nicht Master in einem Replikations-Prozess " +"Dieser Server ist nicht als Master in einem Replikations-Prozess " "konfiguriert. Möchten Sie ihn konfigurieren?" #: libraries/replication_gui.lib.php:401 diff --git a/po/nl.po b/po/nl.po index 2d45fa3b9a73..684520e6c68e 100644 --- a/po/nl.po +++ b/po/nl.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.7.0-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2016-08-17 11:28+0200\n" -"PO-Revision-Date: 2016-08-17 10:19+0000\n" +"PO-Revision-Date: 2016-09-18 17:57+0000\n" "Last-Translator: dingo thirteen \n" "Language-Team: Dutch " "\n" @@ -13,7 +13,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 2.8-dev\n" +"X-Generator: Weblate 2.9-dev\n" #: changelog.php:38 license.php:33 #, fuzzy, php-format @@ -9238,7 +9238,7 @@ msgstr "Startpagina" #: libraries/navigation/NavigationHeader.php:171 msgid "Log out" -msgstr "Aanmelden" +msgstr "Afmelden" #: libraries/navigation/NavigationHeader.php:173 msgid "Empty session data" diff --git a/scripts/create-release.sh b/scripts/create-release.sh index c69be0c17a9a..c4851ca8434d 100755 --- a/scripts/create-release.sh +++ b/scripts/create-release.sh @@ -59,9 +59,17 @@ while [ $# -gt 0 ] ; do ;; *) if [ -z "$version" ] ; then - version="$1" + version=`echo $1 | tr -d -c '0-9a-z.-'` + if [ "x$version" != "x$1" ] ; then + echo "Invalid version: $1" + exit 1 + fi elif [ -z "$branch" ] ; then - branch="$1" + branch=`echo $1 | tr -d -c '0-9A-Za-z_-'` + if [ "x$branch" != "x$1" ] ; then + echo "Invalid branch: $1" + exit 1 + fi else echo "Unknown parameter: $1!" exit 1 @@ -279,7 +287,7 @@ for kit in $KITS ; do tbz|tgz|txz) if [ ! -f $name.tar ] ; then echo "* Creating $name.tar" - tar cf $name.tar $name + tar --owner=root --group=root --numeric-owner --sort=name -cf $name.tar $name fi if [ $comp = tbz ] ; then echo "* Creating $name.tar.bz2" diff --git a/tbl_operations.php b/tbl_operations.php index d45697c195bb..fa3329369b1f 100644 --- a/tbl_operations.php +++ b/tbl_operations.php @@ -59,12 +59,12 @@ // the value for transactional can be implicit // (no create option found, in this case it means 1) // or explicit (option found with a value of 0 or 1) - // ($transactional may have been set by libraries/tbl_info.inc.php, + // ($create_options['transactional'] may have been set by libraries/tbl_info.inc.php, // from the $create_options) - $transactional = (isset($transactional) && $transactional == '0') + $create_options['transactional'] = (isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'; - $page_checksum = (isset($page_checksum)) ? $page_checksum : ''; + $create_options['page_checksum'] = (isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''; } $reread_info = false; @@ -132,24 +132,24 @@ ) = PMA_setGlobalVariablesForEngine($new_tbl_storage_engine); if ($is_aria) { - $transactional = (isset($transactional) && $transactional == '0') + $create_options['transactional'] = (isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'; - $page_checksum = (isset($page_checksum)) ? $page_checksum : ''; + $create_options['page_checksum'] = (isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''; } } else { $new_tbl_storage_engine = ''; } $table_alters = PMA_getTableAltersArray( - $is_myisam_or_aria, $is_isam, $pack_keys, - (empty($checksum) ? '0' : '1'), + $is_myisam_or_aria, $is_isam, $create_options['pack_keys'], + (empty($create_options['checksum']) ? '0' : '1'), $is_aria, - ((isset($page_checksum)) ? $page_checksum : ''), - (empty($delay_key_write) ? '0' : '1'), - $is_innodb, $is_pbxt, $row_format, + ((isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''), + (empty($create_options['delay_key_write']) ? '0' : '1'), + $is_innodb, $is_pbxt, $create_options['row_format'], $new_tbl_storage_engine, - ((isset($transactional) && $transactional == '0') ? '0' : '1'), + ((isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'), $tbl_collation ); @@ -194,7 +194,6 @@ // to avoid showing the old value (for example the AUTO_INCREMENT) after // a change, clear the cache $GLOBALS['dbi']->clearTableCache(); - $page_checksum = $checksum = $delay_key_write = 0; include 'libraries/tbl_info.inc.php'; } unset($reread_info); @@ -330,12 +329,12 @@ $response->addHTML( PMA_getTableOptionDiv( $comment, $tbl_collation, $tbl_storage_engine, - $is_myisam_or_aria, $is_isam, $pack_keys, + $is_myisam_or_aria, $is_isam, $create_options['pack_keys'], $auto_increment, - (empty($delay_key_write) ? '0' : '1'), - ((isset($transactional) && $transactional == '0') ? '0' : '1'), - ((isset($page_checksum)) ? $page_checksum : ''), - $is_innodb, $is_pbxt, $is_aria, (empty($checksum) ? '0' : '1') + (empty($create_options['delay_key_write']) ? '0' : '1'), + ((isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'), + ((isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''), + $is_innodb, $is_pbxt, $is_aria, (empty($create_options['checksum']) ? '0' : '1') ) ); diff --git a/test/bootstrap-dist.php b/test/bootstrap-dist.php index 6eb190694465..f83ad7a04925 100644 --- a/test/bootstrap-dist.php +++ b/test/bootstrap-dist.php @@ -47,12 +47,14 @@ 'TESTSUITE_FULL' => '', 'CI_MODE' => '' ); -foreach ($test_defaults as $varname => $defvalue) { - $envvar = getenv($varname); - if ($envvar) { - $GLOBALS[$varname] = $envvar; - } else { - $GLOBALS[$varname] = $defvalue; +if (PHP_SAPI == 'cli') { + foreach ($test_defaults as $varname => $defvalue) { + $envvar = getenv($varname); + if ($envvar) { + $GLOBALS[$varname] = $envvar; + } else { + $GLOBALS[$varname] = $defvalue; + } } } @@ -70,7 +72,7 @@ // Set proxy information from env, if available $http_proxy = getenv('http_proxy'); -if ($http_proxy && ($url_info = parse_url($http_proxy))) { +if (PHP_SAPI == 'cli' && $http_proxy && ($url_info = parse_url($http_proxy))) { define('PROXY_URL', $url_info['host'] . ':' . $url_info['port']); define('PROXY_USER', empty($url_info['user']) ? '' : $url_info['user']); define('PROXY_PASS', empty($url_info['pass']) ? '' : $url_info['pass']); diff --git a/test/classes/TableTest.php b/test/classes/TableTest.php index efba2cb6a559..02f85f9fc5f1 100644 --- a/test/classes/TableTest.php +++ b/test/classes/TableTest.php @@ -176,6 +176,31 @@ protected function setUp() 'ALL' ) ), + array( + 'SHOW COLUMNS FROM `PMA`.`PMA_BookMark`', + null, + null, + null, + 0, + array( + array( + 'Field'=>'COLUMN_NAME1', + 'Type'=> 'INT(10)', + 'Null'=> 'NO', + 'Key'=> '', + 'Default'=> NULL, + 'Extra'=>'' + ), + array( + 'Field'=>'COLUMN_NAME2', + 'Type'=> 'INT(10)', + 'Null'=> 'YES', + 'Key'=> '', + 'Default'=> NULL, + 'Extra'=>'STORED GENERATED' + ) + ) + ), ); $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface') @@ -1043,7 +1068,8 @@ public function testMoveCopy() $expect, $return ); - $sql_query = "INSERT INTO `PMA_new`.`PMA_BookMark_new` SELECT * FROM " + $sql_query = "INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)" + . " SELECT `COLUMN_NAME1` FROM " . "`PMA`.`PMA_BookMark`"; $this->assertContains( $sql_query, @@ -1066,8 +1092,9 @@ public function testMoveCopy() $expect, $return ); - $sql_query = "INSERT INTO `PMA_new`.`PMA_BookMark_new` SELECT * FROM " - . "`PMA`.`PMA_BookMark`;"; + $sql_query = "INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)" + . " SELECT `COLUMN_NAME1` FROM " + . "`PMA`.`PMA_BookMark`"; $this->assertContains( $sql_query, $GLOBALS['sql_query'] diff --git a/test/classes/plugin/export/ExportOdsTest.php b/test/classes/plugin/export/ExportOdsTest.php index b458b0d7cc81..4a4d1d351f19 100644 --- a/test/classes/plugin/export/ExportOdsTest.php +++ b/test/classes/plugin/export/ExportOdsTest.php @@ -11,7 +11,6 @@ require_once 'libraries/plugins/export/ExportOds.php'; require_once 'libraries/export.lib.php'; require_once 'libraries/config.default.php'; -require_once 'libraries/opendocument.lib.php'; require_once 'test/PMATestCase.php'; /** diff --git a/test/classes/plugin/export/ExportOdtTest.php b/test/classes/plugin/export/ExportOdtTest.php index f720be14897b..6952e47ec193 100644 --- a/test/classes/plugin/export/ExportOdtTest.php +++ b/test/classes/plugin/export/ExportOdtTest.php @@ -313,14 +313,16 @@ public function testSetProperties() */ public function testExportHeader() { - $GLOBALS['OpenDocumentNS'] = "ODNS"; - $this->assertTrue( $this->object->exportHeader() ); $this->assertContains( - "assertContains( + "office:version", $GLOBALS['odt_buffer'] ); } diff --git a/test/libraries/PMA_export_test.php b/test/libraries/PMA_export_test.php index cf4e3dc770e4..3accde572536 100644 --- a/test/libraries/PMA_export_test.php +++ b/test/libraries/PMA_export_test.php @@ -14,7 +14,7 @@ require_once 'libraries/export.lib.php'; /** - * class PMA_DisplayExport_Test + * class PMA_Export_Test * * this class is for testing export.lib.php functions * diff --git a/test/libraries/PMA_insert_edit_test.php b/test/libraries/PMA_insert_edit_test.php index 5d872f8826f7..b23893050f78 100644 --- a/test/libraries/PMA_insert_edit_test.php +++ b/test/libraries/PMA_insert_edit_test.php @@ -1127,7 +1127,7 @@ public function testGetBinaryAndBlobColumn() . 'name="fieldsb" value="" />' . '
 (Max: 64KiB)' . "\n", + . 'field noDragDrop" id="field_1_3" size="10" c/> (Max: 64KiB)' . "\n", $result ); @@ -1185,7 +1185,7 @@ public function testGetBinaryAndBlobColumn() . 'cols="1" dir="/" id="field_1_3" c tabindex="3" data-type="HEX">' . '' . '
 (Max: 64KiB)' . "\n", + . 'field noDragDrop" id="field_1_3" size="10" c/> (Max: 64KiB)' . "\n", $result ); diff --git a/test/libraries/PMA_server_privileges_test.php b/test/libraries/PMA_server_privileges_test.php index 933c9f1f89e2..2739e6d93de7 100644 --- a/test/libraries/PMA_server_privileges_test.php +++ b/test/libraries/PMA_server_privileges_test.php @@ -1636,6 +1636,7 @@ public function testPMAGetChangeLoginInformationHtmlForm() { $username = "pma_username"; $hostname = "pma_hostname"; + $GLOBALS['cfgRelation']['menuswork'] = true; $dbi_old = $GLOBALS['dbi']; $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface') @@ -1648,6 +1649,11 @@ public function testPMAGetChangeLoginInformationHtmlForm() $dbi->expects($this->any())->method('fetchResult') ->will($this->returnValue($fields_info)); + $expected_userGroup = "pma_usergroup"; + + $dbi->expects($this->any())->method('fetchValue') + ->will($this->returnValue($expected_userGroup)); + $GLOBALS['dbi'] = $dbi; //PMA_getChangeLoginInformationHtmlForm @@ -1675,6 +1681,12 @@ public function testPMAGetChangeLoginInformationHtmlForm() $html ); + $this->assertContains( + '', + $html + ); + //Create a new user with the same privileges $this->assertContains( "Create a new user account with the same privileges", @@ -1684,6 +1696,38 @@ public function testPMAGetChangeLoginInformationHtmlForm() $GLOBALS['dbi'] = $dbi_old; } + /** + * Test for PMA_getUserGroupForUser + * + * @return void + */ + public function testPMAGetUserGroupForUser() + { + $username = "pma_username"; + $hostname = "pma_hostname"; + $GLOBALS['cfgRelation']['menuswork'] = true; + + $dbi_old = $GLOBALS['dbi']; + $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $expected_userGroup = "pma_usergroup"; + + $dbi->expects($this->any())->method('fetchValue') + ->will($this->returnValue($expected_userGroup)); + + $GLOBALS['dbi'] = $dbi; + + $returned_userGroup = PMA_getUserGroupForUser($username); + + $this->assertEquals( + $expected_userGroup, + $returned_userGroup + ); + + $GLOBALS['dbi'] = $dbi_old; + } + /** * Test for PMA_getLinkToDbAndTable * diff --git a/themes/original/css/common.css.php b/themes/original/css/common.css.php index cb3d01248619..088e992b7709 100644 --- a/themes/original/css/common.css.php +++ b/themes/original/css/common.css.php @@ -2325,7 +2325,8 @@ } .cEdit .edit_box { - overflow: hidden; + overflow-x: hidden; + overflow-y: scroll; padding: 0; } diff --git a/themes/pmahomme/css/common.css.php b/themes/pmahomme/css/common.css.php index dfbf173a180b..aab324813a02 100644 --- a/themes/pmahomme/css/common.css.php +++ b/themes/pmahomme/css/common.css.php @@ -2875,7 +2875,8 @@ } .cEdit .edit_box { - overflow: hidden; + overflow-x: hidden; + overflow-y: scroll; padding: 0; margin: 0; }