import and export for user preferences (currently JSON file only)

add preferences reset
This commit is contained in:
Crack
2010-07-08 19:01:09 +02:00
parent 104b40cb11
commit 104ac11c1d
11 changed files with 402 additions and 87 deletions

View File

@@ -2,3 +2,5 @@ restore cache'ing in phpmyadmin.css.php
make CSS for darkblue_orange
check input escaping, $cfg is no longer safe to use
preference:
- synchronize language, theme ThemeDefault

View File

@@ -1,5 +1,5 @@
/**
* Functions used in configuration forms
* Functions used in configuration forms and on user preferences pages
*/
// default values for fields
@@ -625,3 +625,48 @@ $(function() {
//
// END: "Restore default" and "set value" buttons
// ------------------------------------------------------------------
// ------------------------------------------------------------------
// User preferences import/export
//
$(function() {
var radios = $('#import_local_storage, #export_local_storage');
if (!radios.length) {
return;
}
// enable JavaScript dependent fields
radios
.attr('disabled', false)
.add('#export_text_file, #import_text_file')
.click(function(){
var show_id = $(this).attr('id');
var hide_id = show_id.match(/local_storage$/)
? show_id.replace(/local_storage$/, 'text_file')
: show_id.replace(/text_file$/, 'local_storage');
$('#opts_'+hide_id).hide('fast');
$('#opts_'+show_id).show('fast');
});
// detect localStorage state
var ls_supported = window.localStorage || false;
var ls_exists = ls_supported ? (window.localStorage['config'] || false) : false;
$('.localStorage-'+(ls_supported ? 'un' : '')+'supported').hide();
$('.localStorage-'+(ls_exists ? 'empty' : 'exists')).hide();
$('form.prefs-form').change(function(){
var form = $(this);
var disabled = false;
if (!ls_supported) {
disabled = form.find('input[type=radio][value$=local_storage]').attr('checked');
} else if (!ls_exists && form.attr('name') == 'prefs_import'
&& $('#import_local_storage')[0].checked) {
disabled = true;
}
form.find('input[type=submit]').attr('disabled', disabled);
});
});
//
// END: User preferences import/export
// ------------------------------------------------------------------

View File

@@ -185,6 +185,20 @@ class ConfigFile
}
}
/**
* Returns default config in a flattened array
*
* @return array
*/
public function getFlatDefaultConfig()
{
$this->_flattenArrayResult = array();
array_walk($this->cfg, array($this, '_flattenArray'), '');
$flat_cfg = $this->_flattenArrayResult;
$this->_flattenArrayResult = null;
return $flat_cfg;
}
/**
* Updates config with values read from PMA_Config class
* (config will contain differences to defaults from config.defaults.php).

View File

@@ -111,12 +111,12 @@ class FormDisplay
* Processes forms, returns true on successful save
*
* @param bool $allow_partial_save allows for partial form saving on failed validation
* @param bool $check_form_submit whether check for $_POST['submit_save']
* @return boolean
*/
public function process($allow_partial_save = true)
public function process($allow_partial_save = true, $check_form_submit = true)
{
// gather list of forms to save
if (!isset($_POST['submit_save'])) {
if ($check_form_submit && !isset($_POST['submit_save'])) {
return false;
}
@@ -475,6 +475,11 @@ class FormDisplay
$work_path = array_search($system_path, $this->system_paths);
$key = $this->translated_paths[$work_path];
// skip groups
if ($form->getOptionType($field) == 'group') {
continue;
}
// ensure the value is set
if (!isset($_POST[$key])) {
// checkboxes aren't set by browsers if they're off

View File

@@ -92,8 +92,10 @@ $tabs['synchronize']['link'] = 'server_synchronize.php';
$tabs['synchronize']['text'] = __('Synchronize');
$tabs['settings']['icon'] = 'b_tblops.png';
$tabs['settings']['link'] = 'prefs_forms.php';
$tabs['settings']['link'] = 'prefs_manage.php';
$tabs['settings']['text'] = __('Settings');
$tabs['settings']['active'] = in_array(basename($GLOBALS['PMA_PHP_SELF']),
array('prefs_forms.php', 'prefs_manage.php'));
echo PMA_generate_html_tabs($tabs, array());
unset($tabs);

View File

@@ -0,0 +1,82 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
*
* @package phpMyAdmin
*/
if (! defined('PHPMYADMIN')) {
exit;
}
// show server tabs
require './libraries/server_links.inc.php';
// build user preferences menu
$form_param = filter_input(INPUT_GET, 'form');
if (!isset($forms[$form_param])) {
$forms_keys = array_keys($forms);
$form_param = array_shift($forms_keys);
}
$tabs_icons = array(
'Features' => 'b_tblops.png',
'Sql_queries' => 'b_sql.png',
'Left_frame' => 'b_select.png',
'Main_frame' => 'b_props.png',
'Import' => 'b_import.png',
'Export' => 'b_export.png');
echo '<ul id="topmenu2">';
echo PMA_generate_html_tab(array(
'link' => 'prefs_manage.php',
'text' => __('Manage your settings'))) . "\n";
echo '<li>&nbsp; &nbsp;</li>' . "\n";
$script_name = basename(basename($GLOBALS['PMA_PHP_SELF']));
foreach (array_keys($forms) as $formset) {
$tab = array(
'link' => 'prefs_forms.php',
'text' => PMA_lang('Form_' . $formset),
'icon' => $tabs_icons[$formset],
'active' => ($script_name == 'prefs_forms.php' && $formset == $form_param));
echo PMA_generate_html_tab($tab, array('form' => $formset)) . "\n";
}
echo '</ul>';
// show "configuration saved" message and reload navigation frame if needed
if (!empty($_GET['saved'])) {
$message = PMA_Message::rawSuccess(__('Configuration has been saved'));
$message->display();
if (isset($_GET['refresh_left_frame']) && $_GET['refresh_left_frame'] == '1') {
?>
<script type="text/javascript">
if (window.parent && window.parent.frame_navigation) {
window.parent.frame_navigation.location.reload();
}
</script>
<?php
}
}
$forms_all_keys = PMA_read_userprefs_fieldnames($forms);
$cf = ConfigFile::getInstance();
$cf->setAllowedKeys($forms_all_keys);
$cf->updateWithGlobalConfig($GLOBALS['PMA_Config']);
// todo: debug - remove
$arr = $cf->getConfigArray();
$arr2 = array();
foreach ($arr as $k => $v) {
$arr2[] = "<b>$k</b> " . var_export($v, true);
}
$arr2 = implode(', ', $arr2);
$arr2 .= '<br />Blacklist: ' . (empty($cfg['UserprefsDisallow'])
? '<i>empty</i>'
: implode(', ', $cfg['UserprefsDisallow']));
$msg = PMA_Message::notice('Debug: ' . $arr2);
$msg->display();
if (isset($error) && $error) {
if (!$error instanceof PMA_Message) {
$error = PMA_Message::error($error);
}
$error->display();
}

View File

@@ -174,4 +174,38 @@ function PMA_persist_option($path, $value, $default_value)
}
PMA_save_userprefs($prefs['config_data']);
}
/**
* Redirects after saving new user preferences
*
* @param array $forms
* @param array $old_settings
* @param string $file_name
* @param array $params
*/
function PMA_userprefs_redirect(array $forms, array $old_settings, $file_name, $params = null)
{
// compute differences and check whether left frame should be refreshed
$old_settings = isset($old_settings['config_data'])
? $old_settings['config_data']
: array();
$new_settings = ConfigFile::getInstance()->getConfigArray();
$diff_keys = array_keys(array_diff_assoc($old_settings, $new_settings)
+ array_diff_assoc($new_settings, $old_settings));
$check_keys = array('NaturalOrder', 'MainPageIconic', 'DefaultTabDatabase');
$check_keys = array_merge($check_keys, $forms['Left_frame']['Left_frame'],
$forms['Left_frame']['Left_servers'], $forms['Left_frame']['Left_databases']);
$diff = array_intersect($check_keys, $diff_keys);
$refresh_left_frame = !empty($diff);
// redirect
$url_params = array(
'saved' => 1,
'refresh_left_frame' => $refresh_left_frame);
if (is_array($params)) {
$url_params = array_merge($params, $url_params);
}
PMA_sendHeaderLocation($GLOBALS['cfg']['PmaAbsoluteUri'] . $file_name
. PMA_generate_common_url($url_params, '&'));
}
?>

View File

@@ -176,7 +176,7 @@ echo '</ul>';
echo '<ul>';
echo PMA_printListItem(__('More settings'), 'li_user_preferences',
'./prefs_forms.php?' . $common_url_query);
'./prefs_manage.php?' . $common_url_query);
echo '<ul>';
echo '</div>';

