diff --git a/setup/config.php b/setup/config.php new file mode 100644 index 000000000..46e5f0e52 --- /dev/null +++ b/setup/config.php @@ -0,0 +1,100 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +require './lib/common.inc.php'; +require_once './setup/lib/Form.class.php'; +require_once './setup/lib/FormDisplay.class.php'; + +/** + * Returns config file contents depending on GET type value: + * o session - uses ConfigFile::getConfigFile() + * o post - uses POST textconfig value + * + * @return string + */ +function get_config() { + $type = PMA_ifSetOr($_GET['type'], 'session'); + + if ($type == 'session') { + $config = ConfigFile::getInstance()->getConfigFile(); + } else { + $config = PMA_ifSetOr($_POST['textconfig'], ''); + // make sure our eol is \n + $config = str_replace("\r\n", "\n", $config); + if ($_SESSION['eol'] == 'win') { + $config = str_replace("\n", "\r\n", $config); + } + } + + return $config; +} + + +$form_display = new FormDisplay(); +$form_display->registerForm('_config.php'); +$form_display->save('_config.php'); +$config_file_path = ConfigFile::getInstance()->getFilePath(); + +if (isset($_POST['eol'])) { + $_SESSION['eol'] = ($_POST['eol'] == 'unix') ? 'unix' : 'win'; +} + +if (PMA_ifSetOr($_POST['submit_clear'], '')) { + // + // Clear current config and return to main page + // + $_SESSION['ConfigFile'] = array(); + // drop post data + header('HTTP/1.1 303 See Other'); + header('Location: index.php'); + exit; +} elseif (PMA_ifSetOr($_POST['submit_download'], '')) { + // + // Output generated config file + // + header('Content-Type: text/plain'); + header('Content-Disposition: attachment; filename="config.inc.php"'); + echo get_config(); + exit; +} elseif (PMA_ifSetOr($_POST['submit_save'], '')) { + // + // Save generated config file on the server + // + file_put_contents($config_file_path, get_config()); + header('HTTP/1.1 303 See Other'); + header('Location: index.php'); + exit; +} elseif (PMA_ifSetOr($_POST['submit_load'], '')) { + // + // Load config file from the server + // + $cfg = array(); + require_once $config_file_path; + $_SESSION['ConfigFile'] = $cfg; + header('HTTP/1.1 303 See Other'); + header('Location: index.php'); + exit; +} elseif (PMA_ifSetOr($_POST['submit_delete'], '')) { + // + // Delete config file on the server + // + @unlink($config_file_path); + header('HTTP/1.1 303 See Other'); + header('Location: index.php'); + exit; +} else { + // + // Show generated config file in a + + + + + + /> +     + + + + \ No newline at end of file diff --git a/setup/frames/form.inc.php b/setup/frames/form.inc.php new file mode 100644 index 000000000..b47f7365d --- /dev/null +++ b/setup/frames/form.inc.php @@ -0,0 +1,47 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +if (!defined('PHPMYADMIN')) { + exit; +} + +require_once './setup/lib/Form.class.php'; +require_once './setup/lib/FormDisplay.class.php'; +require_once './setup/lib/form_processing.lib.php'; + +$formsets = array( + 'features' => array( + 'forms' => array('Import_export', 'Security', 'Sql_queries', 'Other_core_settings')), + 'left_frame' => array( + 'forms' => array('Left_frame', 'Left_servers', 'Left_databases', 'Left_tables')), + 'main_frame' => array( + 'forms' => array('Startup', 'Browse', 'Edit', 'Tabs', 'Sql_box')), + 'import' => array( + 'forms' => array('Import', 'Import_sql', 'Import_csv', 'Import_ldi')), + 'export' => array( + 'forms' => array('Export_defaults')) +); + +$formset_id = filter_input(INPUT_GET, 'formset'); +$mode = filter_input(INPUT_GET, 'mode'); +if (!isset($formsets[$formset_id])) { + die('Incorrect formset'); +} + +$formset = $formsets[$formset_id]; +if (isset($GLOBALS['str']['Formset_' . $formset_id])) { + echo '

' . $GLOBALS['str']['Formset_' . $formset_id] . '

'; +} +$form_display = new FormDisplay(); +foreach ($formset['forms'] as $form_name) { + $form_display->registerForm($form_name); +} +process_formset($form_display); +?> \ No newline at end of file diff --git a/setup/frames/index.inc.php b/setup/frames/index.inc.php new file mode 100644 index 000000000..92ed04b43 --- /dev/null +++ b/setup/frames/index.inc.php @@ -0,0 +1,243 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +if (!defined('PHPMYADMIN')) { + exit; +} + +require_once './libraries/display_select_lang.lib.php'; +require_once './setup/lib/FormDisplay.class.php'; +require_once './setup/lib/index.lib.php'; + +// prepare unfiltered language list +$all_languages = PMA_langList(); +uasort($all_languages, 'PMA_language_cmp'); + +$cf = ConfigFile::getInstance(); +$separator = PMA_get_arg_separator('html'); + +// message handling +messages_begin(); + +// +// Check phpMyAdmin version +// +if (isset($_GET['version_check'])) { + PMA_version_check(); +} + +// +// Perform various security, compatibility and consistency checks +// +perform_config_checks(); + +// +// Check whether we can read/write configuration +// +$config_readable = false; +$config_writable = false; +$config_exists = false; +check_config_rw($config_readable, $config_writable, $config_exists); +if (!$config_writable || !$config_readable) { + messages_set('warning', 'config_rw', 'Cannot_load_config', PMA_lang('Cannot_load_config_desc')); +} +// +// Check https connection +// +$is_https = !empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on'; +if (!$is_https) { + $text = $GLOBALS['str']['Insecure_connection_desc1']; + if (!empty($_SERVER['REQUEST_URI']) && !empty($_SERVER['HTTP_HOST'])) { + $text .= ' ' . PMA_lang('Insecure_connection_desc2', + 'https://' . htmlspecialchars($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'])); + } + messages_set('warning', 'no_https', 'Insecure_connection', $text); +} +?> + +
+ +
+ +
+ +

+ + + + + +

+ 'servers', + 'mode' => 'add' +)); +?> +
+getServerCount() > 0): ?> + + + + + + + + $server): ?> + + + + + + + + +
#Authentication typeDSN
getServerName($id) ?>getValue("Servers/$id/auth_type")) ?>getServerDSN($id)) ?> + + "> + | "> + +
+ + + + + +
+ +
+ + + + + +
+ +
+
+ + +

+ 'simple')); + +// Display language list +$opts = array( + 'doc' => $form_display->getDocLink('DefaultLang'), + 'wiki' => $form_display->getWikiLink('DefaultLang'), + 'values' => array(), + 'values_escaped' => true); +foreach ($all_languages as $each_lang_key => $each_lang) { + if (!file_exists($GLOBALS['lang_path'] . $each_lang[1] . '.inc.php')) { + continue; + } + $lang_name = ucfirst(substr(strrchr($each_lang[0], '|'), 1)); + // Include native name if non empty + if (!empty($each_lang[3])) { + $lang_name = $each_lang[3] . ' - ' . $lang_name; + } + $opts['values'][$each_lang_key] = $lang_name; +} +display_input('DefaultLang', $GLOBALS['str']['Default_language'], '', 'select', + $cf->getValue('DefaultLang'), true, $opts); + +// Display server list +$opts = array( + 'doc' => $form_display->getDocLink('ServerDefault'), + 'wiki' => $form_display->getWikiLink('ServerDefault'), + 'values' => array(), + 'values_disabled' => array()); +if ($cf->getServerCount() > 0) { + $opts['values']['0'] = $GLOBALS['str']['let_the_user_choose']; + $opts['values']['-'] = '------------------------------'; + if ($cf->getServerCount() == 1) { + $opts['values_disabled'][] = '0'; + } + $opts['values_disabled'][] = '-'; + + foreach ($_SESSION['ConfigFile']['Servers'] as $id => $server) { + $opts['values'][(string)$id] = $cf->getServerName($id) . " [$id]"; + } +} else { + $opts['values']['1'] = $GLOBALS['str']['-none-']; + $opts['values_escaped'] = true; +} +display_input('ServerDefault', $GLOBALS['str']['Default_server'], '', 'select', + $cf->getValue('ServerDefault'), true, $opts); + +// Display EOL list +$opts = array( + 'values' => array( + 'unix' => 'UNIX / Linux (\n)', + 'win' => 'Windows (\r\n)'), + 'values_escaped' => true); +$eol = PMA_ifSetOr($_SESSION['eol'], (PMA_IS_WINDOWS ? 'win' : 'unix')); +display_input('eol', $GLOBALS['str']['End_of_lne'], '', 'select', + $eol, true, $opts); +?> + + + + +     + /> + /> + /> +     + + + + + \ No newline at end of file diff --git a/setup/frames/menu.inc.php b/setup/frames/menu.inc.php new file mode 100644 index 000000000..bb8b56709 --- /dev/null +++ b/setup/frames/menu.inc.php @@ -0,0 +1,24 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +if (!defined('PHPMYADMIN')) { + exit; +} + +$separator = PMA_get_arg_separator('html'); +?> + diff --git a/setup/frames/servers.inc.php b/setup/frames/servers.inc.php new file mode 100644 index 000000000..657180b84 --- /dev/null +++ b/setup/frames/servers.inc.php @@ -0,0 +1,47 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +if (!defined('PHPMYADMIN')) { + exit; +} + +require_once './setup/lib/Form.class.php'; +require_once './setup/lib/FormDisplay.class.php'; +require_once './setup/lib/form_processing.lib.php'; + +$mode = filter_input(INPUT_GET, 'mode'); +$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT); + +$cf = ConfigFile::getInstance(); +$server_exists = !empty($id) && $cf->get("Servers/$id") !== null; + +if ($mode == 'edit' && $server_exists) { + $page_title = $GLOBALS['str']['page_servers_edit'] + . ' ' . $id . ' (' . $cf->getServerDSN($id) . ')'; +} elseif ($mode == 'remove' && $server_exists) { + $cf->removeServer($id); + header('Location: index.php'); + exit; +} elseif ($mode == 'revert' && $server_exists) { + // handled by process_formset() +} else { + $page_title = $GLOBALS['str']['page_servers_add']; + $id = 0; +} +?> +

