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