View File

@@ -19,71 +19,11 @@ require_once './libraries/config/FormDisplay.class.php';
require './libraries/config/user_preferences.forms.php';
$GLOBALS['js_include'][] = 'config.js';
require_once './libraries/header.inc.php';
// show server tabs
require './libraries/server_links.inc.php';
// build user preferences menu
$form_param = filter_input(INPUT_GET, 'form');
if (!isset($forms[$form_param])) {
$forms_keys = array_keys($forms);
$form_param = array_shift($forms_keys);
}
$tabs_icons = array(
'Features' => 'b_tblops.png',
'Sql_queries' => 'b_sql.png',
'Left_frame' => 'b_select.png',
'Main_frame' => 'b_props.png',
'Import' => 'b_import.png',
'Export' => 'b_export.png');
echo '<ul id="topmenu2">';
foreach (array_keys($forms) as $formset) {
$tab = array(
'link' => 'prefs_forms.php',
'text' => PMA_lang('Form_' . $formset),
'icon' => $tabs_icons[$formset],
'active' => $formset == $form_param);
echo PMA_generate_html_tab($tab, array('form' => $formset));
}
echo '</ul>';
// show "configuration saved" message and reload navigation frame if needed
if (!empty($_GET['saved'])) {
$message = PMA_Message::rawSuccess(__('Configuration has been saved'));
$message->display();
if (isset($_GET['refresh_left_frame']) && $_GET['refresh_left_frame'] == '1') {
?>
<script type="text/javascript">
if (window.parent && window.parent.frame_navigation) {
window.parent.frame_navigation.location.reload();
}
</script>
<?php
}
}
require_once './libraries/user_preferences.inc.php';
// handle form display and processing
$forms_all_keys = PMA_read_userprefs_fieldnames($forms);
$cf = ConfigFile::getInstance();
$cf->setAllowedKeys($forms_all_keys);
$cf->updateWithGlobalConfig($GLOBALS['PMA_Config']);
// todo: debug - remove
$arr = $cf->getConfigArray();
$arr2 = array();
foreach ($arr as $k => $v) {
$arr2[] = "<b>$k</b> " . var_export($v, true);
}
$arr2 = implode(', ', $arr2);
$arr2 .= '<br />Blacklist: ' . (empty($cfg['UserprefsDisallow'])
? '<i>empty</i>'
: implode(', ', $cfg['UserprefsDisallow']));
$msg = PMA_Message::notice('Debug: ' . $arr2);
$msg->display();
$form_display = new FormDisplay();
foreach ($forms[$form_param] as $form_name => $form) {
$form_display->registerForm($form_name, $form);
@@ -117,26 +57,8 @@ if (!$form_display->process(false)) {
$old_settings = PMA_load_userprefs();
$result = PMA_save_userprefs($cf->getConfigArray());
if ($result === true) {
// compute differences and check whether left frame should be refreshed
$old_settings = isset($old_settings['config_data'])
? $old_settings['config_data']
: array();
$new_settings = ConfigFile::getInstance()->getConfigArray();
$diff_keys = array_keys(array_diff_assoc($old_settings, $new_settings)
+ array_diff_assoc($new_settings, $old_settings));
$check_keys = array('NaturalOrder', 'MainPageIconic', 'DefaultTabDatabase');
$check_keys = array_merge($check_keys, $forms['Left_frame']['Left_frame'],
$forms['Left_frame']['Left_servers'], $forms['Left_frame']['Left_databases']);
$diff = array_intersect($check_keys, $diff_keys);
$refresh_left_frame = !empty($diff);
// redirect
$url_params = array(
'form' => $form_param,
'saved' => 1,
'refresh_left_frame' => $refresh_left_frame);
PMA_sendHeaderLocation($cfg['PmaAbsoluteUri'] . 'prefs_forms.php'
. PMA_generate_common_url($url_params, '&'));
PMA_userprefs_redirect($forms, $old_settings, 'prefs_forms.php', array(
'form' => $form_param));
exit;
} else {
$result->display();

203
prefs_manage.php Normal file
View File

@@ -0,0 +1,203 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* User preferences management page
*
* @package phpMyAdmin
*/
/**
* Gets some core libraries and displays a top message if required
*/
require_once './libraries/common.inc.php';
require_once './libraries/user_preferences.lib.php';
require_once './libraries/config/config_functions.lib.php';
require_once './libraries/config/messages.inc.php';
require_once './libraries/config/ConfigFile.class.php';
require_once './libraries/config/Form.class.php';
require_once './libraries/config/FormDisplay.class.php';
require './libraries/config/user_preferences.forms.php';
$error = '';
if (isset($_POST['submit_export']) && filter_input(INPUT_POST, 'export_type') == 'text_file') {
// export to JSON file
$filename = 'phpMyAdmin-config-' . urlencode(PMA_getenv('HTTP_HOST')) . '.json';
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Expires: ' . date(DATE_RFC1123));
$settings = PMA_load_userprefs();
echo json_encode($settings['config_data']);
return;
} else if (isset($_POST['submit_import'])) {
// load from JSON file
$json = '';
if (filter_input(INPUT_POST, 'import_type') == 'text_file'
&& isset($_FILES['import_file'])
&& $_FILES['import_file']['error'] == UPLOAD_ERR_OK
&& is_uploaded_file($_FILES['import_file']['tmp_name'])) {
// read JSON from uploaded file
$open_basedir = @ini_get('open_basedir');
$file_to_unlink = '';
$import_file = $_FILES['import_file']['tmp_name'];
// If we are on a server with open_basedir, we must move the file
// before opening it. The doc explains how to create the "./tmp"
// directory
if (!empty($open_basedir)) {
$tmp_subdir = (PMA_IS_WINDOWS ? '.\\tmp\\' : './tmp/');
if (is_writable($tmp_subdir)) {
$import_file_new = tempnam($tmp_subdir, 'prefs');
if (move_uploaded_file($import_file, $import_file_new)) {
$import_file = $import_file_new;
$file_to_unlink = $import_file_new;
}
}
}
$json = file_get_contents($import_file);
if ($file_to_unlink) {
unlink($file_to_unlink);
}
} else {
// read from POST value (json)
$json = filter_input(INPUT_POST, 'json');
}
$config = json_decode($json, true);
if (!is_array($config)) {
$error = __('Could not import configuration');
} else {
// sanitize input values: treat them as though they came from HTTP POST request
$form_display = new FormDisplay();
foreach ($forms as $formset_id => $formset) {
foreach ($formset as $form_name => $form) {
$form_display->registerForm($formset_id . ': ' . $form_name, $form);
}
}
$cf = ConfigFile::getInstance();
if (empty($_POST['import_merge'])) {
$cf->resetConfigData();
}
$_POST_bak = $_POST;
foreach ($cf->getFlatDefaultConfig() as $k => $v) {
$_POST[str_replace('/', '-', $k)] = $v;
}
$_POST = array_merge($_POST, $config);
$all_ok = $form_display->process(true, false);
$_POST = $_POST_bak;
if (!$all_ok) {
// todo: ask about saving that what can be saved
$form_display->displayErrors();
die('errors');
}
// save settings
$old_settings = PMA_load_userprefs();
$result = PMA_save_userprefs($cf->getConfigArray());
if ($result === true) {
PMA_userprefs_redirect($forms, $old_settings, 'prefs_manage.php');
exit;
} else {
$error = $result;
}
}
} else if (isset($_POST['submit_clear'])) {
$old_settings = PMA_load_userprefs();
$result = PMA_save_userprefs(array());
ConfigFile::getInstance()->resetConfigData();
if ($result === true) {
PMA_userprefs_redirect($forms, $old_settings, 'prefs_manage.php');
exit;
} else {
$error = $result;
}
exit;
}
$GLOBALS['js_include'][] = 'config.js';
require_once './libraries/header.inc.php';
require_once './libraries/user_preferences.inc.php';
?>
<div id="maincontainer">
<div id="main_pane_left">
<div class="group">
<h2><?php echo __('Import') ?></h2>
<form class="group-cnt prefs-form" name="prefs_import" action="prefs_manage.php" method="post" enctype="multipart/form-data">
<?php
echo PMA_generateHiddenMaxFileSize($max_upload_size) . "\n";
echo PMA_generate_common_hidden_inputs() . "\n";
?>
<div style="padding-bottom:0.5em">
<input type="radio" id="import_text_file" name="import_type" value="text_file" checked="checked" />
<label for="import_text_file"><?php echo __('Import from text file') ?></label>
<br />
<input type="radio" id="import_local_storage" name="import_type" value="local_storage" disabled="disabled" />
<label for="import_local_storage"><?php echo __('Import from browser\'s storage') ?></label>
</div>
<div id="opts_import_text_file">
<label for="input_import_file"><?php echo __('Location of the text file'); ?></label>
<input style="margin: 5px" type="file" name="import_file" id="input_import_file" />
</div>
<div id="opts_import_local_storage" style="display:none">
<span class="localStorage-supported">
<?php echo __('Settings will be imported from your browser\'s local storage.') ?>
<span class="localStorage-empty">
<?php PMA_Message::notice(__('You have no saved settings!'))->display() ?>
</span>
</span>
<span class="localStorage-unsupported">
<?php PMA_Message::notice(__('This feature is not supported by your web browser'))->display() ?>
</span>
</div>
<input type="checkbox" id="import_merge" name="import_merge" />
<label for="import_merge"><?php echo __('Merge with current configuration') ?></label>
<br /><br />
<input type="submit" name="submit_import" value="<?php echo __('Go'); ?>" />
</form>
</div>
</div>
<div id="main_pane_right">
<div class="group">
<h2><?php echo __('Export') ?></h2>
<form class="group-cnt prefs-form" name="prefs_export" action="prefs_manage.php" method="post">
<?php echo PMA_generate_common_hidden_inputs() . "\n" ?>
<div style="padding-bottom:0.5em">
<input type="radio" id="export_text_file" name="export_type" value="text_file" checked="checked" />
<label for="export_text_file"><?php echo __('Save as file') ?></label>
<br />
<input type="radio" id="export_local_storage" name="export_type" value="local_storage" disabled="disabled" />
<label for="export_local_storage"><?php echo __('Save to browser\'s storage') ?></label>
</div>
<div id="opts_export_local_storage" style="display:none">
<span class="localStorage-supported">
<?php echo __('Settings will be saved in your browser\'s local storage.') ?>
<span class="localStorage-exists">
<b><?php PMA_Message::notice(__('Existing settings will be overridden!'))->display() ?></b>
</span>
</span>
<span class="localStorage-unsupported">
<?php PMA_Message::notice(__('This feature is not supported by your web browser'))->display() ?>
</span>
</div>
<br />
<input type="submit" name="submit_export" value="<?php echo __('Go'); ?>" />
</form>
</div>
<div class="group">
<h2><?php echo __('Reset') ?></h2>
<form class="group-cnt prefs-form" name="prefs_export" action="prefs_manage.php" method="post">
<?php echo PMA_generate_common_hidden_inputs() . "\n" ?>
<?php echo __('You can reset all your settings and restore them to default values') ?>
<br /><br />
<input type="submit" name="submit_clear" value="<?php echo __('Reset') ?>" />
</form>
</div>
</div>
<br class="clearfloat" />
</div>
<?php
/**
* Displays the footer
*/
require_once './libraries/footer.inc.php';
?>

View File

@@ -1214,6 +1214,12 @@ code.sql {
margin-top: 0;
}
.group-cnt {
padding: 0 0 0 0.5em;
display: inline-block;
width: 100%;
}
/* for elements that should be revealed only via js */
.hide {
display: none;