+registerForm('Server', $id); +$form_display->registerForm('Server_login_options', $id); +$form_display->registerForm('Server_config', $id); +$form_display->registerForm('Server_pmadb', $id); +process_formset($form_display); +?> \ No newline at end of file diff --git a/setup/index.php b/setup/index.php new file mode 100644 index 000000000..fe0bc5a76 --- /dev/null +++ b/setup/index.php @@ -0,0 +1,51 @@ + + * @copyright Copyright (c) 2008, Piotr Przybylski + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +require './lib/common.inc.php'; + +$page = filter_input(INPUT_GET, 'page'); +$page = preg_replace('/[^a-z]/', '', $page); +if ($page === '') { + $page = 'index'; +} +if (!file_exists("./setup/frames/$page.inc.php")) { + // it will happen only when enterung URL by hand, we don't care for these cases + die('Wrong GET file attribute value'); +} + +// send no-cache headers +require './libraries/header_http.inc.php'; +?> + + + + +phpMyAdmin <?php echo $_SESSION['PMA_Config']->get('PMA_VERSION'); ?> setup + + + + + + + +

phpMyAdmin get('PMA_VERSION'); ?> setup

+ +
+ +
+ + diff --git a/setup/lang/english-utf-8.inc.php b/setup/lang/english-utf-8.inc.php new file mode 100644 index 000000000..663575a85 --- /dev/null +++ b/setup/lang/english-utf-8.inc.php @@ -0,0 +1,424 @@ + + * @copyright Copyright (c) 2008, Piotr Przybylski + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +// page titles +$str['page_servers_add'] = 'Add a new server'; +$str['page_servers_edit'] = 'Edit server'; +$str['Formset_features'] = 'Features'; +$str['Formset_left_frame'] = 'Customize navigation frame'; +$str['Formset_main_frame'] = 'Customize main frame'; +$str['Formset_import'] = 'Customize import defaults'; +$str['Formset_export'] = 'Customize export options'; + +// forms +$str['true'] = 'yes'; +$str['false'] = 'no'; +$str['Display'] = 'Display'; +$str['Download'] = 'Download'; +$str['Clear'] = 'Clear'; +$str['Load'] = 'Load'; +$str['Restore_default'] = 'Restore default value'; +$str['Set_value'] = 'Set value: %s'; +$str['Warning'] = 'Warning'; +$str['Ignore_errors'] = 'Ignore errors'; +$str['Revert_erroneous_fields'] = 'Try to revert erroneous fields to their default values'; +$str['Show_form'] = 'Show form'; + +// main page +$str['Overview'] = 'Overview'; +$str['Show_hidden_messages'] = 'Show hidden messages (#MSG_COUNT)'; +$str['No_servers'] = 'There are no configured servers'; +$str['New_server'] = 'New server'; +$str['Default_language'] = 'Default language'; +$str['Default_server'] = 'Default server'; +$str['let_the_user_choose'] = 'let the user choose'; +$str['-none-'] = '- none -'; +$str['End_of_lne'] = 'End of line'; +$str['Configuration_file'] = 'Configuration file'; +$str['Homepage_link'] = 'phpMyAdmin homepage'; +$str['Donate_link'] = 'Donate'; +$str['Version_check_link'] = 'Check for latest version'; + +// main page messages +$str['Cannot_load_config'] = 'Cannot load or save configuration'; +$str['Cannot_load_config_desc'] = 'Please create web server writeable folder [em]config[/em] in phpMyAdmin top level directory as described in [a@../Documentation.html#setup_script]documentation[/a]. Otherwise you will be only able to download or display it.'; +$str['Insecure_connection'] = 'Insecure connection'; +$str['Insecure_connection_desc1'] = 'You are not using a secure connection, all data (including sensitive, like passwords) is transferred unencrypted!'; +$str['Insecure_connection_desc2'] = 'If your server is also configured to accept HTTPS requests follow [a@%s]this link[/a] to use a secure connection.'; +$str['Version_check'] = 'Version check'; +$str['Version_check_wrapper_error'] = 'Neither URL wrapper nor CURL is available. Version check is not possible.'; +$str['Version_check_data_error'] = 'Reading of version failed. Maybe you\'re offline or the upgrade server does not respond.'; +$str['Version_check_invalid'] = 'Got invalid version string from server'; +$str['Version_check_unparsable'] = 'Unparsable version string'; +$str['Version_check_new_available'] = 'New version of phpMyAdmin is available, you should consider upgrade. New version is %s, released on %s.'; +$str['Version_check_new_available_svn'] = 'You are using subversion version, run [kbd]svn update[/kbd] :-).[br]The latest stable version is %s, released on %s.'; +$str['Version_check_none'] = 'No newer stable version is available'; +$str['Server_ssl_msg'] = 'You should use SSL connections if your web server supports it'; +$str['Server_extension_msg'] = 'You should use mysqli for performance reasons'; +$str['Server_auth_config_msg'] = 'You set [kbd]config[/kbd] authentication type and included username and password for auto-login, which is not a desirable option for live hosts. Anyone who knows phpMyAdmin URL can directly access your phpMyAdmin panel. Set [a@?page=servers&mode=edit&id=%1$d#tab_Server]authentication type[/a] to [kbd]cookie[/kbd] or [kbd]http[/kbd]. If you feel this is necessary, use additional protection settings - [a@?page=servers&mode=edit&id=%1$d#tab_Server_config]host authentication[/a] settings and [a@?page=form&formset=features#tab_Security]trusted proxies list[/a]. However, IP-based protection may not be reliable if your IP belongs to an ISP where thousands of users, including you, are connected to.'; +$str['blowfish_secret_msg'] = 'You didn\'t have blowfish secret set and enabled cookie authentication so the key was generated for you. It is used to encrypt cookies.'; +$str['blowfish_secret_length_msg'] = 'Key is too short, it should have at least 8 characters'; +$str['blowfish_secret_chars_msg'] = 'Key should contain alphanumerics, letters [em]and[/em] special characters'; +$str['ForceSSL_msg'] = 'This [a@?page=form&formset=features#tab_Security]option[/a] should be enabled if your web server supports it'; +$str['AllowArbitraryServer_msg'] = 'This [a@?page=form&formset=features#tab_Security]option[/a] should be disabled as it allows attackers to bruteforce login to any MySQL server. If you feel this is necessary, use [a@?page=form&formset=features#tab_Security]trusted proxies list[/a]. However, IP-based protection may not be reliable if your IP belongs to an ISP where thousands of users, including you, are connected to.'; +$str['LoginCookieValidity_msg'] = '[a@?page=form&formset=features#tab_Security]Login cookie validity[/a] should be should be set to 1800 seconds (30 minutes) at most. Values larger than 1800 may pose a security risk such as impersonation.'; +$str['Directory_notice'] = 'This value should be double checked to ensure that this directory is neither world accessible nor readable or writeable by other users on your server.'; + +// form errors +$str['error_form'] = 'Submitted form contains errors'; +$str['error_missing_field_data'] = 'Missing data for %s'; +$str['error_incorrect_port'] = 'Not a valid port number'; +$str['error_incorrect_value'] = 'Incorrect value'; +$str['error_nan_p'] = 'Not a positive number'; +$str['error_nan_nneg'] = 'Not a non-negative number'; +$str['error_empty_pmadb_user'] = 'Empty phpMyAdmin control user while using pmadb'; +$str['error_empty_pmadb_password'] = 'Empty phpMyAdmin control user password while using pmadb'; +$str['error_empty_user_for_config_auth'] = 'Empty username while using config authentication method'; +$str['error_empty_signon_session'] = 'Empty signon session name while using signon authentication method'; +$str['error_empty_signon_url'] = 'Empty signon URL while using signon authentication method'; +$str['error_connection'] = 'Could not connect to MySQL server'; + +// form names +$str['Form_Server'] = 'Basic settings'; +$str['Form_Server_desc'] = 'Enter server connection parameters'; +$str['Form_Server_login_options'] = 'Signon login options'; +$str['Form_Server_login_options_desc'] = 'Enter login options for signon authentication'; +$str['Form_Server_config'] = 'Server configuration'; +$str['Form_Server_config_desc'] = 'Advanced server configuration, do not change these options unless you know what they are for'; +$str['Form_Server_pmadb'] = 'PMA database'; +$str['Form_Server_pmadb_desc'] = 'Configure phpMyAdmin database to gain access to additional features, see [a@../Documentation.html#linked-tables]linked-tables infrastructure[/a] in documentation'; +$str['Form_Import_export'] = 'Import / export'; +$str['Form_Import_export_desc'] = 'Set import and export directories and compression options'; +$str['Form_Security'] = 'Security'; +$str['Form_Security_desc'] = 'Please note that phpMyAdmin is just a user interface and its features do not limit MySQL'; +$str['Form_Sql_queries'] = 'SQL queries'; +$str['Form_Sql_queries_desc'] = 'SQL queries settings, for SQL Query box options see [a@?page=form&formset=main_frame#tab_Sql_box]Navigation frame[/a] settings'; +$str['Form_Other_core_settings'] = 'Other core settings'; +$str['Form_Other_core_settings_desc'] = 'Settings that didn\'t fit enywhere else'; +$str['Form_Left_frame'] = 'Navigation frame'; +$str['Form_Left_frame_desc'] = 'Customize appearance of the navigation frame'; +$str['Form_Left_servers'] = 'Servers'; +$str['Form_Left_servers_desc'] = 'Servers display options'; +$str['Form_Left_databases'] = 'Databases'; +$str['Form_Left_databases_desc'] = 'Databases display options'; +$str['Form_Left_tables'] = 'Tables'; +$str['Form_Left_tables_desc'] = 'Tables display options'; +$str['Form_Main_frame'] = 'Main frame'; +$str['Form_Startup'] = 'Startup'; +$str['Form_Startup_desc'] = 'Customize startup page'; +$str['Form_Browse'] = 'Browse mode'; +$str['Form_Browse_desc'] = 'Customize browse mode'; +$str['Form_Edit'] = 'Edit mode'; +$str['Form_Edit_desc'] = 'Customize edit mode'; +$str['Form_Tabs'] = 'Tabs display'; +$str['Form_Tabs_desc'] = 'Choose how you want tabs to work'; +$str['Form_Sql_box'] = 'SQL Query box'; +$str['Form_Sql_box_desc'] = 'Customize links shown in SQL Query boxes'; +$str['Form_Import'] = $GLOBALS['strImport']; +$str['Form_Import_desc'] = 'Customize default common import options'; +$str['Form_Import_sql'] = $GLOBALS['strSQL']; +$str['Form_Import_sql_desc'] = 'Customize default SQL import options'; +$str['Form_Import_csv'] = $GLOBALS['strCSV']; +$str['Form_Import_csv_desc'] = 'Customize default CSV import options'; +$str['Form_Import_ldi'] = $GLOBALS['strLDI']; +$str['Form_Import_ldi_desc'] = 'Customize default CSV using LOAD DATA import options'; +$str['Form_Export'] = $GLOBALS['strExport']; +$str['Form_Export_defaults'] = 'Defaults'; +$str['Form_Export_defaults_desc'] = 'Customize default export options'; + +// Form: Server +$str['Servers/1/verbose_name'] = 'Verbose name of this server'; +$str['Servers/1/verbose_desc'] = 'Hostname where MySQL server is running'; +$str['Servers/1/host_name'] = 'Server hostname'; +$str['Servers/1/host_desc'] = ''; +$str['Servers/1/port_name'] = 'Server port'; +$str['Servers/1/port_desc'] = 'Port on which MySQL server is listening, leave empty for default'; +$str['Servers/1/socket_name'] = 'Server socket'; +$str['Servers/1/socket_desc'] = 'Socket on which MySQL server is listening, leave empty for default'; +$str['Servers/1/ssl_name'] = 'Use SSL'; +$str['Servers/1/ssl_desc'] = ''; +$str['Servers/1/connect_type_name'] = 'Connection type'; +$str['Servers/1/connect_type_desc'] = 'How to connect to server, keep tcp if unsure'; +$str['Servers/1/extension_name'] = 'PHP extension to use'; +$str['Servers/1/extension_desc'] = 'What PHP extension to use, use mysqli if supported'; +$str['Servers/1/compress_name'] = 'Compress connection'; +$str['Servers/1/compress_desc'] = 'Compress connection to MySQL server'; +$str['Servers/1/auth_type_name'] = 'Authentication type'; +$str['Servers/1/auth_type_desc'] = 'Authentication method to use'; +$str['Servers/1/user_name'] = 'User for config auth'; +$str['Servers/1/user_desc'] = 'Leave empty if not using config auth'; +$str['Servers/1/password_name'] = 'Password for config auth'; +$str['Servers/1/password_desc'] = 'Leave empty if not using config auth'; +$str['Servers/1/nopassword_name'] = 'Connect without password'; +$str['Servers/1/nopassword_desc'] = 'Try to connect without password'; + +// Form: Server_login_options +$str['Servers/1/SignonSession_name'] = 'Signon session name'; +$str['Servers/1/SignonSession_desc'] = 'See [a@http://wiki.cihar.com/pma/auth_types#signon]authentication types[/a] for an example'; +$str['Servers/1/SignonURL_name'] = 'Signon URL'; +$str['Servers/1/LogoutURL_name'] = 'Logout URL'; +$str['Servers/1/auth_swekey_config_name'] = 'SweKey config file'; +$str['Servers/1/auth_swekey_config_desc'] = 'Config file for [a@http://swekey.com]SweKey hardware authentication[/a], relative to phpMyAdmin root directory, eg. ./swekey.conf'; + +// Form: Server_config +$str['Servers/1/only_db_name'] = 'Show only listed databases'; +$str['Servers/1/only_db_desc'] = 'You can use MySQL wildcard characters (% and _), escape them if you want to use their literal instances, i.e. use \'my\_db\' and not \'my_db\''; +$str['Servers/1/hide_db_name'] = 'Hide databases'; +$str['Servers/1/hide_db_desc'] = 'Hide databases matching regular expression (PCRE)'; +$str['Servers/1/AllowRoot_name'] = 'Allow root login'; +$str['Servers/1/DisableIS_name'] = 'Disable use of INFORMATION_SCHEMA'; +$str['Servers/1/DisableIS_desc'] = 'More information on [a@http://sf.net/support/tracker.php?aid=1849494]PMA bug tracker[/a] and [a@http://bugs.mysql.com/19588]MySQL Bugs[/a]'; +$str['Servers/1/AllowDeny/order_name'] = 'Host authentication order'; +$str['Servers/1/AllowDeny/order_desc'] = 'Leave blank if not used'; +$str['Servers/1/AllowDeny/rules_name'] = 'Host authentication rules'; +$str['Servers/1/AllowDeny/rules_desc'] = 'Leave blank for defaults'; +$str['Servers/1/ShowDatabasesCommand_name'] = 'SHOW DATABASES command'; +$str['Servers/1/ShowDatabasesCommand_desc'] = 'SQL command to fetch available databases'; +$str['Servers/1/CountTables_name'] = 'Count tables'; +$str['Servers/1/CountTables_desc'] = 'Count tables when showing database list'; + +// Form: Server_pmadb +$str['Servers/1/pmadb_name'] = 'PMA database'; +$str['Servers/1/pmadb_desc'] = 'Database used for relations, bookmarks, and PDF features. See [a@http://wiki.cihar.com/pma/pmadb]pmadb[/a] for complete information. Leave blank for no support. Default: [kbd]phpmyadmin[/kbd]'; +$str['Servers/1/controluser_name'] = 'Control user'; +$str['Servers/1/controluser_desc'] = 'A special MySQL user configured with limited permissions, more information available on [a@http://wiki.cihar.com/pma/controluser]wiki[/a]'; +$str['Servers/1/controlpass_name'] = 'Control user password'; +$str['Servers/1/verbose_check_name'] = 'Verbose check'; +$str['Servers/1/verbose_check_desc'] = 'Disable if you know that your pma_* tables are up to date. This prevents compatibility checks and thereby increases performance'; +$str['Servers/1/bookmarktable_name'] = 'Bookmark table'; +$str['Servers/1/bookmarktable_desc'] = 'Leave blank for no [a@http://wiki.cihar.com/pma/bookmark]bookmark[/a] support, default: [kbd]pma_bookmark[/kbd]'; +$str['Servers/1/relation_name'] = 'Relation table'; +$str['Servers/1/relation_desc'] = 'Leave blank for no [a@http://wiki.cihar.com/pma/relation]relation-links[/a] support, default: [kbd]pma_relation[/kbd]'; +$str['Servers/1/table_info_name'] = 'Display fields table'; +$str['Servers/1/table_info_desc'] = 'Table to describe the display fields, leave blank for no support; default: [kbd]pma_table_info[/kbd]'; +$str['Servers/1/table_coords_name'] = 'PDF schema: table coordinates'; +$str['Servers/1/table_coords_desc'] = 'Leave blank for no PDF schema support, default: [kbd]pma_table_coords[/kbd]'; +$str['Servers/1/pdf_pages_name'] = 'PDF schema: pages table'; +$str['Servers/1/pdf_pages_desc'] = 'Leave blank for no PDF schema support, default: [kbd]pma_pdf_pages[/kbd]'; +$str['Servers/1/column_info_name'] = 'Column information table'; +$str['Servers/1/column_info_desc'] = 'Leave blank for no column comments/mime types, default: [kbd]pma_column_info[/kbd]'; +$str['Servers/1/history_name'] = 'SQL query history table'; +$str['Servers/1/history_desc'] = 'Leave blank for no SQL query history support, default: [kbd]pma_history[/kbd]'; +$str['Servers/1/designer_coords_name'] = 'Designer table'; +$str['Servers/1/designer_coords_desc'] = 'Leave blank for no Designer support, default: [kbd]designer_coords[/kbd]'; + +// Form: Import_export +$str['UploadDir_name'] = 'Upload directory'; +$str['UploadDir_desc'] = 'Directory on server where you can upload files for import'; +$str['SaveDir_name'] = 'Save directory'; +$str['SaveDir_desc'] = 'Directory where exports can be saved on server'; +$str['AllowAnywhereRecoding_name'] = 'Allow character set conversion'; +$str['DefaultCharset_name'] = 'Default character set'; +$str['DefaultCharset_desc'] = 'Default character set used for conversions'; +$str['RecodingEngine_name'] = 'Recoding engine'; +$str['RecodingEngine_desc'] = 'Select which functions will be used for character set conversion'; +$str['IconvExtraParams_name'] = 'Extra parameters for iconv'; +$str['ZipDump_name'] = 'ZIP'; +$str['ZipDump_desc'] = 'Enable [a@http://en.wikipedia.org/wiki/ZIP_(file_format)]ZIP[/a] compression for import and export operations'; +$str['GZipDump_name'] = 'GZip'; +$str['GZipDump_desc'] = 'Enable [a@http://en.wikipedia.org/wiki/Gzip]gzip[/a] compression for import and export operations'; +$str['BZipDump_name'] = 'Bzip2'; +$str['BZipDump_desc'] = 'Enable [a@http://en.wikipedia.org/wiki/Bzip2]bzip2[/a] compression for import and export operations'; +$str['CompressOnFly_name'] = 'Compress on the fly'; +$str['CompressOnFly_desc'] = 'Compress gzip/bzip2 exports on the fly without the need for much memory; if you encounter problems with created gzip/bzip2 files disable this feature'; + +// Form: Security +$str['blowfish_secret_name'] = 'Blowfish secret'; +$str['blowfish_secret_desc'] = 'Secret passphrase used for encrypting cookies in [kbd]cookie[/kbd] authentication'; +$str['ForceSSL_name'] = 'Force SSL connection'; +$str['ForceSSL_desc'] = 'Force secured connection while using phpMyAdmin'; +$str['CheckConfigurationPermissions_name'] = 'Check config file permissions'; +$str['TrustedProxies_name'] = 'List of trusted proxies for IP allow/deny'; +$str['AllowUserDropDatabase_name'] = 'Show "Drop database" link to normal users'; +$str['AllowArbitraryServer_name'] = 'Allow login to any MySQL server'; +$str['AllowArbitraryServer_desc'] = 'If enabled user can enter any MySQL server in login form for cookie auth'; +$str['LoginCookieRecall_name'] = 'Recall user name'; +$str['LoginCookieRecall_desc'] = 'Define whether the previous login should be recalled or not in cookie authentication mode'; +$str['LoginCookieValidity_name'] = 'Login cookie validity'; +$str['LoginCookieValidity_desc'] = 'Define how long (in seconds) a login cookie is valid'; +$str['LoginCookieStore_name'] = 'Login cookie store'; +$str['LoginCookieStore_desc'] = 'Define how long (in seconds) a login cookie should be stored in browser. Default 0 means that it will be kept for existing session only, that is it will be deleted as soon as you close the browser window. This is recommended for non-trusted environments.'; +$str['LoginCookieDeleteAll_name'] = 'Delete all cookies on logout'; +$str['LoginCookieDeleteAll_desc'] = 'If enabled logout deletes cookies for all servers, otherwise only for current one. Setting this to FALSE makes it easy to forget to log out from other server, when you are using more of them.'; + +// Form: Sql_queries +$str['ShowSQL_name'] = 'Show SQL queries'; +$str['ShowSQL_desc'] = 'Defines whether SQL queries generated by phpMyAdmin should be displayed'; +$str['Confirm_name'] = 'Confirm DROP queries'; +$str['Confirm_desc'] = 'Whether a warning ("Are your really sure...") should be displayed when you\'re about to lose data'; +$str['QueryHistoryDB_name'] = 'Permanent query history'; +$str['QueryHistoryDB_desc'] = 'Enable if you want DB-based query history (requires pmadb). If disabled, this utilizes JS-routines to display query history (lost by window close).'; +$str['QueryHistoryMax_name'] = 'Query history length'; +$str['QueryHistoryMax_desc'] = 'How many queries are kept in history'; +$str['IgnoreMultiSubmitErrors_name'] = 'Ignore multiple statement errors'; +$str['IgnoreMultiSubmitErrors_desc'] = 'If enabled PMA continues computing multiple-statement queries even if one of the queries failed'; +$str['VerboseMultiSubmit_name'] = 'Verbose multiple statements'; +$str['VerboseMultiSubmit_desc'] = 'Show affected rows of each statement on multiple-statement queries. See libraries/import.lib.php for defaults on how many queries a statement may contain.'; + +// Form: Other_core_options +$str['MaxDbList_name'] = 'Maximum databases'; +$str['MaxDbList_desc'] = 'Maximum number of databases displayed in left frame and database list'; +$str['MaxTableList_name'] = 'Maximum tables'; +$str['MaxTableList_desc'] = 'Maximum number of tables displayed in table list'; +$str['MaxCharactersInDisplayedSQL_name'] = 'Maximum displayed SQL length'; +$str['MaxCharactersInDisplayedSQL_desc'] = 'Maximum number of characters used when a SQL query is displayed'; +$str['OBGzip_name'] = 'GZip output buffering'; +$str['OBGzip_desc'] = 'use GZip output buffering for increased speed in HTTP transfers'; +$str['PersistentConnections_name'] = 'Persistent connections'; +$str['PersistentConnections_desc'] = 'Use persistent connections to MySQL databases'; +$str['ExecTimeLimit_name'] = 'Maximum execution time'; +$str['ExecTimeLimit_desc'] = 'Set the number of seconds a script is allowed to run ([kbd]0[/kbd] for no limit)'; +$str['MemoryLimit_name'] = 'Memory limit'; +$str['MemoryLimit_desc'] = 'The number of bytes a script is allowed to allocate, eg. [kbd]32M[/kbd] ([kbd]0[/kbd] for no limit)'; +$str['SkipLockedTables_name'] = 'Skip locked tables'; +$str['SkipLockedTables_desc'] = 'Mark used tables and make it possible to show databases with locked tables'; +$str['UseDbSearch_name'] = 'Use database search'; +$str['UseDbSearch_desc'] = 'Allow for searching inside the entire database'; + +// Form: Left_frame +$str['LeftFrameLight_name'] = 'Use light version'; +$str['LeftFrameLight_desc'] = 'Disable this if you want to see all databases at once'; +$str['LeftDisplayLogo_name'] = 'Display logo'; +$str['LeftDisplayLogo_desc'] = 'Show logo in left frame'; +$str['LeftLogoLink_name'] = 'Logo link URL'; +$str['LeftLogoLinkWindow_name'] = 'Logo link target'; +$str['LeftLogoLinkWindow_desc'] = 'Open the linked page in the main window ([kbd]main[/kbd]) or in a new one ([kbd]new[/kbd])'; +$str['LeftDefaultTabTable_name'] = 'Target for quick access icon'; +$str['LeftPointerEnable_name'] = 'Enable highlighting'; +$str['LeftPointerEnable_desc'] = 'Highlight server under the mouse cursor'; + +// Form: Left_servers +$str['LeftDisplayServers_name'] = 'Display servers selection'; +$str['LeftDisplayServers_desc'] = 'Display server choice at the top of the left frame'; +$str['DisplayServersList_name'] = 'Display servers as a list'; +$str['DisplayServersList_desc'] = 'Show server listing as a list instead of a drop down'; + +// Form: Left_databases +$str['DisplayDatabasesList_name'] = 'Display databases as a list'; +$str['DisplayDatabasesList_desc'] = 'Show database listing as a list instead of a drop down'; +$str['LeftFrameDBTree_name'] = 'Display databases in a tree'; +$str['LeftFrameDBTree_desc'] = 'Only light version; display databases in a tree (determined by the separator defined below)'; +$str['LeftFrameDBSeparator_name'] = 'Database tree separator'; +$str['LeftFrameDBSeparator_desc'] = 'String that separates databases into different tree levels'; +$str['ShowTooltipAliasDB_name'] = 'Display database comment instead of its name'; +$str['ShowTooltipAliasDB_desc'] = 'If tooltips are enabled and a database comment is set, this will flip the comment and the real name'; + +// Form: Left_tables +$str['LeftFrameTableSeparator_name'] = 'Table tree separator'; +$str['LeftFrameTableSeparator_desc'] = 'String that separates tables into different tree levels'; +$str['LeftFrameTableLevel_name'] = 'Maximum table tree depth'; +$str['ShowTooltip_name'] = 'Display table comments in tooltips'; +$str['ShowTooltipAliasTB_name'] = 'Display table comment instead of its name'; +$str['ShowTooltipAliasTB_desc'] = 'When setting this to [kbd]nested[/kbd], the alias of the table name is only used to split/nest the tables according to the $cfg[\'LeftFrameTableSeparator\'] directive, so only the folder is called like the alias, the table name itself stays unchanged'; + +// Form: Startup +$str['ShowStats_name'] = 'Show statistics'; +$str['ShowStats_desc'] = 'Allow to display database and table statistics (eg. space usage)'; +$str['ShowPhpInfo_name'] = 'Show phpinfo() link'; +$str['ShowPhpInfo_desc'] = 'Shows link to [a@http://php.net/manual/function.phpinfo.php]phpinfo()[/a] output'; +$str['ShowServerInfo_name'] = 'Show detailed MySQL server information'; +$str['ShowChgPassword_name'] = 'Show password change form'; +$str['ShowChgPassword_desc'] = 'Please note that enabling this has no effect with [kbd]config[/kbd] authentication mode because the password is hard coded in the configuration file; this does not limit the ability to execute the same command directly'; +$str['ShowCreateDb_name'] = 'Show create database form'; +$str['SuggestDBName_name'] = 'Suggest new database name'; +$str['SuggestDBName_desc'] = 'Suggest a database name on the "Create Database" form (if possible) or keep the text field empty'; + +// Form: Browse +$str['NavigationBarIconic_name'] = 'Iconic navigation bar'; +$str['NavigationBarIconic_desc'] = 'Use only icons, only text or both'; +$str['ShowAll_name'] = 'Allow to display all the rows'; +$str['ShowAll_desc'] = 'Whether a user should be displayed a "show all (records)" button'; +$str['MaxRows_name'] = 'Maximum number of rows to display'; +$str['MaxRows_desc'] = 'Number of rows displayed when browsing a result set. If the result set contains more rows, "Previous" and "Next" links will be shown.'; +$str['Order_name'] = 'Default sorting order'; +$str['Order_desc'] = '[kbd]SMART[/kbd] - i.e. descending order for fields of type TIME, DATE, DATETIME and TIMESTAMP, ascending order otherwise'; +$str['BrowsePointerEnable_name'] = 'Highlight pointer'; +$str['BrowsePointerEnable_desc'] = 'Highlight row pointed by the mouse cursor'; +$str['BrowseMarkerEnable_name'] = 'Row marker'; +$str['BrowseMarkerEnable_desc'] = 'Highlight selected rows'; + +// Form: Edit +$str['ProtectBinary_name'] = 'Protect binary fields'; +$str['ProtectBinary_desc'] = 'Disallow BLOB or BLOB and BINARY fields from editing'; +$str['ShowFunctionFields_name'] = 'Show function fields'; +$str['ShowFunctionFields_desc'] = 'Display the function fields in edit/insert mode'; +$str['CharEditing_name'] = 'CHAR fields editing'; +$str['CharEditing_desc'] = 'Defines which type of editing controls should be used for CHAR and VARCHAR fields; [kbd]input[/kbd] - allows limiting of input length, [kbd]textarea[/kbd] - allows newlines in fields'; +$str['CharTextareaCols_name'] = 'CHAR textarea columns'; +$str['CharTextareaCols_desc'] = 'Number of columns for textareas, this value will be emphasized (*2) for SQL query textareas and (*1.25) for SQL textareas inside the query window'; +$str['CharTextareaRows_name'] = 'CHAR textarea rows'; +$str['CharTextareaRows_desc'] = 'Number of rows for textareas, this value will be emphasized (*2) for SQL query textareas and (*1.25) for SQL textareas inside the query window'; +$str['InsertRows_name'] = 'Number of inserted rows'; +$str['InsertRows_desc'] = 'How many rows can be inserted at one time'; +$str['ForeignKeyDropdownOrder_name'] = 'Foreign key dropdown order'; +$str['ForeignKeyDropdownOrder_desc'] = 'Sort order for items in a foreign-key dropdown box; [kbd]content[/kbd] is the referenced data, [kbd]id[/kbd] is the key value'; +$str['ForeignKeyMaxLimit_name'] = 'Foreign key limit'; +$str['ForeignKeyMaxLimit_desc'] = 'A dropdown will be used if fewer items are present'; + +// Form: Tabs +$str['LightTabs_name'] = 'Light tabs'; +$str['LightTabs_desc'] = 'Use less graphically intense tabs'; +$str['PropertiesIconic_name'] = 'Iconic table operations'; +$str['PropertiesIconic_desc'] = 'Use only icons, only text or both'; +$str['DefaultTabServer_name'] = 'Default server tab'; +$str['DefaultTabServer_desc'] = 'Tab that is displayed when entering a server'; +$str['DefaultTabDatabase_name'] = 'Default database tab'; +$str['DefaultTabDatabase_desc'] = 'Tab that is displayed when entering a database'; +$str['DefaultTabTable_name'] = 'Default table tab'; +$str['DefaultTabTable_desc'] = 'Tab that is displayed when entering a table'; + +// Form: Sql_Box +$str['SQLQuery/Edit_name'] = $GLOBALS['strEdit']; +$str['SQLQuery/Explain_name'] = $GLOBALS['strExplain']; +$str['SQLQuery/ShowAsPHP_name'] = $GLOBALS['strPhp']; +$str['SQLQuery/Validate_name'] = $GLOBALS['strValidateSQL']; +$str['SQLQuery/Refresh_name'] = $GLOBALS['strRefresh']; + +// Form: Import +$str['Import/format_name'] = $GLOBALS['strImportFormat']; +$str['Import/format_desc'] = 'Default format, mind that this list depends on location (database, table) and only SQL is always avaiable'; +$str['Import/allow_interrupt_name'] = 'Partial import: allow interrupt'; +$str['Import/allow_interrupt_desc'] = $GLOBALS['strAllowInterrupt']; +$str['Import/skip_queries_name'] = 'Partial import: skip queries'; +$str['Import/skip_queries_desc'] = $GLOBALS['strSkipQueries']; + +// Form: Import_sql +$str['Import/sql_compatibility_name'] = $GLOBALS['strSQLCompatibility']; +$str['Import/sql_compatibility_desc'] = 'You can find more information on SQL compatibility modes in [a@http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html]MySQL Reference Manual[/a]'; +// Form: Import_csv +$str['Import/csv_replace_name'] = $GLOBALS['strReplaceTable']; +$str['Import/csv_terminated_name'] = $GLOBALS['strFieldsTerminatedBy']; +$str['Import/csv_enclosed_name'] = $GLOBALS['strFieldsEnclosedBy']; +$str['Import/csv_escaped_name'] = $GLOBALS['strFieldsEscapedBy']; +$str['Import/csv_new_line_name'] = $GLOBALS['strLinesTerminatedBy']; +$str['Import/csv_columns_name'] = $GLOBALS['strColumnNames']; + +// Form: Import_ldi +$str['Import/ldi_replace_name'] = $GLOBALS['strReplaceTable']; +$str['Import/ldi_terminated_name'] = $GLOBALS['strFieldsTerminatedBy']; +$str['Import/ldi_enclosed_name'] = $GLOBALS['strFieldsEnclosedBy']; +$str['Import/ldi_escaped_name'] = $GLOBALS['strFieldsEscapedBy']; +$str['Import/ldi_new_line_name'] = $GLOBALS['strLinesTerminatedBy']; +$str['Import/ldi_columns_name'] = $GLOBALS['strColumnNames']; +$str['Import/ldi_local_option_name'] = $GLOBALS['strLDILocal']; + +// Form: Export_defaults +$str['Export/format_name'] = 'Format'; +$str['Export/compression_name'] = $GLOBALS['strCompression']; +$str['Export/asfile_name'] = $GLOBALS['strSend']; +$str['Export/charset_name'] = $GLOBALS['strCharsetOfFile']; +$str['Export/onserver_name'] = 'Save on server'; +$str['Export/onserver_overwrite_name'] = $GLOBALS['strOverwriteExisting']; +$str['Export/remember_file_template_name'] = 'Remember file name template'; +$str['Export/file_template_table_name'] = 'Table name template'; +$str['Export/file_template_database_name'] = 'Database name template'; +$str['Export/file_template_server_name'] = 'Server name template'; +?> \ No newline at end of file diff --git a/setup/lib/ConfigFile.class.php b/setup/lib/ConfigFile.class.php new file mode 100644 index 000000000..7e645c560 --- /dev/null +++ b/setup/lib/ConfigFile.class.php @@ -0,0 +1,314 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ +class ConfigFile +{ + /** + * Stores default PMA config from config.default.php + * @var array + */ + private $cfg; + + /** + * Stores allowed values for non-standard fields + * @var array + */ + private $cfgDb; + + /** + * Keys which will be always written to config file + * @var array + */ + private $persistKeys; + + /** + * ConfigFile instance + * @var ConfigFile + */ + private static $_instance; + + /** + * Private constructor, use {@link getInstance()} + */ + private function __construct() + { + // load default config values + $cfg = &$this->cfg; + require './libraries/config.default.php'; + + // load additionsl config information + $cfg_db = &$this->cfgDb; + $persist_keys = array(); + require './setup/lib/config_info.inc.php'; + + // apply default values overrides + if (count($cfg_db['_overrides'])) { + foreach ($cfg_db['_overrides'] as $path => $value) { + array_write($path, $cfg, $value); + } + } + + // checking key presence is much faster than searching so move values to keys + $this->persistKeys = array_flip($persist_keys); + } + + /** + * Returns class instance + * + * @return ConfigFile + */ + public static function getInstance() + { + if (is_null(self::$_instance)) { + self::$_instance = new ConfigFile(); + } + return self::$_instance; + } + + /** + * Sets config value + * + * @param string $path + * @param mixed $value + * @param string $canonical_path + */ + public function set($path, $value, $canonical_path = null) + { + if ($canonical_path === null) { + $canonical_path = $this->getCanonicalPath($path); + } + // remove if the path isn't protected and it's empty or has a default value + $default_value = $this->getDefault($canonical_path); + if (!isset($this->persistKeys[$canonical_path]) + && (($value == $default_value) || (empty($value) && empty($default_value)))) { + array_remove($path, $_SESSION['ConfigFile']); + } else { + array_write($path, $_SESSION['ConfigFile'], $value); + } + } + + /** + * Returns config value or $default if it's not set + * + * @param string $path + * @param mixed $default + * @return mixed + */ + public function get($path, $default = null) + { + return array_read($path, $_SESSION['ConfigFile'], $default); + } + + /** + * Returns default config value or $default it it's not set ie. it doesn't + * exist in config.default.php ($cfg) and config_info.inc.php + * ($_cfg_db['_overrides']) + * + * @param string $canonical_path + * @param mixed $default + * @return mixed + */ + public function getDefault($canonical_path, $default = null) + { + return array_read($canonical_path, $this->cfg, $default); + } + + /** + * Returns config value, if it's not set uses the default one; returns + * $default if the path isn't set and doesn't contain a default value + * + * @param string $path + * @param mixed $default + * @return mixed + */ + public function getValue($path, $default = null) + { + $v = array_read($path, $_SESSION['ConfigFile'], null); + if ($v !== null) { + return $v; + } + $path = $this->getCanonicalPath($path); + return $this->getDefault($path, $default); + } + + /** + * Returns canonical path + * + * @param string $path + * @return string + */ + public function getCanonicalPath($path) { + return preg_replace('#^Servers/([\d]+)/#', 'Servers/1/', $path); + } + + /** + * Returns config database entry for $path ($cfg_db in config_info.php) + * + * @param string $path + * @param mixed $default + * @return mixed + */ + public function getDbEntry($path, $default = null) + { + return array_read($path, $this->cfgDb, $default); + } + + /** + * Returns server count + * + * @return int + */ + public function getServerCount() + { + return isset($_SESSION['ConfigFile']['Servers']) + ? count($_SESSION['ConfigFile']['Servers']) + : 0; + } + + /** + * Returns DSN of given server + * + * @param integer $server + * @return string + */ + function getServerDSN($server) + { + if (!isset($_SESSION['ConfigFile']['Servers'][$server])) { + return ''; + } + + $path = 'Servers/' . $server; + $dsn = $this->getValue("$path/extension") . '://'; + if ($this->getValue("$path/auth_type") == 'config') { + $dsn .= $this->getValue("$path/user"); + if (!$this->getValue("$path/nopassword")) { + $dsn .= ':***'; + } + $dsn .= '@'; + } + if ($this->getValue("$path/connect_type") == 'tcp') { + $dsn .= $this->getValue("$path/host"); + $port = $this->getValue("$path/port"); + if ($port) { + $dsn .= ':' . $port; + } + } else { + $dsn .= $this->getValue("$path/socket"); + } + return $dsn; + } + + /** + * Returns server name + * + * @param int $id + * @return string + */ + public function getServerName($id) + { + if (!isset($_SESSION['ConfigFile']['Servers'][$id])) { + return ''; + } + $verbose = $this->get("Servers/$id/verbose"); + if (!empty($verbose)) { + return $verbose; + } + $host = $this->get("Servers/$id/host"); + return empty($host) ? 'localhost' : $host; + } + + /** + * Removes server + * + * @param int $server + */ + public function removeServer($server) + { + if (!isset($_SESSION['ConfigFile']['Servers'][$server])) { + return; + } + $last_server = $this->getServerCount(); + + for ($i = $server; $i < $last_server; $i++) { + $_SESSION['ConfigFile']['Servers'][$i] = $_SESSION['ConfigFile']['Servers'][$i+1]; + } + unset($_SESSION['ConfigFile']['Servers'][$last_server]); + + if (isset($_SESSION['ConfigFile']['ServerDefault']) + && $_SESSION['ConfigFile']['ServerDefault'] >= 0) { + unset($_SESSION['ConfigFile']['ServerDefault']); + } + } + + /** + * Returns config file path + * + * @return unknown + */ + public function getFilePath() + { + return $this->getDbEntry('_config_file_path'); + } + + /** + * Creates config file + * + * @return string + */ + public function getConfigFile() + { + $crlf = (isset($_SESSION['eol']) && $_SESSION['eol'] == 'win') ? "\r\n" : "\n"; + $c = $_SESSION['ConfigFile']; + + // header + $ret = 'get('PMA_VERSION') + . ' setup script by Piotr Przybylski ' . $crlf + . ' * Date: ' . date(DATE_RFC1123) . $crlf + . ' */' . $crlf . $crlf; + + // servers + if ($this->getServerCount() > 0) { + $ret .= "/* Servers configuration */$crlf\$i = 0;" . $crlf . $crlf; + foreach ($c['Servers'] as $id => $server) { + $ret .= '/* Server: ' . $this->getServerName($id) . " [$id] */" . $crlf + . '$i++;' . $crlf; + foreach ($server as $k => $v) { + $ret .= "\$cfg['Servers'][\$i]['$k'] = " + . var_export($v, true) . ';' . $crlf; + } + $ret .= $crlf; + } + $ret .= '/* End of servers configuration */' . $crlf . $crlf; + } + unset($c['Servers']); + + // other settings + $persistKeys = $this->persistKeys; + foreach ($c as $k => $v) { + $ret .= "\$cfg['$k'] = " . var_export($v, true) . ';' . $crlf; + if (isset($persistKeys[$k])) { + unset($persistKeys[$k]); + } + } + // keep 1d array keys which are present in $persist_keys (config_info.inc.php) + foreach (array_keys($persistKeys) as $k) { + if (strpos($k, '/') === false) { + $ret .= "\$cfg['$k'] = " . var_export($this->getDefault($k), true) . ';' . $crlf; + } + } + $ret .= '?>'; + + return $ret; + } +} +?> \ No newline at end of file diff --git a/setup/lib/Form.class.php b/setup/lib/Form.class.php new file mode 100644 index 000000000..259e46aac --- /dev/null +++ b/setup/lib/Form.class.php @@ -0,0 +1,177 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ +class Form +{ + /** + * Form name + * @var string + */ + public $name; + + /** + * Arbitrary index, doesn't affect class' behavior + * @var int + */ + public $index; + + /** + * Form fields (paths), filled by {@link readFormPaths()}, indexed by field name + * @var array + */ + public $fields; + + /** + * Stores default values for some fields (eg. pmadb tables) + * @var array + */ + public $default; + + /** + * Caches field types, indexed by field names + * @var array + */ + private $fieldsTypes; + + /** + * Cached forms + * @var array + */ + private static $_forms; + + /** + * Constructor, reads default config values + * + * @param string $form_name + * @param int $index arbitrary index, stored in Form::$index + */ + public function __construct($form_name, $index = null) + { + $this->index = $index; + $this->loadForm($form_name); + } + + /** + * Returns type of given option + * + * @param string $option_name path or field name + * @return string|null one of: boolean, integer, double, string, select, array + */ + public function getOptionType($option_name) + { + $key = ltrim(substr($option_name, strrpos($option_name, '/')), '/'); + return isset($this->fieldsTypes[$key]) + ? $this->fieldsTypes[$key] + : null; + } + + /** + * Returns allowed values for select fields + * + * @param string $option_path + * @return array + */ + public function getOptionValueList($option_path) + { + $value = ConfigFile::getInstance()->getDbEntry($option_path); + if ($value === null) { + trigger_error("$option_path - select options not defined", E_USER_ERROR); + return array(); + } + if (!is_array($value)) { + trigger_error("$option_path - not a static value list", E_USER_ERROR); + return array(); + } + return $value; + } + + /** + * array_walk callback function, reads path of form fields from + * array (see file comment in forms.inc.php) + * + * @param mixed $value + * @param mixed $key + * @param mixed $prefix + */ + private function _readFormPathsCallback($value, $key, $prefix) + { + if (is_array($value)) { + $prefix .= (empty($prefix) ? '' : '/') . $key; + array_walk($value, array($this, '_readFormPathsCallback'), $prefix); + } else { + if (!is_int($key)) { + $this->default[$prefix . '/' . $key] = $value; + $value = $key; + } + $this->fields[] = $prefix . '/' . $value; + } + } + + /** + * Reads form paths to {@link $fields} + */ + protected function readFormPaths() + { + if (is_null(self::$_forms)) { + $forms =& self::$_forms; + require './setup/lib/forms.inc.php'; + } + + if (!isset(self::$_forms[$this->name])) { + return; + } + + // flatten form fields' paths and save them to $fields + $this->fields = array(); + array_walk(self::$_forms[$this->name], array($this, '_readFormPathsCallback'), ''); + + // $this->fields is an array of the form: [0..n] => 'field path' + // change numeric indexes to contain field names (last part of the path) + $paths = $this->fields; + $this->fields = array(); + foreach ($paths as $path) { + $path = ltrim($path, '/'); + $key = ltrim(substr($path, strrpos($path, '/')), '/'); + $this->fields[$key] = $path; + } + // now $this->fields is an array of the form: 'field name' => 'field path' + } + + /** + * Reads fields' types to $this->fieldsTypes + */ + protected function readTypes() + { + $cf = ConfigFile::getInstance(); + foreach ($this->fields as $name => $path) { + $v = $cf->getDbEntry($path); + if ($v !== null) { + $type = is_array($v) ? 'select' : $v; + } else { + $type = gettype($cf->getDefault($path)); + } + $this->fieldsTypes[$name] = $type; + } + } + + /** + * Reads form settings and prepares class to work with given subset of + * config file + * + * @param string $form_name + */ + public function loadForm($form_name) + { + $this->name = $form_name; + $this->readFormPaths(); + $this->readTypes(); + } +} +?> \ No newline at end of file diff --git a/setup/lib/FormDisplay.class.php b/setup/lib/FormDisplay.class.php new file mode 100644 index 000000000..778106a03 --- /dev/null +++ b/setup/lib/FormDisplay.class.php @@ -0,0 +1,558 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +require_once './setup/lib/FormDisplay.tpl.php'; +require_once './setup/lib/validate.lib.php'; +require_once './libraries/js_escape.lib.php'; + +/** + * Form management class, displays and processes forms + */ +class FormDisplay +{ + /** + * Form list + * @var array + */ + private $forms = array(); + + /** + * Stores validation errors, indexed by paths + * [ Form_name ] is an array of form errors + * [path] is a string storing error associated with single field + * @var array + */ + private $errors = array(); + + /** + * Paths changed so that they can be used as HTML ids, indexed by paths + * @var array + */ + private $translated_paths = array(); + + /** + * Server paths change indexes so we define maps from current server + * path to the first one, indexed by work path + * @var array + */ + private $system_paths = array(); + + /** + * Language strings which will be sent to PMA_messages JS variable + * @var array + */ + private $js_lang_strings = array('error_nan_p', 'error_nan_nneg', + 'error_incorrect_port'); + + /** + * Tells whether forms have been validated + * @var bool + */ + private $is_valdiated = true; + + /** + * Registers form in form manager + * + * @param string $form_name + * @param int $server_id 0 if new server, validation; >= 1 if editing a server + */ + public function registerForm($form_name, $server_id = null) + { + $this->forms[$form_name] = new Form($form_name, $server_id); + $this->is_valdiated = false; + foreach ($this->forms[$form_name]->fields as $path) { + $work_path = $server_id === null + ? $path + : str_replace('Servers/1/', "Servers/$server_id/", $path); + $this->system_paths[$work_path] = $path; + $this->translated_paths[$work_path] = str_replace('/', '-', $work_path); + } + } + + /** + * Processes forms, returns true on successful save + * + * @param bool $allow_partial_save allows for partial form saving on failed validation + * @return boolean + */ + public function process($allow_partial_save = true) + { + // gather list of forms to save + if (!isset($_POST['submit_save'])) { + return false; + } + + // save forms + if (count($this->forms) > 0) { + return $this->save(array_keys($this->forms), $allow_partial_save); + } + return false; + } + + /** + * Runs validation for all registered forms + */ + private function _validate() + { + if ($this->is_valdiated) { + return; + } + + $cf = ConfigFile::getInstance(); + $paths = array(); + $values = array(); + foreach ($this->forms as $form) { + /* @var $form Form */ + $paths[] = $form->name; + // collect values and paths + foreach ($form->fields as $path) { + $work_path = array_search($path, $this->system_paths); + $values[$path] = $cf->getValue($work_path); + $paths[] = $path; + } + } + + // run validation + $errors = validate($paths, $values, false); + + // change error keys from canonical paths to work paths + if (is_array($errors) && count($errors) > 0) { + $this->errors = array(); + foreach ($errors as $path => $error_list) { + $work_path = array_search($path, $this->system_paths); + // field error + if (!$work_path) { + // form error, fix path + $work_path = $path; + } + $this->errors[$work_path] = $error_list; + } + } + $this->is_valdiated = true; + } + + + /** + * Outputs HTML for forms + * + * @param bool $tabbed_form + * @param bool $show_restore_default whether show "restore default" button besides the input field + */ + public function display($tabbed_form = false, $show_restore_default = false) + { + static $js_lang_sent = false; + + $cf = ConfigFile::getInstance(); + $js = array(); + $js_default = array(); + $tabbed_form = $tabbed_form && (count($this->forms) > 1); + $validators = ConfigFile::getInstance()->getDbEntry('_validators'); + + display_form_top(); + + if ($tabbed_form) { + $tabs = array(); + foreach ($this->forms as $form) { + $tabs[$form->name] = PMA_lang("Form_$form->name"); + } + display_tabs_top($tabs); + } + + // valdiate only when we aren't displaying a "new server" form + $is_new_server = false; + foreach ($this->forms as $form) { + /* @var $form Form */ + if ($form->index === 0) { + $is_new_server = true; + break; + } + } + if (!$is_new_server) { + $this->_validate(); + } + + // display forms + foreach ($this->forms as $form) { + /* @var $form Form */ + $form_desc = isset($GLOBALS['str']["Form_{$form->name}_desc"]) + ? PMA_lang("Form_{$form->name}_desc") + : ''; + $form_errors = isset($this->errors[$form->name]) + ? $this->errors[$form->name] : null; + display_fieldset_top(PMA_lang("Form_$form->name"), + $form_desc, $form_errors, array('id' => $form->name)); + + foreach ($form->fields as $field => $path) { + $work_path = array_search($path, $this->system_paths); + $translated_path = $this->translated_paths[$work_path]; + // display input + $this->_displayFieldInput($form, $field, $path, $work_path, + $translated_path, $show_restore_default, $js_default); + // register JS validators for this field + if (isset($validators[$path])) { + js_validate($translated_path, $validators[$path], $js); + } + } + display_fieldset_bottom(); + } + + if ($tabbed_form) { + display_tabs_bottom(); + } + display_form_bottom(); + + // if not already done, send strings used for valdiation to JavaScript + if (!$js_lang_sent) { + $js_lang_sent = true; + $js_lang = array(); + foreach ($this->js_lang_strings as $str) { + $lang = isset($GLOBALS['str'][$str]) + ? $GLOBALS['str'][$str] + : filter_input($GLOBALS["str$str"]); + $js_lang[] = "'$str': '" . PMA_jsFormat($lang, false) . '\''; + } + $js[] = '$extend(PMA_messages, {' . implode(",\n\t", $js_lang) . '})'; + } + + $js[] = '$extend(defaultValues, {' . implode(",\n\t", $js_default) . '})'; + display_js($js); + } + + /** + * Prepares data for input field display and outputs HTML code + * + * @param Form $form + * @param string $field field name as it appears in $form + * @param string $path field path, eg. Servers/4/verbose + * @param string $work_path work path, eg. Servers/1/verbose + * @param string $translated_path field path + * @param bool $show_restore_default whether show "restore default" button besides the input field + * @param array &$js_default array which stores JavaScript code to be displayed + */ + private function _displayFieldInput(Form $form, $field, $path, $work_path, + $translated_path, $show_restore_default, array &$js_default) + { + $name = isset($GLOBALS['str']["{$path}_name"]) + ? $GLOBALS['str']["{$path}_name"] + : $field; + $description = isset($GLOBALS['str']["{$path}_desc"]) + ? PMA_lang("{$path}_desc") + : ''; + + $cf = ConfigFile::getInstance(); + $value = $cf->get($work_path); + $value_default = $cf->getDefault($path); + $value_is_default = false; + if ($value === null || $value === $value_default) { + $value = $value_default; + $value_is_default = true; + } + + $opts = array( + 'doc' => $this->getDocLink($path), + 'wiki' => $this->getWikiLink($path), + 'show_restore_default' => $show_restore_default); + if (isset($form->default[$path])) { + $opts['setvalue'] = $form->default[$path]; + } + + if (isset($this->errors[$work_path])) { + $opts['errors'] = $this->errors[$work_path]; + } + switch ($form->getOptionType($field)) { + case 'string': + $type = 'text'; + break; + case 'double': + $type = 'text'; + break; + case 'integer': + $type = 'text'; + break; + case 'boolean': + $type = 'checkbox'; + break; + case 'select': + $type = 'select'; + $opts['values'] = array(); + $values = $form->getOptionValueList($form->fields[$field]); + foreach ($values as $v) { + $opts['values'][$v] = $v; + } + break; + case 'array': + $type = 'list'; + $value = (array) $value; + $value_default = (array) $value_default; + break; + } + + // send default value to form's JS + $js_line = '\'' . $translated_path . '\': '; + switch ($type) { + case 'text': + $js_line .= '\'' . PMA_escapeJsString($value_default) . '\''; + break; + case 'checkbox': + $js_line .= $value_default ? 'true' : 'false'; + break; + case 'select': + $value_default_js = is_bool($value_default) + ? (int) $value_default + : $value_default; + $js_line .= '[\'' . PMA_escapeJsString($value_default_js) . '\']'; + break; + case 'list': + $js_line .= '\'' . PMA_escapeJsString(implode("\n", $value_default)) . '\''; + break; + } + $js_default[] = $js_line; + + display_input($translated_path, $name, $description, $type, + $value, $value_is_default, $opts); + } + + /** + * Displays errors + */ + public function displayErrors() + { + $this->_validate(); + if (count($this->errors) == 0) { + return; + } + + foreach ($this->errors as $path => $error_list) { + if (isset($this->system_paths[$path])) { + $path = $this->system_paths[$path]; + $name = $GLOBALS['str']["{$path}_name"]; + } else { + $name = $GLOBALS['str']["Form_$path"]; + } + display_errors($name, $error_list); + } + } + + /** + * Reverts erroneous fields to their default values + */ + public function fixErrors() + { + $this->_validate(); + if (count($this->errors) == 0) { + return; + } + + $cf = ConfigFile::getInstance(); + foreach (array_keys($this->errors) as $work_path) { + if (!isset($this->system_paths[$work_path])) { + continue; + } + $canonical_path = $this->system_paths[$work_path]; + $cf->set($work_path, $cf->getDefault($canonical_path)); + } + } + + /** + * Validates select field and casts $value to correct type + * + * @param string $value + * @param array $allowed + * @return bool + */ + private function _validateSelect(&$value, array $allowed) + { + foreach ($allowed as $v) { + if ($value == $v) { + settype($value, gettype($v)); + return true; + } + } + return false; + } + + /** + * Validates and saves form data to session + * + * @param array|string $forms array of form names + * @param bool $allow_partial_save allows for partial form saving on failed validation + * @return boolean true on success (no errors and all saved) + */ + public function save($forms, $allow_partial_save = true) + { + $result = true; + $cf = ConfigFile::getInstance(); + $forms = (array) $forms; + + $values = array(); + $to_save = array(); + $this->errors = array(); + foreach ($forms as $form) { + /* @var $form Form */ + if (isset($this->forms[$form])) { + $form = $this->forms[$form]; + } else { + continue; + } + // get current server id + $change_index = $form->index === 0 + ? $cf->getServerCount() + 1 + : false; + // grab POST values + foreach ($form->fields as $field => $path) { + $work_path = array_search($path, $this->system_paths); + $key = $this->translated_paths[$work_path]; + + // ensure the value is set + if (!isset($_POST[$key])) { + // checkboxes aren't set by browsers if they're off + if ($form->getOptionType($field) == 'boolean') { + $_POST[$key] = false; + } else { + $lang_field = isset($GLOBALS['str']["{$path}_name"]) + ? $GLOBALS['str']["{$path}_name"] : $path; + $this->errors[$form->name][] = PMA_lang( + 'error_missing_field_data', + '' . $lang_field . ''); + $result = false; + continue; + } + } + + // cast variables to correct type + $type = $form->getOptionType($field); + switch ($type) { + case 'double': + settype($_POST[$key], 'float'); + break; + case 'boolean': + case 'integer': + if ($_POST[$key] !== '') { + settype($_POST[$key], $type); + } + break; + case 'select': + if (!$this->_validateSelect($_POST[$key], $form->getOptionValueList($path))) { + $this->errors[$work_path][] = $GLOBALS['str']['error_incorrect_value']; + $result = false; + continue; + } + break; + case 'string': + $_POST[$key] = trim($_POST[$key]); + break; + case 'array': + // eliminate empty values and ensure we have an array + $post_values = explode("\n", $_POST[$key]); + $_POST[$key] = array(); + foreach ($post_values as $v) { + $v = trim($v); + if ($v !== '') { + $_POST[$key][] = $v; + } + } + break; + } + + // now we have value with proper type + $values[$path] = $_POST[$key]; + if ($change_index !== false) { + $work_path = str_replace("Servers/$form->index/", + "Servers/$change_index/", $work_path); + } + $to_save[$work_path] = $path; + } + } + + // save forms + if ($allow_partial_save || empty($this->errors)) { + foreach ($to_save as $work_path => $path) { + $cf->set($work_path, $values[$path], $path); + } + } + + // don't look for non-critical errors + $this->_validate(); + + return $result; + } + + /** + * Tells whether form validation failed + * + * @return boolean + */ + public function hasErrors() + { + return count($this->errors) > 0; + } + + + /** + * Returns link to documentation + * + * @param string $path + * @return string + */ + public function getDocLink($path) + { + $test = substr($path, 0, 6); + if ($test == 'Import' || $test == 'Export') { + return ''; + } + return '../Documentation.html#cfg_' . self::_getOptName($path); + } + + /** + * Returns link to wiki + * + * @param string $path + * @return string + */ + public function getWikiLink($path) + { + $opt_name = self::_getOptName($path); + if (substr($opt_name, 0, 7) == 'Servers') { + $opt_name = substr($opt_name, 8); + if (strpos($opt_name, 'AllowDeny') === 0) { + $opt_name = str_replace('_', '_.28', $opt_name) . '.29'; + } + } + $test = substr($path, 0, 6); + if ($test == 'Import') { + $opt_name = substr($opt_name, 7); + if ($opt_name == 'format') { + $opt_name = 'format_2'; + } + } + if ($test == 'Export') { + $opt_name = substr($opt_name, 7); + } + return 'http://wiki.cihar.com/pma/Config#' . $opt_name; + } + + /** + * Changes path so it can be used in URLs + * + * @param string $path + * @return string + */ + private static function _getOptName($path) + { + return str_replace(array('Servers/1/', '/'), array('Servers/', '_'), $path); + } +} +?> \ No newline at end of file diff --git a/setup/lib/FormDisplay.tpl.php b/setup/lib/FormDisplay.tpl.php new file mode 100644 index 000000000..5271975da --- /dev/null +++ b/setup/lib/FormDisplay.tpl.php @@ -0,0 +1,294 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +/** + * Displays top part of the form + * + * @param string $action default: $_SERVER['REQUEST_URI'] + * @param string $method 'post' or 'get' + * @param array $hidden_fields array of form hidden fields (key: field name) + */ +function display_form_top($action = null, $method = 'post', $hidden_fields = null) +{ + static $has_check_page_refresh = false; + + if ($action === null) { + $action = $_SERVER['REQUEST_URI']; + } + if ($method != 'post') { + $method = 'get'; + } +?> +
+' . "\n"; + } + echo PMA_generate_common_hidden_inputs() . "\n"; + echo PMA_getHiddenFields((array)$hidden_fields); +} + +/** + * Displays form tabs which are given by an array indexed by fieldset id + * ({@link display_fieldset_top}), with values being tab titles. + * + * @param array $tabs + */ +function display_tabs_top($tabs) { +?> +
    + $tab_name): ?> +
  • + +
