1) Show gacl status output
[openemr.git] / phpmyadmin / scripts / setup.php
blob16a9a2aaa9430504dc4dc76538ec06efe35c5cf9
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * phpMyAdmin setup script
6 * PHP versions 4 and 5
8 * @category Setup
9 * @package phpMyAdmin-setup
10 * @author Michal Čihař <michal@cihar.com>
11 * @copyright 2006 Michal Čihař <michal@cihar.com>
12 * @license http://www.gnu.org/licenses/gpl.html GNU GPL 2.0
13 * @version $Id$
16 // Grab phpMyAdmin version and PMA_dl function
17 define('PMA_MINIMUM_COMMON', TRUE);
18 define('PMA_SETUP', TRUE);
19 chdir('..');
20 require_once './libraries/common.inc.php';
22 // Grab configuration defaults
23 // Do not use $PMA_Config, it interferes with the one in $_SESSION
24 // on servers with register_globals enabled
25 $PMA_Config_Setup = new PMA_Config();
27 // Script information
28 $script_info = 'phpMyAdmin ' . $PMA_Config_Setup->get('PMA_VERSION') . ' setup script by Michal Čihař <michal@cihar.com>';
29 $script_version = '$Id$';
31 // Grab action
32 if (isset($_POST['action'])) {
33 $action = $_POST['action'];
34 } else {
35 $action = '';
38 // Grab wanted CRLF type
39 if (isset($_POST['eoltype'])) {
40 $eoltype = $_POST['eoltype'];
41 } else {
42 if (PMA_USR_OS == 'Win') {
43 $eoltype = 'dos';
44 } else {
45 $eoltype = 'unix';
49 // Detect which CRLF to use
50 if ($eoltype == 'dos') {
51 $crlf = "\r\n";
52 } elseif ($eoltype == 'mac') {
53 $crlf = "\r";
54 } else {
55 $crlf = "\n";
58 if (isset($_POST['configuration']) && $action != 'clear') {
59 // Grab previous configuration, if it should not be cleared
60 $configuration = unserialize($_POST['configuration']);
61 } else {
62 // Start with empty configuration
63 $configuration = array();
66 // We rely on Servers array to exist, so create it here
67 if (!isset($configuration['Servers']) || !is_array($configuration['Servers'])) {
68 $configuration['Servers'] = array();
71 // Used later
72 $now = gmdate('D, d M Y H:i:s') . ' GMT';
74 // General header for no caching
75 header('Expires: ' . $now); // rfc2616 - Section 14.21
76 header('Last-Modified: ' . $now);
77 header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); // HTTP/1.1
78 header('Pragma: no-cache'); // HTTP/1.0
80 // whether to show html header?
81 if ($action != 'download') {
83 // Define the charset to be used
84 header('Content-Type: text/html; charset=utf-8');
86 // this needs to be echoed otherwise php with short tags complains
87 echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
89 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
90 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
91 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
92 <head>
93 <link rel="icon" href="../favicon.ico" type="image/x-icon" />
94 <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
95 <title>phpMyAdmin <?php echo $PMA_Config_Setup->get('PMA_VERSION'); ?> setup</title>
96 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
98 <script type="text/javascript">
99 //<![CDATA[
100 // show this window in top frame
101 if (top != self) {
102 window.top.location.href=location;
104 //]]>
105 </script>
106 <style type="text/css">
107 /* message boxes: warning, error, stolen from original theme */
108 div.notice {
109 color: #000000;
110 background-color: #FFFFDD;
112 h1.notice,
113 div.notice {
114 margin: 0.5em 0 0.5em 0;
115 border: 0.1em solid #FFD700;
116 background-image: url(../<?php echo $GLOBALS['cfg']['ThemePath']; ?>/original/img/s_notice.png);
117 background-repeat: no-repeat;
118 background-position: 10px 50%;
119 padding: 10px 10px 10px 36px;
121 div.notice h1 {
122 border-bottom: 0.1em solid #FFD700;
123 font-weight: bold;
124 font-size: large;
125 text-align: left;
126 margin: 0 0 0.2em 0;
129 div.warning {
130 color: #CC0000;
131 background-color: #FFFFCC;
133 h1.warning,
134 div.warning {
135 margin: 0.5em 0 0.5em 0;
136 border: 0.1em solid #CC0000;
137 background-image: url(../<?php echo $GLOBALS['cfg']['ThemePath']; ?>/original/img/s_warn.png);
138 background-repeat: no-repeat;
139 background-position: 10px 50%;
140 padding: 10px 10px 10px 36px;
142 div.warning h1 {
143 border-bottom: 0.1em solid #cc0000;
144 font-weight: bold;
145 text-align: left;
146 font-size: large;
147 margin: 0 0 0.2em 0;
150 div.error {
151 background-color: #FFFFCC;
152 color: #ff0000;
154 h1.error,
155 div.error {
156 margin: 0.5em 0 0.5em 0;
157 border: 0.1em solid #ff0000;
158 background-image: url(../<?php echo $GLOBALS['cfg']['ThemePath']; ?>/original/img/s_error.png);
159 background-repeat: no-repeat;
160 background-position: 10px 50%;
161 padding: 10px 10px 10px 36px;
163 div.error h1 {
164 border-bottom: 0.1em solid #ff0000;
165 font-weight: bold;
166 text-align: left;
167 font-size: large;
168 margin: 0 0 0.2em 0;
171 fieldset.toolbar form.action {
172 display: block;
173 width: auto;
174 clear: none;
175 float: left;
176 margin: 0;
177 padding: 0;
178 border-right: 1px solid black;
180 fieldset.toolbar form.action input, fieldset.toolbar form.action select {
181 margin: 0.7em;
182 padding: 0.1em;
185 fieldset.toolbar {
186 display: block;
187 width: 100%;
188 background-color: #dddddd;
189 padding: 0;
191 fieldset.optbox {
192 padding: 0;
193 background-color: #FFFFDD;
195 div.buttons, div.opts, fieldset.optbox p, fieldset.overview div.row {
196 clear: both;
197 padding: 0.5em;
198 margin: 0;
199 background-color: white;
201 div.opts, fieldset.optbox p, fieldset.overview div.row {
202 border-bottom: 1px dotted black;
204 fieldset.overview {
205 display: block;
206 width: 100%;
207 padding: 0;
209 fieldset.optbox p {
210 background-color: #FFFFDD;
212 div.buttons {
213 background-color: #dddddd;
215 div.buttons input {
216 margin: 0 1em 0 1em;
218 div.buttons form {
219 display: inline;
220 margin: 0;
221 padding: 0;
223 input.save {
224 color: green;
225 font-weight: bolder;
227 input.cancel {
228 color: red;
229 font-weight: bolder;
231 div.desc, label.desc, fieldset.overview div.desc {
232 float: left;
233 width: 27em;
234 max-width: 60%;
236 code:before, code:after {
237 content: '"';
239 span.doc {
240 margin: 0 1em 0 1em;
242 span.doc a {
243 margin: 0 0.1em 0 0.1em;
245 span.doc a img {
246 border: none;
248 </style>
249 </head>
251 <body>
252 <h1>phpMyAdmin <?php echo $PMA_Config_Setup->get('PMA_VERSION'); ?> setup</h1>
253 <?php
254 } // end show html header
257 * Calculates numerical equivalent of phpMyAdmin version string
259 * @param string version
261 * @return mixed FALSE on failure, integer on success
263 function version_to_int($version) {
264 if (!preg_match('/^(\d+)\.(\d+)\.(\d+)((\.|-(pl|rc|dev|beta|alpha))(\d+)?)?$/', $version, $matches)) {
265 return FALSE;
267 if (!empty($matches[6])) {
268 switch ($matches[6]) {
269 case 'pl':
270 $added = 60;
271 break;
272 case 'rc':
273 $added = 30;
274 break;
275 case 'beta':
276 $added = 20;
277 break;
278 case 'alpha':
279 $added = 10;
280 break;
281 case 'dev':
282 $added = 0;
283 break;
284 default:
285 message('notice', 'Unknown version part: ' . htmlspecialchars($matches[5]));
286 $added = 0;
287 break;
289 } else {
290 $added = 50; // for final
292 if (!empty($matches[7])) {
293 $added = $added + $matches[7];
295 return $matches[1] * 1000000 + $matches[2] * 10000 + $matches[3] * 100 + $added;
299 * Returns link to documentation of some configuration directive
301 * @param string confguration directive name
303 * @return string HTML link to documentation
305 function get_cfg_doc($anchor) {
306 /* Link for wiki */
307 $wiki = $anchor;
308 if (strncmp($anchor, 'Servers_', 8) == 0) {
309 $wiki = substr($anchor, 8);
311 return
312 '<span class="doc">' .
313 '<a href="../Documentation.html#cfg_' . $anchor . '" target="pma_doc" class="doc">' .
314 '<img class="icon" src="../' . $GLOBALS['cfg']['ThemePath'] . '/original/img/b_help.png" width="11" height="11" alt="Documentation" title="Documentation" />' .
315 '</a>' .
316 '<a href="http://wiki.phpmyadmin.net/pma/Config#' . $wiki . '" target="pma_doc" class="doc">' .
317 '<img class="icon" src="../' . $GLOBALS['cfg']['ThemePath'] . '/original/img/b_info.png" width="11" height="11" alt="Wiki" title="Wiki" />' .
318 '</a>' .
319 '</span>'
324 * Displays message
326 * @param string type of message (notice/warning/error)
327 * @param string text of message
328 * @param title optional title of message
330 * @return nothing
332 function message($type, $text, $title = '') {
333 echo '<div class="' . $type . '">' . "\n";
334 if (!empty($title)) {
335 echo '<h1>';
336 echo $title;
337 echo '</h1>' . "\n";
339 echo $text . "\n";
340 echo '</div>' . "\n";
344 * Creates hidden input required for keeping current configuraion
346 * @return string HTML with hidden inputs
348 function get_hidden_cfg() {
349 global $configuration, $eoltype;
351 $ret = '<input type="hidden" name="configuration" value="' . htmlspecialchars(serialize($configuration)) . '" />' . "\n";
352 $ret .= '<input type="hidden" name="eoltype" value="' . htmlspecialchars($eoltype) . '" />' . "\n";
354 return $ret;
358 * Returns needed hidden input for forms.
360 * @return string HTML with hidden inputs
362 function get_hidden_inputs() {
363 return '<input type="hidden" name="token" value="' . $_SESSION[' PMA_token '] . '" />';
367 * Creates form for some action
369 * @param string action name
370 * @param string form title
371 * @param string optional additional inputs
373 * @return string HTML with form
375 function get_action($name, $title, $added = '', $enabled = TRUE) {
376 $ret = '';
377 $ret .= '<form class="action" method="post" action="">';
378 $ret .= get_hidden_inputs();
379 $ret .= '<input type="hidden" name="action" value="' . $name . '" />';
380 $ret .= $added;
381 $ret .= '<input type="submit" value="' . $title . '"';
382 if (!$enabled) {
383 $ret .= ' disabled="disabled"';
385 $ret .= ' />';
386 $ret .= get_hidden_cfg();
387 $ret .= '</form>';
388 $ret .= "\n";
389 return $ret;
393 * Creates form for going to some url
395 * @param string URL where to go
396 * @param string form title
397 * @param string optional array of parameters
399 * @return string HTML with form
401 function get_url_action($url, $title, $params = array()) {
402 $ret = '';
403 $ret .= '<form class="action" method="get" action="' . $url . '" target="_blank">';
404 $ret .= get_hidden_inputs();
405 foreach ($params as $key => $val) {
406 $ret .= '<input type="hidden" name="' . $key . '" value="' . $val . '" />';
408 $ret .= '<input type="submit" value="' . $title . '" />';
409 $ret .= '</form>';
410 $ret .= "\n";
411 return $ret;
415 * Terminates script and ends HTML
417 * @return nothing
419 function footer() {
420 echo '</body>';
421 echo '</html>';
422 exit;
426 * Creates string describing server authentication method
428 * @param array server configuration
430 * @return string authentication method description
432 function get_server_auth($val) {
433 global $PMA_Config_Setup;
435 if (isset($val['auth_type'])) {
436 $auth = $val['auth_type'];
437 } else {
438 $auth = $PMA_Config_Setup->default_server['auth_type'];
440 $ret = $auth;
441 if ($auth == 'config') {
442 if (isset($val['user'])) {
443 $ret .= ':' . $val['user'];
444 } else {
445 $ret .= ':' . $PMA_Config_Setup->default_server['user'];
448 return $ret;
452 * Creates nice string with server name
454 * @param array server configuration
455 * @param int optional server id
457 * @return string fancy server name
459 function get_server_name($val, $id = FALSE, $escape = true) {
460 if (!empty($val['verbose'])) {
461 $ret = $val['verbose'];
462 } else {
463 $ret = $val['host'];
465 $ret .= ' (' . get_server_auth($val) . ')';
466 if ($id !== FALSE) {
467 $ret .= ' [' . ($id + 1) . ']' ;
469 if ($escape) {
470 return htmlspecialchars($ret);
471 } else {
472 return $ret;
478 * Exports variable to PHP code, very limited version of var_export
480 * @param string data to export
482 * @see var_export
484 * @return string PHP code containing variable value
486 function PMA_var_export($input) {
487 global $crlf;
489 $output = '';
490 if (is_null($input)) {
491 $output .= 'NULL';
492 } elseif (is_array($input)) {
493 $output .= 'array (' . $crlf;
494 foreach($input as $key => $value) {
495 $output .= PMA_var_export($key) . ' => ' . PMA_var_export($value);
496 $output .= ',' . $crlf;
498 $output .= ')';
499 } elseif (is_string($input)) {
500 $output .= '\'' . addslashes($input) . '\'';
501 } elseif (is_int($input) || is_double($input)) {
502 $output .= (string) $input;
503 } elseif (is_bool($input)) {
504 $output .= $input ? 'true' : 'false';
505 } else {
506 die('Unknown type for PMA_var_export: ' . $input);
508 return $output;
512 * Creates configuration code for one variable
514 * @param string variable name
515 * @param mixed configuration
517 * @return string PHP code containing configuration
519 function get_cfg_val($name, $val) {
520 global $crlf;
522 $ret = '';
523 if (is_array($val)) {
524 $ret .= $crlf;
525 foreach ($val as $k => $v) {
526 if (!isset($type)) {
527 if (is_string($k)) {
528 $type = 'string';
529 } elseif (is_int($k)) {
530 $type = 'int';
531 $ret .= $name . ' = array(' . $crlf;
532 } else {
533 // Something unknown...
534 $ret .= $name. ' = ' . PMA_var_export($val) . ';' . $crlf;
535 break;
538 if ($type == 'string') {
539 $ret .= get_cfg_val($name . "['$k']", $v);
540 } elseif ($type == 'int') {
541 $ret .= ' ' . PMA_var_export($v) . ',' . $crlf;
544 if (!isset($type)) {
545 /* Empty array */
546 $ret .= $name . ' = array();' . $crlf;
547 } elseif ($type == 'int') {
548 $ret .= ');' . $crlf;
550 $ret .= $crlf;
551 unset($type);
552 } else {
553 $ret .= $name . ' = ' . PMA_var_export($val) . ';' . $crlf;
555 return $ret;
559 * Creates configuration PHP code
561 * @param array configuration
563 * @return string PHP code containing configuration
565 function get_cfg_string($cfg) {
566 global $script_info, $script_version, $now, $crlf;
568 $c = $cfg;
569 $ret = "<?php$crlf/*$crlf * Generated configuration file$crlf * Generated by: $script_info$crlf * Version: $script_version$crlf * Date: " . $now . $crlf . ' */' . $crlf . $crlf;
571 if (count($c['Servers']) > 0) {
572 $ret .= "/* Servers configuration */$crlf\$i = 0;" . $crlf;
573 foreach ($c['Servers'] as $cnt => $srv) {
574 $ret .= $crlf . '/* Server ' . strtr(get_server_name($srv, $cnt, false), '*', '-') . " */$crlf\$i++;" . $crlf;
575 foreach ($srv as $key => $val) {
576 $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
577 $ret .= get_cfg_val("\$cfg['Servers'][\$i]['$key']", $val);
580 $ret .= $crlf . '/* End of servers configuration */' . $crlf . $crlf;
582 unset($c['Servers']);
584 foreach ($c as $key => $val) {
585 $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
586 $ret .= get_cfg_val("\$cfg['$key']", $val);
589 $ret .= '?>' . $crlf;
590 return $ret;
594 * Compresses server configuration to be indexed from 0 and contain no gaps
596 * @param array configuration
598 * @return nothing
600 function compress_servers(&$cfg) {
601 $ns = array();
602 foreach ($cfg['Servers'] as $val) {
603 if (!empty($val['host'])) {
604 $ns[] = $val;
607 $cfg['Servers'] = $ns;
611 * Grabs values from POST
613 * @param string list of values to grab, values are separated by ";",
614 * each can have defined type separated by ":", if no type
615 * is defined, string is assumed. Possible types: bool -
616 * boolean value, serialized - serialized value, int -
617 * integer, tristate - "TRUE"/"FALSE" converted to bool,
618 * other strings are kept.
620 * @return array array with grabbed values
622 function grab_values($list)
624 $a = split(';', $list);
625 $res = array();
626 foreach ($a as $val) {
627 $v = split(':', $val);
628 if (!isset($v[1])) {
629 $v[1] = '';
631 switch($v[1]) {
632 case 'bool':
633 $res[$v[0]] = isset($_POST[$v[0]]);
634 break;
635 case 'serialized':
636 if (isset($_POST[$v[0]]) && strlen($_POST[$v[0]]) > 0) {
637 $res[$v[0]] = unserialize($_POST[$v[0]]);
639 break;
640 case 'int':
641 if (isset($_POST[$v[0]]) && strlen($_POST[$v[0]]) > 0) {
642 $res[$v[0]] = (int)$_POST[$v[0]];
644 break;
645 case 'tristate':
646 if (isset($_POST[$v[0]]) && strlen($_POST[$v[0]]) > 0) {
647 $cur = $_POST[$v[0]];
648 if ($cur == 'TRUE') {
649 $res[$v[0]] = TRUE;
650 } elseif ($cur == 'FALSE') {
651 $res[$v[0]] = FALSE;
652 } else {
653 $res[$v[0]] = $cur;
656 break;
657 case 'string':
658 default:
659 if (isset($_POST[$v[0]]) && strlen($_POST[$v[0]]) > 0) {
660 $res[$v[0]] = $_POST[$v[0]];
662 break;
665 return $res;
669 * Displays overview
671 * @param string title of oveview
672 * @param array list of values to display (each element is array of two
673 * values - name and value)
674 * @param string optional buttons to be displayed
676 * @return nothing
678 function show_overview($title, $list, $buttons = '') {
679 echo '<fieldset class="overview">' . "\n";
680 echo '<legend>' . $title . '</legend>' . "\n";
681 foreach ($list as $val) {
682 echo '<div class="row">';
683 echo '<div class="desc">';
684 echo $val[0];
685 echo '</div>';
686 echo '<div class="data">';
687 echo htmlspecialchars($val[1]);
688 echo '</div>';
689 echo '</div>' . "\n";
691 if (!empty($buttons)) {
692 echo '<div class="buttons">';
693 echo '<div class="desc">Actions:</div>';
694 echo $buttons;
695 echo '</div>' . "\n";
697 echo '</fieldset>' . "\n";
698 echo "\n";
702 * Displays configuration, fallback defaults are taken from global $PMA_Config_Setup
704 * @param array list of values to display (each element is array of two or
705 * three values - desription, name and optional type
706 * indicator). Type is determined by type of this parameter,
707 * array means select and array elements are items,
708 * 'password' means password input.
709 * @param string title of configuration
710 * @param string help string for this configuration
711 * @param array optional first level defaults
712 * @param string optional title for save button
713 * @param string optional prefix for documentation links
715 * @return nothing
717 function show_config_form($list, $legend, $help, $defaults = array(), $save = '', $prefix = '') {
718 global $PMA_Config_Setup;
720 if (empty($save)) {
721 $save = 'Update';
724 echo '<fieldset class="optbox">' . "\n";
725 echo '<legend>' . $legend . '</legend>' . "\n";
726 echo '<p>' . $help . '</p>' . "\n";
727 foreach ($list as $val) {
728 echo '<div class="opts">';
729 $type = 'text';
730 if (isset($val[3])) {
731 if (is_array($val[3])) {
732 $type = 'select';
733 } elseif (is_bool($val[3])) {
734 $type = 'check';
735 } elseif ($val[3] == 'password') {
736 $type = 'password';
739 switch ($type) {
740 case 'text':
741 case 'password':
742 echo '<label for="text_' . $val[1] . '" class="desc" title="' . $val[2] . '">' . $val[0] . get_cfg_doc($prefix . $val[1]) . '</label>';
743 echo '<input type="' . $type . '" name="' . $val[1] . '" id="text_' . $val[1] . '" title="' . $val[2] . '" size="50"';
744 if (isset($defaults[$val[1]])) {
745 echo ' value="' . htmlspecialchars($defaults[$val[1]]) . '"';
746 } else {
747 echo ' value="' . htmlspecialchars($PMA_Config_Setup->get($val[1])) . '"';
749 echo ' />';
750 break;
751 case 'check':
752 echo '<input type="checkbox" name="' . $val[1] . '" value="something" id="checkbox_' . $val[1] . '" title="' . $val[2] . '"';
753 if (isset($defaults[$val[1]])) {
754 if ($defaults[$val[1]]) {
755 echo ' checked="checked"';
757 } else {
758 if ($PMA_Config_Setup->get($val[1])) {
759 echo ' checked="checked"';
762 echo ' />';
763 echo '<label for="checkbox_' . $val[1] . '" title="' . $val[2] . '">' . $val[0] . get_cfg_doc($prefix . $val[1]) . '</label>';
764 break;
765 case 'select':
766 echo '<label for="select_' . $val[1] . '" class="desc" title="' . $val[2] . '">' . $val[0] . get_cfg_doc($prefix . $val[1]) . '</label>';
767 echo '<select name="' . $val[1] . '" id="select_' . $val[1] . '" ' . ' title="' . $val[2] . '">';
768 foreach ($val[3] as $opt) {
769 echo '<option value="' . $opt . '"';
770 if (isset($defaults[$val[1]])) {
771 if (is_bool($defaults[$val[1]])) {
772 if (($defaults[$val[1]] && $opt == 'TRUE') || (!$defaults[$val[1]] && $opt == 'FALSE')) {
773 echo ' selected="selected"';
775 } else {
776 if ($defaults[$val[1]] == $opt) {
777 echo ' selected="selected"';
780 } else {
781 $def_val = $PMA_Config_Setup->get($val[1]);
782 if (is_bool($val)) {
783 if (($def_val && $opt == 'TRUE') || (!$def_val && $opt == 'FALSE')) {
784 echo ' selected="selected"';
786 } else {
787 if ($def_val == $opt) {
788 echo ' selected="selected"';
791 unset($def_val);
793 echo '>' . $opt . '</option>';
795 echo '</select>';
796 break;
798 echo '</div>' . "\n";
800 echo '<div class="buttons">';
801 echo '<div class="desc">Actions:</div>';
802 echo '<input type="submit" name="submit_save" value="' . $save .'" class="save" />';
803 echo '<input type="submit" name="submit_ignore" value="Cancel" class="cancel" />';
804 echo '</div>' . "\n";
805 echo '</fieldset>' . "\n";
806 echo "\n";
810 * Shows security options configuration form
812 * @param array optional defaults
814 * @return nothing
816 function show_security_form($defaults = array()) {
818 <form method="post" action="">
819 <?php echo get_hidden_inputs();?>
820 <input type="hidden" name="action" value="feat_security_real" />
821 <?php
822 echo get_hidden_cfg();
823 show_config_form(array(
824 array('Blowfish secret', 'blowfish_secret', 'Secret passphrase used for encrypting cookies'),
825 array('Force SSL connection', 'ForceSSL', 'Whether to force using secured connection while using phpMyAdmin', FALSE),
826 array('Show phpinfo output', 'ShowPhpInfo', 'Whether to allow users to see phpinfo() output', FALSE),
827 array('Show password change form', 'ShowChgPassword', 'Whether to show form for changing password, this does not limit ability to execute the same command directly', FALSE),
828 array('Allow login to any MySQL server', 'AllowArbitraryServer', 'If enabled user can enter any MySQL server in login form for cookie auth.', FALSE),
829 array('Recall user name', 'LoginCookieRecall', 'Whether to recall user name on log in prompt while using cookie auth.', TRUE),
830 array('Login cookie validity', 'LoginCookieValidity', 'How long is login valid without performing any action.'),
832 'Configure security features',
833 'Please note that phpMyAdmin is just a user interface and it\'s features do not limit MySQL.',
834 $defaults);
836 </form>
837 <?php
841 * Shows MySQL manual configuration form
843 * @param array optional defaults
845 * @return nothing
847 function show_manual_form($defaults = array()) {
849 <form method="post" action="">
850 <?php echo get_hidden_inputs();?>
851 <input type="hidden" name="action" value="feat_manual_real" />
852 <?php
853 echo get_hidden_cfg();
854 show_config_form(array(
855 array('Type of MySQL documentation', 'MySQLManualType', 'These types are same as listed on MySQL download page', array('viewable', 'chapters', 'big', 'none')),
856 array('Base URL of MySQL documentation', 'MySQLManualBase', 'Where is MySQL documentation placed, this is usually top level directory.'),
858 'Configure MySQL manual links',
859 'If you have local copy of MySQL documentation, you might want to use it in documentation links. Otherwise use <code>viewable</code> type and <code>http://dev.mysql.com/doc/refman</code> as manual base URL.',
860 $defaults);
862 </form>
863 <?php
867 * Shows charset options configuration form
869 * @param array optional defaults
871 * @return nothing
873 function show_charset_form($defaults = array()) {
874 global $PMA_Config_Setup;
876 <form method="post" action="">
877 <?php echo get_hidden_inputs();?>
878 <input type="hidden" name="action" value="feat_charset_real" />
879 <?php
880 echo get_hidden_cfg();
881 show_config_form(array(
882 array('Allow charset conversion', 'AllowAnywhereRecoding', 'If you want to use such functions.', FALSE),
883 array('Default charset', 'DefaultCharset', 'Default charset for conversion.', $PMA_Config_Setup->get('AvailableCharsets')),
884 array('Recoding engine', 'RecodingEngine', 'PHP can contain iconv and/or recode, select which one to use or keep autodetection.', array('auto', 'iconv', 'recode')),
885 array('Extra params for iconv', 'IconvExtraParams', 'Iconv can get some extra parameters for conversion see man iconv_open.'),
887 'Configure charset conversions',
888 'phpMyAdmin can perform charset conversions so that you can import and export in any charset you want.',
889 $defaults);
891 </form>
892 <?php
896 * Shows PHP extensions configuration form
898 * @param array optional defaults
900 * @return nothing
902 function show_extensions_form($defaults = array()) {
904 <form method="post" action="">
905 <?php echo get_hidden_inputs();?>
906 <input type="hidden" name="action" value="feat_extensions_real" />
907 <?php
908 echo get_hidden_cfg();
909 show_config_form(array(
910 array('GD 2 is available', 'GD2Available', 'Whether you have GD 2 or newer installed', array('auto', 'yes', 'no')),
912 'Configure extensions',
913 'phpMyAdmin can use several extensions, however here are configured only those that didn\'t fit elsewhere. MySQL extension is configured within server, charset conversion one on separate charsets page.',
914 $defaults);
916 </form>
917 <?php
921 * Shows MIME/relation/history configuration form
923 * @param array optional defaults
925 * @return nothing
927 function show_relation_form($defaults = array()) {
928 global $PMA_Config_Setup;
930 <form method="post" action="">
931 <?php echo get_hidden_inputs();?>
932 <input type="hidden" name="action" value="feat_relation_real" />
933 <?php
934 echo get_hidden_cfg();
935 show_config_form(array(
936 array('Permanent query history', 'QueryHistoryDB', 'Store history into database.', FALSE),
937 array('Maximal history size', 'QueryHistoryMax', 'How many queries are kept in history.'),
938 array('Use MIME transformations', 'BrowseMIME', 'Use MIME transformations while browsing.', TRUE),
939 array('PDF default page size', 'PDFDefaultPageSize', 'Default page size for PDF, you can change this while creating page.', $PMA_Config_Setup->get('PDFPageSizes')),
941 'Configure MIME/relation/history',
942 'phpMyAdmin can provide additional features like MIME transformation, internal relations, permanent history and PDF pages generation. You have to configure the database and tables that will store this information on the server page. Behaviour of those functions is configured here.',
943 $defaults);
945 </form>
946 <?php
950 * Shows upload/save configuration form
952 * @param array optional defaults
954 * @return nothing
956 function show_upload_form($defaults = array()) {
958 <form method="post" action="">
959 <?php echo get_hidden_inputs();?>
960 <input type="hidden" name="action" value="feat_upload_real" />
961 <?php
962 echo get_hidden_cfg();
963 show_config_form(array(
964 array('Upload directory', 'UploadDir', 'Directory on server where you can upload files for import'),
965 array('Save directory', 'SaveDir', 'Directory where exports can be saved on server'),
967 'Configure upload/save directories',
968 'Enter directories, either absolute path or relative to phpMyAdmin top level directory.',
969 $defaults);
971 </form>
972 <?php
976 * Shows server configuration form
978 * @param array optional defaults
980 * @return nothing
982 function show_server_form($defaults = array(), $number = FALSE) {
984 <form method="post" action="">
985 <?php echo get_hidden_inputs();?>
986 <input type="hidden" name="action" value="addserver_real" />
987 <?php
988 echo get_hidden_cfg();
989 if (!($number === FALSE)) {
990 echo '<input type="hidden" name="server" value="' . $number . '" />';
992 $hi = array ('bookmarktable', 'relation', 'table_info', 'table_coords', 'pdf_pages', 'column_info', 'designer_coords', 'history', 'AllowDeny');
993 foreach ($hi as $k) {
994 if (isset($defaults[$k]) && (!is_string($defaults[$k]) || strlen($defaults[$k]) > 0)) {
995 echo '<input type="hidden" name="' . $k . '" value="' . htmlspecialchars(serialize($defaults[$k])) . '" />';
998 show_config_form(array(
999 array('Server hostname', 'host', 'Hostname where MySQL server is running'),
1000 array('Server port', 'port', 'Port on which MySQL server is listening, leave empty for default'),
1001 array('Server socket', 'socket', 'Socket on which MySQL server is listening, leave empty for default'),
1002 array('Connection type', 'connect_type', 'How to connect to server, keep tcp if unsure', array('tcp', 'socket')),
1003 array('PHP extension to use', 'extension', 'What PHP extension to use, use mysqli if supported', array('mysql', 'mysqli')),
1004 array('Compress connection', 'compress', 'Whether to compress connection to MySQL server', FALSE),
1005 array('Authentication type', 'auth_type', 'Authentication method to use', array('cookie', 'http', 'config', 'signon')),
1006 array('User for config auth', 'user', 'Leave empty if not using config auth'),
1007 array('Password for config auth', 'password', 'Leave empty if not using config auth', 'password'),
1008 array('Only database to show', 'only_db', 'Limit listing of databases in left frame to this one'),
1009 array('Verbose name of this server', 'verbose', 'Name to display in server selection'),
1010 array('phpMyAdmin control user', 'controluser', 'User which phpMyAdmin can use for various actions'),
1011 array('phpMyAdmin control user password', 'controlpass', 'Password for user which phpMyAdmin can use for various actions', 'password'),
1012 array('phpMyAdmin database for advanced features', 'pmadb', 'phpMyAdmin will allow much more when you enable this. Table names are filled in automatically.'),
1013 array('Session name for signon auth', 'SignonSession', 'Leave empty if not using signon auth'),
1014 array('Login URL for signon auth', 'SignonURL', 'Leave empty if not using signon auth'),
1015 array('Logout URL', 'LogoutURL', 'Where to redirect user after logout'),
1017 'Configure server',
1018 ($number === FALSE) ? 'Enter new server connection parameters.' : 'Editing server ' . get_server_name($defaults, $number),
1019 $defaults, $number === FALSE ? 'Add' : '', 'Servers_');
1021 </form>
1022 <?php
1026 * Shows left frame configuration form
1028 * @param array optional defaults
1030 * @return nothing
1032 function show_left_form($defaults = array()) {
1034 <form method="post" action="">
1035 <?php echo get_hidden_inputs();?>
1036 <input type="hidden" name="action" value="lay_navigation_real" />
1037 <?php
1038 echo get_hidden_cfg();
1039 show_config_form(array(
1040 array('Use light version', 'LeftFrameLight', 'Disable this if you want to see all databases at one time.', TRUE),
1041 array('Display databases in tree', 'LeftFrameDBTree', 'Whether to display databases in tree (determined by separator defined lower)', TRUE),
1042 array('Databases tree separator', 'LeftFrameDBSeparator', 'String that separates databases into different tree level'),
1043 array('Table tree separator', 'LeftFrameTableSeparator', 'String that separates tables into different tree level'),
1044 array('Maximum table tree nesting', 'LeftFrameTableLevel', 'Maximum number of children in table tree'),
1045 array('Show logo', 'LeftDisplayLogo', 'Whether to show logo in left frame', TRUE),
1046 array('Display servers selection', 'LeftDisplayServers', 'Whether to show server selection in left frame', FALSE),
1047 array('Display servers as list', 'DisplayServersList', 'Whether to show server listing as list instead of drop down', FALSE),
1048 array('Display databases as list', 'DisplayDatabasesList', 'Whether to show database listing in navigation as list instead of drop down', array('auto', 'yes', 'no')),
1049 array('Enable pointer highlighting', 'LeftPointerEnable', 'Whether you want to highlight server under mouse', TRUE),
1051 'Configure navigation frame',
1052 'Customize the appears of the navigation frame.',
1053 $defaults);
1055 </form>
1056 <?php
1060 * Shows tabs configuration form
1062 * @param array optional defaults
1064 * @return nothing
1066 function show_tabs_form($defaults = array()) {
1068 <form method="post" action="">
1069 <?php echo get_hidden_inputs();?>
1070 <input type="hidden" name="action" value="lay_tabs_real" />
1071 <?php
1072 echo get_hidden_cfg();
1073 show_config_form(array(
1074 array('Default tab for server', 'DefaultTabServer', 'Tab that is displayed when entering server', array('main.php', 'server_databases.php', 'server_status.php', 'server_variables.php', 'server_privileges.php', 'server_processlist.php')),
1075 array('Default tab for database', 'DefaultTabDatabase', 'Tab that is displayed when entering database', array('db_structure.php', 'db_sql.php', 'db_search.php', 'db_operations.php')),
1076 array('Default tab for table', 'DefaultTabTable', 'Tab that is displayed when entering table', array('tbl_structure.php', 'sql.php', 'tbl_sql.php', 'tbl_select.php', 'tbl_change.php')),
1077 array('Use lighter tabs', 'LightTabs', 'If you want simpler tabs enable this', FALSE),
1079 'Configure tabs',
1080 'Choose how you want tabs to work.',
1081 $defaults);
1083 </form>
1084 <?php
1088 * Shows icons configuration form
1090 * @param array optional defaults
1092 * @return nothing
1094 function show_icons_form($defaults = array()) {
1096 <form method="post" action="">
1097 <?php echo get_hidden_inputs();?>
1098 <input type="hidden" name="action" value="lay_icons_real" />
1099 <?php
1100 echo get_hidden_cfg();
1101 show_config_form(array(
1102 array('Icons on errors', 'ErrorIconic', 'Whether to use icons in error messages.', TRUE),
1103 array('Icons on main page', 'MainPageIconic', 'Whether to use icons on main page.', TRUE),
1104 array('Icons as help links', 'ReplaceHelpImg', 'Whether to use icons as help links.', TRUE),
1105 array('Navigation with icons', 'NavigationBarIconic', 'Whether to display navigation (eg. tabs) with icons.', array('TRUE', 'FALSE', 'both')),
1106 array('Properties pages with icons', 'PropertiesIconic', 'Whether to display properties (eg. table lists and structure) with icons.', array('TRUE', 'FALSE', 'both')),
1108 'Configure icons',
1109 'Select whether you prefer text or icons. Both means that text and icons will be displayed.',
1110 $defaults);
1112 </form>
1113 <?php
1117 * Shows browsing configuration form
1119 * @param array optional defaults
1121 * @return nothing
1123 function show_browse_form($defaults = array()) {
1125 <form method="post" action="">
1126 <?php echo get_hidden_inputs();?>
1127 <input type="hidden" name="action" value="lay_browse_real" />
1128 <?php
1129 echo get_hidden_cfg();
1130 show_config_form(array(
1131 array('Display of values', 'DefaultDisplay', 'How to list values while browsing', array('horizontal', 'vertical', 'horizontalflipped')),
1132 array('Hightlight pointer', 'BrowsePointerEnable', 'Whether to highlight row under mouse.', TRUE),
1133 array('Use row marker', 'BrowseMarkerEnable', 'Whether to highlight selected row.', TRUE),
1134 array('Action buttons on left', 'ModifyDeleteAtLeft', 'Show action buttons on left side of listing?', TRUE),
1135 array('Action buttons on right', 'ModifyDeleteAtRight', 'Show action buttons on right side of listing?', FALSE),
1136 array('Repeat heading', 'RepeatCells', 'After how many rows heading should be repeated.'),
1138 'Configure browsing',
1139 'Select desired browsing look and feel.',
1140 $defaults);
1142 </form>
1143 <?php
1147 * Shows editing options configuration form
1149 * @param array optional defaults
1151 * @return nothing
1153 function show_edit_form($defaults = array()) {
1155 <form method="post" action="">
1156 <?php echo get_hidden_inputs();?>
1157 <input type="hidden" name="action" value="lay_edit_real" />
1158 <?php
1159 echo get_hidden_cfg();
1160 show_config_form(array(
1161 array('Display of properties while editing', 'DefaultPropDisplay', 'How to list properties (table structure or values) while editing', array('horizontal', 'vertical')),
1162 array('Number of inserted rows', 'InsertRows', 'How many rows can be inserted at once'),
1163 array('Move using Ctrl+arrows', 'CtrlArrowsMoving', 'Whether to enable moving using Ctrl+Arrows', TRUE),
1164 array('Autoselect text in textarea', 'TextareaAutoSelect', 'Whether to automatically select text in textarea on focus.', TRUE),
1165 array('Textarea columns', 'TextareaCols', 'Number of columns in textarea while editing TEXT fields'),
1166 array('Textarea rows', 'TextareaRows', 'Number of rows in textarea while editing TEXT fields'),
1167 array('Double textarea for LONGTEXT', 'LongtextDoubleTextarea', 'Whether to double textarea size for LONGTEXT fields', TRUE),
1168 array('Edit CHAR fields in textarea', 'CharEditing', 'Whether to edit CHAR fields in textarea', array('input', 'textarea')),
1169 array('CHAR textarea columns', 'CharTextareaCols', 'Number of columns in textarea while editing CHAR fields (must be enabled above)'),
1170 array('CHAR textarea rows', 'CharTextareaRows', 'Number of rows in textarea while editing CHAR fields (must be enabled above)'),
1172 'Configure editing',
1173 'Select desired editing look and feel.',
1174 $defaults);
1176 </form>
1177 <?php
1181 * Shows query window configuration form
1183 * @param array optional defaults
1185 * @return nothing
1187 function show_window_form($defaults = array()) {
1189 <form method="post" action="">
1190 <?php echo get_hidden_inputs();?>
1191 <input type="hidden" name="action" value="lay_window_real" />
1192 <?php
1193 echo get_hidden_cfg();
1194 show_config_form(array(
1195 array('Edit SQL in window', 'EditInWindow', 'Whether edit links will edit in query window.', TRUE),
1196 array('Query window height', 'QueryWindowHeight', 'Height of query window'),
1197 array('Query window width', 'QueryWindowWidth', 'Width of query window'),
1198 array('Default tab', 'QueryWindowDefTab', 'Default tab on query window', array('sql', 'files', 'history', 'full')),
1200 'Configure query window',
1201 'Select desired query window look and feel.',
1202 $defaults);
1204 </form>
1205 <?php
1209 * Creates selection with servers
1211 * @param array configuraion
1213 * @return string HTML for server selection
1215 function get_server_selection($cfg) {
1216 if (count($cfg['Servers']) == 0) {
1217 return '';
1219 $ret = '<select name="server">';
1220 foreach ($cfg['Servers'] as $key => $val) {
1221 $ret .= '<option value="' . $key . '">' . get_server_name($val, $key) . '</option>';
1223 $ret .= '</select>';
1224 return $ret;
1228 * Loads configuration from file
1230 * @param string filename
1232 * @return mixed FALSE on failure, new config array on success
1234 function load_config($config_file) {
1235 if (file_exists($config_file)) {
1236 $success_apply_user_config = FALSE;
1237 $old_error_reporting = error_reporting(0);
1238 if (function_exists('file_get_contents')) {
1239 $success_apply_user_config = eval('?>' . trim(file_get_contents($config_file)));
1240 } else {
1241 $success_apply_user_config =
1242 eval('?>' . trim(implode("\n", file($config_file))));
1244 error_reporting($old_error_reporting);
1245 unset($old_error_reporting);
1246 if ($success_apply_user_config === FALSE) {
1247 message('error', 'Error while parsing configuration file!');
1248 } elseif (!isset($cfg) || count($cfg) == 0) {
1249 message('error', 'Config file seems to contain no configuration!');
1250 } else {
1251 // This must be set
1252 if (!isset($cfg['Servers'])) {
1253 $cfg['Servers'] = array();
1255 message('notice', 'Configuration loaded');
1256 compress_servers($cfg);
1257 return $cfg;
1259 } else {
1260 message('error', 'Configuration file not found!');
1262 return FALSE;
1265 if ($action != 'download') {
1266 // Check whether we can write to configuration
1267 $fail_dir = FALSE;
1268 $fail_dir = $fail_dir || !is_dir('./config/');
1269 $fail_dir = $fail_dir || !is_writable('./config/');
1270 $fail_dir = $fail_dir || (file_exists('./config/config.inc.php') && !is_writable('./config/config.inc.php'));
1271 $config = @fopen('./config/config.inc.php', 'a');
1272 $fail_dir = $fail_dir || ($config === FALSE);
1273 @fclose($config);
1277 * @var boolean whether to show configuration overview
1279 $show_info = FALSE;
1281 // Do the main work depending on selected action
1282 switch ($action) {
1283 case 'download':
1284 header('Content-Type: text/plain');
1285 header('Content-Disposition: attachment; filename="config.inc.php"');
1287 echo get_cfg_string($configuration);
1288 exit;
1289 break;
1290 case 'display':
1291 echo '<form method="none" action=""><textarea name="config" cols="50" rows="20" id="textconfig" wrap="off">' . "\n";
1292 echo htmlspecialchars(get_cfg_string($configuration));
1293 echo '</textarea></form>' . "\n";
1295 <script type="text/javascript">
1296 //<![CDATA[
1297 var bodyWidth=null; var bodyHeight=null;
1298 if (document.getElementById('textconfig')) {
1299 bodyWidth = self.innerWidth;
1300 bodyHeight = self.innerHeight;
1301 if(!bodyWidth && !bodyHeight){
1302 if (document.compatMode && document.compatMode == "BackCompat") {
1303 bodyWidth = document.body.clientWidth;
1304 bodyHeight = document.body.clientHeight;
1305 } else if (document.compatMode && document.compatMode == "CSS1Compat") {
1306 bodyWidth = document.documentElement.clientWidth;
1307 bodyHeight = document.documentElement.clientHeight;
1310 document.getElementById('textconfig').style.width=(bodyWidth-50) + 'px';
1311 document.getElementById('textconfig').style.height=(bodyHeight-100) + 'px';
1313 //]]>
1314 </script>
1315 <?php
1316 break;
1317 case 'save':
1318 $config = @fopen('./config/config.inc.php', 'w');
1319 if ($config === FALSE) {
1320 message('error', 'Could not open config file for writing! Bad permissions?');
1321 break;
1323 $s = get_cfg_string($configuration);
1324 $r = fwrite($config, $s);
1325 if (!$r || $r != strlen($s)) {
1326 message('error', 'Could not write to config file! Not enough space?');
1327 break;
1328 } else {
1329 message('notice', 'Configuration saved to file config/config.inc.php in phpMyAdmin top level directory, copy it to top level one and delete directory config to use it.', 'File saved');
1331 unset($r, $s);
1332 fclose($config);
1333 break;
1334 case 'load':
1335 if ($fail_dir) {
1336 message('error', 'Reading of configuration disabled because of permissions.');
1337 break;
1339 $new_cfg = load_config('./config/config.inc.php');
1340 if (!($new_cfg === FALSE)) {
1341 $configuration = $new_cfg;
1343 $show_info = TRUE;
1344 break;
1346 case 'addserver_real':
1347 if (isset($_POST['submit_save'])) {
1348 $new_server = grab_values('host;extension;port;socket;connect_type;compress:bool;controluser;controlpass;auth_type;user;password;only_db;verbose;pmadb;bookmarktable:serialized;relation:serialized;table_info:serialized;table_coords:serialized;pdf_pages:serialized;column_info:serialized;designer_coords:serialized;history:serialized;AllowDeny:serialized;SignonSession;SignonURL;LogoutURL');
1349 $err = FALSE;
1350 if (empty($new_server['host'])) {
1351 message('error', 'Empty hostname!');
1352 $err = TRUE;
1354 if ($new_server['auth_type'] == 'config' && empty($new_server['user'])) {
1355 message('error', 'Empty username while using config authentication method!');
1356 $err = TRUE;
1358 if ($new_server['auth_type'] == 'signon' && empty($new_server['SignonSession'])) {
1359 message('error', 'Empty signon session name while using signon authentication method!');
1360 $err = TRUE;
1362 if ($new_server['auth_type'] == 'signon' && empty($new_server['SignonURL'])) {
1363 message('error', 'Empty signon URL while using signon authentication method!');
1364 $err = TRUE;
1366 if (isset($new_server['pmadb']) && strlen($new_server['pmadb'])) {
1367 // Just use defaults, should be okay for most users
1368 $pmadb = array();
1369 $pmadb['bookmarktable'] = 'pma_bookmark';
1370 $pmadb['relation'] = 'pma_relation';
1371 $pmadb['table_info'] = 'pma_table_info';
1372 $pmadb['table_coords'] = 'pma_table_coords';
1373 $pmadb['pdf_pages'] = 'pma_pdf_pages';
1374 $pmadb['column_info'] = 'pma_column_info';
1375 $pmadb['designer_coords'] = 'pma_designer_coords';
1376 $pmadb['history'] = 'pma_history';
1378 $new_server = array_merge($pmadb, $new_server);
1379 unset($pmadb);
1380 if (empty($new_server['controluser'])) {
1381 message('error', 'Empty phpMyAdmin control user while using pmadb!');
1382 $err = TRUE;
1384 if (empty($new_server['controlpass'])) {
1385 message('error', 'Empty phpMyAdmin control user password while using pmadb!');
1386 $err = TRUE;
1388 /* Check whether we can connect as control user */
1389 if (!empty($new_server['controluser']) && !empty($new_server['controlpass'])) {
1390 if ($new_server['extension'] == 'mysql') {
1391 $socket = empty($new_server['socket']) || $new_server['connect_type'] == 'tcp' ? '' : ':' . $new_server['socket'];
1392 $port = empty($new_server['port']) || $new_server['connect_type'] == 'socket' ? '' : ':' . $new_server['port'];
1393 $conn = @mysql_connect($new_server['host'] . $socket . $port, $new_server['controluser'], $new_server['controlpass']);
1394 if ($conn === FALSE) {
1395 message('error', 'Could not connect as control user!');
1396 $err = TRUE;
1397 } else {
1398 mysql_close($conn);
1400 } else {
1401 $socket = empty($new_server['socket']) || $new_server['connect_type'] == 'tcp' ? NULL : $new_server['socket'];
1402 $port = empty($new_server['port']) || $new_server['connect_type'] == 'socket' ? NULL : $new_server['port'];
1403 $conn = @mysqli_connect($new_server['host'], $new_server['controluser'], $new_server['controlpass'], NULL, $port, $socket);
1404 if ($conn === FALSE) {
1405 message('error', 'Could not connect as control user!');
1406 $err = TRUE;
1407 } else {
1408 mysqli_close($conn);
1412 } else {
1413 message('warning', 'You didn\'t set phpMyAdmin database, so you can not use all phpMyAdmin features.');
1415 if ($new_server['auth_type'] == 'config') {
1416 message('warning', 'Remember to protect your installation while using config authentication method!');
1417 } else {
1418 // Not needed:
1419 unset($new_server['user']);
1420 unset($new_server['password']);
1422 if ($err) {
1423 show_server_form($new_server, isset($_POST['server']) ? $_POST['server'] : FALSE);
1424 } else {
1425 if (isset($_POST['server'])) {
1426 $configuration['Servers'][$_POST['server']] = $new_server;
1427 message('notice', 'Changed server ' . get_server_name($new_server, $_POST['server']));
1428 } else {
1429 $configuration['Servers'][] = $new_server;
1430 message('notice', 'New server added');
1432 $show_info = TRUE;
1433 if ($new_server['auth_type'] == 'cookie' && empty($configuration['blowfish_secret'])) {
1434 message('notice', 'You did not have configured blowfish secret and you want to use cookie authentication so I generated blowfish secret for you. It is used to encrypt cookies.', 'Blowfish secret generated');
1435 $configuration['blowfish_secret'] = uniqid('', TRUE);
1438 unset($new_server);
1439 } else {
1440 $show_info = TRUE;
1442 break;
1443 case 'addserver':
1444 if (count($configuration['Servers']) == 0) {
1445 // First server will use defaults as in config.default.php
1446 $defaults = $PMA_Config_Setup->default_server;
1447 unset($defaults['AllowDeny']); // Ignore this for now
1448 } else {
1449 $defaults = array();
1452 // Guess MySQL extension to use, prefer mysqli
1453 if (!function_exists('mysql_get_client_info')) {
1454 PMA_dl('mysql');
1456 if (!function_exists('mysqli_get_client_info')) {
1457 PMA_dl('mysqli');
1459 if (function_exists('mysqli_get_client_info')) {
1460 $defaults['extension'] = 'mysqli';
1461 } elseif (function_exists('mysql_get_client_info')) {
1462 $defaults['extension'] = 'mysql';
1463 } else {
1464 message('warning', 'Could not load either mysql or mysqli extension, you might not be able to use phpMyAdmin! Check your PHP configuration.');
1466 if (isset($defaults['extension'])) {
1467 message('notice', 'Autodetected MySQL extension to use: ' . $defaults['extension']);
1470 // Display form
1471 show_server_form($defaults);
1472 break;
1473 case 'editserver':
1474 if (!isset($_POST['server'])) {
1475 footer();
1477 show_server_form($configuration['Servers'][$_POST['server']], $_POST['server']);
1478 break;
1479 case 'deleteserver':
1480 if (!isset($_POST['server'])) {
1481 footer();
1483 message('notice', 'Deleted server ' . get_server_name($configuration['Servers'][$_POST['server']], $_POST['server']));
1484 unset($configuration['Servers'][$_POST['server']]);
1485 compress_servers($configuration);
1486 $show_info = TRUE;
1487 break;
1488 case 'servers':
1489 if (count($configuration['Servers']) == 0) {
1490 message('notice', 'No servers defined, so none can be shown');
1491 } else {
1492 foreach ($configuration['Servers'] as $i => $srv) {
1493 $data = array();
1494 if (!empty($srv['verbose'])) {
1495 $data[] = array('Verbose name', $srv['verbose']);
1497 $data[] = array('Host', $srv['host']);
1498 $data[] = array('MySQL extension', isset($srv['extension']) ? $srv['extension'] : $PMA_Config_Setup->default_server['extension']);
1499 $data[] = array('Authentication type', get_server_auth($srv));
1500 $data[] = array('phpMyAdmin advanced features', empty($srv['pmadb']) || empty($srv['controluser']) || empty($srv['controlpass']) ? 'disabled' : 'enabled, db: ' . $srv['pmadb'] . ', user: ' . $srv['controluser']);
1501 $buttons =
1502 get_action('deleteserver', 'Delete', '<input type="hidden" name="server" value="' . $i . '" />') .
1503 get_action('editserver', 'Edit', '<input type="hidden" name="server" value="' . $i . '" />');
1504 show_overview('Server ' . get_server_name($srv, $i), $data, $buttons);
1507 break;
1509 case 'feat_upload_real':
1510 if (isset($_POST['submit_save'])) {
1511 $dirs = grab_values('UploadDir;SaveDir');
1512 $err = FALSE;
1513 if (!empty($dirs['UploadDir']) && !is_dir($dirs['UploadDir'])) {
1514 message('error', 'Upload directory ' . htmlspecialchars($dirs['UploadDir']) . ' does not exist!');
1515 $err = TRUE;
1517 if (!empty($dirs['SaveDir']) && !is_dir($dirs['SaveDir'])) {
1518 message('error', 'Save directory ' . htmlspecialchars($dirs['SaveDir']) . ' does not exist!');
1519 $err = TRUE;
1521 if ($err) {
1522 show_upload_form($dirs);
1523 } else {
1524 $configuration = array_merge($configuration, $dirs);
1525 message('notice', 'Configuration changed');
1526 $show_info = TRUE;
1528 } else {
1529 $show_info = TRUE;
1531 break;
1532 case 'feat_upload':
1533 show_upload_form($configuration);
1534 break;
1536 case 'feat_security_real':
1537 if (isset($_POST['submit_save'])) {
1538 $vals = grab_values('blowfish_secret;ForceSSL:bool;ShowPhpInfo:bool;ShowChgPassword:bool;AllowArbitraryServer:bool;LoginCookieRecall:book;LoginCookieValidity:int');
1539 $err = FALSE;
1540 if (empty($vals['blowfish_secret'])) {
1541 message('warning', 'Blowfish secret is empty, you will not be able to use cookie authentication.');
1543 if ($vals['AllowArbitraryServer']) {
1544 message('warning', 'Arbitrary server connection might be dangerous as it might allow access to internal servers that are not reachable from outside.');
1546 if (isset($vals['LoginCookieValidity']) && $vals['LoginCookieValidity'] < 1) {
1547 message('error', 'Invalid cookie validity time');
1548 $err = TRUE;
1550 if ($err) {
1551 show_security_form($vals);
1552 } else {
1553 $configuration = array_merge($configuration, $vals);
1554 message('notice', 'Configuration changed');
1555 $show_info = TRUE;
1557 } else {
1558 $show_info = TRUE;
1560 break;
1561 case 'feat_security':
1562 show_security_form($configuration);
1563 break;
1565 case 'feat_manual_real':
1566 if (isset($_POST['submit_save'])) {
1567 $vals = grab_values('MySQLManualBase;MySQLManualType');
1568 $err = FALSE;
1569 if ($vals['MySQLManualType'] != 'none' && empty($vals['MySQLManualBase'])) {
1570 message('error', 'You need to set manual base URL or choose type \'none\'.');
1571 $err = TRUE;
1573 if ($err) {
1574 show_manual_form($vals);
1575 } else {
1576 $configuration = array_merge($configuration, $vals);
1577 message('notice', 'Configuration changed');
1578 $show_info = TRUE;
1580 } else {
1581 $show_info = TRUE;
1583 break;
1584 case 'feat_manual':
1585 show_manual_form($configuration);
1586 break;
1588 case 'feat_charset_real':
1589 if (isset($_POST['submit_save'])) {
1590 $vals = grab_values('AllowAnywhereRecoding:bool;DefaultCharset;RecodingEngine;IconvExtraParams');
1591 $err = FALSE;
1592 if ($err) {
1593 show_charset_form($vals);
1594 } else {
1595 $configuration = array_merge($configuration, $vals);
1596 message('notice', 'Configuration changed');
1597 $show_info = TRUE;
1599 } else {
1600 $show_info = TRUE;
1602 break;
1603 case 'feat_charset':
1604 $d = $configuration;
1605 if (!isset($d['RecodingEngine'])) {
1606 if (@extension_loaded('iconv')) {
1607 $d['RecodingEngine'] = 'iconv';
1608 } elseif (@extension_loaded('recode')) {
1609 $d['RecodingEngine'] = 'recode';
1610 } else {
1611 PMA_dl('iconv');
1612 if (!@extension_loaded('iconv')) {
1613 PMA_dl('recode');
1614 if (!@extension_loaded('recode')) {
1615 message('warning', 'Neither recode nor iconv could be loaded so charset conversion will most likely not work.');
1616 } else {
1617 $d['RecodingEngine'] = 'recode';
1619 } else {
1620 $d['RecodingEngine'] = 'iconv';
1623 if (isset($d['RecodingEngine'])) {
1624 message('notice', 'Autodetected recoding engine: ' . $d['RecodingEngine']);
1627 show_charset_form($d);
1628 unset($d);
1629 break;
1631 case 'feat_extensions_real':
1632 if (isset($_POST['submit_save'])) {
1633 $vals = grab_values('GD2Available');
1634 $err = FALSE;
1635 if ($err) {
1636 show_extensions_form($vals);
1637 } else {
1638 $configuration = array_merge($configuration, $vals);
1639 message('notice', 'Configuration changed');
1640 $show_info = TRUE;
1642 } else {
1643 $show_info = TRUE;
1645 break;
1646 case 'feat_extensions':
1647 $d = $configuration;
1648 if (!@extension_loaded('mbstring')) {
1649 PMA_dl('mbstring');
1651 if (!@extension_loaded('mbstring')) {
1652 message('warning', 'Could not load <code>mbstring</code> extension, which is required for work with multibyte strings like UTF-8 ones. Please consider installing it.');
1654 if (!isset($d['GD2Available'])) {
1655 if (PMA_IS_GD2 == 1) {
1656 message('notice', 'GD 2 or newer found.');
1657 $d['GD2Available'] = 'yes';
1658 } else {
1659 message('warning', 'GD 2 or newer is not present.');
1660 $d['GD2Available'] = 'no';
1663 show_extensions_form($d);
1664 unset($d);
1665 break;
1667 case 'feat_relation_real':
1668 if (isset($_POST['submit_save'])) {
1669 $vals = grab_values('QueryHistoryDB:bool;QueryHistoryMax:int;BrowseMIME:bool;PDFDefaultPageSize');
1670 $err = FALSE;
1671 if (isset($vals['QueryHistoryMax']) && $vals['QueryHistoryMax'] < 1) {
1672 message('error', 'Invalid value for query maximum history size!');
1673 $err = TRUE;
1675 if ($err) {
1676 show_relation_form($vals);
1677 } else {
1678 $configuration = array_merge($configuration, $vals);
1679 message('notice', 'Configuration changed');
1680 $show_info = TRUE;
1682 } else {
1683 $show_info = TRUE;
1685 break;
1686 case 'feat_relation':
1687 show_relation_form($configuration);
1688 break;
1690 case 'lay_navigation_real':
1691 if (isset($_POST['submit_save'])) {
1692 $vals = grab_values('LeftFrameLight:bool;LeftFrameDBTree:bool;LeftFrameDBSeparator;LeftFrameTableSeparator;LeftFrameTableLevel:int;LeftDisplayLogo:bool;LeftDisplayServers:bool;DisplayServersList:bool;DisplayDatabasesList;LeftPointerEnable:bool');
1693 $err = FALSE;
1694 if (isset($vals['DisplayDatabasesList'])) {
1695 if ($vals['DisplayDatabasesList'] == 'yes') {
1696 $vals['DisplayDatabasesList'] = true;
1697 } elseif ($vals['DisplayDatabasesList'] == 'no') {
1698 $vals['DisplayDatabasesList'] = false;
1701 if (isset($vals['LeftFrameTableLevel']) && $vals['LeftFrameTableLevel'] < 1) {
1702 message('error', 'Invalid value for maximum table nesting level!');
1703 $err = TRUE;
1705 if ($err) {
1706 show_left_form($vals);
1707 } else {
1708 $configuration = array_merge($configuration, $vals);
1709 message('notice', 'Configuration changed');
1710 $show_info = TRUE;
1712 } else {
1713 $show_info = TRUE;
1715 break;
1716 case 'lay_navigation':
1717 show_left_form($configuration);
1718 break;
1720 case 'lay_tabs_real':
1721 if (isset($_POST['submit_save'])) {
1722 $vals = grab_values('DefaultTabServer;DefaultTabDatabase;DefaultTabTable;LightTabs:bool');
1723 $err = FALSE;
1724 if ($err) {
1725 show_tabs_form($vals);
1726 } else {
1727 $configuration = array_merge($configuration, $vals);
1728 message('notice', 'Configuration changed');
1729 $show_info = TRUE;
1731 } else {
1732 $show_info = TRUE;
1734 break;
1735 case 'lay_tabs':
1736 show_tabs_form($configuration);
1737 break;
1739 case 'lay_icons_real':
1740 if (isset($_POST['submit_save'])) {
1741 $vals = grab_values('ErrorIconic:bool;MainPageIconic:bool;ReplaceHelpImg:bool;NavigationBarIconic:tristate;PropertiesIconic:tristate');
1742 $err = FALSE;
1743 if ($err) {
1744 show_icons_form($vals);
1745 } else {
1746 $configuration = array_merge($configuration, $vals);
1747 message('notice', 'Configuration changed');
1748 $show_info = TRUE;
1750 } else {
1751 $show_info = TRUE;
1753 break;
1754 case 'lay_icons':
1755 show_icons_form($configuration);
1756 break;
1758 case 'lay_browse_real':
1759 if (isset($_POST['submit_save'])) {
1760 $vals = grab_values('BrowsePointerEnable:bool;BrowseMarkerEnable:bool;ModifyDeleteAtRight:bool;ModifyDeleteAtLeft:bool;RepeatCells:int;DefaultDisplay');
1761 $err = FALSE;
1762 if (isset($vals['RepeatCells']) && $vals['RepeatCells'] < 1) {
1763 message('error', 'Invalid value for header repeating!');
1764 $err = TRUE;
1766 if (!$vals['ModifyDeleteAtLeft'] && !$vals['ModifyDeleteAtRight']) {
1767 message('error', 'No action buttons enabled!');
1768 $err = TRUE;
1770 if ($err) {
1771 show_browse_form($vals);
1772 } else {
1773 $configuration = array_merge($configuration, $vals);
1774 message('notice', 'Configuration changed');
1775 $show_info = TRUE;
1777 } else {
1778 $show_info = TRUE;
1780 break;
1781 case 'lay_browse':
1782 show_browse_form($configuration);
1783 break;
1785 case 'lay_edit_real':
1786 if (isset($_POST['submit_save'])) {
1787 $vals = grab_values('TextareaCols:int;TextareaRows:int;LongtextDoubleTextarea:bool;TextareaAutoSelect:bool;CharEditing;CharTextareaCols:int;CharTextareaRows:int;CtrlArrowsMoving:bool;DefaultPropDisplay;InsertRows:int');
1788 $err = FALSE;
1789 if (isset($vals['TextareaCols']) && $vals['TextareaCols'] < 1) {
1790 message('error', 'Invalid value for textarea columns!');
1791 $err = TRUE;
1793 if (isset($vals['TextareaRows']) && $vals['TextareaRows'] < 1) {
1794 message('error', 'Invalid value for textarea rows!');
1795 $err = TRUE;
1797 if (isset($vals['CharTextareaCols']) && $vals['CharTextareaCols'] < 1) {
1798 message('error', 'Invalid value for CHAR textarea columns!');
1799 $err = TRUE;
1801 if (isset($vals['CharTextareaRows']) && $vals['CharTextareaRows'] < 1) {
1802 message('error', 'Invalid value for CHAR textarea rows!');
1803 $err = TRUE;
1805 if (isset($vals['InsertRows']) && $vals['InsertRows'] < 1) {
1806 message('error', 'Invalid value for inserted rows count!');
1807 $err = TRUE;
1809 if ($err) {
1810 show_edit_form($vals);
1811 } else {
1812 $configuration = array_merge($configuration, $vals);
1813 message('notice', 'Configuration changed');
1814 $show_info = TRUE;
1816 } else {
1817 $show_info = TRUE;
1819 break;
1820 case 'lay_edit':
1821 show_edit_form($configuration);
1822 break;
1824 case 'lay_window_real':
1825 if (isset($_POST['submit_save'])) {
1826 $vals = grab_values('EditInWindow:bool;QueryWindowHeight:int;QueryWindowWidth:int;QueryWindowDefTab');
1827 $err = FALSE;
1828 if (isset($vals['QueryWindowWidth']) && $vals['QueryWindowWidth'] < 1) {
1829 message('error', 'Invalid value for query window width!');
1830 $err = TRUE;
1832 if (isset($vals['QueryWindowHeight']) && $vals['QueryWindowHeight'] < 1) {
1833 message('error', 'Invalid value for query window height');
1834 $err = TRUE;
1836 if ($err) {
1837 show_window_form($vals);
1838 } else {
1839 $configuration = array_merge($configuration, $vals);
1840 message('notice', 'Configuration changed');
1841 $show_info = TRUE;
1843 } else {
1844 $show_info = TRUE;
1846 break;
1847 case 'lay_window':
1848 show_window_form($configuration);
1849 break;
1851 /* Template for new actions:
1852 case 'blah_real':
1853 if (isset($_POST['submit_save'])) {
1854 $vals = grab_values('value1:bool;value2');
1855 $err = FALSE;
1856 if (somechekcfails) {
1857 message('error', 'Invalid value for blah!');
1858 $err = TRUE;
1860 if ($err) {
1861 show_blah_form($vals);
1862 } else {
1863 $configuration = array_merge($configuration, $vals);
1864 message('notice', 'Configuration changed');
1865 $show_info = TRUE;
1867 } else {
1868 $show_info = TRUE;
1870 break;
1871 case 'blah':
1872 show_blah_form($configuration);
1873 break;
1875 case 'versioncheck': // Check for latest available version
1876 PMA_dl('curl');
1877 $url = 'http://phpmyadmin.net/home_page/version.php';
1878 $data = '';
1879 $f = @fopen($url, 'r');
1880 if ($f === FALSE) {
1881 if (!function_exists('curl_init')) {
1882 message('error', 'Neither URL wrappers nor CURL are available. Version check is not possible.');
1883 break;
1885 } else {
1886 $data = fread($f, 20);
1887 fclose($f);
1889 if (empty($data) && function_exists('curl_init')) {
1890 $ch = curl_init($url);
1891 curl_setopt($ch, CURLOPT_HEADER, FALSE);
1892 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1893 $data = curl_exec($ch);
1894 curl_close($ch);
1896 if (empty($data)) {
1897 message('error', 'Reading of version failed. Maybe you\'re offline or the upgrade server does not respond.');
1898 break;
1901 /* Format: version\ndate\n(download\n)* */
1902 $data_list = split("\n", $data);
1904 if (count($data_list) > 0) {
1905 $version = $data_list[0];
1906 } else {
1907 $version = '';
1910 $version_upstream = version_to_int($version);
1911 if ($version_upstream === FALSE) {
1912 message('error', 'Got invalid version string from server.');
1913 break;
1916 $version_local = version_to_int($PMA_Config_Setup->get('PMA_VERSION'));
1917 if ($version_local === FALSE) {
1918 message('error', 'Unparsable version string.');
1919 break;
1922 if ($version_upstream > $version_local) {
1923 message('notice', 'New version of phpMyAdmin is available, you should consider upgrade. New version is ' . htmlspecialchars($version) . '.');
1924 } else {
1925 if ($version_local % 100 == 0) {
1926 message('notice', 'You are using subversion version, run <code>svn update</code> :-). However latest released version is ' . htmlspecialchars($version) . '.');
1927 } else {
1928 message('notice', 'No newer stable version is available.');
1931 break;
1933 case 'seteol':
1934 $eoltype = $_POST['neweol'];
1935 message('notice', 'End of line format changed.');
1936 case 'clear': // Actual clearing is done on beginning of this script
1937 case 'main':
1938 $show_info = TRUE;
1939 break;
1941 case '':
1942 message('notice', 'You want to configure phpMyAdmin using web interface. Please note that this only allows basic setup, please read <a href="../Documentation.html#config">documentation</a> to see full description of all configuration directives.', 'Welcome');
1944 if ($PMA_Config_Setup->get('PMA_PHP_INT_VERSION') < 40100) {
1945 message('warning', 'Please upgrade to PHP 4.1.0, it is required for phpMyAdmin.', 'Too old PHP');
1948 if ($fail_dir) {
1949 message('warning', 'Please create web server writable folder config in phpMyAdmin toplevel directory as described in <a href="../Documentation.html#setup_script">documentation</a>. Otherwise you will be only able to download or display it.', 'Can not load or save configuration');
1952 if (empty($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off') {
1953 if (empty($_SERVER['REQUEST_URI']) || empty($_SERVER['HTTP_HOST'])) {
1954 $redir = '';
1955 } else {
1956 $redir = ' If your server is also configured to accept HTTPS request'
1957 . ' follow <a href="https://'
1958 . htmlspecialchars($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'])
1959 . '">this link</a> to use secure connection.';
1961 message('warning', 'You are not using secure connection, all data (including sensitive, like passwords) are transfered unencrypted!' . $redir, 'Not secure connection');
1963 break;
1966 // Should we show information?
1967 if ($show_info) {
1968 $servers = 'none';
1969 $servers_text = 'Servers';
1970 if (count($configuration['Servers']) == 0) {
1971 message('warning', 'No servers defined, you probably want to add one.');
1972 } else {
1973 $servers = '';
1974 $servers_text = 'Servers (' . count($configuration['Servers']) . ')';
1976 $sep = '';
1977 foreach ($configuration['Servers'] as $key => $val) {
1978 $servers .= $sep;
1979 $sep = ', ';
1980 $servers .= get_server_name($val, $key);
1982 unset($sep);
1984 show_overview('Current configuration overview',
1985 array(
1986 array($servers_text, $servers),
1987 array('SQL files upload', empty($configuration['UploadDir']) ? 'disabled' : 'enabled'),
1988 array('Exported files on server', empty($configuration['SaveDir']) ? 'disabled' : 'enabled'),
1989 array('Charset conversion', isset($configuration['AllowAnywhereRecoding']) && $configuration['AllowAnywhereRecoding'] ? 'enabled' : 'disabled'),
1991 unset($servers_text, $servers);
1994 // And finally display all actions:
1995 echo '<p>Available global actions (please note that these will delete any changes you could have done above):</p>';
1997 echo '<fieldset class="toolbar"><legend>Servers</legend>' . "\n";
1998 echo get_action('addserver', 'Add');
1999 $servers = get_server_selection($configuration);
2000 if (!empty($servers)) {
2001 echo get_action('servers', 'List');
2002 echo get_action('deleteserver', 'Delete', $servers);
2003 echo get_action('editserver', 'Edit', $servers);
2005 echo '</fieldset>' . "\n\n";
2007 echo '<fieldset class="toolbar"><legend>Layout</legend>' . "\n";
2008 echo get_action('lay_navigation', 'Navigation frame');
2009 echo get_action('lay_tabs', 'Tabs');
2010 echo get_action('lay_icons', 'Icons');
2011 echo get_action('lay_browse', 'Browsing');
2012 echo get_action('lay_edit', 'Editing');
2013 echo get_action('lay_window', 'Query window');
2014 echo '</fieldset>' . "\n\n";
2016 echo '<fieldset class="toolbar"><legend>Features</legend>' . "\n";
2017 echo get_action('feat_upload', 'Upload/Download');
2018 echo get_action('feat_security', 'Security');
2019 echo get_action('feat_manual', 'MySQL manual');
2020 echo get_action('feat_charset', 'Charsets');
2021 echo get_action('feat_extensions', 'Extensions');
2022 echo get_action('feat_relation', 'MIME/Relation/History');
2023 echo '</fieldset>' . "\n\n";
2025 echo '<fieldset class="toolbar"><legend>Configuration</legend>' . "\n";
2026 echo get_action('main', 'Overview');
2027 echo get_action('display', 'Display');
2028 echo get_action('download', 'Download');
2029 echo get_action('save', 'Save', '', !$fail_dir);
2030 echo get_action('load', 'Load', '', !$fail_dir);
2031 echo get_action('clear', 'Clear');
2032 echo get_action('seteol', 'Change end of line',
2033 '<select name="neweol">' .
2034 '<option value="unix" ' . ($eoltype == 'unix' ? ' selected="selected"' : '') . '>UNIX/Linux (\\n)</option>' .
2035 '<option value="dos" ' . ($eoltype == 'dos' ? ' selected="selected"' : '') . '>DOS/Windows (\\r\\n)</option>' .
2036 '<option value="mac" ' . ($eoltype == 'mac' ? ' selected="selected"' : '') . '>Macintosh (\\r)</option>' . '
2037 </select>');
2038 echo '</fieldset>' . "\n\n";
2040 echo '<fieldset class="toolbar"><legend>Other actions</legend>' . "\n";
2041 echo get_action('versioncheck', 'Check for latest version');
2042 echo get_url_action('http://www.phpmyadmin.net/', 'Go to homepage');
2043 echo get_url_action('https://sourceforge.net/donate/index.php', 'Donate to phpMyAdmin', array('group_id' => 23067));
2044 echo '</fieldset>' . "\n\n";
2046 footer();