]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - configurator.php
Use HTML 5 DOCTYPE; force CHARSET=utf-8
[SourceForge/phpwiki.git] / configurator.php
1 <?php
2 /*
3  * Copyright 2002,2003,2005,2008-2010 $ThePhpWikiProgrammingTeam
4  * Copyright 2002 Martin Geisler <gimpster@gimpster.com>
5  * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  * Parts of this file were based on PHPWeather's configurator.php file.
9  *   http://sourceforge.net/projects/phpweather/
10  *
11  * PhpWiki is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * PhpWiki is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 /**
27  * Starts automatically the first time by IniConfig("config/config.ini")
28  * if it doesn't exist.
29  *
30  * DONE:
31  * o Initial expand ?show=_part1 (the part id)
32  * o read config-default.ini and use this as default_values
33  * o commented / optional: non-default values should not be commented!
34  *                         default values if optional can be omitted.
35  * o validate input (fix javascript, add POST checks)
36  * o start this automatically the first time
37  * o fix include_path
38  *
39  * 1.3.11 TODO: (or 1.3.12?)
40  * o parse_ini_file("config-dist.ini") for the commented vars
41  * o check automatically for commented and optional vars
42  * o fix _optional, to ignore existing config.ini and only use config-default.ini values
43  * o mixin class for commented
44  * o fix SQL quotes, AUTH_ORDER quotes and file forward slashes
45  * o posted values validation, extend js validation for sane DB values
46  * o read config-dist.ini into sections, comments, and optional/required settings
47  *
48  * A file config/config.ini will be automatically generated, if writable.
49  *
50  * NOTE: If you have a starterscript outside PHPWIKI_DIR but no
51  * config/config.ini yet (very unlikely!), you must define DATA_PATH in the
52  * starterscript, otherwise the webpath to configurator is unknown, and
53  * subsequent requests will fail. (POST to save the INI)
54  */
55
56 global $HTTP_POST_VARS, $tdwidth;
57 if (empty($_SERVER)) $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
58 if (empty($_GET)) $_GET =& $GLOBALS['HTTP_GET_VARS'];
59 if (empty($_ENV)) $_ENV =& $GLOBALS['HTTP_ENV_VARS'];
60 if (empty($_POST)) $_POST =& $GLOBALS['HTTP_POST_VARS'];
61
62 if (empty($configurator))
63     $configurator = "configurator.php";
64 if (!strstr($_SERVER["SCRIPT_NAME"], $configurator) and defined('DATA_PATH'))
65     $configurator = DATA_PATH . "/" . $configurator;
66 $scriptname = str_replace('configurator.php', 'index.php', $_SERVER["SCRIPT_NAME"]);
67 if (strstr($_SERVER["SCRIPT_NAME"], "/php")) { // cgi got this different
68     if (defined('DATA_PATH'))
69         $scriptname = DATA_PATH . "/index.php";
70     else
71         $scriptname = str_replace('configurator.php', 'index.php', $_SERVER["PHP_SELF"]);
72 }
73
74 $tdwidth = 700;
75 $config_file = (substr(PHP_OS, 0, 3) == 'WIN') ? 'config\\config.ini' : 'config/config.ini';
76 $fs_config_file = dirname(__FILE__) . (substr(PHP_OS, 0, 3) == 'WIN' ? '\\' : '/') . $config_file;
77 if (isset($_POST['create'])) header('Location: ' . $configurator . '?show=_part1&create=1#create');
78
79 // helpers from lib/WikiUser/HttpAuth.php
80 if (!function_exists('_http_user')) {
81     function _http_user()
82     {
83         if (!isset($_SERVER))
84             $_SERVER = $GLOBALS['HTTP_SERVER_VARS'];
85         if (!empty($_SERVER['PHP_AUTH_USER']))
86             return array($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
87         if (!empty($_SERVER['REMOTE_USER']))
88             return array($_SERVER['REMOTE_USER'], $_SERVER['PHP_AUTH_PW']);
89         if (!empty($GLOBALS['HTTP_ENV_VARS']['REMOTE_USER']))
90             return array($GLOBALS['HTTP_ENV_VARS']['REMOTE_USER'],
91                 $GLOBALS['HTTP_ENV_VARS']['PHP_AUTH_PW']);
92         if (!empty($GLOBALS['REMOTE_USER']))
93             return array($GLOBALS['REMOTE_USER'], $GLOBALS['PHP_AUTH_PW']);
94
95         // MsWindows IIS:
96         if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
97             list($userid, $passwd) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
98             return array($userid, $passwd);
99         }
100         return array('', '');
101     }
102
103     function _http_logout()
104     {
105         if (!isset($_SERVER))
106             $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
107         // maybe we should random the realm to really force a logout. but the next login will fail.
108         // better_srand(); $realm = microtime().rand();
109         header('WWW-Authenticate: Basic realm="' . WIKI_NAME . '"');
110         if (strstr(php_sapi_name(), 'apache'))
111             header('HTTP/1.0 401 Unauthorized');
112         else
113             header("Status: 401 Access Denied"); //IIS and CGI need that
114         unset($GLOBALS['REMOTE_USER']);
115         unset($_SERVER['PHP_AUTH_USER']);
116         unset($_SERVER['PHP_AUTH_PW']);
117
118         trigger_error("Permission denied. Require ADMIN_USER.", E_USER_ERROR);
119         exit();
120     }
121 }
122
123 // If config.ini exists, we require ADMIN_USER access by faking HttpAuth.
124 // So nobody can see or reset the password(s).
125 if (file_exists($fs_config_file)) {
126     // Require admin user
127     if (!defined('ADMIN_USER') or !defined('ADMIN_PASSWD')) {
128         if (!function_exists("IniConfig")) {
129             include_once 'lib/prepend.php';
130             include_once 'lib/IniConfig.php';
131         }
132         IniConfig($fs_config_file);
133     }
134     if (!defined('ADMIN_USER') or ADMIN_USER == '') {
135         trigger_error("Configuration problem:\nADMIN_USER not defined in \"$fs_config_file\".\n"
136             . "Cannot continue: You have to fix that manually.", E_USER_ERROR);
137         exit();
138     }
139
140     list($admin_user, $admin_pw) = _http_user();
141     //$required_user = ADMIN_USER;
142     if (empty($admin_user) or $admin_user != ADMIN_USER) {
143         _http_logout();
144     }
145     // check password
146     if (ENCRYPTED_PASSWD and function_exists('crypt')) {
147         if (crypt($admin_pw, ADMIN_PASSWD) != ADMIN_PASSWD)
148             _http_logout();
149     } elseif ($admin_pw != ADMIN_PASSWD) {
150         _http_logout();
151     }
152 } else {
153     if (!function_exists("IniConfig")) {
154         include_once 'lib/prepend.php';
155         include_once 'lib/IniConfig.php';
156     }
157     $def_file = (substr(PHP_OS, 0, 3) == 'WIN') ? 'config\\config-default.ini' : 'config/config-default.ini';
158     $fs_def_file = dirname(__FILE__) . (substr(PHP_OS, 0, 3) == 'WIN' ? '\\' : '/') . $def_file;
159     IniConfig($fs_def_file);
160 }
161
162 echo '<', '?xml version="1.0" encoding="utf-8"?', ">\n";
163 ?>
164 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
165         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
166 <html xmlns="http://www.w3.org/1999/xhtml">
167 <head>
168     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
169     <title>Configuration tool for PhpWiki <?php echo $config_file ?></title>
170     <style type="text/css" media="screen">
171         <!--
172             /* TABLE { border: thin solid black } */
173         body {
174             font-family: Verdana, Arial, Helvetica, sans-serif;
175             font-size: 80%;
176         }
177
178         pre {
179             font-size: 120%;
180         }
181
182         td {
183             border: thin solid black
184         }
185
186         tr {
187             border: none
188         }
189
190         div.hint {
191             background-color: #eeeeee;
192         }
193
194         tr.hidden {
195             border: none;
196             display: none;
197         }
198
199         td.part {
200             background-color: #eeeeee;
201             color: inherit;
202         }
203
204         td.instructions {
205             background-color: #ffffee;
206             width: <?php echo $tdwidth ?>px;
207             color: inherit;
208         }
209
210         td.unchangeable-variable-top {
211             border-bottom: none;
212             background-color: #ffffee;
213             color: inherit;
214         }
215
216         td.unchangeable-variable-left {
217             border-top: none;
218             background-color: #ffffee;
219             color: inherit;
220         }
221
222         -->
223     </style>
224     <script type="text/javascript">
225         <!--
226                 function update(accepted, error, value, output) {
227                     var msg = document.getElementById(output);
228                     if (accepted) {
229                         /* MSIE 5.0 fails here */
230                         if (msg && msg.innerHTML) {
231                             msg.innerHTML = "<font color=\"green\">Input accepted.</font>";
232                         }
233                     } else {
234                         while ((index = error.indexOf("%s")) > -1) {
235                             error = error.substring(0, index) + value + error.substring(index + 2);
236                         }
237                         if (msg) {
238                             msg.innerHTML = "<font color=\"red\">" + error + "</font>";
239                         }
240                     }
241                     if (submit = document.getElementById('submit')) submit.disabled = accepted ? false : true;
242                 }
243
244         function validate(error, value, output, field) {
245             update(field.value == value, error, field.value, output);
246         }
247
248         function validate_ereg(error, ereg, output, field) {
249             regex = new RegExp(ereg);
250             update(regex.test(field.value), error, field.value, output);
251         }
252
253         function validate_range(error, low, high, empty_ok, output, field) {
254             update((empty_ok == 1 && field.value == "") ||
255                     (field.value >= low && field.value <= high),
256                     error, field.value, output);
257         }
258
259         function toggle_group(id) {
260             var text = document.getElementById(id + "_text");
261             var do_hide = false;
262             if (text.innerHTML == "Hide options.") {
263                 do_hide = true;
264                 text.innerHTML = "Show options.";
265             } else {
266                 text.innerHTML = "Hide options.";
267             }
268
269             var rows = document.getElementsByTagName('tr');
270             var i = 0;
271             for (i = 0; i < rows.length; i++) {
272                 var tr = rows[i];
273                 if (tr.className == 'header' && tr.id == id) {
274                     i++;
275                     break;
276                 }
277             }
278             for (; i < rows.length; i++) {
279                 var tr = rows[i];
280                 if (tr.className == 'header')
281                     break;
282                 tr.className = do_hide ? 'hidden' : 'nonhidden';
283             }
284         }
285
286         function do_init() {
287             // Hide all groups.  We do this via JavaScript to avoid
288             // hiding the groups if JavaScript is not supported...
289             var rows = document.getElementsByTagName('tr');
290             var show = '<?php echo $_GET["show"] ?>';
291             for (var i = 0; i < rows.length; i++) {
292                 var tr = rows[i];
293                 if (tr.className == 'header')
294                     if (!show || tr.id != show)
295                         toggle_group(tr.id);
296             }
297
298             // Select text in textarea upon focus
299             var area = document.getElementById('config-output');
300             if (area) {
301                 listener = { handleEvent:function (e) {
302                     area.select();
303                 } };
304                 area.addEventListener('focus', listener, false);
305             }
306         }
307
308         // -->
309     </script>
310 </head>
311 <body onload="do_init();">
312
313 <h1>Configuration for PhpWiki <?php echo $config_file ?></h1>
314
315 <div class="hint">
316     Using this configurator.php is experimental!<br/>
317     On any configuration problems, please edit the resulting config.ini manually.
318 </div>
319
320 <?php
321 define('DEBUG', 0);
322 //define('DEBUG', 1);
323 /**
324  * The Configurator is a php script to aid in the configuration of PhpWiki.
325  * Parts of this file were based on PHPWeather's configurator.php file.
326  *   http://sourceforge.net/projects/phpweather/
327  *
328  * TO CHANGE THE CONFIGURATION OF YOUR PHPWIKI, DO *NOT* MODIFY THIS FILE!
329  * more instructions go here
330  *
331  * Todo:
332  *   * fix include_path
333  *   * eval config.ini to get the actual settings.
334  */
335
336 //////////////////////////////
337 // begin configuration options
338
339 /**
340  * Notes for the description parameter of $property:
341  *
342  * - Descriptive text will be changed into comments (preceeded by ; )
343  *   for the final output to config.ini.
344  *
345  * - Only a limited set of html is allowed: pre, dl dt dd; it will be
346  *   stripped from the final output.
347  *
348  * - Line breaks and spacing will be preserved for the final output.
349  *
350  * - Double line breaks are automatically converted to paragraphs
351  *   for the html version of the descriptive text.
352  *
353  * - Double-quotes and dollar signs in the descriptive text must be
354  *   escaped: \" and \$. Instead of escaping double-quotes you can use
355  *   single (') quotes for the enclosing quotes.
356  *
357  * - Special characters like < and > must use html entities,
358  *   they will be converted back to characters for the final output.
359  */
360
361 $SEPARATOR = ";=========================================================================";
362
363 $preamble = "
364 ; This is the main configuration file for PhpWiki in INI-style format.
365 ; Note that certain characters are used as comment char and therefore
366 ; these entries must be in double-quotes. Such as \":\", \";\", \",\" and \"|\"
367 ; Take special care for DBAUTH_ sql statements. (Part 3a)
368 ;
369 ; This file is divided into several parts: Each one has different configuration
370 ; settings you can change; in all cases the default should work on your system,
371 ; however, we recommend you tailor things to your particular setting.
372 ; Here undefined definitions get defined by config-default.ini settings.
373 ";
374
375 // Detect not here listed configs:
376 // for x in `perl -ne 'print $1,"\n" if /^;(\w+) =/' config/config-dist.ini`; do \
377 //   grep \'$x\' configurator.php >/dev/null || echo $x ; done
378
379 $properties["Part Zero"] =
380     new part('_part0', $SEPARATOR . "\n", "
381 Part Zero: (optional)
382 Latest Development and Tricky Options");
383
384 if (defined('INCLUDE_PATH'))
385     $include_path = INCLUDE_PATH;
386 else {
387     if (substr(PHP_OS, 0, 3) == 'WIN') {
388         $include_path = dirname(__FILE__) . ';' . ini_get('include_path');
389         if (strchr(ini_get('include_path'), '/'))
390             $include_path = strtr($include_path, '\\', '/');
391     } else {
392         $include_path = dirname(__FILE__) . ':' . ini_get('include_path');
393     }
394 }
395
396 $properties["PHP include_path"] =
397     new _define('INCLUDE_PATH', $include_path);
398
399 // TODO: Convert this to a checkbox row as in tests/unit/test.php
400 $properties["DEBUG"] =
401     new numeric_define_optional('DEBUG', DEBUG);
402
403 $properties["ENABLE_EDIT_TOOLBAR"] =
404     new boolean_define_commented_optional('ENABLE_EDIT_TOOLBAR');
405
406 $properties["JS_SEARCHREPLACE"] =
407     new boolean_define_commented_optional('JS_SEARCHREPLACE');
408
409 // TESTME: use config-default:  = false
410 $properties["ENABLE_DOUBLECLICKEDIT"] =
411     new boolean_define_commented_optional('ENABLE_DOUBLECLICKEDIT');
412
413 $properties["ENABLE_WYSIWYG"] =
414     new boolean_define_commented_optional('ENABLE_WYSIWYG');
415
416 $properties["WYSIWYG_BACKEND"] =
417     new _define_selection(
418         'WYSIWYG_BACKEND',
419         array('Wikiwyg' => 'Wikiwyg',
420             'tinymce' => 'tinymce',
421             'FCKeditor' => 'FCKeditor',
422             'spaw' => 'spaw',
423             'htmlarea3' => 'htmlarea3',
424             'htmlarea2' => 'htmlarea2',
425         ));
426
427 $properties["WYSIWYG_DEFAULT_PAGETYPE_HTML"] =
428     new boolean_define_commented_optional('WYSIWYG_DEFAULT_PAGETYPE_HTML');
429
430 $properties["UPLOAD_USERDIR"] =
431     new boolean_define_commented_optional('UPLOAD_USERDIR');
432
433 $properties["DISABLE_UNITS"] =
434     new boolean_define_commented_optional('DISABLE_UNITS');
435
436 $properties["UNITS_EXE"] =
437     new _define_commented_optional('UNITS_EXE');
438
439 $properties["ENABLE_XHTML_XML"] =
440     new boolean_define_commented_optional('ENABLE_XHTML_XML');
441
442 $properties["ENABLE_OPEN_GRAPH"] =
443     new boolean_define_commented_optional('ENABLE_OPEN_GRAPH');
444
445 $properties["ENABLE_SPAMASSASSIN"] =
446     new boolean_define_commented_optional('ENABLE_SPAMASSASSIN');
447
448 $properties["ENABLE_SPAMBLOCKLIST"] =
449     new boolean_define_optional('ENABLE_SPAMBLOCKLIST');
450
451 $properties["NUM_SPAM_LINKS"] =
452     new numeric_define_optional('NUM_SPAM_LINKS');
453
454 $properties["GOOGLE_LINKS_NOFOLLOW"] =
455     new boolean_define_commented_optional('GOOGLE_LINKS_NOFOLLOW');
456
457 $properties["ENABLE_LIVESEARCH"] =
458     new boolean_define_commented_optional('ENABLE_LIVESEARCH');
459
460 $properties["ENABLE_ACDROPDOWN"] =
461     new boolean_define_commented_optional('ENABLE_ACDROPDOWN');
462
463 $properties["ENABLE_DISCUSSION_LINK"] =
464     new boolean_define_commented_optional('ENABLE_DISCUSSION_LINK');
465
466 $properties["ENABLE_CAPTCHA"] =
467     new boolean_define_commented_optional('ENABLE_CAPTCHA');
468
469 $properties["USE_CAPTCHA_RANDOM_WORD"] =
470     new boolean_define_commented_optional('USE_CAPTCHA_RANDOM_WORD');
471
472 $properties["USE_SAFE_DBSESSION"] =
473     new boolean_define_commented_optional('USE_SAFE_DBSESSION');
474
475 $properties["BLOG_DEFAULT_EMPTY_PREFIX"] =
476     new boolean_define_commented_optional('BLOG_DEFAULT_EMPTY_PREFIX');
477
478 $properties["ENABLE_SEARCHHIGHLIGHT"] =
479     new boolean_define_commented_optional('ENABLE_SEARCHHIGHLIGHT');
480
481 $properties["Part One"] =
482     new part('_part1', $SEPARATOR . "\n", "
483 Part One: Authentication and security settings. See Part Three for more.");
484
485 $properties["Wiki Name"] =
486     new _define_optional('WIKI_NAME', WIKI_NAME);
487
488 $properties["Admin Username"] =
489     new _define_notempty('ADMIN_USER', ADMIN_USER, "
490 You must set this! Username and password of the administrator.",
491         "onchange=\"validate_ereg('Sorry, ADMIN_USER cannot be empty.', '^.+$', 'ADMIN_USER', this);\"");
492
493 $properties["Admin Password"] =
494     new _define_password('ADMIN_PASSWD', ADMIN_PASSWD, "
495 You must set this!
496 For heaven's sake pick a good password.
497
498 If your version of PHP supports encrypted passwords, your password will be
499 automatically encrypted within the generated config file.
500 Use the \"Create Random Password\" button to create a good (random) password.
501
502 ADMIN_PASSWD is ignored on HttpAuth",
503         "onchange=\"validate_ereg('Sorry, ADMIN_PASSWD must be at least 4 chars long.', '^....+$', 'ADMIN_PASSWD', this);\"");
504
505 $properties["Encrypted Passwords"] =
506     new boolean_define
507     ('ENCRYPTED_PASSWD',
508         array('true' => "true.  use crypt for all passwords",
509             'false' => "false. use plaintest passwords (not recommended)"));
510
511 $properties["Reverse DNS"] =
512     new boolean_define_optional
513     ('ENABLE_REVERSE_DNS',
514         array('true' => "true. perform additional reverse dns lookups",
515             'false' => "false. just record the address as given by the httpd server"));
516
517 $properties["ZIP Dump Authentication"] =
518     new boolean_define_optional('ZIPDUMP_AUTH',
519         array('false' => "false. Everyone may download zip dumps",
520             'true' => "true. Only admin may download zip dumps"));
521
522 $properties["Enable RawHtml Plugin"] =
523     new boolean_define_commented_optional('ENABLE_RAW_HTML');
524
525 $properties["Allow RawHtml Plugin only on locked pages"] =
526     new boolean_define_commented_optional('ENABLE_RAW_HTML_LOCKEDONLY');
527
528 $properties["Allow RawHtml Plugin if safe HTML code"] =
529     new boolean_define_commented_optional('ENABLE_RAW_HTML_SAFE', '', "
530 If this is set, all unsafe html code is stripped automatically (experimental!)
531 See <a href=\"http://chxo.com/scripts/safe_html-test.php\" target=\"_new\">chxo.com/scripts/safe_html-test.php</a>
532 ");
533
534 $properties["Maximum Upload Size"] =
535     new numeric_define_optional('MAX_UPLOAD_SIZE', MAX_UPLOAD_SIZE);
536
537 $properties["Minor Edit Timeout"] =
538     new numeric_define_optional('MINOR_EDIT_TIMEOUT', MINOR_EDIT_TIMEOUT);
539
540 $properties["Disabled Actions"] =
541     new array_define('DISABLED_ACTIONS', DISABLED_ACTIONS /*array()*/);
542
543 $properties["Moderate all Pagechanges"] =
544     new boolean_define_commented_optional('ENABLE_MODERATEDPAGE_ALL');
545
546 $properties["Access Log File"] =
547     new _define_commented_optional('ACCESS_LOG', ACCESS_LOG);
548
549 $properties["Access Log SQL"] =
550     new _define_selection(
551         'ACCESS_LOG_SQL',
552         array('0' => 'disabled',
553             '1' => 'read only',
554             '2' => 'read + write'));
555
556 $properties["Compress Output"] =
557     new boolean_define_commented_optional
558     ('COMPRESS_OUTPUT',
559         array('' => 'undefined - GZIP compress when appropriate.',
560             'false' => 'Never compress output.',
561             'true' => 'Always try to compress output.'));
562
563 $properties["HTTP Cache Control"] =
564     new _define_selection_optional
565     ('CACHE_CONTROL',
566         array('LOOSE' => 'LOOSE',
567             'STRICT' => 'STRICT',
568             'NO_CACHE' => 'NO_CACHE',
569             'ALLOW_STALE' => 'ALLOW_STALE'),
570         "
571 HTTP CACHE_CONTROL
572
573 This controls how PhpWiki sets the HTTP cache control
574 headers (Expires: and Cache-Control:)
575
576 Choose one of:
577 <dl>
578 <dt>NO_CACHE</dt>
579 <dd>This is roughly the old (pre 1.3.4) behaviour.  PhpWiki will
580     instruct proxies and browsers never to cache PhpWiki output.</dd>
581 <dt>STRICT</dt>
582 <dd>Cached pages will be invalidated whenever the database global
583     timestamp changes.  This should behave just like NONE (modulo
584     bugs in PhpWiki and your proxies and browsers), except that
585     things will be slightly more efficient.</dd>
586 <dt>LOOSE</dt>
587 <dd>Cached pages will be invalidated whenever they are edited,
588     or, if the pages include plugins, when the plugin output could
589     concievably have changed.
590     <p>Behavior should be much like STRICT, except that sometimes
591        wikilinks will show up as undefined (with the question mark)
592        when in fact they refer to (recently) created pages.
593        (Hitting your browsers reload or perhaps shift-reload button
594        should fix the problem.)</p></dd>
595 <dt>ALLOW_STALE</dt>
596 <dd>Proxies and browsers will be allowed to used stale pages.
597     (The timeout for stale pages is controlled by CACHE_CONTROL_MAX_AGE.)
598     <p>This setting will result in quirky behavior.  When you edit a
599        page your changes may not show up until you shift-reload the
600        page, etc...</p>
601     <p>This setting is generally not advisable, however it may be useful
602        in certain cases (e.g. if your wiki gets lots of page views,
603        and few edits by knowledgable people who won't freak over the quirks.)</p>
604 </dd>
605 </dl>
606 The default is currently LOOSE.");
607
608 $properties["HTTP Cache Control Max Age"] =
609     new numeric_define_optional('CACHE_CONTROL_MAX_AGE', CACHE_CONTROL_MAX_AGE);
610
611 $properties["Markup Caching"] =
612     new boolean_define_commented_optional
613     ('WIKIDB_NOCACHE_MARKUP',
614         array('false' => 'Enable markup cache',
615             'true' => 'Disable markup cache'));
616
617 $properties["COOKIE_EXPIRATION_DAYS"] =
618     new numeric_define_optional('COOKIE_EXPIRATION_DAYS', COOKIE_EXPIRATION_DAYS);
619
620 $properties["COOKIE_DOMAIN"] =
621     new _define_commented_optional('COOKIE_DOMAIN', COOKIE_DOMAIN);
622
623 $properties["Path for PHP Session Support"] =
624     new _define_optional('SESSION_SAVE_PATH', defined('SESSION_SAVE_PATH') ? SESSION_SAVE_PATH : ini_get('session.save_path'));
625
626 $properties["Force PHP Database Sessions"] =
627     new boolean_define_commented_optional
628     ('USE_DB_SESSION',
629         array('false' => 'Disable database sessions, use files',
630             'true' => 'Enable database sessions'));
631
632 ///////// database selection
633
634 $properties["Part Two"] =
635     new part('_part2', $SEPARATOR . "\n", "
636
637 Part Two:
638 Database Configuration
639 ");
640
641 $properties["Database Type"] =
642     new _define_selection("DATABASE_TYPE",
643         array('dba' => "dba",
644             'SQL' => "SQL PEAR",
645             'ADODB' => "SQL ADODB",
646             'PDO' => "PDO (php5 only)",
647             'file' => "flatfile",
648             'cvs' => "CVS File handler")/*, "
649 Select the database backend type:
650 Choose dba (default) to use one of the standard UNIX dba libraries. This is the fastest.
651 Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
652 Choose PDO on php5 to use an SQL database. (experimental, no paging yet)
653 flatfile is simple and slow.
654 CVS is highly experimental and slow.
655 Recommended is dba or SQL: PEAR or ADODB."*/);
656
657 $properties["SQL DSN Setup"] =
658     new unchangeable_variable('_sqldsnstuff', "", "
659 For SQL based backends, specify the database as a DSN
660 The most general form of a DSN looks like:
661 <pre>
662   phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
663 </pre>
664 For a MySQL database, the following should work:
665 <pre>
666    mysql://user:password@host/databasename
667 </pre>
668 To connect over a unix socket, use something like
669 <pre>
670    mysql://user:password@unix(/path/to/socket)/databasename
671 </pre>
672 <pre>
673   DATABASE_DSN = mysql://guest@:/var/lib/mysql/mysql.sock/phpwiki
674   DATABASE_DSN = mysql://guest@localhost/phpwiki
675   DATABASE_DSN = pgsql://localhost/user_phpwiki
676 </pre>");
677
678 // Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
679 // Choose dba to use one of the standard UNIX dbm libraries.
680
681 $properties["SQL Type"] =
682     new _variable_selection('_dsn_sqltype',
683         array('mysql' => "MySQL",
684             'pgsql' => "PostgreSQL",
685             'mssql' => "Microsoft SQL Server",
686             'mssqlnative' => "Microsoft SQL Server (native)",
687             'oci8' => "Oracle 8",
688             'mysqli' => "mysqli (only ADODB)",
689             'mysqlt' => "mysqlt (only ADODB)",
690             'ODBC' => "ODBC (only ADODB or PDO)",
691             'firebird' => "Firebird (only PDO)",
692             'oracle' => "Oracle (only PDO)",
693         ), "
694 SQL DB types. The DSN hosttype.");
695
696 $properties["SQL User"] =
697     new _variable('_dsn_sqluser', "wikiuser", "
698 SQL User Id:");
699
700 $properties["SQL Password"] =
701     new _variable('_dsn_sqlpass', "", "
702 SQL Password:");
703
704 $properties["SQL Database Host"] =
705     new _variable('_dsn_sqlhostorsock', "localhost", "
706 SQL Database Hostname:
707
708 To connect over a local named socket, use something like
709 <pre>
710   unix(/var/lib/mysql/mysql.sock)
711 </pre>
712 here.
713 mysql on Windows via named pipes might need 127.0.0.1");
714
715 $properties["SQL Database Name"] =
716     new _variable('_dsn_sqldbname', "phpwiki", "
717 SQL Database Name:");
718
719 $dsn_sqltype = $properties["SQL Type"]->value();
720 $dsn_sqluser = $properties["SQL User"]->value();
721 $dsn_sqlpass = $properties["SQL Password"]->value();
722 $dsn_sqlhostorsock = $properties["SQL Database Host"]->value();
723 $dsn_sqldbname = $properties["SQL Database Name"]->value();
724 $dsn_sqlstring = $dsn_sqltype . "://{$dsn_sqluser}:{$dsn_sqlpass}@{$dsn_sqlhostorsock}/{$dsn_sqldbname}";
725
726 $properties["SQL dsn"] =
727     new unchangeable_define("DATABASE_DSN",
728         $dsn_sqlstring, "
729 Calculated from the settings above:");
730
731 $properties["Filename / Table name Prefix"] =
732     new _define_commented('DATABASE_PREFIX', DATABASE_PREFIX, "
733 Used by all DB types:
734
735 Prefix for filenames or table names, e.g. \"phpwiki_\"
736
737 Currently <b>you MUST EDIT THE SQL file too!</b> (in the schemas/
738 directory because we aren't doing on the fly sql generation
739 during the installation.
740
741 Note: This prefix is NOT prepended to the default DBAUTH_
742       tables user, pref and member!
743 ");
744
745 $properties["DATABASE_PERSISTENT"] =
746     new boolean_define_commented_optional
747     ('DATABASE_PERSISTENT',
748         array('false' => "Disabled",
749             'true' => "Enabled"));
750
751 $properties["DB Session table"] =
752     new _define_optional("DATABASE_SESSION_TABLE", DATABASE_SESSION_TABLE, "
753 Tablename to store session information. Only supported by SQL backends.
754
755 A word of warning - any prefix defined above will be prepended to whatever is given here.
756 ");
757
758 //TODO: $TEMP
759 $temp = !empty($_ENV['TEMP']) ? $_ENV['TEMP'] : "/tmp";
760 $properties["dba directory"] =
761     new _define("DATABASE_DIRECTORY", $temp);
762
763 // TODO: list the available methods
764 $properties["dba handler"] =
765     new _define_selection('DATABASE_DBA_HANDLER',
766         array('gdbm' => "gdbm - GNU database manager (not recommended anymore)",
767             'dbm' => "DBM - Redhat default. On sf.net there's dbm and not gdbm anymore",
768             'db2' => "DB2 - BerkeleyDB (Sleepycat) DB2",
769             'db3' => "DB3 - BerkeleyDB (Sleepycat) DB3. Default on Windows but not on every Linux",
770             'db4' => "DB4 - BerkeleyDB (Sleepycat) DB4."), "
771 Use 'gdbm', 'dbm', 'db2', 'db3' or 'db4' depending on your DBA handler methods supported: <br />  "
772             . join(", ", dba_handlers())
773             . "\n\nBetter not use other hacks such as inifile, flatfile or cdb");
774
775 $properties["dba timeout"] =
776     new numeric_define("DATABASE_TIMEOUT", DATABASE_TIMEOUT, "
777 Recommended values are 10-20 seconds. The more load the server has, the higher the timeout.");
778
779 $properties["DATABASE_OPTIMISE_FREQUENCY"] =
780     new numeric_define_optional('DATABASE_OPTIMISE_FREQUENCY', DATABASE_OPTIMISE_FREQUENCY);
781
782 $properties["DBADMIN_USER"] =
783     new _define_optional('DBADMIN_USER', DBADMIN_USER);
784
785 $properties["DBADMIN_PASSWD"] =
786     new _define_password_optional('DBADMIN_PASSWD', DBADMIN_PASSWD);
787
788 $properties["USECACHE"] =
789     new boolean_define_commented_optional('USECACHE');
790
791 ///////////////////
792
793 $properties["Page Revisions"] =
794     new unchangeable_variable('_parttworevisions', "", "
795
796 Section 2a: Archive Cleanup
797 The next section controls how many old revisions of each page are kept in the database.
798
799 There are two basic classes of revisions: major and minor. Which
800 class a revision belongs in is determined by whether the author
801 checked the \"this is a minor revision\" checkbox when they saved the
802 page.
803
804 There is, additionally, a third class of revisions: author
805 revisions. The most recent non-mergable revision from each distinct
806 author is and author revision.
807
808 The expiry parameters for each of those three classes of revisions
809 can be adjusted separately. For each class there are five
810 parameters (usually, only two or three of the five are actually
811 set) which control how long those revisions are kept in the
812 database.
813 <dl>
814    <dt>max_keep:</dt> <dd>If set, this specifies an absolute maximum for the
815             number of archived revisions of that class. This is
816             meant to be used as a safety cap when a non-zero
817             min_age is specified. It should be set relatively high,
818             and it's purpose is to prevent malicious or accidental
819             database overflow due to someone causing an
820             unreasonable number of edits in a short period of time.</dd>
821
822   <dt>min_age:</dt>  <dd>Revisions younger than this (based upon the supplanted
823             date) will be kept unless max_keep is exceeded. The age
824             should be specified in days. It should be a
825             non-negative, real number,</dd>
826
827   <dt>min_keep:</dt> <dd>At least this many revisions will be kept.</dd>
828
829   <dt>keep:</dt>     <dd>No more than this many revisions will be kept.</dd>
830
831   <dt>max_age:</dt>  <dd>No revision older than this age will be kept.</dd>
832 </dl>
833 Supplanted date: Revisions are timestamped at the instant that they
834 cease being the current revision. Revision age is computed using
835 this timestamp, not the edit time of the page.
836
837 Merging: When a minor revision is deleted, if the preceding
838 revision is by the same author, the minor revision is merged with
839 the preceding revision before it is deleted. Essentially: this
840 replaces the content (and supplanted timestamp) of the previous
841 revision with the content after the merged minor edit, the rest of
842 the page metadata for the preceding version (summary, mtime, ...)
843 is not changed.
844 ");
845
846 // For now the expiration parameters are statically inserted as
847 // an unchangeable property. You'll have to edit the resulting
848 // config file if you really want to change these from the default.
849
850 $properties["Major Edits: keep minimum days"] =
851     new numeric_define('MAJOR_MIN_KEEP', MAJOR_MIN_KEEP, "
852 Default: Keep for unlimited time.
853 Set to 0 to enable archive cleanup");
854 $properties["Minor Edits: keep minumum days"] =
855     new numeric_define('MINOR_MIN_KEEP', MINOR_MIN_KEEP, "
856 Default: Keep for unlimited time.
857 Set to 0 to enable archive cleanup");
858
859 $properties["Major Edits: how many"] =
860     new numeric_define('MAJOR_KEEP', MAJOR_KEEP, "
861 Keep up to 8 major edits");
862 $properties["Major Edits: how many days"] =
863     new numeric_define('MAJOR_MAX_AGE', MAJOR_MAX_AGE, "
864 keep them no longer than a month");
865
866 $properties["Minor Edits: how many"] =
867     new numeric_define("MINOR_KEEP", MINOR_KEEP, "
868 Keep up to 4 minor edits");
869 $properties["Minor Edits: how many days"] =
870     new numeric_define("MINOR_MAX_AGE", "7", "
871 keep them no longer than a week");
872
873 $properties["per Author: how many"] =
874     new numeric_define("AUTHOR_KEEP", "8", "
875 Keep the latest contributions of the last 8 authors,");
876 $properties["per Author: how many days"] =
877     new numeric_define("AUTHOR_MAX_AGE", "365", "
878 up to a year.");
879 $properties["per Author: keep minumum days"] =
880     new numeric_define("AUTHOR_MIN_AGE", "7", "
881 Additionally, (in the case of a particularly active page) try to
882 keep the latest contributions of all authors in the last week (even if there are more than eight of them,)");
883 $properties["per Author: max revisions"] =
884     new numeric_define("AUTHOR_MAX_KEEP", "20", "
885 but in no case keep more than twenty unique author revisions.");
886
887 /////////////////////////////////////////////////////////////////////
888
889 $properties["Part Three"] =
890     new part('_part3', $SEPARATOR . "\n", "
891
892 Part Three: (optional)
893 Basic User Authentication Setup
894 ");
895
896 $properties["Publicly viewable"] =
897     new boolean_define_optional('ALLOW_ANON_USER',
898         array('true' => "true. Permit anonymous view. (Default)",
899             'false' => "false. Force login even on view (strictly private)"), "
900 If ALLOW_ANON_USER is false, you have to login before viewing any page or doing any other action on a page.");
901
902 $properties["Allow anonymous edit"] =
903     new boolean_define_optional('ALLOW_ANON_EDIT',
904         array('true' => "true. Permit anonymous users to edit. (Default)",
905             'false' => "false. Force login on edit (moderately locked)"), "
906 If ALLOW_ANON_EDIT is false, you have to login before editing or changing any page. See below.");
907
908 $properties["Allow Bogo Login"] =
909     new boolean_define_optional('ALLOW_BOGO_LOGIN',
910         array('true' => "true. Users may Sign In with any WikiWord, without password. (Default)",
911             'false' => "false. Require stricter authentication."), "
912 If ALLOW_BOGO_LOGIN is false, you may not login with any wikiword username and empty password.
913 If true, users are allowed to create themselves with any WikiWord username. See below.");
914
915 $properties["Allow User Passwords"] =
916     new boolean_define_optional('ALLOW_USER_PASSWORDS',
917         array('true' => "True user authentication with password checking. (Default)",
918             'false' => "false. Ignore authentication settings below."), "
919 If ALLOW_USER_PASSWORDS is true, the authentication settings below define where and how to
920 check against given username/passwords. For completely security disable BOGO_LOGIN and ANON_EDIT above.");
921
922 $properties["User Authentication Methods"] =
923     new array_define('USER_AUTH_ORDER', array("PersonalPage", "Db"), "
924 Many different methods can be used to check user's passwords.
925 Try any of these in the given order:
926 <dl>
927 <dt>BogoLogin</dt>
928         <dd>WikiWord username, with no *actual* password checking,
929         although the user will still have to enter one.</dd>
930 <dt>PersonalPage</dt>
931         <dd>Store passwords in the users homepage metadata (simple)</dd>
932 <dt>Db</dt>
933         <dd>Use DBAUTH_AUTH_* (see below) with PearDB or ADODB only.</dd>
934 <dt>LDAP</dt>
935         <dd>Authenticate against LDAP_AUTH_HOST with LDAP_BASE_DN.</dd>
936 <dt>IMAP</dt>
937         <dd>Authenticate against IMAP_AUTH_HOST (email account)</dd>
938 <dt>POP3</dt>
939         <dd>Authenticate against POP3_AUTH_HOST (email account)</dd>
940 <dt>Session</dt>
941         <dd>Get username and level from a PHP session variable. (e.g. for FusionForge)</dd>
942 <dt>File</dt>
943         <dd>Store username:crypted-passwords in .htaccess like files.
944          Use Apache's htpasswd to manage this file.</dd>
945 <dt>HttpAuth</dt>
946         <dd>Use the protection by the webserver (.htaccess/.htpasswd) (experimental)
947         Enforcing HTTP Auth not yet. Note that the ADMIN_USER should exist also.
948         Using HttpAuth disables all other methods and no userauth sessions are used.</dd>
949 </dl>
950
951 Several of these methods can be used together, in the manner specified by
952 USER_AUTH_POLICY, below.  To specify multiple authentication methods,
953 separate the name of each one with colons.
954 <pre>
955   USER_AUTH_ORDER = 'PersonalPage : Db'
956   USER_AUTH_ORDER = 'BogoLogin : PersonalPage'
957 </pre>");
958
959 $properties["ENABLE_AUTH_OPENID"] =
960     new boolean_define('ENABLE_AUTH_OPENID');
961
962 $properties["PASSWORD_LENGTH_MINIMUM"] =
963     new numeric_define('PASSWORD_LENGTH_MINIMUM', PASSWORD_LENGTH_MINIMUM);
964
965 $properties["USER_AUTH_POLICY"] =
966     new _define_selection('USER_AUTH_POLICY',
967         array('first-only' => "first-only - use only the first method in USER_AUTH_ORDER",
968             'old' => "old - ignore USER_AUTH_ORDER (legacy)",
969             'strict' => "strict - check all methods for userid + password (recommended)",
970             'stacked' => "stacked - check all methods for userid, and if found for password"), "
971 The following policies are available for user authentication:
972 <dl>
973 <dt>first-only</dt>
974         <dd>use only the first method in USER_AUTH_ORDER</dd>
975 <dt>old</dt>
976         <dd>ignore USER_AUTH_ORDER and try to use all available
977         methods as in the previous PhpWiki releases (slow)</dd>
978 <dt>strict</dt>
979         <dd>check if the user exists for all methods:
980         on the first existing user, try the password.
981         dont try the other methods on failure then</dd>
982 <dt>stacked</dt>
983         <dd>check the given user - password combination for all
984         methods and return true on the first success.</dd></dl>");
985
986 $properties["ENABLE_USER_NEW"] =
987     new boolean_define_commented_optional('ENABLE_USER_NEW');
988
989 $properties["ENABLE_PAGEPERM"] =
990     new boolean_define_commented_optional('ENABLE_PAGEPERM');
991
992 ///////////////////
993
994 $properties["Part Three A"] =
995     new part('_part3a', $SEPARATOR . "\n", "
996
997 Part Three A: (optional)
998 Group Membership");
999
1000 $properties["Group membership"] =
1001     new _define_selection("GROUP_METHOD",
1002         array('WIKIPAGE' => "WIKIPAGE - List at \"CategoryGroup\". (Slowest, but easiest to maintain)",
1003             'NONE' => "NONE - Disable group membership (Fastest)",
1004             'DB' => "DB - SQL Database, Optionally external. See USERS/GROUPS queries",
1005             'FILE' => "Flatfile. See AUTH_GROUP_FILE below.",
1006             'LDAP' => "LDAP - See \"LDAP authentication options\" above. (Experimental)"), "
1007 Group membership.  PhpWiki supports defining permissions for a group as
1008 well as for individual users.  This defines how group membership information
1009 is obtained.  Supported values are:
1010 <dl>
1011 <dt>\"NONE\"</dt>
1012           <dd>Disable group membership (Fastest). Note the required quoting.</dd>
1013 <dt>WIKIPAGE</dt>
1014           <dd>Define groups as list at \"CategoryGroup\". (Slowest, but easiest to maintain)</dd>
1015 <dt>DB</dt>
1016           <dd>Stored in an SQL database. Optionally external. See USERS/GROUPS queries</dd>
1017 <dt>FILE</dt>
1018           <dd>Flatfile. See AUTH_GROUP_FILE below.</dd>
1019 <dt>LDAP</dt>
1020           <dd>LDAP groups. See \"LDAP authentication options\" above and
1021           lib/WikiGroup.php. (experimental)</dd></dl>");
1022
1023 $properties["CATEGORY_GROUP_PAGE"] =
1024     new _define_optional('CATEGORY_GROUP_PAGE', _("CategoryGroup"), "
1025 If GROUP_METHOD = WIKIPAGE:
1026
1027 Page where all groups are listed.");
1028
1029 $properties["AUTH_GROUP_FILE"] =
1030     new _define_optional('AUTH_GROUP_FILE', _("/etc/groups"), "
1031 For GROUP_METHOD = FILE, the file given below is referenced to obtain
1032 group membership information.  It should be in the same format as the
1033 standard unix /etc/groups(5) file.");
1034
1035 $properties["Part Three B"] =
1036     new part('_part3b', $SEPARATOR . "\n", "
1037
1038 Part Three B: (optional)
1039 External database authentication and authorization.
1040
1041 If USER_AUTH_ORDER includes Db, or GROUP_METHOD = DB, the options listed
1042 below define the SQL queries used to obtain the information out of the
1043 database, and (optionally) store the information back to the DB.");
1044
1045 $properties["DBAUTH_AUTH_DSN"] =
1046     new _define_optional('DBAUTH_AUTH_DSN', $dsn_sqlstring, "
1047 A database DSN to connect to.  Defaults to the DSN specified for the Wiki as a whole.");
1048
1049 $properties["User Exists Query"] =
1050     new _define('DBAUTH_AUTH_USER_EXISTS', "SELECT userid FROM user WHERE userid='\$userid'", "
1051 USER/PASSWORD queries:
1052
1053 For USER_AUTH_POLICY=strict and the Db method is required");
1054
1055 $properties["Check Query"] =
1056     new _define_optional('DBAUTH_AUTH_CHECK', "SELECT IF(passwd='\$password',1,0) AS ok FROM user WHERE userid='\$userid'", "
1057
1058 Check to see if the supplied username/password pair is OK
1059
1060 Plaintext passwords: (DBAUTH_AUTH_CRYPT_METHOD = plain)<br />
1061 ; DBAUTH_AUTH_CHECK = \"SELECT IF(passwd='\$password',1,0) AS ok FROM user WHERE userid='\$userid'\"
1062
1063 database-hashed passwords (more secure):<br />
1064 ; DBAUTH_AUTH_CHECK = \"SELECT IF(passwd=PASSWORD('\$password'),1,0) AS ok FROM user WHERE userid='\$userid'\"");
1065
1066 $properties["Crypt Method"] =
1067     new _define_selection_optional
1068     ('DBAUTH_AUTH_CRYPT_METHOD',
1069         array('plain' => 'plain',
1070             'crypt' => 'crypt'), "
1071 If you want to use Unix crypt()ed passwords, you can use DBAUTH_AUTH_CHECK
1072 to get the password out of the database with a simple SELECT query, and
1073 specify DBAUTH_AUTH_USER_EXISTS and DBAUTH_AUTH_CRYPT_METHOD:
1074
1075 ; DBAUTH_AUTH_CHECK = \"SELECT passwd FROM user where userid='\$userid'\" <br />
1076 ; DBAUTH_AUTH_CRYPT_METHOD = crypt");
1077
1078 $properties["Update the user's authentication credential"] =
1079     new _define('DBAUTH_AUTH_UPDATE', "UPDATE user SET passwd='\$password' WHERE userid='\$userid'", "
1080 If this is not defined but DBAUTH_AUTH_CHECK is, then the user will be unable to update their
1081 password.
1082
1083 Plaintext passwords:<br />
1084   DBAUTH_AUTH_UPDATE = \"UPDATE user SET passwd='\$password' WHERE userid='\$userid'\"<br />
1085 Database-hashed passwords:<br />
1086   DBAUTH_AUTH_UPDATE = \"UPDATE user SET passwd=PASSWORD('\$password') WHERE userid='\$userid'\"");
1087
1088 $properties["Allow the user to create their own account"] =
1089     new _define_optional('DBAUTH_AUTH_CREATE', "INSERT INTO user SET passwd=PASSWORD('\$password'),userid='\$userid'", "
1090 If this is empty, Db users cannot subscribe by their own.");
1091
1092 $properties["USER/PREFERENCE queries"] =
1093     new _define_optional('DBAUTH_PREF_SELECT', "SELECT prefs FROM user WHERE userid='\$userid'", "
1094 If you choose to store your preferences in an external database, enable
1095 the following queries.  Note that if you choose to store user preferences
1096 in the 'user' table, only registered users get their prefs from the database,
1097 self-created users do not.  Better to use the special 'pref' table.
1098
1099 The prefs field stores the serialized form of the user's preferences array,
1100 to ease the complication of storage.
1101 <pre>
1102   DBAUTH_PREF_SELECT = \"SELECT prefs FROM user WHERE userid='\$userid'\"
1103   DBAUTH_PREF_SELECT = \"SELECT prefs FROM pref WHERE userid='\$userid'\"
1104 </pre>");
1105
1106 $properties["Update the user's preferences"] =
1107     new _define_optional('DBAUTH_PREF_UPDATE', "UPDATE user SET prefs='\$pref_blob' WHERE userid='\$userid'", "
1108 Note that REPLACE works only with mysql and destroy all other columns!
1109
1110 Mysql: DBAUTH_PREF_UPDATE = \"REPLACE INTO pref SET prefs='\$pref_blob',userid='\$userid'\"");
1111
1112 $properties["Create new user's preferences"] =
1113     new _define_optional('DBAUTH_PREF_INSERT', "INSERT INTO pref (userid,prefs) VALUES ('\$userid','\$pref_blob')", "
1114 Define this if new user can be create by themselves.
1115 ");
1116
1117 $properties["USERS/GROUPS queries"] =
1118     new _define_optional('DBAUTH_IS_MEMBER', "SELECT user FROM user WHERE user='\$userid' AND group='\$groupname'", "
1119 You can define 1:n or n:m user<=>group relations, as you wish.
1120
1121 Sample configurations:
1122
1123 only one group per user (1:n):<br />
1124    DBAUTH_IS_MEMBER = \"SELECT user FROM user WHERE user='\$userid' AND group='\$groupname'\"<br />
1125    DBAUTH_GROUP_MEMBERS = \"SELECT user FROM user WHERE group='\$groupname'\"<br />
1126    DBAUTH_USER_GROUPS = \"SELECT group FROM user WHERE user='\$userid'\"<br />
1127 multiple groups per user (n:m):<br />
1128    DBAUTH_IS_MEMBER = \"SELECT userid FROM member WHERE userid='\$userid' AND groupname='\$groupname'\"<br />
1129    DBAUTH_GROUP_MEMBERS = \"SELECT DISTINCT userid FROM member WHERE groupname='\$groupname'\"<br />
1130    DBAUTH_USER_GROUPS = \"SELECT groupname FROM member WHERE userid='\$userid'\"<br />");
1131 $properties["DBAUTH_GROUP_MEMBERS"] =
1132     new _define_optional('DBAUTH_GROUP_MEMBERS', "SELECT user FROM user WHERE group='\$groupname'", "");
1133 $properties["DBAUTH_USER_GROUPS"] =
1134     new _define_optional('DBAUTH_USER_GROUPS', "SELECT group FROM user WHERE user='\$userid'", "");
1135
1136 if (function_exists('ldap_connect')) {
1137
1138     $properties["LDAP AUTH Host"] =
1139         new _define_optional('LDAP_AUTH_HOST', "ldap://localhost:389", "
1140 If USER_AUTH_ORDER contains Ldap:
1141
1142 The LDAP server to connect to.  Can either be a hostname, or a complete
1143 URL to the server (useful if you want to use ldaps or specify a different
1144 port number).");
1145
1146     $properties["LDAP BASE DN"] =
1147         new _define_optional('LDAP_BASE_DN', "ou=mycompany.com,o=My Company", "
1148 The organizational or domain BASE DN: e.g. \"dc=mydomain,dc=com\".
1149
1150 Note: ou=Users and ou=Groups are used for GroupLdap Membership
1151 Better use LDAP_OU_USERS and LDAP_OU_GROUP with GROUP_METHOD=LDAP.");
1152
1153     $properties["LDAP SET OPTION"] =
1154         new _define_optional('LDAP_SET_OPTION', "LDAP_OPT_PROTOCOL_VERSION=3:LDAP_OPT_REFERRALS=0", "
1155 Some LDAP servers need some more options, such as the Windows Active
1156 Directory Server.  Specify the options (as allowed by the PHP LDAP module)
1157 and their values as NAME=value pairs separated by colons.");
1158
1159     $properties["LDAP AUTH USER"] =
1160         new _define_optional('LDAP_AUTH_USER', "CN=ldapuser,ou=Users,o=Development,dc=mycompany.com", "
1161 DN to initially bind to the LDAP server as. This is needed if the server doesn't
1162 allow anonymous queries. (Windows Active Directory Server)");
1163
1164     $properties["LDAP AUTH PASSWORD"] =
1165         new _define_optional('LDAP_AUTH_PASSWORD', "secret", "
1166 Password to use to initially bind to the LDAP server, as the DN
1167 specified in the LDAP_AUTH_USER option (above).");
1168
1169     $properties["LDAP SEARCH FIELD"] =
1170         new _define_optional('LDAP_SEARCH_FIELD', "uid", "
1171 If you want to match usernames against an attribute other than uid,
1172 specify it here. Default: uid
1173
1174 e.g.: LDAP_SEARCH_FIELD = sAMAccountName");
1175
1176     $properties["LDAP OU USERS"] =
1177         new _define_optional('LDAP_OU_USERS', "ou=Users", "
1178 If you have an organizational unit for all users, define it here.
1179 This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1180 Default: ou=Users");
1181
1182     $properties["LDAP OU GROUP"] =
1183         new _define_optional('LDAP_OU_GROUP', "ou=Groups", "
1184 If you have an organizational unit for all groups, define it here.
1185 This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1186 The entries in this ou must have a gidNumber and cn attribute.
1187 Default: ou=Groups");
1188
1189 } else { // function_exists('ldap_connect')
1190
1191     $properties["LDAP Authentication"] =
1192         new unchangeable_variable('LDAP Authentication', "
1193 ; If USER_AUTH_ORDER contains Ldap:
1194 ;
1195 ; The LDAP server to connect to.  Can either be a hostname, or a complete
1196 ; URL to the server (useful if you want to use ldaps or specify a different
1197 ; port number).
1198 ;LDAP_AUTH_HOST = \"ldap://localhost:389\"
1199 ;
1200 ; The organizational or domain BASE DN: e.g. \"dc=mydomain,dc=com\".
1201 ;
1202 ; Note: ou=Users and ou=Groups are used for GroupLdap Membership
1203 ; Better use LDAP_OU_USERS and LDAP_OU_GROUP with GROUP_METHOD=LDAP.
1204 ;LDAP_BASE_DN = \"ou=Users,o=Development,dc=mycompany.com\"
1205
1206 ; Some LDAP servers need some more options, such as the Windows Active
1207 ; Directory Server.  Specify the options (as allowed by the PHP LDAP module)
1208 ; and their values as NAME=value pairs separated by colons.
1209 ; LDAP_SET_OPTION = \"LDAP_OPT_PROTOCOL_VERSION=3:LDAP_OPT_REFERRALS=0\"
1210
1211 ; DN to initially bind to the LDAP server as. This is needed if the server doesn't
1212 ; allow anonymous queries. (Windows Active Directory Server)
1213 ; LDAP_AUTH_USER = \"CN=ldapuser,ou=Users,o=Development,dc=mycompany.com\"
1214
1215 ; Password to use to initially bind to the LDAP server, as the DN
1216 ; specified in the LDAP_AUTH_USER option (above).
1217 ; LDAP_AUTH_PASSWORD = secret
1218
1219 ; If you want to match usernames against an attribute other than uid,
1220 ; specify it here. Default: uid
1221 ; LDAP_SEARCH_FIELD = sAMAccountName
1222
1223 ; If you have an organizational unit for all users, define it here.
1224 ; This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1225 ; Default: ou=Users
1226 ; LDAP_OU_USERS = ou=Users
1227
1228 ; If you have an organizational unit for all groups, define it here.
1229 ; This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1230 ; The entries in this ou must have a gidNumber and cn attribute.
1231 ; Default: ou=Groups
1232 ; LDAP_OU_GROUP = ou=Groups", "
1233 ; Ignored. No LDAP support in this php. configure --with-ldap");
1234 }
1235
1236 if (function_exists('imap_open')) {
1237
1238     $properties["IMAP Auth Host"] =
1239         new _define_optional('IMAP_AUTH_HOST', 'localhost:143/imap/notls', "
1240 If USER_AUTH_ORDER contains IMAP:
1241
1242 The IMAP server to check usernames from. Defaults to localhost.
1243
1244 Some IMAP_AUTH_HOST samples:
1245   localhost, localhost:143/imap/notls,
1246   localhost:993/imap/ssl/novalidate-cert (SuSE refuses non-SSL conections)");
1247
1248 } else { // function_exists('imap_open')
1249
1250     $properties["IMAP Authentication"] =
1251         new unchangeable_variable('IMAP_AUTH_HOST', "
1252 ; If USER_AUTH_ORDER contains IMAP:
1253 ; The IMAP server to check usernames from. Defaults to localhost.
1254 ;
1255 ; Some IMAP_AUTH_HOST samples:
1256 ;   localhost, localhost:143/imap/notls,
1257 ;   localhost:993/imap/ssl/novalidate-cert (SuSE refuses non-SSL conections)
1258 ;IMAP_AUTH_HOST = localhost:143/imap/notls", "
1259 Ignored. No IMAP support in this php. configure --with-imap");
1260
1261 }
1262
1263 $properties["POP3 Authentication"] =
1264     new _define_optional('POP3_AUTH_HOST', 'localhost:110', "
1265 If USER_AUTH_ORDER contains POP3:
1266
1267 The POP3 mail server to check usernames and passwords against.");
1268 $properties["File Authentication"] =
1269     new _define_optional('AUTH_USER_FILE', '/etc/shadow', "
1270 If USER_AUTH_ORDER contains File:
1271
1272 File to read for authentication information.
1273 Popular choices are /etc/shadow and /etc/httpd/.htpasswd");
1274
1275 $properties["File Storable?"] =
1276     new boolean_define_commented_optional('AUTH_USER_FILE_STORABLE');
1277
1278 $properties["Session Auth USER"] =
1279     new _define_optional('AUTH_SESS_USER', 'userid', "
1280 If USER_AUTH_ORDER contains Session:
1281
1282 Name of the session variable which holds the already authenticated username.
1283 Sample: 'userid', 'user[username]', 'user->username'");
1284
1285 $properties["Session Auth LEVEL"] =
1286     new numeric_define('AUTH_SESS_LEVEL', '2', "
1287 Which level will the user be? 1 = Bogo or 2 = Pass");
1288
1289 /////////////////////////////////////////////////////////////////////
1290
1291 $properties["Part Four"] =
1292     new part('_part4', $SEPARATOR . "\n", "
1293
1294 Part Four:
1295 Page appearance and layout");
1296
1297 $properties["Theme"] =
1298     new _define_selection_optional('THEME',
1299         array('default' => "default",
1300             'MacOSX' => "MacOSX",
1301             'smaller' => 'smaller',
1302             'Wordpress' => 'Wordpress',
1303             'Portland' => "Portland",
1304             'Sidebar' => "Sidebar",
1305             'Crao' => 'Crao',
1306             'wikilens' => 'wikilens (Ratings)',
1307             'shamino_com' => 'shamino_com',
1308             'SpaceWiki' => "SpaceWiki",
1309             'Hawaiian' => "Hawaiian",
1310             'MonoBook' => 'MonoBook [experimental]',
1311             'blog' => 'blog [experimental]',
1312         ), "
1313 THEME
1314
1315 Most of the page appearance is controlled by files in the theme
1316 subdirectory.
1317
1318 There are a number of pre-defined themes shipped with PhpWiki.
1319 Or you may create your own, deriving from existing ones.
1320 <pre>
1321   THEME = Sidebar (default)
1322   THEME = default
1323   THEME = MacOSX
1324   THEME = MonoBook (WikiPedia)
1325   THEME = smaller
1326   THEME = Wordpress
1327   THEME = Portland
1328   THEME = Crao
1329   THEME = wikilens (with Ratings)
1330   THEME = Hawaiian
1331   THEME = SpaceWiki
1332   THEME = Hawaiian
1333   THEME = blog     (Kubrick)   [experimental]
1334 </pre>");
1335
1336 $properties["Language"] =
1337     new _define_selection_optional('DEFAULT_LANGUAGE',
1338         array('en' => "English",
1339             '' => "&lt;empty&gt; (user-specific)",
1340             'fr' => "Français",
1341             'de' => "Deutsch",
1342             'nl' => "Nederlands",
1343             'es' => "Español",
1344             'sv' => "Svenska",
1345             'it' => "Italiano",
1346             'ja' => "Japanese",
1347             'zh' => "Chinese"), "
1348 Select your language/locale - default language is \"en\" for English.
1349 Other languages available:<pre>
1350 English  \"en\" (English    - HomePage)
1351 German   \"de\" (Deutsch    - StartSeite)
1352 French   \"fr\" (Français   - Accueil)
1353 Dutch    \"nl\" (Nederlands - ThuisPagina)
1354 Spanish  \"es\" (Español    - PáginaPrincipal)
1355 Swedish  \"sv\" (Svenska    - Framsida)
1356 Italian  \"it\" (Italiano   - PaginaPrincipale)
1357 Japanese \"ja\" (Japanese   - ホームページ)
1358 Chinese  \"zh\" (Chinese    - 首頁)
1359 </pre>
1360 If you set DEFAULT_LANGUAGE to the empty string, your systems default language
1361 (as determined by the applicable environment variables) will be
1362 used.");
1363
1364 $properties["Wiki Page Source"] =
1365     new _define_optional('WIKI_PGSRC', 'pgsrc', "
1366 WIKI_PGSRC -- specifies the source for the initial page contents of
1367 the Wiki. The setting of WIKI_PGSRC only has effect when the wiki is
1368 accessed for the first time (or after clearing the database.)
1369 WIKI_PGSRC can either name a directory or a zip file. In either case
1370 WIKI_PGSRC is scanned for files -- one file per page.
1371 <pre>
1372 // Default (old) behavior:
1373 define('WIKI_PGSRC', 'pgsrc');
1374 // New style:
1375 define('WIKI_PGSRC', 'wiki.zip');
1376 define('WIKI_PGSRC',
1377        '../Logs/Hamwiki/hamwiki-20010830.zip');
1378 </pre>");
1379
1380 $properties["Default Wiki Page Source"] =
1381     new _define('DEFAULT_WIKI_PGSRC', 'pgsrc', "
1382 DEFAULT_WIKI_PGSRC is only used when the language is *not* the
1383 default (English) and when reading from a directory: in that case
1384 some English pages are inserted into the wiki as well.
1385 DEFAULT_WIKI_PGSRC defines where the English pages reside.
1386 ");
1387
1388 $properties["Generic Pages"] =
1389     new array_variable('DEFAULT_WIKI_PAGES', array('ReleaseNotes', 'TestPage'), "
1390 These are ':'-separated pages which will get loaded untranslated from DEFAULT_WIKI_PGSRC.
1391 ");
1392
1393 ///////////////////
1394
1395 $properties["Part Five"] =
1396     new part('_part5', $SEPARATOR . "\n", "
1397
1398 Part Five:
1399 Mark-up options");
1400
1401 $properties["Allowed Protocols"] =
1402     new list_define('ALLOWED_PROTOCOLS', 'http|https|mailto|ftp|news|nntp|ssh|gopher', "
1403 Allowed protocols for links - be careful not to allow \"javascript:\"
1404 URL of these types will be automatically linked.
1405 within a named link [name|uri] one more protocol is defined: phpwiki");
1406
1407 $properties["Inline Images"] =
1408     new list_define('INLINE_IMAGES', 'png|jpg|jpeg|gif|swf');
1409
1410 $properties["WikiName Regexp"] =
1411     new _define('WIKI_NAME_REGEXP', "(?<![[:alnum:]])(?:[[:upper:]][[:lower:]]+){2,}(?![[:alnum:]])", "
1412 Perl regexp for WikiNames (\"bumpy words\")
1413 (?&lt;!..) &amp; (?!...) used instead of '\b' because \b matches '_' as well");
1414
1415 $properties["Subpage Separator"] =
1416     new _define_optional('SUBPAGE_SEPARATOR', '"/"', "
1417 One character which separates pages from subpages. Defaults to '/', but '.' or ':' were also used.",
1418         "onchange=\"validate_ereg('Sorry, \'%s\' must be a single character. Currently only :, / or .', '^[/:.]$', 'SUBPAGE_SEPARATOR', this);\""
1419     );
1420
1421 $properties["InterWiki Map File"] =
1422     new _define('INTERWIKI_MAP_FILE', 'lib/interwiki.map', "
1423 InterWiki linking -- wiki-style links to other wikis on the web
1424
1425 The map will be taken from a page name InterWikiMap.
1426 If that page is not found (or is not locked), or map
1427 data can not be found in it, then the file specified
1428 by INTERWIKI_MAP_FILE (if any) will be used.");
1429
1430 $properties["WARN_NONPUBLIC_INTERWIKIMAP"] =
1431     new boolean_define('WARN_NONPUBLIC_INTERWIKIMAP');
1432
1433 $properties["Keyword Link Regexp"] =
1434     new _define_optional('KEYWORDS', '\"Category* OR Topic*\"', "
1435 Search term used for automatic page classification by keyword extraction.
1436
1437 Any links on a page to pages whose names match this search
1438 will be used keywords in the keywords html meta tag. This is an aid to
1439 classification by search engines. The value of the match is
1440 used as the keyword.
1441
1442 The default behavior is to match Category* or Topic* links.");
1443
1444 $properties["Author and Copyright Site Navigation Links"] =
1445     new _define_commented_optional('COPYRIGHTPAGE_TITLE', "GNU General Public License", "
1446
1447 These will be inserted as &lt;link rel&gt; tags in the html header of
1448 every page, for search engines and for browsers like Mozilla which
1449 take advantage of link rel site navigation.
1450
1451 If you have your own copyright and contact information pages change
1452 these as appropriate.");
1453
1454 $properties["COPYRIGHTPAGE URL"] =
1455     new _define_commented_optional('COPYRIGHTPAGE_URL', "http://www.gnu.org/copyleft/gpl.html#SEC1", "
1456
1457 Other useful alternatives to consider:
1458 <pre>
1459  COPYRIGHTPAGE_TITLE = \"GNU Free Documentation License\"
1460  COPYRIGHTPAGE_URL = \"http://www.gnu.org/copyleft/fdl.html\"
1461  COPYRIGHTPAGE_TITLE = \"Creative Commons License 2.0\"
1462  COPYRIGHTPAGE_URL = \"http://creativecommons.org/licenses/by/2.0/\"</pre>
1463 See http://creativecommons.org/learn/licenses/ for variations");
1464
1465 $properties["AUTHORPAGE_TITLE"] =
1466     new _define_commented_optional('AUTHORPAGE_TITLE', "The PhpWiki Programming Team", "
1467 Default Author Names");
1468 $properties["AUTHORPAGE_URL"] =
1469     new _define_commented_optional('AUTHORPAGE_URL', "http://phpwiki.org/ThePhpWikiProgrammingTeam", "
1470 Default Author URL");
1471
1472 $properties["TOC_FULL_SYNTAX"] =
1473     new boolean_define_optional('TOC_FULL_SYNTAX');
1474
1475 $properties["ENABLE_MARKUP_COLOR"] =
1476     new boolean_define_optional('ENABLE_MARKUP_COLOR');
1477
1478 $properties["DISABLE_MARKUP_WIKIWORD"] =
1479     new boolean_define_optional('DISABLE_MARKUP_WIKIWORD');
1480
1481 $properties["ENABLE_MARKUP_DIVSPAN"] =
1482     new boolean_define_optional('ENABLE_MARKUP_DIVSPAN');
1483
1484 ///////////////////
1485
1486 $properties["Part Six"] =
1487     new part('_part6', $SEPARATOR . "\n", "
1488
1489 Part Six (optional):
1490 URL options -- you can probably skip this section.
1491
1492 For a pretty wiki (no index.php in the url) set a separate DATA_PATH.");
1493
1494 $properties["Server Name"] =
1495     new _define_commented_optional('SERVER_NAME', $_SERVER['SERVER_NAME'], "
1496 Canonical name of the server on which this PhpWiki resides.");
1497
1498 $properties["Server Port"] =
1499     new numeric_define_commented('SERVER_PORT', $_SERVER['SERVER_PORT'], "
1500 Canonical httpd port of the server on which this PhpWiki resides.",
1501         "onchange=\"validate_ereg('Sorry, \'%s\' is no valid port number.', '^[0-9]+$', 'SERVER_PORT', this);\"");
1502
1503 $properties["Server Protocol"] =
1504     new _define_selection_optional_commented('SERVER_PROTOCOL',
1505         array('http' => 'http',
1506             'https' => 'https'));
1507
1508 $properties["Script Name"] =
1509     new _define_commented_optional('SCRIPT_NAME', $scriptname);
1510
1511 $properties["Data Path"] =
1512     new _define_commented_optional('DATA_PATH', dirname($scriptname));
1513
1514 $properties["PhpWiki Install Directory"] =
1515     new _define_commented_optional('PHPWIKI_DIR', dirname(__FILE__));
1516
1517 $properties["Use PATH_INFO"] =
1518     new _define_selection_optional_commented('USE_PATH_INFO',
1519         array('' => 'automatic',
1520             'true' => 'use PATH_INFO',
1521             'false' => 'do not use PATH_INFO'), "
1522 PhpWiki will try to use short urls to pages, eg
1523 http://www.example.com/index.php/HomePage
1524 If you want to use urls like
1525 http://www.example.com/index.php?pagename=HomePage
1526 then define 'USE_PATH_INFO' as false by uncommenting the line below.
1527 NB:  If you are using Apache >= 2.0.30, then you may need to to use
1528 the directive \"AcceptPathInfo On\" in your Apache configuration file
1529 (or in an appropriate <.htaccess> file) for the short urls to work:
1530 See http://httpd.apache.org/docs-2.0/mod/core.html#acceptpathinfo
1531
1532 See also http://phpwiki.sourceforge.net/phpwiki/PrettyWiki for more ideas
1533 on prettifying your urls.
1534
1535 Default: PhpWiki will try to divine whether use of PATH_INFO
1536 is supported in by your webserver/PHP configuration, and will
1537 use PATH_INFO if it thinks that is possible.");
1538
1539 $properties["Virtual Path"] =
1540     new _define_commented_optional('VIRTUAL_PATH', '/SomeWiki', "
1541 VIRTUAL_PATH is the canonical URL path under which your your wiki
1542 appears. Normally this is the same as dirname(SCRIPT_NAME), however
1543 using e.g. separate starter scripts, apaches mod_actions (or mod_rewrite),
1544 you can make it something different.
1545
1546 If you do this, you should set VIRTUAL_PATH here or in the starter scripts.
1547
1548 E.g. your phpwiki might be installed at at /scripts/phpwiki/index.php,
1549 but you've made it accessible through eg. /wiki/HomePage.
1550
1551 One way to do this is to create a directory named 'wiki' in your
1552 server root. The directory contains only one file: an .htaccess
1553 file which reads something like:
1554 <pre>
1555     Action x-phpwiki-page /scripts/phpwiki/index.php
1556     SetHandler x-phpwiki-page
1557     DirectoryIndex /scripts/phpwiki/index.php
1558 </pre>
1559 In that case you should set VIRTUAL_PATH to '/wiki'.
1560
1561 (VIRTUAL_PATH is only used if USE_PATH_INFO is true.)
1562 ");
1563
1564 $upload_file_path = defined('UPLOAD_FILE_PATH') ? UPLOAD_FILE_PATH : getUploadFilePath();
1565 new _define_optional('UPLOAD_FILE_PATH', $temp);
1566
1567 $upload_data_path = defined('UPLOAD_DATA_PATH') ? UPLOAD_DATA_PATH : getUploadDataPath();
1568 new _define_optional('UPLOAD_DATA_PATH', $temp);
1569
1570 $temp = !empty($_ENV['TEMP']) ? $_ENV['TEMP'] : "/tmp";
1571 $properties["TEMP_DIR"] =
1572     new _define_optional('TEMP_DIR', $temp);
1573
1574 ///////////////////
1575
1576 $properties["Part Seven"] =
1577     new part('_part7', $SEPARATOR . "\n", "
1578
1579 Part Seven:
1580
1581 Miscellaneous settings
1582 ");
1583
1584 $properties["Strict Mailable Pagedumps"] =
1585     new boolean_define_optional('STRICT_MAILABLE_PAGEDUMPS',
1586         array('false' => "binary",
1587             'true' => "quoted-printable"));
1588
1589 $properties["Default local Dump Directory"] =
1590     new _define_optional('DEFAULT_DUMP_DIR');
1591
1592 $properties["Default local HTML Dump Directory"] =
1593     new _define_optional('HTML_DUMP_DIR');
1594
1595 $properties["HTML Dump Filename Suffix"] =
1596     new _define_optional('HTML_DUMP_SUFFIX');
1597
1598 $properties["Pagename of Recent Changes"] =
1599     new _define_optional('RECENT_CHANGES',
1600         "RecentChanges");
1601
1602 $properties["Disable HTTP Redirects"] =
1603     new boolean_define_commented_optional('DISABLE_HTTP_REDIRECT');
1604
1605 $properties["Disable GETIMAGESIZE"] =
1606     new boolean_define_commented_optional('DISABLE_GETIMAGESIZE');
1607
1608 $properties["EDITING_POLICY"] =
1609     new _define_optional('EDITING_POLICY');
1610
1611 $properties["TOOLBAR_PAGELINK_PULLDOWN"] =
1612     new _define_commented_optional('TOOLBAR_PAGELINK_PULLDOWN');
1613 $properties["TOOLBAR_TEMPLATE_PULLDOWN"] =
1614     new _define_commented_optional('TOOLBAR_TEMPLATE_PULLDOWN');
1615 $properties["TOOLBAR_IMAGE_PULLDOWN"] =
1616     new _define_commented_optional('TOOLBAR_IMAGE_PULLDOWN');
1617 $properties["FULLTEXTSEARCH_STOPLIST"] =
1618     new _define_commented_optional('FULLTEXTSEARCH_STOPLIST');
1619
1620 $properties["Part Seven A"] =
1621     new part('_part7a', $SEPARATOR . "\n", "
1622
1623 Part Seven A:
1624
1625 Optional Plugin Settings and external executables
1626 ");
1627
1628 $properties["FORTUNE_DIR"] =
1629     new _define_commented_optional('FORTUNE_DIR', "/usr/share/fortune");
1630 $properties["USE_EXTERNAL_HTML2PDF"] =
1631     new _define_commented_optional('USE_EXTERNAL_HTML2PDF', "htmldoc --quiet --format pdf14 --no-toc --no-title %s");
1632 $properties["EXTERNAL_HTML2PDF_PAGELIST"] =
1633     new _define_commented_optional('EXTERNAL_HTML2PDF_PAGELIST');
1634 $properties["BABYCART_PATH"] =
1635     new _define_commented_optional('BABYCART_PATH', "/usr/local/bin/babycart");
1636 $properties["GOOGLE_LICENSE_KEY"] =
1637     new _define_commented_optional('GOOGLE_LICENSE_KEY');
1638 $properties["RATEIT_IMGPREFIX"] =
1639     new _define_commented_optional('RATEIT_IMGPREFIX'); //BStar
1640 $properties["GRAPHVIZ_EXE"] =
1641     new _define_commented_optional('GRAPHVIZ_EXE', "/usr/bin/dot");
1642
1643 if (PHP_OS == "Darwin") // Mac OS X
1644     $ttfont = "/System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Home/lib/fonts/LucidaSansRegular.ttf";
1645 elseif (isWindows()) {
1646     $ttfont = $_ENV['windir'] . '\Fonts\Arial.ttf';
1647 } else {
1648     $ttfont = 'luximr'; // This is the only what sourceforge offered.
1649     //$ttfont = 'Helvetica';
1650 }
1651 $properties["TTFONT"] =
1652     new _define_commented_optional('TTFONT', $ttfont);
1653 $properties["VISUALWIKIFONT"] =
1654     new _define_commented_optional('VISUALWIKIFONT'); // Arial
1655 $properties["VISUALWIKI_ALLOWOPTIONS"] =
1656     new boolean_define_commented_optional('VISUALWIKI_ALLOWOPTIONS'); // false
1657 $properties["PLOTICUS_EXE"] =
1658     new _define_commented_optional('PLOTICUS_EXE'); // /usr/local/bin/pl
1659 $properties["PLOTICUS_PREFABS"] =
1660     new _define_commented_optional('PLOTICUS_PREFABS'); // /usr/share/ploticus
1661 $properties["MY_JABBER_ID"] =
1662     new _define_commented_optional('MY_JABBER_ID'); //
1663 $properties["PHPWEATHER_BASE_DIR"] =
1664     new _define_commented_optional('PHPWEATHER_BASE_DIR'); //
1665 $properties["HIGHLIGHT_EXE"] =
1666     new _define_commented_optional('HIGHLIGHT_EXE'); // /usr/local/bin/highlight
1667 $properties["HIGHLIGHT_DATA_DIR"] =
1668     new _define_commented_optional('HIGHLIGHT_DATA_DIR'); // /usr/share/highlight
1669
1670 $properties["Part Eight"] =
1671     new part('_part8', $SEPARATOR . "\n", "
1672
1673 Part Eight:
1674
1675 Cached Plugin Settings. (pear Cache)
1676 ");
1677
1678 $properties["pear Cache USECACHE"] =
1679     new boolean_define_optional('PLUGIN_CACHED_USECACHE',
1680         array('true' => 'Enabled',
1681             'false' => 'Disabled'), "
1682 Enable or disable pear caching of plugins.");
1683 $properties["pear Cache Database Container"] =
1684     new _define_selection_optional('PLUGIN_CACHED_DATABASE',
1685         array('file' => 'file'), "
1686 Curently only file is supported.
1687 db, trifile and imgfile might be supported, but you must hack that by yourself.");
1688
1689 $properties["pear Cache cache directory"] =
1690     new _define_commented_optional('PLUGIN_CACHED_CACHE_DIR', "/tmp/cache", "
1691 Should be writable to the webserver.");
1692 $properties["pear Cache Filename Prefix"] =
1693     new _define_optional('PLUGIN_CACHED_FILENAME_PREFIX', "phpwiki", "");
1694 $properties["pear Cache HIGHWATER"] =
1695     new numeric_define_optional('PLUGIN_CACHED_HIGHWATER', "4194304", "
1696 Garbage collection parameter.");
1697 $properties["pear Cache LOWWATER"] =
1698     new numeric_define_optional('PLUGIN_CACHED_LOWWATER', "3145728", "
1699 Garbage collection parameter.");
1700 $properties["pear Cache MAXLIFETIME"] =
1701     new numeric_define_optional('PLUGIN_CACHED_MAXLIFETIME', "2592000", "
1702 Garbage collection parameter.");
1703 $properties["pear Cache MAXARGLEN"] =
1704     new numeric_define_optional('PLUGIN_CACHED_MAXARGLEN', "1000", "
1705 max. generated url length.");
1706 $properties["pear Cache FORCE_SYNCMAP"] =
1707     new boolean_define_optional('PLUGIN_CACHED_FORCE_SYNCMAP',
1708         array('true' => 'Enabled',
1709             'false' => 'Disabled'), "");
1710 $properties["pear Cache IMGTYPES"] =
1711     new list_define('PLUGIN_CACHED_IMGTYPES', "png|gif|gd|gd2|jpeg|wbmp|xbm|xpm", "
1712 Handle those image types via GD handles. Check your GD supported image types.");
1713
1714 $end = "\n" . $SEPARATOR . "\n";
1715
1716 // performance hack
1717 text_from_dist("_MAGIC_CLOSE_FILE");
1718
1719 // end of configuration options
1720 ///////////////////////////////
1721 // begin class definitions
1722
1723 /**
1724  * A basic config-dist.ini configuration line in the form of a variable.
1725  * (not needed anymore, we have only defines)
1726  *
1727  * Produces a string in the form "$name = value;"
1728  * e.g.:
1729  * $WikiNameRegexp = "value";
1730  */
1731 class _variable
1732 {
1733
1734     var $config_item_name;
1735     var $default_value;
1736     var $description;
1737     var $prefix;
1738     var $jscheck;
1739
1740     function _variable($config_item_name, $default_value = '', $description = '', $jscheck = '')
1741     {
1742         $this->config_item_name = $config_item_name;
1743         if (!$description)
1744             $description = text_from_dist($config_item_name);
1745         $this->description = $description;
1746         if (defined($config_item_name)
1747             and !preg_match("/(selection|boolean)/", get_class($this))
1748                 and !preg_match("/^(SCRIPT_NAME|VIRTUAL_PATH|TEMP_DIR)$/", $config_item_name)
1749         )
1750             $this->default_value = constant($config_item_name); // ignore given default value
1751         elseif ($config_item_name == $default_value)
1752             $this->default_value = ''; else
1753             $this->default_value = $default_value;
1754         $this->jscheck = $jscheck;
1755         if (preg_match("/variable/i", get_class($this)))
1756             $this->prefix = "\$";
1757         elseif (preg_match("/ini_set/i", get_class($this)))
1758             $this->prefix = "ini_get: "; else
1759             $this->prefix = "";
1760     }
1761
1762     function _define($config_item_name, $default_value = '', $description = '', $jscheck = '')
1763     {
1764         $this->_variable($config_item_name, $default_value, $description, $jscheck);
1765     }
1766
1767     function value()
1768     {
1769         global $HTTP_POST_VARS;
1770         if (isset($HTTP_POST_VARS[$this->config_item_name]))
1771             return $HTTP_POST_VARS[$this->config_item_name];
1772         else
1773             return $this->default_value;
1774     }
1775
1776     function _config_format($value)
1777     {
1778         return '';
1779         $v = $this->get_config_item_name();
1780         // handle arrays: a|b --> a['b']
1781         if (strpos($v, '|')) {
1782             list($a, $b) = explode('|', $v);
1783             $v = sprintf("%s['%s']", $a, $b);
1784         }
1785         if (preg_match("/[\"']/", $value))
1786             $value = '"' . $value . '"';
1787         return sprintf("%s = \"%s\"", $v, $value);
1788     }
1789
1790     function get_config_item_name()
1791     {
1792         return $this->config_item_name;
1793     }
1794
1795     function get_config_item_id()
1796     {
1797         return str_replace('|', '-', $this->config_item_name);
1798     }
1799
1800     function get_config_item_header()
1801     {
1802         if (strchr($this->config_item_name, '|')) {
1803             list($var, $param) = explode('|', $this->config_item_name);
1804             return "<b>" . $this->prefix . $var . "['" . $param . "']</b><br />";
1805         } elseif ($this->config_item_name[0] != '_')
1806             return "<b>" . $this->prefix . $this->config_item_name . "</b><br />"; else
1807             return '';
1808     }
1809
1810     function _get_description()
1811     {
1812         return $this->description;
1813     }
1814
1815     function _get_config_line($posted_value)
1816     {
1817         return "\n" . $this->_config_format($posted_value);
1818     }
1819
1820     function get_config($posted_value)
1821     {
1822         $d = stripHtml($this->_get_description());
1823         $d = str_replace("\n", "\n; ", $d) . $this->_get_config_line($posted_value) . "\n";
1824         return $d;
1825     }
1826
1827     function get_instructions($title)
1828     {
1829         global $tdwidth;
1830         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1831         return "<tr>\n<td width=\"$tdwidth\" class=\"instructions\">\n" . $i . "</td>\n";
1832     }
1833
1834     function get_html()
1835     {
1836         $size = strlen($this->default_value) > 45 ? 90 : 50;
1837         return $this->get_config_item_header() .
1838             "<input type=\"text\" size=\"$50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . htmlspecialchars($this->default_value) . "\" " .
1839             $this->jscheck . " />" . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1840     }
1841 }
1842
1843 class unchangeable_variable
1844     extends _variable
1845 {
1846     function _config_format($value)
1847     {
1848         return "";
1849     }
1850
1851     // function get_html() { return false; }
1852     function get_html()
1853     {
1854         return $this->get_config_item_header() .
1855             "<em>Not editable.</em>" .
1856             "<pre>" . $this->default_value . "</pre>";
1857     }
1858
1859     function _get_config_line($posted_value)
1860     {
1861         if ($this->description)
1862             $n = "\n";
1863         return "${n}" . $this->default_value;
1864     }
1865
1866     function get_instructions($title)
1867     {
1868         global $tdwidth;
1869         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1870         // $i .= "<em>Not editable.</em><br />\n<pre>" . $this->default_value."</pre>";
1871         return '<tr><td width="100%" class="unchangeable-variable-top" colspan="2">' . "\n" . $i . "</td></tr>\n"
1872             . '<tr style="border-top: none;"><td class="unchangeable-variable-left" width="' . $tdwidth . '">&nbsp;</td>';
1873     }
1874 }
1875
1876 class unchangeable_define
1877     extends unchangeable_variable
1878 {
1879     function _get_config_line($posted_value)
1880     {
1881         if ($this->description)
1882             $n = "\n";
1883         if (!$posted_value)
1884             $posted_value = $this->default_value;
1885         return "${n}" . $this->_config_format($posted_value);
1886     }
1887
1888     function _config_format($value)
1889     {
1890         return sprintf("%s = \"%s\"", $this->get_config_item_name(), $value);
1891     }
1892 }
1893 class unchangeable_ini_set
1894     extends unchangeable_variable
1895 {
1896     function _config_format($value)
1897     {
1898         return "";
1899     }
1900 }
1901
1902 class _variable_selection
1903     extends _variable
1904 {
1905     function value()
1906     {
1907         global $HTTP_POST_VARS;
1908         if (!empty($HTTP_POST_VARS[$this->config_item_name]))
1909             return $HTTP_POST_VARS[$this->config_item_name];
1910         else {
1911             list($option, $label) = each($this->default_value);
1912             return $option;
1913         }
1914     }
1915
1916     function get_html()
1917     {
1918         $output = $this->get_config_item_header();
1919         $output .= '<select name="' . $this->get_config_item_name() . "\">\n";
1920         /* The first option is the default */
1921         $values = $this->default_value;
1922         if (defined($this->get_config_item_name()))
1923             $this->default_value = constant($this->get_config_item_name());
1924         else
1925             $this->default_value = null;
1926
1927         foreach ($values as $option => $label) {
1928             if (!is_null($this->default_value) && $this->default_value === $option)
1929                 $output .= "  <option value=\"$option\" selected=\"selected\">$label</option>\n";
1930             else
1931                 $output .= "  <option value=\"$option\">$label</option>\n";
1932         }
1933         $output .= "</select>\n";
1934         return $output;
1935     }
1936 }
1937
1938 class _define
1939     extends _variable
1940 {
1941     function _config_format($value)
1942     {
1943         return sprintf("%s = \"%s\"", $this->get_config_item_name(), $value);
1944     }
1945
1946     function _get_config_line($posted_value)
1947     {
1948         if ($this->description)
1949             $n = "\n";
1950         if ($posted_value == '')
1951             return "${n};" . $this->_config_format("");
1952         else
1953             return "${n}" . $this->_config_format($posted_value);
1954     }
1955
1956     function get_html()
1957     {
1958         $size = strlen($this->default_value) > 45 ? 90 : 50;
1959         return $this->get_config_item_header()
1960             . "<input type=\"text\" size=\"$size\" name=\"" . htmlentities($this->get_config_item_name())
1961             . "\" value=\"" . htmlentities($this->default_value) . "\" {$this->jscheck} />"
1962             . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1963     }
1964 }
1965
1966 class _define_commented
1967     extends _define
1968 {
1969     function _get_config_line($posted_value)
1970     {
1971         if ($this->description)
1972             $n = "\n";
1973         if ($posted_value == $this->default_value)
1974             return "${n};" . $this->_config_format($posted_value);
1975         elseif ($posted_value == '')
1976             return "${n};" . $this->_config_format(""); else
1977             return "${n}" . $this->_config_format($posted_value);
1978     }
1979 }
1980
1981 /**
1982  * We don't use _optional anymore, because INI-style config's don't need that.
1983  * IniConfig.php does the optional logic now.
1984  * But we use _optional for config-default.ini options
1985  */
1986 class _define_commented_optional
1987     extends _define_commented
1988 {
1989 }
1990
1991 class _define_optional
1992     extends _define
1993 {
1994 }
1995
1996 class _define_notempty
1997     extends _define
1998 {
1999     function get_html()
2000     {
2001         $s = $this->get_config_item_header()
2002             . "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name()
2003             . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />";
2004         if (empty($this->default_value))
2005             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
2006         else
2007             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2008     }
2009 }
2010
2011 class _variable_commented
2012     extends _variable
2013 {
2014     function _get_config_line($posted_value)
2015     {
2016         if ($this->description)
2017             $n = "\n";
2018         if ($posted_value == $this->default_value)
2019             return "${n};" . $this->_config_format($posted_value);
2020         elseif ($posted_value == '')
2021             return "${n};" . $this->_config_format(""); else
2022             return "${n}" . $this->_config_format($posted_value);
2023     }
2024 }
2025
2026 class numeric_define
2027     extends _define
2028 {
2029
2030     function numeric_define($config_item_name, $default_value = '', $description = '', $jscheck = '')
2031     {
2032         $this->_define($config_item_name, $default_value, $description, $jscheck);
2033         if (!$jscheck)
2034             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
2035     }
2036
2037     function _config_format($value)
2038     {
2039         //return sprintf("define('%s', %s);", $this->get_config_item_name(), $value);
2040         return sprintf("%s = %s", $this->get_config_item_name(), $value);
2041     }
2042
2043     function _get_config_line($posted_value)
2044     {
2045         if ($this->description)
2046             $n = "\n";
2047         if ($posted_value == '')
2048             return "${n};" . $this->_config_format('0');
2049         else
2050             return "${n}" . $this->_config_format($posted_value);
2051     }
2052 }
2053
2054 class numeric_define_optional
2055     extends numeric_define
2056 {
2057 }
2058
2059 class numeric_define_commented
2060     extends numeric_define
2061 {
2062     function _get_config_line($posted_value)
2063     {
2064         if ($this->description)
2065             $n = "\n";
2066         if ($posted_value == $this->default_value)
2067             return "${n};" . $this->_config_format($posted_value);
2068         elseif ($posted_value == '')
2069             return "${n};" . $this->_config_format('0'); else
2070             return "${n}" . $this->_config_format($posted_value);
2071     }
2072 }
2073
2074 class _define_selection
2075     extends _variable_selection
2076 {
2077     function _config_format($value)
2078     {
2079         return sprintf("%s = %s", $this->get_config_item_name(), $value);
2080     }
2081
2082     function _get_config_line($posted_value)
2083     {
2084         return _define::_get_config_line($posted_value);
2085     }
2086
2087     function get_html()
2088     {
2089         return _variable_selection::get_html();
2090     }
2091 }
2092
2093 class _define_selection_optional
2094     extends _define_selection
2095 {
2096 }
2097
2098 class _variable_selection_optional
2099     extends _variable_selection
2100 {
2101 }
2102
2103 class _define_selection_optional_commented
2104     extends _define_selection_optional
2105 {
2106     function _get_config_line($posted_value)
2107     {
2108         if ($this->description)
2109             $n = "\n";
2110         if ($posted_value == $this->default_value)
2111             return "${n};" . $this->_config_format($posted_value);
2112         elseif ($posted_value == '')
2113             return "${n};" . $this->_config_format(""); else
2114             return "${n}" . $this->_config_format($posted_value);
2115     }
2116 }
2117
2118 class _define_password
2119     extends _define
2120 {
2121
2122     function _define_password($config_item_name, $default_value = '', $description = '', $jscheck = '')
2123     {
2124         if ($config_item_name == $default_value) $default_value = '';
2125         $this->_define($config_item_name, $default_value, $description, $jscheck);
2126         if (!$jscheck)
2127             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '"
2128                 . $this->get_config_item_name() . "', this);\"";
2129     }
2130
2131     function _get_config_line($posted_value)
2132     {
2133         if ($this->description)
2134             $n = "\n";
2135         if ($posted_value == '') {
2136             $p = "${n};" . $this->_config_format("");
2137             $p .= "\n; If you used the passencrypt.php utility to encode the password";
2138             $p .= "\n; then uncomment this line:";
2139             $p .= "\n;ENCRYPTED_PASSWD = true";
2140             return $p;
2141         } else {
2142             if (function_exists('crypt')) {
2143                 $salt_length = max(CRYPT_SALT_LENGTH,
2144                     2 * CRYPT_STD_DES,
2145                     9 * CRYPT_EXT_DES,
2146                     12 * CRYPT_MD5,
2147                     16 * CRYPT_BLOWFISH);
2148                 // generate an encrypted password
2149                 $crypt_pass = crypt($posted_value, rand_ascii($salt_length));
2150                 $p = "${n}" . $this->_config_format($crypt_pass);
2151                 return $p . "\nENCRYPTED_PASSWD = true";
2152             } else {
2153                 $p = "${n}" . $this->_config_format($posted_value);
2154                 $p .= "\n; Encrypted passwords cannot be used:";
2155                 $p .= "\n; 'function crypt()' not available in this version of php";
2156                 $p .= "\nENCRYPTED_PASSWD = false";
2157                 return $p;
2158             }
2159         }
2160     }
2161
2162     function get_html()
2163     {
2164         return _variable_password::get_html();
2165     }
2166 }
2167
2168 class _define_password_optional
2169     extends _define_password
2170 {
2171
2172     function _define_password_optional($config_item_name, $default_value = '', $description = '', $jscheck = '')
2173     {
2174         if ($config_item_name == $default_value) $default_value = '';
2175         if (!$jscheck) $this->jscheck = " ";
2176         $this->_define($config_item_name, $default_value, $description, $jscheck);
2177     }
2178
2179     function _get_config_line($posted_value)
2180     {
2181         if ($this->description)
2182             $n = "\n";
2183         if ($posted_value == '') {
2184             return "${n};" . $this->_config_format("");
2185         } else {
2186             return "${n}" . $this->_config_format($posted_value);
2187         }
2188     }
2189
2190     function get_html()
2191     {
2192         $s = $this->get_config_item_header();
2193         // dont re-encrypt already encrypted passwords
2194         $value = $this->value();
2195         $encrypted = !empty($GLOBALS['properties']["Encrypted Passwords"]) and
2196             $GLOBALS['properties']["Encrypted Passwords"]->value();
2197         if (empty($value))
2198             $encrypted = false;
2199         $s .= "<input type=\"" . ($encrypted ? "text" : "password") . "\" name=\"" . $this->get_config_item_name()
2200             . "\" value=\"" . $value . "\" {$this->jscheck} />";
2201         return $s;
2202     }
2203 }
2204
2205 class _define_password_commented_optional
2206     extends _define_password_optional
2207 {
2208 }
2209
2210 class _variable_password
2211     extends _variable
2212 {
2213     function _variable_password($config_item_name, $default_value = '', $description = '', $jscheck = '')
2214     {
2215         if ($config_item_name == $default_value) $default_value = '';
2216         $this->_define($config_item_name, $default_value, $description, $jscheck);
2217         if (!$jscheck)
2218             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
2219     }
2220
2221     function get_html()
2222     {
2223         global $HTTP_POST_VARS, $HTTP_GET_VARS;
2224         $s = $this->get_config_item_header();
2225         if (isset($HTTP_POST_VARS['create']) or isset($HTTP_GET_VARS['create'])) {
2226             $new_password = random_good_password();
2227             $this->default_value = $new_password;
2228             $s .= "Created password: <strong>$new_password</strong><br />&nbsp;<br />";
2229         }
2230         // dont re-encrypt already encrypted passwords
2231         $value = $this->value();
2232         $encrypted = !empty($GLOBALS['properties']["Encrypted Passwords"]) and
2233             $GLOBALS['properties']["Encrypted Passwords"]->value();
2234         if (empty($value))
2235             $encrypted = false;
2236         $s .= "<input type=\"" . ($encrypted ? "text" : "password") . "\" name=\"" . $this->get_config_item_name()
2237             . "\" value=\"" . $value . "\" {$this->jscheck} />"
2238             . "&nbsp;&nbsp;<input type=\"submit\" name=\"create\" value=\"Create Random Password\" />";
2239         if (empty($value))
2240             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
2241         elseif (strlen($this->default_value) < 4)
2242             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Must be longer than 4 chars.</p>"; else
2243             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2244         return $s;
2245     }
2246 }
2247
2248 class list_variable
2249     extends _variable
2250 {
2251     function _get_config_line($posted_value)
2252     {
2253         // split the phrase by any number of commas or space characters,
2254         // which include " ", \r, \t, \n and \f
2255         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2256         if ($list_values)
2257             $list_values = join("|", $list_values);
2258         return _variable::_get_config_line($list_values);
2259     }
2260
2261     function get_html()
2262     {
2263         $list_values = explode("|", $this->default_value);
2264         $rows = max(3, count($list_values) + 1);
2265         $list_values = join("\n", $list_values);
2266         $ta = $this->get_config_item_header();
2267         $ta .= "<textarea cols=\"18\" rows=\"" . $rows . "\" name=\"" . $this->get_config_item_name() . "\" {$this->jscheck}>";
2268         $ta .= $list_values . "</textarea>";
2269         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2270         return $ta;
2271     }
2272 }
2273
2274 class list_define
2275     extends _define
2276 {
2277     function _get_config_line($posted_value)
2278     {
2279         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2280         if ($list_values)
2281             $list_values = join("|", $list_values);
2282         return _variable::_get_config_line($list_values);
2283     }
2284
2285     function get_html()
2286     {
2287         $list_values = explode("|", $this->default_value);
2288         $rows = max(3, count($list_values) + 1);
2289         if ($list_values)
2290             $list_values = join("\n", $list_values);
2291         $ta = $this->get_config_item_header();
2292         $ta .= "<textarea cols=\"18\" rows=\"" . $rows . "\" name=\"" . $this->get_config_item_name() . "\" {$this->jscheck}>";
2293         $ta .= $list_values . "</textarea>";
2294         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2295         return $ta;
2296     }
2297 }
2298
2299 class array_variable
2300     extends _variable
2301 {
2302     function _config_format($value)
2303     {
2304         return sprintf("%s = \"%s\"", $this->get_config_item_name(),
2305             is_array($value) ? join(':', $value) : $value);
2306     }
2307
2308     function _get_config_line($posted_value)
2309     {
2310         // split the phrase by any number of commas or space characters,
2311         // which include " ", \r, \t, \n and \f
2312         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2313         if (!empty($list_values)) {
2314             $list_values = "'" . join("', '", $list_values) . "'";
2315             return "\n" . $this->_config_format($list_values);
2316         } else
2317             return "\n;" . $this->_config_format('');
2318     }
2319
2320     function get_html()
2321     {
2322         if (is_array($this->default_value))
2323             $list_values = join("\n", $this->default_value);
2324         else
2325             $list_values = $this->default_value;
2326         $rows = max(3, count($this->default_value) + 1);
2327         $ta = $this->get_config_item_header();
2328         $ta .= "<textarea cols=\"18\" rows=\"" . $rows . "\" name=\"" . $this->get_config_item_name() . "\" {$this->jscheck}>";
2329         $ta .= $list_values . "</textarea>";
2330         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2331         return $ta;
2332     }
2333 }
2334
2335 class array_define
2336     extends _define
2337 {
2338     function _config_format($value)
2339     {
2340         return sprintf("%s = \"%s\"", $this->get_config_item_name(),
2341             is_array($value) ? join(' : ', $value) : $value);
2342     }
2343
2344     function _get_config_line($posted_value)
2345     {
2346         // split the phrase by any number of commas or space characters,
2347         // which include " ", \r, \t, \n and \f
2348         $list_values = preg_split("/[\s,:]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2349         if (!empty($list_values)) {
2350             $list_values = join(" : ", $list_values);
2351             return "\n" . $this->_config_format($list_values);
2352         } else
2353             return "\n;" . $this->_config_format('');
2354     }
2355
2356     function get_html()
2357     {
2358         if (!$this->default_value)
2359             $this->default_value = array();
2360         elseif (is_string($this->default_value))
2361             $this->default_value = preg_split("/[\s,:]+/", $this->default_value, -1, PREG_SPLIT_NO_EMPTY);
2362         $list_values = join(" : \n", $this->default_value);
2363         $rows = max(3, count($this->default_value) + 1);
2364         $ta = $this->get_config_item_header();
2365         $ta .= "<textarea cols=\"18\" rows=\"" . $rows . "\" name=\"" . $this->get_config_item_name() . "\" {$this->jscheck}>";
2366         $ta .= $list_values . "</textarea>";
2367         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2368         return $ta;
2369     }
2370 }
2371
2372 /*
2373 class _ini_set
2374 extends _variable {
2375     function value() {
2376         global $HTTP_POST_VARS;
2377         if ($v = $HTTP_POST_VARS[$this->config_item_name])
2378             return $v;
2379         else {
2380             return ini_get($this->get_config_item_name);
2381         }
2382     }
2383     function _config_format($value) {
2384         return sprintf("ini_set('%s', '%s');", $this->get_config_item_name(), $value);
2385     }
2386     function _get_config_line($posted_value) {
2387         if ($posted_value && ! $posted_value == $this->default_value)
2388             return "\n" . $this->_config_format($posted_value);
2389         else
2390             return "\n;" . $this->_config_format($this->default_value);
2391     }
2392 }
2393 */
2394
2395 class boolean_define
2396     extends _define
2397 {
2398
2399     // adds ->values property, instead of ->default_value
2400     function boolean_define($config_item_name, $values = false, $description = '', $jscheck = '')
2401     {
2402         $this->config_item_name = $config_item_name;
2403         if (!$description)
2404             $description = text_from_dist($config_item_name);
2405         $this->description = $description;
2406         // TESTME: get boolean default value from config-default.ini
2407         if (defined($config_item_name))
2408             $this->default_value = constant($config_item_name); // ignore given default value
2409         elseif (is_array($values))
2410             list($this->default_value, $dummy) = $values[0];
2411         if (!$values)
2412             $values = array('false' => "Disabled",
2413                 'true' => "Enabled");
2414         $this->values = $values;
2415         $this->jscheck = $jscheck;
2416         $this->prefix = "";
2417     }
2418
2419     function _get_config_line($posted_value)
2420     {
2421         if ($this->description)
2422             $n = "\n";
2423         return "${n}" . $this->_config_format($posted_value);
2424     }
2425
2426     function _config_format($value)
2427     {
2428         if (strtolower(trim($value)) == 'false')
2429             $value = false;
2430         return sprintf("%s = %s", $this->get_config_item_name(),
2431             (bool)$value ? 'true' : 'false');
2432     }
2433
2434     //TODO: radiobuttons, no list
2435     function get_html()
2436     {
2437         $output = $this->get_config_item_header();
2438         $name = $this->get_config_item_name();
2439         $output .= '<select name="' . $name . "\" {$this->jscheck}>\n";
2440         $values = $this->values;
2441         $default_value = $this->default_value ? 'true' : 'false';
2442         /* There can usually only be two options, there can be
2443          * three options in the case of a boolean_define_commented_optional */
2444         while (list($option, $label) = each($values)) {
2445             if (!is_null($this->default_value) and $option === $default_value)
2446                 $output .= "  <option value=\"$option\" selected=\"selected\">$label</option>\n";
2447             else
2448                 $output .= "  <option value=\"$option\">$label</option>\n";
2449         }
2450         $output .= "</select>\n";
2451         return $output;
2452     }
2453 }
2454
2455 class boolean_define_optional
2456     extends boolean_define
2457 {
2458 }
2459
2460 class boolean_define_commented
2461     extends boolean_define
2462 {
2463     function _get_config_line($posted_value)
2464     {
2465         if ($this->description)
2466             $n = "\n";
2467         list($default_value, $label) = each($this->default_value);
2468         if ($posted_value == $default_value)
2469             return "${n};" . $this->_config_format($posted_value);
2470         elseif ($posted_value == '')
2471             return "${n};" . $this->_config_format('false'); else
2472             return "${n}" . $this->_config_format($posted_value);
2473     }
2474 }
2475
2476 class boolean_define_commented_optional
2477     extends boolean_define_commented
2478 {
2479 }
2480
2481 class part
2482     extends _variable
2483 {
2484     function value()
2485     {
2486         return;
2487     }
2488
2489     function get_config($posted_value)
2490     {
2491         $d = stripHtml($this->_get_description());
2492         global $SEPARATOR;
2493         return "\n" . $SEPARATOR . str_replace("\n", "\n; ", $d) . "\n" . $this->default_value;
2494     }
2495
2496     function get_instructions($title)
2497     {
2498         $id = preg_replace("/\W/", "", $this->config_item_name);
2499         $group_name = preg_replace("/\W/", "", $title);
2500         $i = "<tr class=\"header\" id=\"$id\">\n<td class=\"part\" width=\"100%\" colspan=\"2\" bgcolor=\"#eeeeee\">\n";
2501         $i .= "<h2>" . $title . "</h2>\n    " . nl2p($this->_get_description()) . "\n";
2502         $i .= "<p><a href=\"javascript:toggle_group('$id')\" id=\"{$id}_text\">Hide options.</a></p>";
2503         return $i . "</td>\n";
2504     }
2505
2506     function get_html()
2507     {
2508         return "";
2509     }
2510 }
2511
2512 // html utility functions
2513 function nl2p($text)
2514 {
2515     preg_match_all("@\s*(<pre>.*?</pre>|<dl>.*?</dl>|.*?(?=\n\n|<pre>|<dl>|$))@s",
2516         $text, $m, PREG_PATTERN_ORDER);
2517
2518     $text = '';
2519     foreach ($m[1] as $par) {
2520         if (!($par = trim($par)))
2521             continue;
2522         if (!preg_match('/^<(pre|dl)>/', $par))
2523             $par = "<p>$par</p>";
2524         $text .= $par;
2525     }
2526     return $text;
2527 }
2528
2529 function text_from_dist($var)
2530 {
2531     static $distfile = 0;
2532     static $f;
2533
2534     if (!$distfile) {
2535         $sep = (substr(PHP_OS, 0, 3) == 'WIN' ? '\\' : '/');
2536         $distfile = dirname(__FILE__) . $sep . "config" . $sep . "config-dist.ini";
2537         $f = fopen($distfile, "r");
2538     }
2539     if ($var == '_MAGIC_CLOSE_FILE') {
2540         fclose($f);
2541         return;
2542     }
2543     // if all vars would be in natural order as in the config-dist this would not be needed.
2544     fseek($f, 0);
2545     $par = "\n";
2546     while (!feof($f)) {
2547         $s = fgets($f);
2548         if (preg_match("/^; \w/", $s)) {
2549             $par .= (substr($s, 2) . " ");
2550         } elseif (preg_match("/^;\s*$/", $s)) {
2551             $par .= "\n\n";
2552         }
2553         if (preg_match("/^;?" . preg_quote($var) . "\s*=/", $s))
2554             return $par;
2555         if (preg_match("/^\s*$/", $s)) // new paragraph
2556             $par = "\n";
2557     }
2558     return '';
2559 }
2560
2561 function stripHtml($text)
2562 {
2563     $d = str_replace("<pre>", "", $text);
2564     $d = str_replace("</pre>", "", $d);
2565     $d = str_replace("<dl>", "", $d);
2566     $d = str_replace("</dl>", "", $d);
2567     $d = str_replace("<dt>", "", $d);
2568     $d = str_replace("</dt>", "", $d);
2569     $d = str_replace("<dd>", "", $d);
2570     $d = str_replace("</dd>", "", $d);
2571     $d = str_replace("<p>", "", $d);
2572     $d = str_replace("</p>", "", $d);
2573     //restore html entities into characters
2574     // http://www.php.net/manual/en/function.htmlentities.php
2575     $trans = get_html_translation_table(HTML_ENTITIES);
2576     $trans = array_flip($trans);
2577     $d = strtr($d, $trans);
2578     return $d;
2579 }
2580
2581 include_once(dirname(__FILE__) . "/lib/stdlib.php");
2582
2583 ////
2584 // Function to create better user passwords (much larger keyspace),
2585 // suitable for user passwords.
2586 // Sequence of random ASCII numbers, letters and some special chars.
2587 // Note: There exist other algorithms for easy-to-remember passwords.
2588 function random_good_password($minlength = 5, $maxlength = 8)
2589 {
2590     $newpass = '';
2591     // assume ASCII ordering (not valid on EBCDIC systems!)
2592     $valid_chars = "!#%&+-.0123456789=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
2593     $start = ord($valid_chars);
2594     $end = ord(substr($valid_chars, -1));
2595     better_srand();
2596     if (function_exists('mt_rand')) // mersenne twister
2597         $length = mt_rand($minlength, $maxlength);
2598     else // the usually bad glibc rand()
2599         $length = rand($minlength, $maxlength);
2600     while ($length > 0) {
2601         if (function_exists('mt_rand'))
2602             $newchar = mt_rand($start, $end);
2603         else
2604             $newchar = rand($start, $end);
2605         if (!strrpos($valid_chars, $newchar)) continue; // skip holes
2606         $newpass .= sprintf("%c", $newchar);
2607         $length--;
2608     }
2609     return ($newpass);
2610 }
2611
2612 // debugging
2613 function printArray($a)
2614 {
2615     echo "<hr />\n<pre>\n";
2616     print_r($a);
2617     echo "\n</pre>\n<hr />\n";
2618 }
2619
2620 // end of class definitions
2621 /////////////////////////////
2622 // begin auto generation code
2623
2624 if (!function_exists('is_a')) {
2625     function is_a($object, $class)
2626     {
2627         $class = strtolower($class);
2628         return (get_class($object) == $class) or is_subclass_of($object, $class);
2629     }
2630 }
2631
2632 if (!empty($HTTP_POST_VARS['action'])
2633     and $HTTP_POST_VARS['action'] == 'make_config'
2634         and !empty($HTTP_POST_VARS['ADMIN_USER'])
2635             and !empty($HTTP_POST_VARS['ADMIN_PASSWD'])
2636 ) {
2637
2638     $timestamp = date('dS \of F, Y H:i:s');
2639
2640     $config = "
2641 ; This is a local configuration file for PhpWiki.
2642 ; It was automatically generated by the configurator script
2643 ; on the $timestamp.
2644 ;
2645 ; $preamble
2646 ";
2647
2648     $posted = $GLOBALS['HTTP_POST_VARS'];
2649     /*if (defined('DEBUG'))
2650      printArray($GLOBALS['HTTP_POST_VARS']);*/
2651
2652     foreach ($properties as $option_name => $a) {
2653         $posted_value = stripslashes($posted[$a->config_item_name]);
2654         $config .= $properties[$option_name]->get_config($posted_value);
2655     }
2656
2657     $config .= $end;
2658
2659     if (is_writable($fs_config_file)) {
2660         // We first check if the config-file exists.
2661         if (file_exists($fs_config_file)) {
2662             // We make a backup copy of the file
2663             $new_filename = preg_replace('/\.ini$/', '-' . time() . '.ini', $fs_config_file);
2664             if (@copy($fs_config_file, $new_filename)) {
2665                 $fp = @fopen($fs_config_file, 'w');
2666             }
2667         } else {
2668             $fp = @fopen($fs_config_file, 'w');
2669         }
2670     } else {
2671         $fp = false;
2672     }
2673
2674     if ($fp) {
2675         fputs($fp, utf8_encode($config));
2676         fclose($fp);
2677         echo "<p>The configuration was written to <code><b>$config_file</b></code>.</p>\n";
2678         if ($new_filename) {
2679             echo "<p>A backup was made to <code><b>$new_filename</b></code>.</p>\n";
2680         } else {
2681             ; //echo "<p><strong>You must rename or copy this</strong> <code><b>$config_file</b></code> <strong>file to</strong> <code><b>config/config.ini</b></code>.</p>\n";
2682         }
2683     } else {
2684         echo "<p>The configuration file could <b>not</b> be written.<br />\n",
2685         " You should copy the above configuration to a file, ",
2686         "and manually save it as <code><b>config/config.ini</b></code>.</p>\n";
2687     }
2688
2689     echo "<hr />\n<p>Here's the configuration file based on your answers:</p>\n";
2690     echo "<form method=\"get\" action=\"", $configurator, "\">\n";
2691     echo "<textarea id='config-output' readonly='readonly' style='width:100%;' rows='30' cols='100'>\n";
2692     echo htmlentities($config, ENT_COMPAT, "UTF-8");
2693     echo "</textarea></form>\n";
2694     echo "<hr />\n";
2695
2696     echo "<p>To make any corrections, <a href=\"configurator.php\">edit the settings again</a>.</p>\n";
2697
2698 } else { // first time or create password
2699     $posted = $GLOBALS['HTTP_POST_VARS'];
2700     // No action has been specified - we make a form.
2701
2702     if (!empty($GLOBALS['HTTP_GET_VARS']['start_debug']))
2703         $configurator .= ("?start_debug=" . $GLOBALS['HTTP_GET_VARS']['start_debug']);
2704     echo '
2705 <form action="', $configurator, '" method="post">
2706 <input type="hidden" name="action" value="make_config" />
2707 <table cellpadding="4" cellspacing="0">
2708 ';
2709
2710     while (list($property, $obj) = each($properties)) {
2711         echo $obj->get_instructions($property);
2712         if ($h = $obj->get_html()) {
2713             if (defined('DEBUG') and DEBUG) $h = get_class($obj) . "<br />\n" . $h;
2714             echo "<td>" . $h . "</td>\n";
2715         }
2716         echo '</tr>';
2717     }
2718
2719     echo '
2720 </table>
2721 <p><input type="submit" id="submit" value="Save ', $config_file, '" /> <input type="reset" value="Clear" /></p>
2722 </form>
2723 ';
2724 }
2725 ?>
2726 </body>
2727 </html>