+
+
+ 'optbox'), $attributes); + foreach ($attributes as $k => &$attr) { + $attr = $k . '="' . htmlspecialchars($attr) . '"'; + } + + echo '
'; + echo '' . $title . ''; + if (!empty($description)) { + echo '

' . $description . '

'; + } + // this must match with displayErrors() in scripts.js + if (is_array($errors) && count($errors) > 0) { + echo '
'; + foreach ($errors as $error) { + echo '
' . $error . '
'; + } + echo '
'; + } +?> + + fields + * o values_escaped - (boolean) tells whether values array is already escaped (defaults to false) + * o values_disabled - (array)list of disabled values (keys from values) + * o wiki - (string) wiki link + * + * @param string $path + * @param string $name + * @param string $description + * @param string $type + * @param mixed $value + * @param bool $value_is_default + * @param array $opts + */ +function display_input($path, $name, $description = '', $type, $value, $value_is_default = true, $opts = null) +{ + $field_class = $value_is_default ? '' : ' class="custom"'; + $name_id = 'name="' . $path . '" id="' . $path . '"'; +?> + + + + + + + + +
+ + + + Doc + Wiki + + + + + + '; + break; + case 'checkbox': + echo ''; + break; + case 'select': + echo ''; + break; + case 'list': + echo ''; + break; + } + if (isset($opts['setvalue']) && $opts['setvalue']) { + ?> + " title="" style="display:none">set-value + + + "; + foreach ($opts['errors'] as $error) { + echo '
' . htmlspecialchars($error) . '
'; + } + echo ''; + } + ?> + +
+ + +
+
+ + + + + +\n"; +} + +/** + * Displays bottom part of the form + */ +function display_form_bottom() +{ + echo "\n"; +} + +/** + * Appends JS validation code to $js_array + * + * @param string $field_id + * @param string $validator + * @param array $js_array + */ +function js_validate($field_id, $validator, &$js_array) { + $js_array[] = "validateField('$field_id', '$validator', true)"; +} + +/** + * Displays JavaScript code + * + * @param array $js_array + */ +function display_js($js_array) { + if (empty($js_array)) { + return; + } +?> + +'; + echo '
' . htmlspecialchars($name) . '
'; + foreach ($error_list as $error) { + echo '
' . htmlspecialchars($error) . '
'; + } + echo ''; +} +?> \ No newline at end of file diff --git a/setup/lib/common.inc.php b/setup/lib/common.inc.php new file mode 100644 index 000000000..f7f3d2ef9 --- /dev/null +++ b/setup/lib/common.inc.php @@ -0,0 +1,214 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +// TODO: remove +error_reporting(E_ALL | E_STRICT); + +define('PMA_MINIMUM_COMMON', TRUE); +define('PMA_SETUP', TRUE); +chdir('..'); + +require_once './libraries/common.inc.php'; +require_once './libraries/url_generating.lib.php'; +require_once './setup/lib/ConfigFile.class.php'; + +// TODO: remove +restore_error_handler(); +if ($error_handler->countErrors() > 0) { + $error_handler->dispAllErrors(); +} + +// check selected language +$lang_file = './setup/lang/' . $GLOBALS['available_languages'][$GLOBALS['lang']][1] . '.inc.php'; +if (!file_exists($lang_file)) { + // select_lang.lib.php did detection for us, so if language failed assume + // English is the only matching choice + $GLOBALS['lang'] = 'en-utf-8'; + require_once $GLOBALS['lang_path'] . 'english-utf-8.inc.php'; +} + +// Load setup script translation +$lang_file = './setup/lang/' . $GLOBALS['available_languages'][$GLOBALS['lang']][1] . '.inc.php'; +if (!file_exists($lang_file)) { + $lang_file = './setup/lang/english-utf-8.inc.php'; +} +require_once $lang_file; +if (file_exists('./setup/lang/added_messages.php')) { + include './setup/lang/added_messages.php'; +} + +if (PMA_ifSetOr($_COOKIE['pma_lang'], '') != $GLOBALS['lang']) { + PMA_setCookie('pma_lang', $GLOBALS['lang']); +} + +if (!isset($_SESSION['ConfigFile'])) { + $_SESSION['ConfigFile'] = array(); +} + +// allows for redirection even after sending some data +ob_start(); + +/** + * Returns value of an element in $array given by $path. + * $path is a string describing position of an element in an associative array, + * eg. Servers/1/host refers to $array[Servers][1][host] + * + * @param string $path + * @param array $array + * @param mixed $default + * @return mixed array element or $default + */ +function array_read($path, $array, $default = null) +{ + $keys = explode('/', $path); + $value =& $array; + foreach ($keys as $key) { + if (!isset($value[$key])) { + return $default; + } + $value =& $value[$key]; + } + return $value; +} + +/** + * Stores value in an array + * + * @param string $path + * @param array &$array + * @param mixed $value + */ +function array_write($path, &$array, $value) +{ + $keys = explode('/', $path); + $last_key = array_pop($keys); + $a =& $array; + foreach ($keys as $key) { + if (!isset($a[$key])) { + $a[$key] = array(); + } + $a =& $a[$key]; + } + $a[$last_key] = $value; +} + +/** + * Removes value from an array + * + * @param string $path + * @param array &$array + * @param mixed $value + */ +function array_remove($path, &$array) +{ + $keys = explode('/', $path); + $keys_last = array_pop($keys); + $path = array(); + $depth = 0; + + $path[0] =& $array; + $found = true; + // go as deep as required or possible + foreach ($keys as $key) { + if (!isset($path[$depth][$key])) { + $found = false; + break; + } + $depth++; + $path[$depth] =& $path[$depth-1][$key]; + } + // if element found, remove it + if ($found) { + unset($path[$depth][$keys_last]); + $depth--; + } + + // remove empty nested arrays + for (; $depth >= 0; $depth--) { + if (!isset($path[$depth+1]) || count($path[$depth+1]) == 0) { + unset($path[$depth][$keys[$depth]]); + } else { + break; + } + } +} + +/** + * Returns sanitized language string, taking into account our special codes + * for formatting. Takes variable number of arguments. + * Based on PMA_sanitize from sanitize.lib.php. + * + * @param string $lang_key + * @param mixed $args arguments for sprintf + * @return string + */ +function PMA_lang($lang_key) +{ + static $search, $replace; + + // some quick cache'ing + if ($search === null) { + $replace_pairs = array( + '<' => '<', + '>' => '>', + '[em]' => '', + '[/em]' => '', + '[strong]' => '', + '[/strong]' => '', + '[code]' => '', + '[/code]' => '', + '[kbd]' => '', + '[/kbd]' => '', + '[br]' => '
', + '[sup]' => '', + '[/sup]' => ''); + $search = array_keys($replace_pairs); + $replace = array_values($replace_pairs); + } + if (!isset($GLOBALS['str'][$lang_key])) { + return $lang_key; + } + $message = str_replace($search, $replace, $GLOBALS['str'][$lang_key]); + // replace [a@"$1"]$2[/a] with $2 + $message = preg_replace('#\[a@("?)([^\]]+)\1\]([^\[]+)\[/a\]#e', + "PMA_lang_link_replace('$2', '$3')", $message); + + if (func_num_args() == 1) { + return $message; + } else { + $args = func_get_args(); + array_shift($args); + return vsprintf($message, $args); + } +} + +/** + * Wraps link in tags and replaces argument separator in internal links + * to the one returned by PMA_get_arg_separator() + * + * @param string $link + * @param string $text + * @return string + */ +function PMA_lang_link_replace($link, $text) +{ + static $separator; + + if (!isset($separator)) { + $separator = PMA_get_arg_separator('html'); + } + + if (!preg_match('#^http://#', $link)) { + $link = str_replace('&', $separator, $link); + } + + return '' . $text . ''; +} +?> \ No newline at end of file diff --git a/setup/lib/config_info.inc.php b/setup/lib/config_info.inc.php new file mode 100644 index 000000000..614d0f149 --- /dev/null +++ b/setup/lib/config_info.inc.php @@ -0,0 +1,135 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +$cfg_db = array(); + +// path to config file, relative to phpMyAdmin's root path +$cfg_db['_config_file_path'] = './config/config.inc.php'; + +/** + * Value meaning: + * o array - select field, array contains allowed values + * o string - type override + * + * Use normal array, paths won't be expanded + */ +$cfg_db['Servers'] = array(1 => array( + 'port' => 'integer', + 'connect_type' => array('tcp', 'socket'), + 'extension' => array('mysql', 'mysqli'), + 'auth_type' => array('config', 'http', 'signon', 'cookie'), + 'AllowDeny' => array( + 'order' => array('', 'deny,allow', 'allow,deny', 'explicit')), + 'only_db' => 'array')); +$cfg_db['RecodingEngine'] = array('auto', 'iconv', 'recode'); +$cfg_db['DefaultCharset'] = $GLOBALS['cfg']['AvailableCharsets']; +$cfg_db['OBGzip'] = array('auto', true, false); +$cfg_db['ShowTooltipAliasTB'] = array('nested', true, false); +$cfg_db['DisplayDatabasesList'] = array('auto', true, false); +$cfg_db['LeftLogoLinkWindow'] = array('main', 'new'); +$cfg_db['LeftDefaultTabTable'] = array( + 'tbl_structure.php', // fields list + 'tbl_sql.php', // SQL form + 'tbl_select.php', // search page + 'tbl_change.php', // insert row page + 'sql.php'); // browse page +$cfg_db['NavigationBarIconic'] = array(true, false, 'both'); +$cfg_db['Order'] = array('ASC', 'DESC', 'SMART'); +$cfg_db['ProtectBinary'] = array(false, 'blob', 'all'); +$cfg_db['CharEditing'] = array('input', 'textarea'); +$cfg_db['PropertiesIconic'] = array(true, false, 'both'); +$cfg_db['DefaultTabServer'] = array( + 'main.php', // the welcome page (recommended for multiuser setups) + 'server_databases.php', // list of databases + 'server_status.php', // runtime information + 'server_variables.php', // MySQL server variables + 'server_privileges.php', // user management + 'server_processlist.php'); // process list +$cfg_db['DefaultTabDatabase'] = array( + 'db_structure.php', // tables list + 'db_sql.php', // SQL form + 'db_search.php', // search query + 'db_operations.php'); // operations on database +$cfg_db['DefaultTabTable'] = array( + 'tbl_structure.php', // fields list + 'tbl_sql.php', // SQL form + 'tbl_select.php', // search page + 'tbl_change.php', // insert row page + 'sql.php'); // browse page +$cfg_db['Import']['format'] = array( + 'csv', // CSV + 'docsql', // DocSQL + 'ldi', // CSV using LOAD DATA + 'sql'); // SQL +$cfg_db['Import']['sql_compatibility'] = array( + 'NONE', 'ANSI', 'DB2', 'MAXDB', 'MYSQL323', 'MYSQL40', 'MSSQL', 'ORACLE', + // removed; in MySQL 5.0.33, this produces exports that + // can't be read by POSTGRESQL (see our bug #1596328) + //'POSTGRESQL', + 'TRADITIONAL'); +$cfg_db['Import']['ldi_local_option'] = array('auto', true, false); +$cfg_db['Export']['format'] = array('codegen', 'csv', 'excel', 'htmlexcel', + 'htmlword', 'latex', 'ods', 'odt', 'pdf', 'sql', 'texytext', 'xls', 'xml', + 'yaml'); +$cfg_db['Export']['compression'] = array('none', 'zip', 'gzip', 'bzip2'); +$cfg_db['Export']['charset'] = array_merge(array(''), $GLOBALS['cfg']['AvailableCharsets']); + +/** + * Config options which will be placed in config file even if they are set + * to their default values (use only full paths) + */ +$persist_keys = array( + 'DefaultLang', + 'ServerDefault', + 'UploadDir', + 'SaveDir', + 'Servers/1/verbose', + 'Servers/1/host', + 'Servers/1/port', + 'Servers/1/socket', + 'Servers/1/extension', + 'Servers/1/connect_type', + 'Servers/1/auth_type', + 'Servers/1/user', + 'Servers/1/password'); + +/** + * Default values overrides + * Use only full paths + */ +$cfg_db['_overrides'] = array(); +$cfg_db['_overrides']['Servers/1/extension'] = extension_loaded('mysqli') + ? 'mysqli' : 'mysql'; + +/** + * Validator assignments (functions from validate.lib.php and 'validators' + * object in scripts.js) + * Use only full paths and form ids + */ +$cfg_db['_validators'] = array( + 'Server' => 'validate_server', + 'Server_pmadb' => 'validate_pmadb', + 'Servers/1/port' => 'validate_port_number', + 'Servers/1/hide_db' => 'validate_regex', + 'LoginCookieValidity' => 'validate_positive_number', + 'LoginCookieStore' => 'validate_non_negative_number', + 'QueryHistoryMax' => 'validate_positive_number', + 'LeftFrameTableLevel' => 'validate_positive_number', + 'MaxRows' => 'validate_positive_number', + 'CharTextareaCols' => 'validate_positive_number', + 'CharTextareaRows' => 'validate_positive_number', + 'InsertRows' => 'validate_positive_number', + 'ForeignKeyMaxLimit' => 'validate_positive_number', + 'Import/skip_queries' => 'validate_non_negative_number'); +?> \ No newline at end of file diff --git a/setup/lib/form_processing.lib.php b/setup/lib/form_processing.lib.php new file mode 100644 index 000000000..08e50cd75 --- /dev/null +++ b/setup/lib/form_processing.lib.php @@ -0,0 +1,61 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +/** + * Processes forms registered in $form_display, handles error correction + * + * @param FormDisplay $form_display + */ +function process_formset(FormDisplay $form_display) { + if (filter_input(INPUT_GET, 'mode') == 'revert') { + // revert erroneous fields to their default values + $form_display->fixErrors(); + // drop post data + header('HTTP/1.1 303 See Other'); + header('Location: index.php'); + exit; + } + if (!$form_display->process(false)) { + // handle form view and failed POST + $form_display->display(true, true); + } else { + // check for form errors + if ($form_display->hasErrors()) { + // form has errors, show warning + $separator = PMA_get_arg_separator('html'); + $page = filter_input(INPUT_GET, 'page'); + $formset = filter_input(INPUT_GET, 'formset'); + $formset = $formset ? "{$separator}formset=$formset" : ''; + $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT); + if ($id === null && $page == 'servers') { + // we've just added a new server, get it's id + $id = ConfigFile::getInstance()->getServerCount(); + } + $id = $id ? "{$separator}id=$id" : ''; + ?> +
+

+
+ +
+ displayErrors() ?> + +   + + \ No newline at end of file diff --git a/setup/lib/forms.inc.php b/setup/lib/forms.inc.php new file mode 100644 index 000000000..3261eaece --- /dev/null +++ b/setup/lib/forms.inc.php @@ -0,0 +1,191 @@ + array(1 => array('host'))); + * can be written as + * $forms['Form name'] = array('Servers/1/host'); + * + * You can assign default values set by special button ("set value: ..."), eg.: + * $forms['Server_pmadb'] = array('Servers' => array(1 => array( + * 'pmadb' => 'phpmyadmin'))); + * + * @package phpMyAdmin-setup + * @author Piotr Przybylski + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +$forms = array(); +$forms['_config.php'] = array( + 'DefaultLang', + 'ServerDefault'); +$forms['Server'] = array('Servers' => array(1 => array( + 'verbose', + 'host', + 'port', + 'socket', + 'ssl', + 'connect_type', + 'extension', + 'compress', + 'auth_type', + 'user', + 'password', + 'nopassword'))); +$forms['Server_login_options'] = array('Servers' => array(1 => array( + 'SignonSession', + 'SignonURL', + 'LogoutURL', + 'auth_swekey_config' => './swekey.conf'))); +$forms['Server_config'] = array('Servers' => array(1 => array( + 'only_db', + 'hide_db', + 'AllowRoot', + 'DisableIS', + 'AllowDeny/order', + 'AllowDeny/rules', + 'ShowDatabasesCommand', + 'CountTables'))); +$forms['Server_pmadb'] = array('Servers' => array(1 => array( + 'pmadb' => 'phpmyadmin', + 'controluser', + 'controlpass', + 'verbose_check', + 'bookmarktable' => 'pma_bookmark', + 'relation' => 'pma_relation', + 'table_info' => 'pma_table_info', + 'table_coords' => 'pma_table_coords', + 'pdf_pages' => 'pma_pdf_pages', + 'column_info' => 'pma_column_info', + 'history' => 'pma_history', + 'designer_coords' => 'designer_coords'))); +$forms['Import_export'] = array( + 'UploadDir', + 'SaveDir', + 'AllowAnywhereRecoding', + 'DefaultCharset', + 'RecodingEngine', + 'IconvExtraParams', + 'ZipDump', + 'GZipDump', + 'BZipDump', + 'CompressOnFly'); +$forms['Security'] = array( + 'blowfish_secret', + 'ForceSSL', + 'CheckConfigurationPermissions', + 'TrustedProxies', + 'AllowUserDropDatabase', + 'AllowArbitraryServer', + 'LoginCookieRecall', + 'LoginCookieValidity', + 'LoginCookieStore', + 'LoginCookieDeleteAll'); +$forms['Sql_queries'] = array( + 'ShowSQL', + 'Confirm', + 'QueryHistoryDB', + 'QueryHistoryMax', + 'IgnoreMultiSubmitErrors', + 'VerboseMultiSubmit'); +$forms['Other_core_settings'] = array( + 'MaxDbList', + 'MaxTableList', + 'MaxCharactersInDisplayedSQL', + 'OBGzip', + 'PersistentConnections', + 'ExecTimeLimit', + 'MemoryLimit', + 'SkipLockedTables', + 'UseDbSearch'); +$forms['Left_frame'] = array( + 'LeftFrameLight', + 'LeftDisplayLogo', + 'LeftLogoLink', + 'LeftLogoLinkWindow', + 'LeftDefaultTabTable', + 'LeftPointerEnable'); +$forms['Left_servers'] = array( + 'LeftDisplayServers', + 'DisplayServersList'); +$forms['Left_databases'] = array( + 'DisplayDatabasesList', + 'LeftFrameDBTree', + 'LeftFrameDBSeparator', + 'ShowTooltipAliasDB'); +$forms['Left_tables'] = array( + 'LeftFrameTableSeparator', + 'LeftFrameTableLevel', + 'ShowTooltip', + 'ShowTooltipAliasTB'); +$forms['Startup'] = array( + 'ShowStats', + 'ShowPhpInfo', + 'ShowServerInfo', + 'ShowChgPassword', + 'ShowCreateDb', + 'SuggestDBName'); +$forms['Browse'] = array( + 'NavigationBarIconic', + 'ShowAll', + 'MaxRows', + 'Order', + 'BrowsePointerEnable', + 'BrowseMarkerEnable'); +$forms['Edit'] = array( + 'ProtectBinary', + 'ShowFunctionFields', + 'CharEditing', + 'CharTextareaCols', + 'CharTextareaRows', + 'InsertRows', + 'ForeignKeyDropdownOrder', + 'ForeignKeyMaxLimit'); +$forms['Tabs'] = array( + 'LightTabs', + 'PropertiesIconic', + 'DefaultTabServer', + 'DefaultTabDatabase', + 'DefaultTabTable'); +$forms['Sql_box'] = array('SQLQuery' => array( + 'Edit', + 'Explain', + 'ShowAsPHP', + 'Validate', + 'Refresh')); +$forms['Import'] = array('Import' => array( + 'format', + 'allow_interrupt', + 'skip_queries')); +$forms['Import_sql'] = array('Import' => array( + 'sql_compatibility')); +$forms['Import_csv'] = array('Import' => array( + 'csv_replace', + 'csv_terminated', + 'csv_enclosed', + 'csv_escaped', + 'csv_new_line', + 'csv_columns')); +$forms['Import_ldi'] = array('Import' => array( + 'ldi_replace', + 'ldi_terminated', + 'ldi_enclosed', + 'ldi_escaped', + 'ldi_new_line', + 'ldi_columns', + 'ldi_local_option')); +$forms['Export_defaults'] = array('Export' => array( + 'format', + 'compression', + 'asfile', + 'charset', + 'onserver', + 'onserver_overwrite', + 'remember_file_template', + 'file_template_table', + 'file_template_database', + 'file_template_server')); +?> \ No newline at end of file diff --git a/setup/lib/index.lib.php b/setup/lib/index.lib.php new file mode 100644 index 000000000..32e6312b6 --- /dev/null +++ b/setup/lib/index.lib.php @@ -0,0 +1,379 @@ +, http://yehg.net/lab + * Version check taken from the old setup script by Michal Čihař + * + * @package phpMyAdmin-setup + * @author Piotr Przybylski + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +/** + * Initializes message list + */ +function messages_begin() +{ + if (!isset($_SESSION['messages']) || !is_array($_SESSION['messages'])) { + $_SESSION['messages'] = array('error' => array(), 'warning' => array(), 'notice' => array()); + } else { + // reset message states + foreach ($_SESSION['messages'] as &$messages) { + foreach ($messages as &$msg) { + $msg['fresh'] = false; + $msg['active'] = false; + } + } + } +} + +/** + * Adds a new message to message list + * + * @param string $id unique message identifier + * @param string $type one of: notice, warning, error + * @param string $title language string id (in $str array) + * @param string $message message text + */ +function messages_set($type, $id, $title, $message) +{ + $fresh = !isset($_SESSION['messages'][$type][$id]); + $title = PMA_lang($title); + $_SESSION['messages'][$type][$id] = array('fresh' => $fresh, 'active' => true, 'title' => $title, 'message' => $message); +} + +/** + * Cleans up message list + */ +function messages_end() +{ + foreach ($_SESSION['messages'] as &$messages) { + $remove_ids = array(); + foreach ($messages as $id => &$msg) { + if ($msg['active'] == false) { + $remove_ids[] = $id; + } + } + foreach ($remove_ids as $id) { + unset($messages[$id]); + } + } +} + +/** + * Prints message list, must be called after messages_end() + */ +function messages_show_html() +{ + $old_ids = array(); + foreach ($_SESSION['messages'] as $type => $messages) { + foreach ($messages as $id => $msg) { + echo '
' . '

' . $msg['title'] . '

' . $msg['message'] . '
'; + if (!$msg['fresh']) { + $old_ids[] = $id; + } + } + } + + echo "\n" . '\n"; +} + +/** + * Checks for newest phpMyAdmin version and sets result as a new notice + */ +function PMA_version_check() +{ + // version check messages should always be visible so let's make + // a unique message id each time we run it + $message_id = uniqid('version_check'); + // wait 3s at most for server response, it's enough to get information + // from a working server + $connection_timeout = 3; + + $url = 'http://phpmyadmin.net/home_page/version.php'; + $context = stream_context_create(array( + 'http' => array( + 'timeout' => $connection_timeout))); + $data = @file_get_contents($url, null, $context); + if ($data === false) { + if (function_exists('curl_init')) { + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, $connection_timeout); + $data = curl_exec($ch); + curl_close($ch); + } else { + messages_set('error', $message_id, 'Version_check', + PMA_lang('Version_check_wrapper_error')); + return; + } + } + + if (empty($data)) { + messages_set('error', $message_id, 'Version_check', + PMA_lang('Version_check_data_error')); + return; + } + + /* Format: version\ndate\n(download\n)* */ + $data_list = explode("\n", $data); + + if (count($data_list) > 1) { + $version = $data_list[0]; + $date = $data_list[1]; + } else { + $version = $date = ''; + } + + $version_upstream = version_to_int($version); + if ($version_upstream === false) { + messages_set('error', $message_id, 'Version_check', + PMA_lang('Version_check_invalid')); + return; + } + + $version_local = version_to_int($_SESSION['PMA_Config']->get('PMA_VERSION')); + if ($version_local === false) { + messages_set('error', $message_id, 'Version_check', + PMA_lang('Version_check_unparsable')); + return; + } + + if ($version_upstream > $version_local) { + $version = htmlspecialchars($version); + $date = htmlspecialchars($date); + messages_set('notice', $message_id, 'Version_check', + PMA_lang('Version_check_new_available', $version, $date)); + } else { + if ($version_local % 100 == 0) { + messages_set('notice', $message_id, 'Version_check', + PMA_lang('Version_check_new_available_svn', $version, $date)); + } else { + messages_set('notice', $message_id, 'Version_check', + PMA_lang('Version_check_none')); + } + } +} + +/** + * Calculates numerical equivalent of phpMyAdmin version string + * + * @param string version + * @return mixed false on failure, integer on success + */ +function version_to_int($version) +{ + $matches = array(); + if (!preg_match('/^(\d+)\.(\d+)\.(\d+)((\.|-(pl|rc|dev|beta|alpha))(\d+)?)?$/', $version, $matches)) { + return false; + } + if (!empty($matches[6])) { + switch ($matches[6]) { + case 'pl': + $added = 60; + break; + case 'rc': + $added = 30; + break; + case 'beta': + $added = 20; + break; + case 'alpha': + $added = 10; + break; + case 'dev': + $added = 0; + break; + default: + messages_set('notice', 'version_match', 'Version_check', 'Unknown version part: ' . htmlspecialchars($matches[6])); + $added = 0; + break; + } + } else { + $added = 50; // for final + } + if (!empty($matches[7])) { + $added = $added + $matches[7]; + } + return $matches[1] * 1000000 + $matches[2] * 10000 + $matches[3] * 100 + $added; +} + +/** + * Checks whether config file is readable/writable + * + * @param bool &$is_readable + * @param bool &$is_writable + * @param bool &$file_exists + */ +function check_config_rw(&$is_readable, &$is_writable, &$file_exists) +{ + $file_path = ConfigFile::getInstance()->getFilePath(); + $file_dir = dirname($file_path); + $is_readable = true; + $is_writable = is_dir($file_dir) && is_writable($file_dir); + $file_exists = file_exists($file_path); + if ($file_exists) { + $is_readable = is_readable($file_path); + $is_writable = $is_writable && is_writable($file_path); + } +} + +/** + * Performs various compatibility, security and consistency checks on current config + * + * Outputs results to message list, must be called between messages_begin() + * and messages_end() + */ +function perform_config_checks() +{ + $cf = ConfigFile::getInstance(); + $blowfish_secret = $cf->get('blowfish_secret'); + $blowfish_secret_set = false; + $cookie_auth_used = false; + for ($i = 1; $i <= $cf->getServerCount(); $i++) { + $cookie_auth_server = ($cf->getValue("Servers/$i/auth_type") == 'cookie'); + $cookie_auth_used |= $cookie_auth_server; + $server_name = $cf->getServerName($i); + if ($server_name == 'localhost') { + $server_name .= " [$i]"; + } + + if ($cookie_auth_server && $blowfish_secret === null) { + $blowfish_secret = uniqid('', true); + $blowfish_secret_set = true; + $cf->set('blowfish_secret', $blowfish_secret); + } + + // + // $cfg['Servers'][$i]['ssl'] + // should be enabled if possible + // + if (!$cf->getValue("Servers/$i/ssl")) { + $title = PMA_lang('Servers/1/ssl_name') . " ($server_name)"; + messages_set('notice', "Servers/$i/ssl", $title, PMA_lang('Server_ssl_msg')); + } + + // + // $cfg['Servers'][$i]['extension'] + // warn about using 'mysql' + // + if ($cf->getValue("Servers/$i/extension") == 'mysql') { + $title = PMA_lang('Servers/1/extension_name') . " ($server_name)"; + messages_set('notice', "Servers/$i/extension", $title, PMA_lang('Server_extension_msg')); + } + + // + // $cfg['Servers'][$i]['auth_type'] + // warn about full user credentials if 'auth_type' is 'config' + // + if ($cf->getValue("Servers/$i/auth_type") == 'config' + && $cf->getValue("Servers/$i/user") != '' + && $cf->getValue("Servers/$i/password") != '') { + $title = PMA_lang('Servers/1/auth_type_name') . " ($server_name)"; + messages_set('warning', "Servers/$i/auth_type", $title, PMA_lang('Server_auth_config_msg', $i)); + } + } + + // + // $cfg['blowfish_secret'] + // it's required for 'cookie' authentication + // + if ($cookie_auth_used) { + if ($blowfish_secret_set) { + // 'cookie' auth used, blowfish_secret was generated + messages_set('notice', 'blowfish_secret_created', 'blowfish_secret_name', + PMA_lang('blowfish_secret_msg')); + } else { + $blowfish_warnings = array(); + // check length + if (strlen($blowfish_secret) < 8) { + // too short key + $blowfish_warnings[] = PMA_lang('blowfish_secret_length_msg'); + } + // check used characters + $has_digits = (bool) preg_match('/\d/', $blowfish_secret); + $has_chars = (bool) preg_match('/\S/', $blowfish_secret); + $has_nonword = (bool) preg_match('/\W/', $blowfish_secret); + if (!$has_digits || !$has_chars || !$has_nonword) { + $blowfish_warnings[] = PMA_lang('blowfish_secret_chars_msg'); + } + if (!empty($blowfish_warnings)) { + messages_set('warning', 'blowfish_warnings' . count($blowfish_warnings), + 'blowfish_secret_name', implode("
", $blowfish_warnings)); + } + } + } + + // + // $cfg['ForceSSL'] + // should be enabled if possible + // + if (!$cf->getValue('ForceSSL')) { + messages_set('notice', 'ForceSSL', 'ForceSSL_name', PMA_lang('ForceSSL_msg')); + } + + // + // $cfg['AllowArbitraryServer'] + // should be disabled + // + if ($cf->getValue('AllowArbitraryServer')) { + messages_set('warning', 'AllowArbitraryServer', 'AllowArbitraryServer_name', + PMA_lang('AllowArbitraryServer_msg')); + } + + // + // $cfg['LoginCookieValidity'] + // should be at most 1800 (30 min) + // + if ($cf->getValue('LoginCookieValidity') > 1800) { + messages_set('warning', 'LoginCookieValidity', 'LoginCookieValidity_name', + PMA_lang('LoginCookieValidity_msg')); + } + + // + // $cfg['SaveDir'] + // should not be world-accessible + // + if ($cf->getValue('SaveDir') != '') { + messages_set('notice', 'SaveDir', 'SaveDir_name', + PMA_lang('Directory_notice')); + } + + // + // $cfg['TempDir'] + // should not be world-accessible + // + if ($cf->getValue('TempDir') != '') { + messages_set('notice', 'TempDir', 'TempDir_name', + PMA_lang('Directory_notice')); + } +} + +/* + * add checks for compression options: + * + * import: +if ($cfg['GZipDump'] && @function_exists('gzopen')) { + $compressions .= ', gzip'; +} +if ($cfg['BZipDump'] && @function_exists('bzopen')) { + $compressions .= ', bzip2'; +} +if ($cfg['ZipDump'] && @function_exists('zip_open')) { + $compressions .= ', zip'; +} + +export: +$is_zip = ($cfg['ZipDump'] && @function_exists('gzcompress')); +$is_gzip = ($cfg['GZipDump'] && @function_exists('gzencode')); +$is_bzip = ($cfg['BZipDump'] && @function_exists('bzcompress')); + */ +?> \ No newline at end of file diff --git a/setup/lib/validate.lib.php b/setup/lib/validate.lib.php new file mode 100644 index 000000000..4b8265792 --- /dev/null +++ b/setup/lib/validate.lib.php @@ -0,0 +1,314 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0 + * @version $Id$ + */ + +/** + * Runs validation $validator_id on values $values and returns error list. + * + * Return values: + * o array, keys - field path or formset id, values - array of errors + * when $isPostSource is true values is an empty array to allow for error list + * cleanup in HTML documen + * o false - when no validators match name(s) given by $validator_id + * + * @param string|array $validator_id + * @param array $values + * @param bool $isPostSource tells whether $values are directly from POST request + * @return bool|array + */ +function validate($validator_id, &$values, $isPostSource) +{ + // find validators + $cf = ConfigFile::getInstance(); + $validator_id = (array) $validator_id; + $validators = $cf->getDbEntry('_validators'); + $vids = array(); + foreach ($validator_id as &$vid) { + $vid = $cf->getCanonicalPath($vid); + if (isset($validators[$vid])) { + $vids[] = $vid; + } + } + if (empty($vids)) { + return false; + } + + // create argument list with canonical paths and remember path mapping + $arguments = array(); + $key_map = array(); + foreach ($values as $k => $v) { + $k2 = $isPostSource ? str_replace('-', '/', $k) : $k; + $k2 = strpos($k2, '/') ? $cf->getCanonicalPath($k2) : $k2; + $key_map[$k2] = $k; + $arguments[$k2] = $v; + } + + // validate + $result = array(); + foreach ($vids as $vid) { + $r = call_user_func($validators[$vid], $vid, $arguments); + // merge results + if (is_array($r)) { + foreach ($r as $key => $error_list) { + // skip empty values if $isPostSource is false + if (!$isPostSource && empty($error_list)) { + continue; + } + if (!isset($result[$key])) { + $result[$key] = array(); + } + $result[$key] = array_merge($result[$key], (array)$error_list); + } + } + } + + // restore original paths + $new_result = array(); + foreach ($result as $k => $v) { + $k2 = isset($key_map[$k]) ? $key_map[$k] : $k; + $new_result[$k2] = $v; + } + return empty($new_result) ? true : $new_result; +} + +/** + * Ensures that $php_errormsg variable will be registered in case of an error + * and enables output buffering (when $start = true). + * Called with $start = false disables output buffering end restores + * html_errors and track_errors. + * + * @param boolean $start + */ +function test_php_errormsg($start = true) +{ + static $old_html_errors, $old_track_errors; + if ($start) { + $old_html_errors = ini_get('html_errors'); + $old_track_errors = ini_get('track_errors'); + ini_set('html_errors', false); + ini_set('track_errors', true); + ob_start(); + } else { + ob_end_clean(); + ini_set('html_errors', $old_html_errors); + ini_set('track_errors', $old_track_errors); + } +} + +/** + * Test database connection + * + * @param string $extension 'mysql' or 'mysqli' + * @param string $connect_type 'tcp' or 'socket' + * @param string $host + * @param string $port + * @param string $socket + * @param string $user + * @param string $pass + * @param string $error_key + * @return bool|array + */ +function test_db_connection($extension, $connect_type, $host, $port, $socket, $user, $pass = null, $error_key = 'Server') +{ + // test_php_errormsg(); + $socket = empty($socket) || $connect_type == 'tcp' ? null : ':' . $socket; + $port = empty($port) || $connect_type == 'socket' ? null : ':' . $port; + $error = null; + if ($extension == 'mysql') { + $conn = @mysql_connect($host . $socket . $port, $user, $pass); + if (!$conn) { + $error = PMA_lang('error_connection'); + } else { + mysql_close($conn); + } + } else { + $conn = @mysqli_connect($host, $user, $pass, null, $port, $socket); + if (!$conn) { + $error = PMA_lang('error_connection'); + } else { + mysqli_close($conn); + } + } + // test_php_errormsg(false); + if (isset($php_errormsg)) { + $error .= " - $php_errormsg"; + } + return is_null($error) ? true : array($error_key => $error); +} + +/** + * Validate server config + * + * @param string $path + * @param array $values + * @return array + */ +function validate_server($path, $values) +{ + $result = array('Server' => '', 'Servers/1/user' => '', 'Servers/1/SignonSession' => '', 'Servers/1/SignonURL' => ''); + $error = false; + if ($values['Servers/1/auth_type'] == 'config' && empty($values['Servers/1/user'])) { + $result['Servers/1/user'] = PMA_lang('error_empty_user_for_config_auth'); + $error = true; + } + if ($values['Servers/1/auth_type'] == 'signon' && empty($values['Servers/1/SignonSession'])) { + $result['Servers/1/SignonSession'] = PMA_lang('error_empty_signon_session'); + $error = true; + } + if ($values['Servers/1/auth_type'] == 'signon' && empty($values['Servers/1/SignonURL'])) { + $result['Servers/1/SignonURL'] = PMA_lang('error_empty_signon_url'); + $error = true; + } + + if (!$error && $values['Servers/1/auth_type'] == 'config') { + $password = $values['Servers/1/nopassword'] ? null : $values['Servers/1/password']; + $test = test_db_connection($values['Servers/1/extension'], $values['Servers/1/connect_type'], $values['Servers/1/host'], $values['Servers/1/port'], $values['Servers/1/socket'], $values['Servers/1/user'], $password, 'Server'); + if ($test !== true) { + $result = array_merge($result, $test); + } + } + return $result; +} + +/** + * Validate pmadb config + * + * @param string $path + * @param array $values + * @return array + */ +function validate_pmadb($path, $values) +{ + $tables = array('Servers/1/bookmarktable', 'Servers/1/relation', 'Servers/1/table_info', 'Servers/1/table_coords', 'Servers/1/pdf_pages', 'Servers/1/column_info', 'Servers/1/history', 'Servers/1/designer_coords'); + $result = array('Server_pmadb' => '', 'Servers/1/controluser' => '', 'Servers/1/controlpass' => ''); + $error = false; + + if ($values['Servers/1/pmadb'] == '') { + return $result; + } + + $result = array(); + if ($values['Servers/1/controluser'] == '') { + $result['Servers/1/controluser'] = PMA_lang('error_empty_pmadb_user'); + $error = true; + } + if ($values['Servers/1/controlpass'] == '') { + $result['Servers/1/controlpass'] = PMA_lang('error_empty_pmadb_password'); + $error = true; + } + if (!$error) { + $test = test_db_connection($values['Servers/1/extension'], $values['Servers/1/connect_type'], $values['Servers/1/host'], $values['Servers/1/port'], $values['Servers/1/socket'], $values['Servers/1/controluser'], $values['Servers/1/controlpass'], 'Server_pmadb'); + if ($test !== true) { + $result = array_merge($result, $test); + } + } + return $result; +} + + +/** + * Validates regular expression + * + * @param string $path + * @param array $values + * @return array + */ +function validate_regex($path, $values) +{ + $result = array($path => ''); + + if ($values[$path] == '') { + return $result; + } + + test_php_errormsg(); + + $matches = array(); + preg_match($values[$path], '', $matches); + ob_end_clean(); + + test_php_errormsg(false); + + if (isset($php_errormsg)) { + $error = preg_replace('/^preg_match\(\): /', '', $php_errormsg); + return array($path => $error); + } + + return $result; +} + +/** + * Tests integer value + * + * @param string $path + * @param array $values + * @param bool $allow_neg allow negative values + * @param bool $allow_zero allow zero + * @param int $max_value max allowed value + * @param string $error_lang_key error message key in $str + * @return string empty string if test is successful + */ +function test_number($path, $values, $allow_neg, $allow_zero, $max_value, $error_lang_key) +{ + if ($values[$path] === '') { + return ''; + } + + if (intval($values[$path]) != $values[$path] || (!$allow_neg && $values[$path] < 0) || (!$allow_zero && $values[$path] == 0) || $values[$path] > $max_value) { + return PMA_lang($error_lang_key); + } + + return ''; +} + +/** + * Validates port number + * + * @param string $path + * @param array $values + * @return array + */ +function validate_port_number($path, $values) +{ + return array($path => test_number($path, $values, false, false, 65536, 'error_incorrect_port')); +} + +/** + * Validates positive number + * + * @param string $path + * @param array $values + * @return array + */ +function validate_positive_number($path, $values) +{ + return array($path => test_number($path, $values, false, false, PHP_INT_MAX, 'error_nan_p')); +} + +/** + * Validates non-negative number + * + * @param string $path + * @param array $values + * @return array + */ +function validate_non_negative_number($path, $values) +{ + return array($path => test_number($path, $values, false, true, PHP_INT_MAX, 'error_nan_nneg')); +} +?> \ No newline at end of file diff --git a/setup/scripts.js b/setup/scripts.js new file mode 100644 index 000000000..5f0a75aaf --- /dev/null +++ b/setup/scripts.js @@ -0,0 +1,704 @@ +/** + * functions used in setup script + * + * @version $Id$ + */ + +// show this window in top frame +if (top != self) { + window.top.location.href = location; +} + +// default values for fields +var defaultValues = {}; + +// language strings +var PMA_messages = {}; + +/** + * Returns field type + * + * @param Element field + */ +function getFieldType(field) { + if (field.tagName == 'INPUT') { + return field.getProperty('type'); + } else if (field.tagName == 'SELECT') { + return 'select'; + } else if (field.tagName == 'TEXTAREA') { + return 'text'; + } + return ''; +} + +/** + * Sets field value + * + * value must be of type: + * o undefined (omitted) - restore default value (form default, not PMA default) + * o String - if type is 'text' + * o boolean - if type is 'checkbox' + * o Array of values - if type is 'select' + * + * @param Element field + * @param String field_type see getFieldType + * @param mixed value + */ +function setFieldValue(field, field_type, value) { + switch (field_type) { + case 'text': + field.value = $defined(value) ? value : field.defaultValue; + break; + case 'checkbox': + field.checked = $defined(value) ? value : field.defaultChecked; + break; + case 'select': + var i, imax = field.options.length; + if (!$defined(value)) { + for (i = 0; i < imax; i++) { + field.options[i].selected = field.options[i].defaultSelected; + } + } else { + for (i = 0; i < imax; i++) { + field.options[i].selected = (value.indexOf(field.options[i].value) != -1); + } + } + break; + } + markField(field); +} + +/** + * Gets field value + * + * Will return one of: + * o String - if type is 'text' + * o boolean - if type is 'checkbox' + * o Array of values - if type is 'select' + * + * @param Element field + * @param String field_type see getFieldType + * @return mixed + */ +function getFieldValue(field, field_type) { + switch (field_type) { + case 'text': + return field.value; + case 'checkbox': + return field.checked; + case 'select': + var i, imax = field.options.length, items = []; + for (i = 0; i < imax; i++) { + if (field.options[i].selected) { + items.push(field.options[i].value); + } + } + return items; + } +} + +/** + * Returns values for all fields in fieldsets + */ +function getAllValues() { + var elements = $$('fieldset input, fieldset select, fieldset textarea'); + var values = {} + var type, value; + for (var i = 0; i < elements.length; i++) { + type = getFieldType(elements[i]); + value = getFieldValue(elements[i], type); + if (typeof value != 'undefined') { + // we only have single selects, fatten array + if (type == 'select') { + value = value[0]; + } + values[elements[i].name] = value; + } + } + return values; +} + +/** + * Checks whether field has its default value + * + * @param Element field + * @param String type + * @return boolean + */ +function checkFieldDefault(field, type) { + if (!$defined(defaultValues[field.id])) { + return true; + } + var isDefault = true + var currentValue = getFieldValue(field, type); + if (type != 'select') { + isDefault = currentValue == defaultValues[field.id]; + } else { + // compare arrays, will work for our representation of select values + if (currentValue.length != defaultValues[field.id].length) { + isDefault = false; + } + else { + for (var i = 0; i < currentValue.length; i++) { + if (currentValue[i] != defaultValues[field.id][i]) { + isDefault = false; + break; + } + } + } + } + return isDefault; +} + +/** + * Returns element's id prefix + * @param Element element + */ +function getIdPrefix(element) { + return element.id.replace(/[^-]+$/, ''); +} + +// ------------------------------------------------------------------ +// Messages +// + +// stores hidden message ids +var hiddenMessages = []; + +window.addEvent('domready', function() { + var hidden = hiddenMessages.length; + for (var i = 0; i < hidden; i++) { + $(hiddenMessages[i]).style.display = 'none'; + } + if (hidden > 0) { + var link = $('show_hidden_messages'); + link.addEvent('click', function(e) { + e.stop(); + for (var i = 0; i < hidden; i++) { + $(hiddenMessages[i]).style.display = ''; + } + this.dispose(); + }); + link.set('html', link.get('html').replace('#MSG_COUNT', hidden)); + link.style.display = ''; + } +}); + +// +// END: Messages +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// Form validation and field operations +// + +// form validator assignments +var validate = {}; + +// form validator list +var validators = { + /** + * Validates positive number + * + * @param boolean isKeyUp + */ + validate_positive_number: function (isKeyUp) { + var result = this.value.test('^[0-9]*$') && this.value != '0'; + return result ? true : PMA_messages['error_nan_p']; + }, + /** + * Validates non-negative number + * + * @param boolean isKeyUp + */ + validate_non_negative_number: function (isKeyUp) { + var result = this.value.test('^[0-9]*$'); + return result ? true : PMA_messages['error_nan_nneg']; + }, + /** + * Validates port number + * + * @param boolean isKeyUp + */ + validate_port_number: function(isKeyUp) { + var result = this.value.test('^[0-9]*$') && this.value != '0'; + if (!result || this.value > 65536) { + result = PMA_messages['error_incorrect_port']; + } + return result; + }, + // field validators + _field: { + /** + * hide_db field + * + * @param boolean isKeyUp + */ + hide_db: function(isKeyUp) { + if (!isKeyUp && this.value != '') { + var data = {}; + data[this.id] = this.value; + ajaxValidate(this, 'Servers/1/hide_db', data); + } + return true; + } + }, + // fieldset validators + _fieldset: { + /** + * Validates Server fieldset + * + * @param boolean isKeyUp + */ + Server: function(isKeyUp) { + if (!isKeyUp) { + ajaxValidate(this, 'Server', getAllValues()); + } + return true; + }, + /** + * Validates Server_login_options fieldset + * + * @param boolean isKeyUp + */ + Server_login_options: function(isKeyUp) { + return validators._fieldset.Server.bind(this)(isKeyUp); + }, + /** + * Validates Server_pmadb fieldset + * + * @param boolean isKeyUp + */ + Server_pmadb: function(isKeyUp) { + if (isKeyUp) { + return true; + } + + var prefix = getIdPrefix(this.getElement('input')); + var pmadb_active = $(prefix + 'pmadb').value != ''; + if (pmadb_active) { + ajaxValidate(this, 'Server_pmadb', getAllValues()); + } + + return true; + } + } +} + +/** + * Calls server-side validation procedures + * + * @param Element parent input field in
or
+ * @param String id validator id + * @param Object values values hash (element_id: value) + */ +function ajaxValidate(parent, id, values) { + // ensure that parent is a fieldset + if (parent.tagName != 'FIELDSET') { + parent = parent.getParent('fieldset'); + if (!parent) { + return false; + } + } + // ensure that we have a Request object + if (typeof parent.request == 'undefined') { + parent.validate = { + request: new Request.JSON({ + url: 'validate.php', + autoCancel: true, + onSuccess: function(response) { + if (response == null) { + return; + } + var error = {}; + if ($type(response) != 'object') { + error[parent.id] = [response]; + } else if (typeof response['error'] != 'undefined') { + error[parent.id] = [response['error']]; + } else { + $each(response, function(value, key) { + error[key] = $type(value) == 'array' ? value : [value]; + }); + } + displayErrors(error); + }}), + token: parent.getParent('form').token.value + }; + } + + parent.validate.request.send({ + data: { + token: parent.validate.token, + id: id, + values: JSON.encode(values)} + }); + + return true; +} + +/** + * Registers validator for given field + * + * @param String id field id + * @param String type validator (key in validators object) + * @param boolean onKeyUp whether fire on key up + * @param mixed params validation function parameters + */ +function validateField(id, type, onKeyUp, params) { + if (typeof validators[type] == 'undefined') { + return; + } + if (typeof validate[id] == 'undefined') { + validate[id] = []; + } + validate[id].push([type, params, onKeyUp]); +} + +/** + * Returns valdiation functions associated with form field + * + * @param String field_id form field id + * @param boolean onKeyUpOnly see validateField + * @return Array array of [function, paramseters to be passed to function] + */ +function getFieldValidators(field_id, onKeyUpOnly) { + // look for field bound validator + var name = field_id.match(/[^-]+$/)[0]; + if (typeof validators._field[name] != 'undefined') { + return [[validators._field[name], null]]; + } + + // look for registered validators + var functions = []; + if (typeof validate[field_id] != 'undefined') { + // validate[field_id]: array of [type, params, onKeyUp] + for (var i = 0, imax = validate[field_id].length; i < imax; i++) { + if (onKeyUpOnly && !validate[field_id][i][2]) { + continue; + } + functions.push([validators[validate[field_id][i][0]], validate[field_id][i][1]]); + } + } + + return functions; +} + +/** + * Displays errors for given form fields + * + * WARNING: created DOM elements must be identical with the ones made by + * display_input() in FormDisplay.tpl.php! + * + * @param Object error list (key: field id, value: error array) + */ +function displayErrors(errors) { + $each(errors, function(errors, field_id) { + var field = $(field_id); + var isFieldset = field.tagName == 'FIELDSET'; + var errorCnt = isFieldset + ? field.getElement('dl.errors') + : field.getNext('.inline_errors'); + + // remove empty errors (used to clear error list) + errors = errors.filter(function(item) { + return item != ''; + }); + + if (errors.length) { + // if error container doesn't exist, create it + if (errorCnt === null) { + if (isFieldset) { + errorCnt = new Element('dl', { + 'class': 'errors' + }); + errorCnt.inject(field.getElement('table'), 'before'); + } else { + errorCnt = new Element('dl', { + 'class': 'inline_errors' + }); + errorCnt.inject(field.getParent('td'), 'bottom'); + } + } + + var html = ''; + for (var i = 0, imax = errors.length; i < imax; i++) { + html += '
' + errors[i] + '
'; + } + errorCnt.set('html', html); + } else if (errorCnt !== null) { + // remove useless error container + errorCnt.dispose(); + } + }); +} + +/** + * Validates fieldset and puts errors in 'errors' object + * + * @param Element field + * @param boolean isKeyUp + * @param Object errors + */ +function validate_fieldset(fieldset, isKeyUp, errors) { + if (fieldset && typeof validators._fieldset[fieldset.id] != 'undefined') { + var fieldset_errors = validators._fieldset[fieldset.id].bind(fieldset)(isKeyUp); + $each(fieldset_errors, function(field_errors, field_id) { + if (typeof errors[field_id] == 'undefined') { + errors[field_id] = []; + } + errors[field_id][$type(field_errors) == 'array' ? 'extend' : 'push'](field_errors); + }); + } +} + +/** + * Validates form field and puts errors in 'errors' object + * + * @param Element field + * @param boolean isKeyUp + * @param Object errors + */ +function validate_field(field, isKeyUp, errors) { + errors[field.id] = []; + var functions = getFieldValidators(field.id, isKeyUp); + for (var i = 0; i < functions.length; i++) { + var result = functions[i][0].bind(field)(isKeyUp, functions[i][1]); + if (result !== true) { + errors[field.id][$type(result) == 'array' ? 'extend' : 'push'](result); + } + } +} + +/** + * Validates form field and parent fieldset + * + * @param Element field + * @param boolean isKeyUp + */ +function validate_field_and_fieldset(field, isKeyUp) { + var errors = {}; + validate_field(field, isKeyUp, errors); + validate_fieldset(field.getParent('fieldset'), isKeyUp, errors); + displayErrors(errors); +} + +/** + * Marks field depending on its value (system default or custom) + * + * @param Element field + */ +function markField(field) { + var type = getFieldType(field); + var isDefault = checkFieldDefault(field, type); + + // checkboxes uses parent for marking + var fieldMarker = (type == 'checkbox') ? field.getParent() : field; + setRestoreDefaultBtn(field, !isDefault); + fieldMarker[isDefault ? 'removeClass' : 'addClass']('custom'); +} + +/** + * Enables or disables the "restore default value" button + * + * @param Element field + * @param bool display + */ +function setRestoreDefaultBtn(field, display) { + var td = field.getParent('td'); + if (!td) return; + var el = td.getElement('.restore-default'); + if (!el) return; + el.style.display = (display ? '' : 'none'); +} + +window.addEvent('domready', function() { + var elements = $$('input[id], select[id], textarea[id]'); + var elements_count = elements.length; + + // register validators and mark custom values + for (var i = 0; i < elements_count; i++) { + var el = elements[i]; + markField(el); + el.addEvent('change', function(e) { + validate_field_and_fieldset(this, false); + markField(this); + }); + // text fields can be validated after each change + if (el.tagName == 'INPUT' && el.type == 'text') { + el.addEvent('keyup', function(e) { + validate_field_and_fieldset(this, true); + markField(el); + }); + } + // disable textarea spellcheck + if (el.tagName == 'TEXTAREA') { + el.setProperty('spellcheck', false) + } + } + + // check whether we've refreshed a page and browser remembered modified + // form values + var check_page_refresh = $('check_page_refresh'); + if (!check_page_refresh || check_page_refresh.value == '1') { + // run all field validators + var errors = {}; + for (var i = 0; i < elements_count; i++) { + validate_field(elements[i], false, errors); + } + // run all fieldset validators + $$('fieldset').each(function(el){ + validate_fieldset(el, false, errors); + }); + + displayErrors(errors); + } else if (check_page_refresh) { + check_page_refresh.value = '1'; + } +}); + +// +// END: Form validation and field operations +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// Tabbed forms +// + +/** + * Sets active tab + * + * @param Element tab_link + */ +function setTab(tab_link) { + var tabs_menu = tab_link.getParent('.tabs'); + + var links = tabs_menu.getElements('a'); + var contents; + for (var i = 0, imax = links.length; i < imax; i++) { + contents = $(links[i].getProperty('href').substr(1)); + if (links[i] == tab_link) { + links[i].addClass('active'); + contents.style.display = 'block'; + } else { + links[i].removeClass('active'); + contents.style.display = 'none'; + } + } + location.hash = 'tab_' + tab_link.getProperty('href').substr(1); +} + +window.addEvent('domready', function() { + var tabs = $$('.tabs'); + var url_tab = location.hash.match(/^#tab_.+/) + ? $$('a[href$="' + location.hash.substr(5) + '"]') : null; + if (url_tab) { + url_tab = url_tab[0]; + } + // add tabs events and activate one tab (the first one or indicated by location hash) + for (var i = 0, imax = tabs.length; i < imax; i++) { + var links = tabs[i].getElements('a'); + var selected_tab = links[0]; + for (var j = 0, jmax = links.length; j < jmax; j++) { + links[j].addEvent('click', function(e) { + e.stop(); + setTab(this); + }); + if (links[j] == url_tab) { + selected_tab = links[j]; + } + } + setTab(selected_tab); + } + // tab links handling, check each 200ms + // (works with history in FF, further browser support here would be an overkill) + var prev_hash = location.hash; + (function() { + if (location.hash != prev_hash) { + prev_hash = location.hash; + var url_tab = location.hash.match(/^#tab_.+/) + ? $$('a[href$="' + location.hash.substr(5) + '"]') : null; + if (url_tab) { + setTab(url_tab[0]); + } + } + }).periodical(200); +}); + +// +// END: Tabbed forms +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// Form reset buttons +// + +window.addEvent('domready', function() { + var buttons = $$('input[type=button]'); + for (var i = 0, imax = buttons.length; i < imax; i++) { + buttons[i].addEvent('click', function(e) { + var fields = this.getParent('fieldset').getElements('input, select, textarea'); + for (var i = 0, imax = fields.length; i < imax; i++) { + setFieldValue(fields[i], getFieldType(fields[i])); + } + }); + } +}); + +// +// END: Form reset buttons +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// "Restore default" and "set value" buttons +// + +/** + * Restores field's default value + * + * @param String field_id + */ +function restoreField(field_id) { + var field = $(field_id); + if (!field || !$defined(defaultValues[field_id])) { + return; + } + setFieldValue(field, getFieldType(field), defaultValues[field_id]); +} + +window.addEvent('domready', function() { + var buttons = $$('.restore-default, .set-value'); + var fixIE = Browser.Engine.name == 'trident' && Browser.Engine.version == 4; + for (var i = 0, imax = buttons.length; i < imax; i++) { + buttons[i].set('opacity', 0.25); + if (!buttons[i].hasClass('restore-default')) { + // restore-default is handled by markField + buttons[i].style.display = ''; + } + buttons[i].addEvents({ + mouseenter: function(e) {this.set('opacity', 1);}, + mouseleave: function(e) {this.set('opacity', 0.25);}, + click: function(e) { + e.stop(); + var href = this.getProperty('href').substr(1); + var field_id; + if (this.hasClass('restore-default')) { + field_id = href; + restoreField(field_id); + } else { + field_id = href.match(/^[^=]+/)[0]; + var value = href.match(/=(.+)$/)[1]; + setFieldValue($(field_id), 'text', value); + } + $(field_id).fireEvent('change'); + } + }); + // fix IE showing alt text instead of link title + if (fixIE) { + buttons[i].getChildren('img')[0].alt = buttons[i].title; + } + } +}); + +// +// END: "Restore default" and "set value" buttons +// ------------------------------------------------------------------ diff --git a/setup/styles.css b/setup/styles.css new file mode 100644 index 000000000..271a0ded5 --- /dev/null +++ b/setup/styles.css @@ -0,0 +1,379 @@ +/* global styles */ + +body { + padding-bottom: 1em; +} + +img { + border: 0; +} + +a { + color: #004C96; +} + +a:hover, a:active { + color: #000; +} + +h1 { + font-size: 1.5em; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +/* language selection box */ + +#select_lang { + position: absolute; + right: 1em; + top: 1em; +} + +/* menu */ + +#menu { + float: left; + width: 200px; +} + +#menu ul { + margin: 1em 1em 1em 0.5em; + padding: 0 0.5em; + list-style: none; +} + +#menu li a { + padding: 3px; + font-weight: bold; + display: block; + color: #669; + text-decoration: none; + zoom: 1; /* IE fix */ +} + +#menu li a:hover, #menu li a:active { + color: #C00; +} + +/* page contents and footer layout */ + +#page { + margin-left: 200px; +} + +#footer { + margin-top: 1em; +} + +#footer a { + margin-right: 0.5em; + text-decoration: none; + font-size: small; +} + +/* phpMyAdmin logo colors */ + +.blue { + color: #7584B3; +} + +.orange { + color: #FFAD17; +} + +.red { + color: #C00; +} + +/* main page messages */ + +div.notice, div.warning, div.error { + margin: 0.5em 0; + padding: 10px 10px 10px 36px; + border: 1px solid #000; + background: #FFD url(../themes/original/img/b_tipp.png) no-repeat 10px 0.8em; +} + +div.notice h4, div.warning h4, div.error h4 { + font-weight: bold; + font-size: large; + margin: 0 0 0.2em 0; + border-bottom: 1px solid #000; +} + +div.notice { + border-color: #FFD700; + background-color: #FFD; + background-image: url(../themes/original/img/s_notice.png); +} + +div.notice h4 { + border-color: #FFD700; +} + +div.warning { + border-color: #C00; + background-color: #FFC; + background-image: url(../themes/original/img/s_warn.png); +} + +div.warning h4 { + color: #C00; + border-color: #C00; +} + +div.error { + border-color: #D00; + background-color: #FFC; + background-image: url(../themes/original/img/s_errro.png); +} + +div.error h4 { + color: #D00; + border-color: #D00; +} + +/* form tabs */ + +ul.tabs { + margin: 0; + padding: 0 0 7px 0; + list-style: none; + font-weight: bold; +} + +ul.tabs li { + float: left; +} + +ul.tabs li a { + display: block; + margin: 2px 2px 0; + padding: 2px 8px; + background: #DEE1FF; + white-space: nowrap; + text-decoration: none; + border: 1px #9AA4FF solid; + border-bottom: none; +} + +ul.tabs li a:hover, ul.tabs li a:active, ul.tabs li a.active { + margin: 0; + padding: 2px 10px 4px; + background: #F7FBFF; +} + +ul.tabs li a:hover, ul.tabs li a:active { + color: #C00; +} + +.tabs_contents { + border-top: 2px #66B solid; +} + +.tabs_contents fieldset { + margin-top: 0; + border-top: none; +} + +.tabs_contents legend { + display: none; +} + +/* "restore default value" and "set value: foo" buttons */ + +.restore-default img, .set-value img { + margin-bottom: -3px; +} + +/* forms */ + +fieldset { + padding: 0; + margin-top: 1em; + border: 2px #DEE1FF solid; + background: #DEE1FF; +} + +.form { + border: 2px #DEE1FF solid; +} + +fieldset legend { + margin-left: 1em; + padding: 2px 8px; + font-weight: bold; + background: #F7FBFF; + border: 1px #9AA4FF solid; +} + +fieldset p { + margin: 0; + padding: 0.5em; + background: #DEE1FF; +} + +fieldset .errors { /* form error list */ + margin: 0 -2px 1em -2px; + padding: 0.5em 1.5em; + background: #FBEAD9; + border: 1px #C83838 solid; + border-width: 1px 0; + list-style: none; + font-family: sans-serif; + font-size: small; +} + +fieldset .inline_errors { /* field error list */ + margin: 0.3em 0.3em 0.3em 0; + padding: 0; + list-style: none; + color: #9A0000; +} + +fieldset table { + background: #FFF; +} + +fieldset th { + width: 40%; + min-width: 350px; + padding: 0.3em 0.3em 0.3em 0.5em; + text-align: left; + vertical-align: top; +} + +fieldset th small { + display: block; +} + +fieldset .doc { + margin-left: 1em; +} + +fieldset td { + padding-top: 0.3em; + vertical-align: top; +} + +fieldset th small { + font-weight: normal; + font-family: sans-serif; + font-size: x-small; + color: #666; +} + +fieldset th, fieldset td { + border-top: 1px #555 dotted; +} + +fieldset .lastrow, .form .lastrow { + background: #F7FBFF; + padding: 0.5em; + text-align: center; +} + +.form .lastrow { + border-top: 1px #555 dotted; +} + +fieldset .lastrow input, .form .lastrow input { + font-weight: bold; +} + +/* simple form, without header and legend */ + +fieldset.simple { + border-top-color: #DEE1FF; +} + +fieldset.simple legend { + display: none; +} + +fieldset.simple th, fieldset.simple td { + border-top: none; + border-bottom: 1px #555 dotted; +} + +fieldset.simple .lastrow { + border: 0; +} + +/* form elements */ + +span.checkbox { + padding: 2px; +} + +.custom { /* customized field */ + background: #FFC; +} + +span.checkbox.custom { + padding: 1px; + border: 1px #EDEC90 solid; + background: #FFC; +} + +input[type="text"], select, textarea { + border: 1px #A7A6AA solid; +} + +input[type="text"]:focus, select:focus, textarea:focus { + border: 1px #6676FF solid; + background: #F7FBFF; +} + +.green { /* default form button */ + color: #080; +} + +table.datatable { + margin: 0.5em 0 1em; +} + +table.datatable th { + padding: 0 1em 0 0.5em; + border-bottom: 2px #66F solid; + text-align: left; +} + +table.datatable td { + padding: 1px 0.5em; + border-bottom: 1px #DEE1FF solid; +} + +/* textarea with config file's contents */ + +#textconfig { + width: 100%; + border: 0; +} + +/* error list */ + +dd { + margin-left: 0.5em; +} + +dd:before { + content: "\25B8 "; +} + +/* links on failed validation page, when saving a form */ + +a.btn { + padding: 1px 5px; + text-decoration: none; + background: #E2E8FF; + border: 1px #A6C8FF solid; + border-top-color: #AFD0FF; + border-left-color: #AFD0FF; + font-weight: bold; +} + +a.btn:hover, a.btn:active { + background: #E6F5FF; + color: #004C96; +} diff --git a/setup/validate.php b/setup/validate.php new file mode 100644 index 000000000..f1d03d838 --- /dev/null +++ b/setup/validate.php @@ -0,0 +1,20 @@ + \ No newline at end of file