]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - configurator.php
Add option to prevent HTTP redirect.
[SourceForge/phpwiki.git] / configurator.php
1 <?php 
2 /*
3  * Todo: 
4  *   * validate input (fix javascript, add POST checks)
5  *   * start this automatically the first time
6  *   * fix include_path
7  *   * eval index-user.php or index.php to get the actual settings.
8  *   * ask to store it in index.php or index-user.php
9  * 
10  * The file index-user.php will be generated which you can use as your index.php.
11  */
12
13 $tdwidth = 700;
14 $config_file = 'index-user.php';
15 $fs_config_file = dirname(__FILE__) . (substr(PHP_OS,0,3) == 'WIN' ? '\\' : "/") . $config_file;
16 if (isset($HTTP_POST_VARS['create']))  header('Location: configurator.php?create=1#create');
17 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", 'iso-8859-1'); 
18 ?>
19 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
20   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
21 <html xmlns="http://www.w3.org/1999/xhtml">
22 <head>
23 <!-- $Id: configurator.php,v 1.13 2003-03-07 02:48:23 dairiki Exp $ -->
24 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
25 <title>Configuration tool for PhpWiki 1.3.x</title>
26 <style type="text/css" media="screen">
27 <!--
28 /* TABLE { border: thin solid black } */
29 body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; }
30 pre { font-size: 120%; }
31 td { border: thin solid black }
32 tr { border: none }
33 tr.hidden { border: none; display: none; }
34 td.part { background-color: #eeaaaa; color: inherit; }
35 td.instructions { background-color: #ffffee; width: <?php echo $tdwidth ?>px; color: inherit; }
36 td.unchangeable-variable-top   { border-bottom: none; background-color: #eeeeee; color:inherit; }
37 td.unchangeable-variable-left  { border-top: none; background-color: #eeeeee; color:inherit; }
38 -->
39 </style>
40 <script language="JavaScript" type="text/javascript">
41 <!--
42 function update(accepted, error, value, output) {
43   if (accepted) {
44     document.getElementById(output).innerHTML = "<font color=\"green\">Input accepted.</font>";
45   } else {
46     while ((index = error.indexOf("%s")) > -1) {
47       error = error.substring(0, index) + value + error.substring(index+2);
48     }
49     document.getElementById(output).innerHTML = "<font color=\"red\">" + error + "</font>";
50   }
51 }
52
53 function validate(error, value, output, field) {
54   update(field.value == value, error, field.value, output);
55 }
56
57 function validate_ereg(error, ereg, output, field) {
58   regex = new RegExp(ereg);
59   update(regex.test(field.value), error, field.value, output);
60 }
61
62 function validate_range(error, low, high, empty_ok, output, field) {
63   update((empty_ok == 1 && field.value == "") ||
64          (field.value >= low && field.value <= high),
65          error, field.value, output);
66 }
67
68 function toggle_group(id) {
69   var text = document.getElementById(id + "_text");
70   var do_hide = false;
71   if (text.innerHTML == "Hide options.") {
72     do_hide = true;
73     text.innerHTML = "Show options.";
74   } else {
75     text.innerHTML = "Hide options.";
76   }
77
78   var rows = document.getElementsByTagName('tr');
79   var i = 0;
80   for (i = 0; i < rows.length; i++) {
81     var tr = rows[i];
82     if (tr.className == 'header' && tr.id == id) {
83       i++;
84       break;
85     }
86   }
87   for (; i < rows.length; i++) {
88     var tr = rows[i];
89     if (tr.className == 'header')
90       break;
91     tr.className = do_hide ? 'hidden': 'nonhidden';
92   }
93 }
94
95 function do_init() {
96   // Hide all groups.  We do this via JavaScript to avoid
97   // hiding the groups if JavaScript is not supported...
98   var rows = document.getElementsByTagName('tr');
99   for (var i = 0; i < rows.length; i++) {
100     var tr = rows[i];
101     if (tr.className == 'header')
102       toggle_group(tr.id);
103   }
104
105   // Select text in textarea upon focus
106   var area = document.getElementById('config-output');
107   if (area) {
108     listener = { handleEvent: function (e) { area.select(); } };
109     area.addEventListener('focus', listener, false);
110   }
111 }
112   
113 -->
114 </script>
115 </head>
116 <body onload="do_init();">
117
118 <h1>Configuration tool for PhpWiki 1.3.x</h1>
119
120 <?php
121 //define('DEBUG', 1);
122 /**
123  * The Configurator is a php script to aid in the configuration of PhpWiki.
124  * Parts of this file are based on PHPWeather's configurator.php file.
125  * http://sourceforge.net/projects/phpweather/
126  *
127  *
128  * TO CHANGE THE CONFIGURATION OF YOUR PHPWIKI, DO *NOT* MODIFY THIS FILE!
129  * more instructions go here
130  *
131  * Todo: 
132  *   * start this automatically the first time
133  *   * fix include_path
134  *   * eval index.php to get the actual settings.
135  *   * ask to store it in index.php or settings.php
136  * 
137  * The file settings.php will be generated which you can use as your index.php.
138  */
139
140
141 //////////////////////////////
142 // begin configuration options
143
144
145 /**
146  * Notes for the description parameter of $property:
147  *
148  * - Descriptive text will be changed into comments (preceeded by //)
149  *   for the final output to index.php.
150  *
151  * - Only a limited set of html is allowed: pre, dl dt dd; it will be
152  *   stripped from the final output.
153  *
154  * - Line breaks and spacing will be preserved for the final output.
155  *
156  * - Double line breaks are automatically converted to paragraphs
157  *   for the html version of the descriptive text.
158  *
159  * - Double-quotes and dollar signs in the descriptive text must be
160  *   escaped: \" and \$. Instead of escaping double-quotes you can use 
161  *   single (') quotes for the enclosing quotes. 
162  *
163  * - Special characters like < and > must use html entities,
164  *   they will be converted back to characters for the final output.
165  */
166
167 $SEPARATOR = "///////////////////////////////////////////////////////////////////";
168
169 $copyright = '
170 Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam = array(
171 "Steve Wainstead", "Clifford A. Adams", "Lawrence Akka", 
172 "Scott R. Anderson", "Jon Åslund", "Neil Brown", "Jeff Dairiki",
173 "Stéphane Gourichon", "Jan Hidders", "Arno Hollosi", "John Jorgensen",
174 "Antti Kaihola", "Jeremie Kass", "Carsten Klapp", "Marco Milanesi",
175 "Grant Morgan", "Jan Nieuwenhuizen", "Aredridel Niothke", 
176 "Pablo Roca Rozas", "Sandino Araico Sánchez", "Joel Uckelman", 
177 "Reini Urban", "Tim Voght", "Jochen Kalmbach");
178
179 This file is part of PhpWiki.
180
181 PhpWiki is free software; you can redistribute it and/or modify
182 it under the terms of the GNU General Public License as published by
183 the Free Software Foundation; either version 2 of the License, or
184 (at your option) any later version.
185
186 PhpWiki is distributed in the hope that it will be useful,
187 but WITHOUT ANY WARRANTY; without even the implied warranty of
188 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
189 GNU General Public License for more details.
190
191 You should have received a copy of the GNU General Public License
192 along with PhpWiki; if not, write to the Free Software
193 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
194 ';
195
196
197
198 $preamble = "
199   This is the starting file for PhpWiki. All this file does is set
200   configuration options, and at the end of the file it includes() the
201   file lib/main.php, where the real action begins.
202
203   If you include this file to override the default settings here, 
204   you must also include lib/main.php.
205
206   This file is divided into seven parts: Parts Zero, One, Two, Three,
207   Four, Five and Six. Each one has different configuration settings you can
208   change; in all cases the default should work on your system,
209   however, we recommend you tailor things to your particular setting.
210 ";
211
212
213
214 $properties["Part Zero"] =
215 new part('_part0', false, "
216 Part Zero: If PHP needs help in finding where you installed the
217 rest of the PhpWiki code, you can set the include_path here.");
218
219 if (substr(PHP_OS,0,3) == 'WIN') {
220     $include_path = ini_get('include_path') . ';' . dirname(__FILE__);
221     if (strchr(ini_get('include_path'),'/'))
222         $include_path = strtr($include_path,'\\','/');
223 } else {
224     $include_path = ini_get('include_path') . ':' . dirname(__FILE__);
225 }
226
227 $properties["PHP include_path"] =
228 new _ini_set('include_path', $include_path, "
229 NOTE: phpwiki uses the PEAR library of php code for SQL database
230 access. Your PHP is probably already configured to set
231 include_path so that PHP can find the pear code. If not (or if you
232 change include_path here) make sure you include the path to the
233 PEAR code in include_path. (To find the PEAR code on your system,
234 search for a file named 'PEAR.php'. Some common locations are:
235 <pre>
236   Unixish systems:
237     /usr/share/php
238     /usr/local/share/php
239   Mac OS X:
240     /System/Library/PHP
241 </pre>
242 The above examples are already included by PhpWiki. You shouldn't
243 have to change this unless you see a WikiFatalError:
244 <pre>
245     lib/FileFinder.php:82: Fatal[256]: 
246     DB.php: file not found
247 </pre>
248 Define the include path for this wiki: pear plus the phpwiki path
249 <pre>
250 \$include_path = '.:/Apache/php/pear:/prog/php/phpwiki';
251 </pre>
252 Windows needs ';' as path delimiter. cygwin, mac and unix ':'
253 <pre>
254 if (substr(PHP_OS,0,3) == 'WIN') {
255   \$include_path = implode(';',explode(':',\$include_path));
256 } elseif (substr(PHP_OS,0,6) == 'CYGWIN') {
257   \$include_path = '.:/usr/local/lib/php/pear'.
258                      ':/usr/src/php/phpwiki';
259 } else {
260   ;
261 }</pre>");
262
263 $properties["Part Null"] =
264 new part('_partnullheader', "", "
265 Part Null: Don't touch this!");
266
267
268
269 $properties["Part Null Settings"] =
270 new unchangeable_variable('_partnullsettings', "
271 define ('PHPWIKI_VERSION', '1.3.5pre');
272 require \"lib/prepend.php\";
273 rcs_id('\$Id: configurator.php,v 1.13 2003-03-07 02:48:23 dairiki Exp $');", "");
274
275
276 $properties["Part One"] =
277 new part('_partone', $SEPARATOR."\n", "
278
279 Part One:
280 Authentication and security settings. See Part Three for more.
281 ");
282
283
284
285 $properties["Wiki Name"] =
286 new _define_optional('WIKI_NAME', 'PhpWiki', "
287 The name of your wiki.
288 This is used to generate a keywords meta tag in the HTML templates,
289 in bookmark titles for any bookmarks made to pages in your wiki,
290 and during RSS generation for the title of the RSS channel.");
291
292
293 $properties["Reverse DNS"] =
294 new boolean_define('ENABLE_REVERSE_DNS',
295                     array('true'  => "true. perform additional reverse dns lookups",
296                           'false' => "false. just record the address as given by the httpd server"), "
297 If set, we will perform reverse dns lookups to try to convert the
298 users IP number to a host name, even if the http server didn't do it for us.");
299
300 $properties["Admin Username"] =
301 new _define_optional_notempty('ADMIN_USER', "", "
302 <a name=\"create\">You must set this! Username and password of the administrator.</a>",
303 "onchange=\"validate_ereg('Sorry, ADMIN_USER cannot be empty.', '^.+$', 'ADMIN_USER', this);\"");
304
305 $properties["Admin Password"] =
306 new _define_password_optional('ADMIN_PASSWD', "", "
307 For heaven's sake pick a good password.
308 You can also use our <a target=\"_new\" href=\"passencrypt.php\">passwordencrypter</a> to encrypt an existing password or 
309 the \"Create Password\" button to create a good password.",
310 "onchange=\"validate_ereg('Sorry, ADMIN_PASSWD must be at least 4 chars long.', '^....+$', 'ADMIN_PASSWD', this);\"");
311
312 $properties["Encrypted Password"] = 
313 new boolean_define_optional('ENCRYPTED_PASSWD',
314                     array('true'  => "true. ADMIN_PASSWD is encrypted",
315                           'false' => "false. ADMIN_PASSWD is plaintext. Not recommended!"), "
316 If you used the passencrypt.php utility to encode the password or use an existing unix-crypt password,
317 then set this to true. Recommended!");
318
319 $properties["ZIPdump Authentication"] =
320 new boolean_define_optional('ZIPDUMP_AUTH', 
321                     array('false' => "false. Everyone may download zip dumps",
322                           'true'  => "true. Only admin may download zip dumps"), "
323 If true, only the admin user can make zip dumps, else zip dumps
324 require no authentication.");
325
326 $properties["Enable Plugin RawHtml"] =
327 new boolean_define_optional('ENABLE_RAW_HTML', 
328                     array('false' => "Disabled. Recommended on public sites.",
329                           'true'  => "Enabled"), "
330 Allow &lt; ?plugin RawHtml ...&gt;. Don't do this on a publicly accessable wiki for now.");
331
332 $properties["Strict Mailable Pagedumps"] =
333 new boolean_define('STRICT_MAILABLE_PAGEDUMPS', 
334                     array('false' => "binary",
335                           'true'  => "quoted-printable"), "
336 If you define this to true, (MIME-type) page-dumps (either zip dumps,
337 or \"dumps to directory\" will be encoded using the quoted-printable
338 encoding.  If you're actually thinking of mailing the raw page dumps,
339 then this might be useful, since (among other things,) it ensures
340 that all lines in the message body are under 80 characters in length.
341
342 Also, setting this will cause a few additional mail headers
343 to be generated, so that the resulting dumps are valid
344 RFC 2822 e-mail messages.
345
346 Probably, you can just leave this set to false, in which case you get
347 raw ('binary' content-encoding) page dumps.");
348
349
350
351 $properties["HTML Dump Filename Suffix"] =
352 new _variable('HTML_DUMP_SUFFIX', ".html", "
353 Here you can change the filename suffix used for XHTML page dumps.
354 If you don't want any suffix just comment this out.");
355
356
357
358 $properties["Maximum Upload Size"] =
359 new numeric_define('MAX_UPLOAD_SIZE', "16 * 1024 * 1024", "
360 The maximum file upload size.");
361
362
363
364 $properties["Minor Edit Timeout"] =
365 new numeric_define('MINOR_EDIT_TIMEOUT', "7 * 24 * 3600", "
366 If the last edit is older than MINOR_EDIT_TIMEOUT seconds, the
367 default state for the \"minor edit\" checkbox on the edit page form
368 will be off.");
369
370
371
372 $properties["Disabled Actions"] =
373 new array_variable('DisabledActions', array(), "
374 Actions listed in this array will not be allowed. Actions are:
375 browse, create, diff, dumphtml, dumpserial, edit, loadfile, lock, remove, 
376 unlock, upload, viewsource, zip, ziphtml");
377
378 $properties["Access Log"] =
379 new _define_commented('ACCESS_LOG', "/var/logs/wiki_access.log", "
380 PhpWiki can generate an access_log (in \"NCSA combined log\" format)
381 for you. If you want one, define this to the name of the log file,
382 such as /tmp/wiki_access_log.");
383
384 $properties["Compress Output"] =
385 new boolean_define_commented_optional
386 ( 'COMPRESS_OUTPUT', 
387   array(''  => 'Compress when PhpWiki thinks approriate.',
388         'false' => 'Never compress output.',
389         'true' => 'Always try to compress output.'),
390   "
391 By default PhpWiki will try to have PHP compress it's output
392 before sending it to the browser (if you have a recent enough
393 version of PHP and the browser supports it.
394
395 Define COMPRESS_OUTPUT to false to prevent output compression.
396
397 Define COMPRESS_OUTPUT to true to force output compression,
398 even if we think your version of PHP does this in a buggy
399 fashion.
400
401 Leave it undefined to leave the choice up to PhpWiki.");
402
403 $properties["HTTP Cache Control"] =
404 new _define_selection_optional
405 ('CACHE_CONTROL',
406  array('LOOSE' => 'LOOSE',
407        'STRICT' => 'STRICT',
408        'NONE' => 'NONE',
409        'ALLOW_STALE' => 'ALLOW_STALE'),
410  "
411 HTTP CACHE_CONTROL
412
413 This controls how PhpWiki sets the HTTP cache control
414 headers (Expires: and Cache-Control:) 
415
416 Choose one of:
417
418 <dl>
419 <dt>NONE</dt>
420 <dd>This is roughly the old (pre 1.3.4) behavior.  PhpWiki will
421     instruct proxies and browsers never to cache PhpWiki output.</dd>
422
423 <dt>STRICT</dt>
424 <dd>Cached pages will be invalidated whenever the database global
425     timestamp changes.  This should behave just like NONE (modulo
426     bugs in PhpWiki and your proxies and browsers), except that
427     things will be slightly more efficient.</dd>
428
429 <dt>LOOSE</dt>
430 <dd>Cached pages will be invalidated whenever they are edited,
431     or, if the pages include plugins, when the plugin output could
432     concievably have changed.
433
434     <p>Behavior should be much like STRICT, except that sometimes
435        wikilinks will show up as undefined (with the question mark)
436        when in fact they refer to (recently) created pages.
437        (Hitting your browsers reload or perhaps shift-reload button
438        should fix the problem.)</p></dd>
439
440 <dt>ALLOW_STALE</dt>
441 <dd>Proxies and browsers will be allowed to used stale pages.
442     (The timeout for stale pages is controlled by CACHE_CONTROL_MAX_AGE.)
443
444     <p>This setting will result in quirky behavior.  When you edit a
445        page your changes may not show up until you shift-reload the
446        page, etc...</p>
447
448     <p>This setting is generally not advisable, however it may be useful
449        in certain cases (e.g. if your wiki gets lots of page views,
450        and few edits by knowledgable people who won't freak over the quirks.)</p>
451 </dd>
452
453 The default is currently LOOSE.");
454
455 $properties["HTTP Cache Control Max Age"] =
456 new numeric_define('CACHE_CONTROL_MAX_AGE', 600,
457             "
458 Maximum page staleness, in seconds.");
459
460 $properties["Markup Caching"] =
461 new boolean_define_commented_optional
462 ('WIKIDB_NOCACHE_MARKUP',
463  array('false' => 'Enable markup cache',
464        'true' => 'Disable markup cache'),
465  "
466 MARKUP CACHING
467
468 PhpWiki normally caches a preparsed version (i.e. mostly
469 converted to HTML) of the most recent version of each page.
470 (Parsing the wiki-markup takes a fair amount of CPU.)
471
472 Define WIKIDB_NOCACHE_MARKUP to true to disable the
473 caching of marked-up page content.
474
475 Note that you can also disable markup caching on a per-page
476 temporary basis by addinging a query arg of '?nocache=1'
477 to the URL to the page.  (Use '?nocache=purge' to completely
478 discard the cached version of the page.)
479
480 You can also purge the cached markup globally by using the
481 \"Purge Markup Cache\" button on the PhpWikiAdministration page.");
482
483
484 $properties["Path for PHP Session Support"] =
485 new _ini_set('session.save_path', '/tmp', "
486 The login code now uses PHP's session support. Usually, the default
487 configuration of PHP is to store the session state information in
488 /tmp. That probably will work fine, but fails e.g. on clustered
489 servers where each server has their own distinct /tmp (this is the
490 case on SourceForge's project web server.) You can specify an
491 alternate directory in which to store state information like so
492 (whatever user your httpd runs as must have read/write permission
493 in this directory):");
494
495
496
497 $properties["Disable PHP Transparent Session ID"] =
498 new unchangeable_ini_set('session.use_trans_sid', "@ini_set('session.use_trans_sid', 0);", "
499 If your php was compiled with --enable-trans-sid it tries to
500 add a PHPSESSID query argument to all URL strings when cookie
501 support isn't detected in the client browser.  For reasons
502 which aren't entirely clear (PHP bug) this screws up the URLs
503 generated by PhpWiki.  Therefore, transparent session ids
504 should be disabled.  This next line does that.
505
506 (At the present time, you will not be able to log-in to PhpWiki,
507 or set any user preferences, unless your browser supports cookies.)");
508
509
510
511 ///////// database selection
512
513
514 $properties["Part Two"] =
515 new part('_parttwo', $SEPARATOR."\n", "
516
517 Part Two:
518 Database Selection
519 ");
520
521
522 $properties["Database Type"] =
523 new _variable_selection("DBParams|dbtype",
524               array('dba'   => "dba DBM",
525                     'SQL'   => "SQL PEAR",
526                     'ADODB' => "SQL ADODB",
527                     'cvs'   => "CVS File handler"), "
528 Select the database backend type:
529 Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
530 Choose dba to use one of the standard UNIX dbm libraries.
531 CVS is not yet tested nor supported.
532 Recommended is SQL PEAR.");
533
534 $properties["Filename / Table name Prefix"] =
535 new _variable_commented("DBParams|prefix", "phpwiki_", "
536 Used by all DB types:
537
538 Prefix for filenames or table names
539
540 Currently you MUST EDIT THE SQL file too (in the schemas/
541 directory because we aren't doing on the fly sql generation
542 during the installation.");
543
544
545 $properties["SQL dsn Setup"] =
546 new unchangeable_variable('_sqldsnstuff', "", "
547 For SQL based backends, specify the database as a DSN
548 The most general form of a DSN looks like:
549 <pre>
550   phptype(dbsyntax)://username:password@protocol+hostspec/database
551 </pre>
552 For a MySQL database, the following should work:
553 <pre>
554    mysql://user:password@host/databasename
555 </pre>
556 To connect over a unix socket, use something like
557 <pre>
558    mysql://user:password@unix(/path/to/socket)/databasename
559 </pre>
560 <pre>'dsn' => 'mysql://guest@:/var/lib/mysql/mysql.sock/test',
561 'dsn' => 'mysql://guest@localhost/test',
562 'dsn' => 'pgsql://localhost/test',</pre>");
563
564 // Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
565 // Choose dba to use one of the standard UNIX dbm libraries.
566
567 $properties["SQL Type"] =
568 new _variable_selection('_dsn_sqltype',
569               array('mysql' => "MySQL",
570                     'pgsql' => "PostgreSQL"), "
571 SQL DB types");
572
573
574
575 $properties["SQL User"] =
576 new _variable('_dsn_sqluser', "wikiuser", "
577 SQL User Id:");
578
579
580
581 $properties["SQL Password"] =
582 new _variable('_dsn_sqlpass', "", "
583 SQL Password:");
584
585
586
587 $properties["SQL Database Host"] =
588 new _variable('_dsn_sqlhostorsock', "localhost", "
589 SQL Database Hostname:
590
591 To connect over a local named socket, use something like
592 <pre>
593   unix(/var/lib/mysql/mysql.sock)
594 </pre>
595 here.");
596
597
598
599 $properties["SQL Database Name"] =
600 new _variable('_dsn_sqldbname', "phpwiki", "
601 SQL Database Name:");
602
603 list($dsn_sqltype,) = $properties["SQL Type"]->value();
604 $dsn_sqluser = $properties["SQL User"]->value();
605 $dsn_sqlpass = $properties["SQL Password"]->value();
606 $dsn_sqlhostorsock = $properties["SQL Database Host"]->value();
607 $dsn_sqldbname = $properties["SQL Database Name"]->value();
608
609 $properties["SQL dsn"] =
610 new unchangeable_variable("DBParams['dsn']", 
611   "\$DBParams['dsn'] = \"\$_dsn_sqltype://{$dsn_sqluser}:{$dsn_sqlpass}@{$dsn_sqlhostorsock}/{$dsn_sqldbname}\";", "");
612
613 $properties["dba directory"] =
614 new _variable("DBParams|directory", "/tmp", "
615 dba directory:");
616
617
618 $properties["dba handler"] =
619 new _variable_selection('DBParams|dba_handler',
620               array('gdbm' => "Gdbm - GNU database manager",
621                     'dbm'  => "DBM - Redhat default. On sf.net there's dbm and gdbm",
622                     'db2'  => "DB2 - Sleepycat Software's DB2",
623                     'db3'  => "DB3 - Sleepycat Software's DB3. Fine on Windows but not on every Linux"), "
624 Use 'gdbm', 'dbm', 'db2' or 'db3' depending on your DBA handler methods supported:");
625
626 $properties["dba timeout"] =
627 new _variable("DBParams|timeout", "20", "
628 Recommended values are 20 or 5.");
629
630
631
632 ///////////////////
633
634
635
636 $properties["Page Revisions"] =
637 new unchangeable_variable('_parttworevisions', "", "
638
639 The next section controls how many old revisions of each page are
640 kept in the database.
641
642 There are two basic classes of revisions: major and minor. Which
643 class a revision belongs in is determined by whether the author
644 checked the \"this is a minor revision\" checkbox when they saved the
645 page.
646  
647 There is, additionally, a third class of revisions: author
648 revisions. The most recent non-mergable revision from each distinct
649 author is and author revision.
650
651 The expiry parameters for each of those three classes of revisions
652 can be adjusted seperately. For each class there are five
653 parameters (usually, only two or three of the five are actually
654 set) which control how long those revisions are kept in the
655 database.
656 <dl>
657    <dt>max_keep:</dt> <dd>If set, this specifies an absolute maximum for the
658             number of archived revisions of that class. This is
659             meant to be used as a safety cap when a non-zero
660             min_age is specified. It should be set relatively high,
661             and it's purpose is to prevent malicious or accidental
662             database overflow due to someone causing an
663             unreasonable number of edits in a short period of time.</dd>
664
665   <dt>min_age:</dt>  <dd>Revisions younger than this (based upon the supplanted
666             date) will be kept unless max_keep is exceeded. The age
667             should be specified in days. It should be a
668             non-negative, real number,</dd>
669
670   <dt>min_keep:</dt> <dd>At least this many revisions will be kept.</dd>
671
672   <dt>keep:</dt>     <dd>No more than this many revisions will be kept.</dd>
673
674   <dt>max_age:</dt>  <dd>No revision older than this age will be kept.</dd>
675 </dl>
676 Supplanted date: Revisions are timestamped at the instant that they
677 cease being the current revision. Revision age is computed using
678 this timestamp, not the edit time of the page.
679
680 Merging: When a minor revision is deleted, if the preceding
681 revision is by the same author, the minor revision is merged with
682 the preceding revision before it is deleted. Essentially: this
683 replaces the content (and supplanted timestamp) of the previous
684 revision with the content after the merged minor edit, the rest of
685 the page metadata for the preceding version (summary, mtime, ...)
686 is not changed.
687 ");
688
689
690 // For now the expiration parameters are statically inserted as
691 // an unchangeable property. You'll have to edit the resulting
692 // config file if you really want to change these from the default.
693
694 $properties["Expiration Parameters for Major Edits"] =
695 new unchangeable_variable('ExpireParams|major',
696 "\$ExpireParams['major'] = array('max_age' => 32,
697                                'keep'    => 8);", "
698 Keep up to 8 major edits, but keep them no longer than a month.");
699
700 $properties["Expiration Parameters for Minor Edits"] =
701 new unchangeable_variable('ExpireParams|minor',
702 "\$ExpireParams['minor'] = array('max_age' => 7,
703                                'keep'    => 4);", "
704 Keep up to 4 minor edits, but keep them no longer than a week.");
705
706
707
708 $properties["Expiration Parameters by Author"] =
709 new unchangeable_variable('ExpireParams|author',
710 "\$ExpireParams['author'] = array('max_age'  => 365,
711                                 'keep'     => 8,
712                                 'min_age'  => 7,
713                                 'max_keep' => 20);", "
714 Keep the latest contributions of the last 8 authors up to a year.
715 Additionally, (in the case of a particularly active page) try to
716 keep the latest contributions of all authors in the last week (even
717 if there are more than eight of them,) but in no case keep more
718 than twenty unique author revisions.");
719
720 /////////////////////////////////////////////////////////////////////
721
722 $properties["Part Three"] =
723 new part('_partthree', $SEPARATOR."\n", "
724
725 Part Three: (optional)
726 User Authentication
727 ");
728
729 $properties["User Authentication"] =
730 new boolean_define_optional('ALLOW_USER_LOGIN',
731                     array('true'  => "true. Check any defined passwords. (Default)",
732                           'false' => "false. Don't check passwords. Legacy &lt; 1.3.4"), "
733 If ALLOW_USER_LOGIN is true, any defined internal and external
734 authentication method is tried. 
735 If not, we don't care about passwords, but check the next two constants.");
736
737 $properties["HTTP Authentication"] =
738 new boolean_define_optional('ALLOW_HTTP_AUTH_LOGIN',
739                     array('false' => "false. Ignore HTTP Authentication. (Default)",
740                           'true'  => "true. Allow .htpasswd users login automatically."), "
741 The wiki can be optionally be protected by HTTP Auth. Use the username and password 
742 from there, and if this fails, try the other methods also.");
743
744 $properties["Strict Login"] =
745 new boolean_define_optional('ALLOW_BOGO_LOGIN',
746                     array('true'  => "Users may Sign In with any WikiWord",
747                           'false' => "Only admin may Sign In"), "
748 If ALLOW_BOGO_LOGIN is true, users are allowed to login (with
749 any/no password) using any userid which: 1) is not the ADMIN_USER,
750 2) is a valid WikiWord (matches \$WikiNameRegexp.)
751 If true, users may be created by themselves. Otherwise we need seperate auth. 
752 This might be renamed to ALLOW_SELF_REGISTRATION");
753
754 $properties["Require Sign In Before Editing"] =
755 new boolean_define_optional('REQUIRE_SIGNIN_BEFORE_EDIT',
756                     array('false' => "Do not require Sign In",
757                           'true'  => "Require Sign In"), "
758 If set, then if an anonymous user attempts to edit a page he will
759 be required to sign in.  (If ALLOW_BOGO_LOGIN is true, of course,
760 no password is required, but the user must still sign in under
761 some sort of BogoUserId.)");
762
763 if (function_exists('ldap_connect')) {
764 $properties["LDAP Authentication"] =
765   new boolean_define_optional('ALLOW_LDAP_LOGIN',
766                     array('true'  => "Allow LDAP Authentication",
767                           'false' => "Ignore LDAP"), "
768 LDAP Authentication
769 ");
770 $properties["LDAP Host"] =
771   new _define_optional('LDAP_AUTH_HOST', "localhost", "");
772 $properties["LDAP Root Search"] =
773   new _define_optional('LDAP_AUTH_SEARCH', "ou=mycompany.com,o=My Company", "
774 Give the right LDAP root search information in the next statement.");
775
776 } else {
777
778 $properties["LDAP Authentication"] =
779 new unchangeable_define('ALLOW_LDAP_LOGIN', "
780 if (!defined('ALLOW_LDAP_LOGIN')) define('ALLOW_LDAP_LOGIN', true and function_exists('ldap_connect'));
781 if (!defined('LDAP_AUTH_HOST'))   define('LDAP_AUTH_HOST', 'localhost');
782 // Give the right LDAP root search information in the next statement. 
783 if (!defined('LDAP_AUTH_SEARCH')) define('LDAP_AUTH_SEARCH', 'ou=mycompany.com,o=My Company');
784 ", "
785 Ignored. No LDAP support in this php. configure --with-ldap");
786 }
787
788 if (function_exists('imap_open')) {
789 $properties["IMAP Authentication"] =
790   new boolean_define_optional('ALLOW_IMAP_LOGIN',
791                     array('true'  => "Allow IMAP Authentication",
792                           'false' => "Ignore IMAP"), "
793 IMAP Authentication
794 ");
795 $properties["IMAP Host"] =
796   new _define_optional('IMAP_AUTH_HOST', 'localhost', '');
797 } else {
798 $properties["IMAP Authentication"] =
799   new unchangeable_define('ALLOW_IMAP_LOGIN',"
800 // IMAP auth: check userid/passwords from a imap server, defaults to localhost
801 if (!defined('ALLOW_IMAP_LOGIN')) define('ALLOW_IMAP_LOGIN', true and function_exists('imap_open'));
802 if (!defined('IMAP_AUTH_HOST'))   define('IMAP_AUTH_HOST', 'localhost');
803 ", "Ignored. No IMAP support in this php. configure --with-imap");
804 }
805
806
807 /////////////////////////////////////////////////////////////////////
808
809 $properties["Part Four"] =
810 new part('_partfour', $SEPARATOR."\n", "
811
812 Part Four:
813 Page appearance and layout
814 ");
815
816
817
818 $properties["Theme"] =
819 new _define_selection_optional('THEME',
820               array('default'  => "default",
821                     'Hawaiian' => "Hawaiian",
822                     'MacOSX'   => "MacOSX",
823                     'Portland' => "Portland",
824                     'Sidebar'  => "Sidebar",
825                     'SpaceWiki' => "SpaceWiki"), "
826 THEME
827
828 Most of the page appearance is controlled by files in the theme
829 subdirectory.
830
831 There are a number of pre-defined themes shipped with PhpWiki.
832 Or you may create your own (e.g. by copying and then modifying one of
833 stock themes.)
834
835 Pick one.
836 <pre>
837 define('THEME', 'default');
838 define('THEME', 'Hawaiian');
839 define('THEME', 'MacOSX');
840 define('THEME', 'Portland');
841 define('THEME', 'Sidebar');
842 define('THEME', 'SpaceWiki');</pre>");
843
844
845
846 $properties["Character Set"] =
847 new _define_optional('CHARSET', 'iso-8859-1', "
848 Select a valid charset name to be inserted into the xml/html pages, 
849 and to reference links to the stylesheets (css). For more info see: 
850 http://www.iana.org/assignments/character-sets. Note that PhpWiki 
851 has been extensively tested only with the latin1 (iso-8859-1) 
852 character set.
853
854 If you change the default from iso-8859-1 PhpWiki may not work 
855 properly and it will require code modifications. However, character 
856 sets similar to iso-8859-1 may work with little or no modification 
857 depending on your setup. The database must also support the same 
858 charset, and of course the same is true for the web browser. (Some 
859 work is in progress hopefully to allow more flexibility in this 
860 area in the future).");
861
862
863
864 $properties["Language"] =
865 new _variable_selection_optional('LANG',
866               array('en' => "English",
867                     'nl' => "Nederlands",
868                     'es' => "Español",
869                     'fr' => "Français",
870                     'de' => "Deutsch",
871                     'sv' => "Svenska",
872                     'it' => "Italiano",
873                     ''   => "none"), "
874 Select your language/locale - default language is \"en\" for English.
875 Other languages available:<pre>
876 English \"en\"  (English    - HomePage)
877 Dutch   \"nl\" (Nederlands - ThuisPagina)
878 Spanish \"es\" (Español    - PáginaPrincipal)
879 French  \"fr\" (Français   - Accueil)
880 German  \"de\" (Deutsch    - StartSeite)
881 Swedish \"sv\" (Svenska    - Framsida)
882 Italian \"it\" (Italiano   - PaginaPrincipale)
883 </pre>
884 If you set \$LANG to the empty string, your systems default language
885 (as determined by the applicable environment variables) will be
886 used.");
887
888 $properties["Language Locales"] =
889 new unchangeable_variable('language_locales',
890 "\$language_locales = array('en' => 'C',
891                             'de' => 'de_DE',
892                             'es' => 'es_MX',
893                             'nl' => 'nl_NL',
894                             'fr' => 'fr_FR',
895                             'it' => 'it_IT',
896                             'sv' => 'sv_SV'
897                             );
898 if (empty(\$LC_ALL)) {
899   if (empty(\$language_locales[\$LANG]))
900      \$LC_ALL = \$LANG;
901   else
902      \$LC_ALL = \$language_locales[\$LANG];
903 }
904 putenv(\"LC_TIME=\$LC_ALL\");
905 ", "
906 Setting the LANG environment variable (accomplished above) may or
907 may not be sufficient to cause PhpWiki to produce dates in your
908 native language. (It depends on the configuration of the operating
909 system on your http server.)  The problem is that, e.g. 'de' is
910 often not a valid locale.
911
912 A standard locale name is typically of  the  form
913 language[_territory][.codeset][@modifier],  where  language is
914 an ISO 639 language code, territory is an ISO 3166 country code,
915 and codeset  is  a  character  set or encoding identifier like
916 ISO-8859-1 or UTF-8.
917
918 You can tailor the locale used for time and date formatting by
919 setting the LC_TIME environment variable. You'll have to experiment
920 to find the correct setting.
921 gettext() fix: With setlocale() we must use the long form, 
922 like 'de_DE','nl_NL', 'es_MX', 'es_AR', 'fr_FR'. 
923 For Windows maybe even 'german'. You might fix this accordingly.");
924
925 $properties["Wiki Page Source"] =
926 new _define_optional('WIKI_PGSRC', 'pgsrc', "
927 WIKI_PGSRC -- specifies the source for the initial page contents of
928 the Wiki. The setting of WIKI_PGSRC only has effect when the wiki is
929 accessed for the first time (or after clearing the database.)
930 WIKI_PGSRC can either name a directory or a zip file. In either case
931 WIKI_PGSRC is scanned for files -- one file per page.
932 <pre>
933 // Default (old) behavior:
934 define('WIKI_PGSRC', 'pgsrc'); 
935 // New style:
936 define('WIKI_PGSRC', 'wiki.zip'); 
937 define('WIKI_PGSRC', 
938        '../Logs/Hamwiki/hamwiki-20010830.zip'); 
939 </pre>");
940
941
942
943 $properties["Default Wiki Page Source"] =
944 new _define('DEFAULT_WIKI_PGSRC', 'pgsrc', "
945 DEFAULT_WIKI_PGSRC is only used when the language is *not* the
946 default (English) and when reading from a directory: in that case
947 some English pages are inserted into the wiki as well.
948 DEFAULT_WIKI_PGSRC defines where the English pages reside.
949
950 FIXME: is this really needed?
951 ");
952
953
954
955 $properties["Generic Pages"] =
956 new array_variable('GenericPages', array('ReleaseNotes', 'SteveWainstead', 'TestPage'), "
957 These are the pages which will get loaded from DEFAULT_WIKI_PGSRC.      
958
959 FIXME: is this really needed?  Can't we just copy these pages into
960 the localized pgsrc?
961 ");
962
963
964
965
966 $properties["Part Five"] =
967 new part('_partfive', $SEPARATOR."\n", "
968
969 Part Five:
970 Mark-up options.
971 ");
972
973
974
975 $properties["Allowed Protocols"] =
976 new list_variable('AllowedProtocols', 'http|https|mailto|ftp|news|nntp|ssh|gopher', "
977 allowed protocols for links - be careful not to allow \"javascript:\"
978 URL of these types will be automatically linked.
979 within a named link [name|uri] one more protocol is defined: phpwiki");
980
981
982
983 $properties["Inline Images"] =
984 new list_variable('InlineImages', 'png|jpg|gif', "
985 URLs ending with the following extension should be inlined as images");
986
987
988
989 $properties["WikiName Regexp"] =
990 new _variable('WikiNameRegexp', "(?<![[:alnum:]])(?:[[:upper:]][[:lower:]]+){2,}(?![[:alnum:]])", "
991 Perl regexp for WikiNames (\"bumpy words\")
992 (?&lt;!..) &amp; (?!...) used instead of '\b' because \b matches '_' as well");
993
994 $properties["Subpage Separator"] =
995 new _define_optional('SUBPAGE_SEPARATOR', '/', "
996 One character which seperates pages from subpages. Defaults to '/', but '.' or ':' were also used.",
997 "onchange=\"validate_ereg('Sorry, \'%s\' must be a single character. Currently only :, / or .', '^[/:.]$', 'SUBPAGE_SEPARATOR', this);\""
998 );
999
1000 $properties["InterWiki Map File"] =
1001 new _define('INTERWIKI_MAP_FILE', 'lib/interwiki.map', "
1002 InterWiki linking -- wiki-style links to other wikis on the web
1003
1004 The map will be taken from a page name InterWikiMap.
1005 If that page is not found (or is not locked), or map
1006 data can not be found in it, then the file specified
1007 by INTERWIKI_MAP_FILE (if any) will be used.");
1008
1009 $properties["WARN_NONPUBLIC_INTERWIKIMAP"] =
1010 new boolean_define('WARN_NONPUBLIC_INTERWIKIMAP',   
1011         array('true'  => "true",
1012                           'false' => "false"), "
1013 Display a warning if the internal lib/interwiki.map is used, and 
1014 not the public InterWikiMap page. This map is not readable from outside.");
1015
1016
1017 $properties["Part Six"] =
1018 new part('_partsix', $SEPARATOR."\n", "
1019
1020 Part Six (optional):
1021 URL options -- you can probably skip this section.
1022 ");
1023
1024 $properties["Server Name"] =
1025 new _define_commented_optional('SERVER_NAME', $HTTP_SERVER_VARS['SERVER_NAME'], "
1026 Canonical name and httpd port of the server on which this PhpWiki
1027 resides.");
1028
1029
1030
1031 $properties["Server Port"] =
1032 new numeric_define_commented('SERVER_PORT', $HTTP_SERVER_VARS['SERVER_PORT'], "",
1033 "onchange=\"validate_ereg('Sorry, \'%s\' is no valid port number.', '^[0-9]+$', 'SERVER_PORT', this);\"");
1034
1035 $scriptname = preg_replace('/configurator.php/','index.php',$HTTP_SERVER_VARS["SCRIPT_NAME"]);
1036
1037 $properties["Script Name"] =
1038 new _define_commented_optional('SCRIPT_NAME', $scriptname, "
1039 Relative URL (from the server root) of the PhpWiki script.");
1040
1041 $properties["Data Path"] =
1042 new _define_commented_optional('DATA_PATH', dirname($scriptname), "
1043 URL of the PhpWiki install directory.  (You only need to set this
1044 if you've moved index.php out of the install directory.)  This can
1045 be either a relative URL (from the directory where the top-level
1046 PhpWiki script is) or an absolute one.");
1047
1048
1049
1050 $properties["PhpWiki Install Directory"] =
1051 new _define_commented_optional('PHPWIKI_DIR', dirname(__FILE__), "
1052 Path to the PhpWiki install directory.  This is the local
1053 filesystem counterpart to DATA_PATH.  (If you have to set
1054 DATA_PATH, your probably have to set this as well.)  This can be
1055 either an absolute path, or a relative path interpreted from the
1056 directory where the top-level PhpWiki script (normally index.php)
1057 resides.");
1058
1059
1060
1061 $properties["Use PATH_INFO"] =
1062 new boolean_define_commented_optional('USE_PATH_INFO', 
1063                     array('true'  => 'use PATH_INFO',
1064                           'false' => 'do not use PATH_INFO'), "
1065 Define to 'true' to use PATH_INFO to pass the pagenames.
1066 e.g. http://www.some.where/index.php/HomePage instead
1067 of http://www.some.where/index.php?pagename=HomePage
1068 FIXME: more docs (maybe in README). Default: true");
1069
1070
1071
1072 $properties["Virtual Path"] =
1073 new _define_commented_optional('VIRTUAL_PATH', '/SomeWiki', "
1074 VIRTUAL_PATH is the canonical URL path under which your your wiki
1075 appears. Normally this is the same as dirname(SCRIPT_NAME), however
1076 using, e.g. apaches mod_actions (or mod_rewrite), you can make it
1077 something different.
1078
1079 If you do this, you should set VIRTUAL_PATH here.
1080
1081 E.g. your phpwiki might be installed at at /scripts/phpwiki/index.php,
1082 but you've made it accessible through eg. /wiki/HomePage.
1083
1084 One way to do this is to create a directory named 'wiki' in your
1085 server root. The directory contains only one file: an .htaccess
1086 file which reads something like:
1087 <pre>
1088     Action x-phpwiki-page /scripts/phpwiki/index.php
1089     SetHandler x-phpwiki-page
1090     DirectoryIndex /scripts/phpwiki/index.php
1091 </pre>
1092 In that case you should set VIRTUAL_PATH to '/wiki'.
1093
1094 (VIRTUAL_PATH is only used if USE_PATH_INFO is true.)
1095 ");
1096
1097
1098 $properties["Part Seven"] =
1099 new part('_partseven', $SEPARATOR."\n", "
1100
1101 Part Seven:
1102
1103 Miscellaneous settings
1104 ");
1105
1106 $properties["Pagename of Recent Changes"] =
1107 new _define_optional('RECENT_CHANGES', 'RecentChanges', "
1108 Page name of RecentChanges page.  Used for RSS Auto-discovery.");
1109
1110 $properties["Disable HTTP Redirects"] =
1111 new boolean_define_commented_optional
1112 ('DISABLE_HTTP_REDIRECT',
1113  array('false' => 'Enable HTTP Redirects',
1114        'true' => 'Disable HTTP Redirects'),
1115 "
1116 (You probably don't need to touch this.)
1117
1118 PhpWiki uses HTTP redirects for some of it's functionality.
1119 (e.g. after saving changes, PhpWiki redirects your browser to
1120 view the page you just saved.)
1121
1122 Some web service providers (notably free European Lycos) don't seem to
1123 allow these redirects.  (On Lycos the result in an \"Internal Server Error\"
1124 report.)  In that case you can set DISABLE_HTTP_REDIRECT to true.
1125 (In which case, PhpWiki will revert to sneakier tricks to try to
1126 redirect the browser...)");
1127
1128 $end = "
1129
1130 $SEPARATOR
1131 // Check if we were included by some other wiki version (getimg, en, ...) 
1132 // or not. 
1133 // If the server requested this index.php fire up the code by loading lib/main.php.
1134 // Parallel wiki scripts can now simply include /index.php for the 
1135 // main configuration, extend or redefine some settings and 
1136 // load lib/main.php by themselves. 
1137 // This overcomes the index as config problem.
1138 $SEPARATOR
1139
1140 // This doesn't work with php as CGI yet!
1141 if (defined('VIRTUAL_PATH') and defined('USE_PATH_INFO')) {
1142     if (\$HTTP_SERVER_VARS['SCRIPT_NAME'] == VIRTUAL_PATH) {
1143         include \"lib/main.php\";
1144     }
1145 } else {
1146     if (defined('SCRIPT_NAME') and 
1147         (\$HTTP_SERVER_VARS['SCRIPT_NAME'] == SCRIPT_NAME)) {
1148         include \"lib/main.php\";
1149     } elseif (strstr(\$HTTP_SERVER_VARS['PHP_SELF'],'index.php')) {
1150         include \"lib/main.php\";
1151     }
1152 }
1153
1154 // (c-file-style: \"gnu\")
1155 // Local Variables:
1156 // mode: php
1157 // tab-width: 8
1158 // c-basic-offset: 4
1159 // c-hanging-comment-ender-p: nil
1160 // indent-tabs-mode: nil
1161 // End:   
1162 ?>
1163 ";
1164
1165
1166
1167 // end of configuration options
1168 ///////////////////////////////
1169 // begin class definitions
1170
1171 /**
1172  * A basic index.php configuration line in the form of a variable.
1173  *
1174  * Produces a string in the form "$name = value;"
1175  * e.g.:
1176  * $WikiNameRegexp = "value";
1177  */
1178 class _variable {
1179
1180     var $config_item_name;
1181     var $default_value;
1182     var $description;
1183     var $prefix;
1184     var $jscheck;
1185
1186     function _variable($config_item_name, $default_value, $description, $jscheck = '') {
1187         $this->config_item_name = $config_item_name;
1188         $this->description = $description;
1189         $this->default_value = $default_value;
1190         $this->jscheck = $jscheck;
1191         if (preg_match("/variable/i",get_class($this)))
1192             $this->prefix = "\$";
1193         elseif (preg_match("/ini_set/i",get_class($this)))
1194             $this->prefix = "ini_get: ";
1195         else
1196             $this->prefix = "";
1197     }
1198
1199     function value() {
1200       global $HTTP_POST_VARS;
1201       if (isset($HTTP_POST_VARS[$this->config_item_name]))
1202           return $HTTP_POST_VARS[$this->config_item_name];
1203       else 
1204           return $this->default_value;
1205     }
1206
1207     function _config_format($value) {
1208         $v = $this->get_config_item_name();
1209         // handle arrays: a|b --> a['b']
1210         if (strpos($v, '|')) {
1211             list($a, $b) = explode('|', $v);
1212             $v = sprintf("%s['%s']", $a, $b);
1213         }
1214         return sprintf("\$%s = \"%s\";", $v, $value);
1215     }
1216
1217     function get_config_item_name() {
1218         return $this->config_item_name;
1219     }
1220
1221     function get_config_item_id() {
1222         return str_replace('|', '-', $this->config_item_name);
1223     }
1224
1225     function get_config_item_header() {
1226        if (strchr($this->config_item_name,'|')) {
1227           list($var,$param) = explode('|',$this->config_item_name);
1228           return "<b>" . $this->prefix . $var . "['" . $param . "']</b><br />";
1229        }
1230        elseif ($this->config_item_name[0] != '_')
1231           return "<b>" . $this->prefix . $this->config_item_name . "</b><br />";
1232        else 
1233           return '';
1234     }
1235
1236     function _get_description() {
1237         return $this->description;
1238     }
1239
1240     function _get_config_line($posted_value) {
1241         return "\n" . $this->_config_format($posted_value);
1242     }
1243
1244     function get_config($posted_value) {
1245         $d = stripHtml($this->_get_description());
1246         $d = str_replace("\n", "\n// ", $d) . $this->_get_config_line($posted_value) ."\n";
1247         return $d;
1248     }
1249
1250     function get_instructions($title) {
1251         global $tdwidth;
1252         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1253         return "<tr>\n<td width=\"$tdwidth\" class=\"instructions\">\n" . $i . "</td>\n";
1254     }
1255
1256     function get_html() {
1257         return $this->get_config_item_header() . 
1258             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . htmlspecialchars($this->default_value) . "\" " . 
1259             $this->jscheck . " />" . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1260     }
1261 }
1262
1263 class unchangeable_variable
1264 extends _variable {
1265     function _config_format($value) {
1266         return "";
1267     }
1268     // function get_html() { return false; }
1269     function get_html() {
1270         return $this->get_config_item_header() . 
1271         "<em>Not editable.</em>" . 
1272         "<pre>" . $this->default_value."</pre>";
1273     }
1274     function _get_config_line($posted_value) {
1275         if ($this->description)
1276             $n = "\n";
1277         return "${n}".$this->default_value;
1278     }
1279     function get_instructions($title) {
1280         global $tdwidth;
1281         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1282         // $i = $i ."<em>Not editable.</em><br />\n<pre>" . $this->default_value."</pre>";
1283         return "<tr><td width=\"100%\" class=\"unchangeable-variable-top\" colspan=\"2\">\n".$i ."</td></tr>\n".
1284         "<tr style=\"border-top: none;\"><td class=\"unchangeable-variable-left\" width=\"$tdwidth\" bgcolor=\"#eeeeee\">&nbsp;</td>";
1285     }
1286 }
1287
1288 class unchangeable_define
1289 extends unchangeable_variable {
1290     function _config_format($value) {
1291         return "";
1292     }
1293 }
1294 class unchangeable_ini_set
1295 extends unchangeable_variable {
1296     function _config_format($value) {
1297         return "";
1298     }
1299 }
1300
1301
1302 class _variable_selection
1303 extends _variable {
1304     function value() {
1305         global $HTTP_POST_VARS;
1306         if (!empty($HTTP_POST_VARS[$this->config_item_name]))
1307             return $HTTP_POST_VARS[$this->config_item_name];
1308         else {
1309             list($option, $label) = current($this->default_value);
1310             return $this->$option;
1311         }
1312     }
1313     function get_html() {
1314         $output = $this->get_config_item_header();
1315         $output .= '<select name="' . $this->get_config_item_name() . "\">\n";
1316         /* The first option is the default */
1317         while(list($option, $label) = each($this->default_value)) {
1318             $output .= "  <option value=\"$option\">$label</option>\n";
1319         }
1320         $output .= "</select>\n";
1321         return $output;
1322     }
1323 }
1324
1325
1326 class _define
1327 extends _variable {
1328     function _config_format($value) {
1329         return sprintf("define('%s', '%s');", $this->get_config_item_name(), $value);
1330     }
1331     function _get_config_line($posted_value) {
1332         if ($this->description)
1333             $n = "\n";
1334         if ($posted_value == '')
1335             return "${n}//" . $this->_config_format("");
1336         else
1337             return "${n}" . $this->_config_format($posted_value);
1338     }
1339     function get_html() {
1340         return $this->get_config_item_header() . 
1341             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />" .
1342             "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1343     }
1344 }
1345
1346 class _define_commented
1347 extends _define {
1348     function _get_config_line($posted_value) {
1349         if ($this->description)
1350             $n = "\n";
1351         if ($posted_value == $this->default_value)
1352             return "${n}//" . $this->_config_format($posted_value);
1353         else if ($posted_value == '')
1354             return "${n}//" . $this->_config_format("");
1355         else
1356             return "${n}" . $this->_config_format($posted_value);
1357     }
1358 }
1359
1360 class _define_commented_optional
1361 extends _define_commented {
1362     function _config_format($value) {
1363         $name = $this->get_config_item_name();
1364         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1365     }
1366 }
1367
1368 class _define_optional
1369 extends _define {
1370     function _config_format($value) {
1371         $name = $this->get_config_item_name();
1372         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1373     }
1374 }
1375
1376 class _define_optional_notempty
1377 extends _define_optional {
1378     function get_html() {
1379         $s = $this->get_config_item_header() . 
1380             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />";
1381         if (empty($this->default_value))
1382             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
1383         else
1384             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1385     }
1386 }
1387
1388 class _variable_commented
1389 extends _variable {
1390     function _get_config_line($posted_value) {
1391         if ($this->description)
1392             $n = "\n";
1393         if ($posted_value == $this->default_value)
1394             return "${n}//" . $this->_config_format($posted_value);
1395         else if ($posted_value == '')
1396             return "${n}//" . $this->_config_format("");
1397         else
1398             return "${n}" . $this->_config_format($posted_value);
1399     }
1400 }
1401
1402 class numeric_define_commented
1403 extends _define {
1404     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
1405
1406     function get_html() {
1407         return numeric_define::get_html();
1408     }
1409     function _get_config_line($posted_value) {
1410         if ($this->description)
1411             $n = "\n";
1412         if ($posted_value == $this->default_value)
1413             return "${n}//" . $this->_config_format($posted_value);
1414         else if ($posted_value == '')
1415             return "${n}//" . $this->_config_format('0');
1416         else
1417             return "${n}" . $this->_config_format($posted_value);
1418     }
1419 }
1420
1421 class _define_selection
1422 extends _variable_selection {
1423     function _config_format($value) {
1424         return sprintf("define('%s', '%s');", $this->get_config_item_name(), $value);
1425     }
1426     function _get_config_line($posted_value) {
1427         return _define::_get_config_line($posted_value);
1428     }
1429     function get_html() {
1430         return _variable_selection::get_html();
1431     }
1432 }
1433
1434 class _define_selection_optional
1435 extends _define_selection {
1436     function _config_format($value) {
1437         $name = $this->get_config_item_name();
1438         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1439     }
1440 }
1441
1442 class _variable_selection_optional
1443 extends _variable_selection {
1444     function _config_format($value) {
1445         $v = $this->get_config_item_name();
1446         // handle arrays: a|b --> a['b']
1447         if (strpos($v, '|')) {
1448             list($a, $b) = explode('|', $v);
1449             $v = sprintf("%s['%s']", $a, $b);
1450         }
1451         return sprintf("if (!isset(\$%s)) { \$%s = \"%s\"; }", $v, $v, $value);
1452     }
1453 }
1454
1455 class _define_password
1456 extends _define {
1457     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
1458
1459     function _get_config_line($posted_value) {
1460         if ($this->description)
1461             $n = "\n";
1462         if ($posted_value == '') {
1463             $p = "${n}//" . $this->_config_format("");
1464             $p = $p . "\n// If you used the passencrypt.php utility to encode the password";
1465             $p = $p . "\n// then uncomment this line:";
1466             $p = $p . "\n//if (!defined('ENCRYPTED_PASSWD')) define('ENCRYPTED_PASSWD', true);";
1467             return $p;
1468         } else {
1469             if (function_exists('crypt')) {
1470                 $salt_length = max(CRYPT_SALT_LENGTH,
1471                                     2 * CRYPT_STD_DES,
1472                                     9 * CRYPT_EXT_DES,
1473                                    12 * CRYPT_MD5,
1474                                    16 * CRYPT_BLOWFISH);
1475                 // generate an encrypted password
1476                 $crypt_pass = crypt($posted_value, rand_ascii($salt_length));
1477                 $p = "${n}" . $this->_config_format($crypt_pass);
1478                 return $p . "\ndefine('ENCRYPTED_PASSWD', true);";
1479             } else {
1480                 $p = "${n}" . $this->_config_format($posted_value);
1481                 $p = $p . "\n// If you used the passencrypt.php utility to encode the password";
1482                 $p = $p . "\n// then uncomment this line:";
1483                 $p = $p . "\n//define('ENCRYPTED_PASSWD', false);";
1484                 $p = $p . "\n// Encrypted passwords cannot be used:";
1485                 $p = $p . "\n// 'function crypt()' not available in this version of php";
1486                 return $p;
1487             }
1488         }
1489     }
1490     function get_html() {
1491         return _variable_password::get_html();
1492     }
1493 }
1494
1495 class _define_password_optional
1496 extends _define_password {
1497     function _config_format($value) {
1498         $name = $this->get_config_item_name();
1499         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1500     }
1501 }
1502
1503
1504 class _variable_password
1505 extends _variable {
1506     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
1507
1508     function get_html() {
1509         global $HTTP_POST_VARS, $HTTP_GET_VARS;
1510         $s = $this->get_config_item_header();
1511         $s .= "<input type=\"password\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />" . 
1512 "&nbsp;&nbsp;<input type=\"submit\" name=\"create\" value=\"Create Password\" />";
1513         if (isset($HTTP_POST_VARS['create']) or isset($HTTP_GET_VARS['create'])) {
1514             $new_password = random_good_password();
1515             $this->default_value = $new_password;
1516             $s .= "<br />&nbsp;<br />Created password: <strong>$new_password</strong>";
1517         }
1518         if (empty($this->default_value))
1519             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
1520         elseif (strlen($this->default_value) < 4)
1521             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Must be longer than 4 chars.</p>";
1522         else
1523             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1524         return $s;
1525     }
1526 }
1527
1528 class numeric_define
1529 extends _define {
1530     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
1531
1532     function _config_format($value) {
1533         return sprintf("define('%s', %s);", $this->get_config_item_name(), $value);
1534     }
1535     function _get_config_line($posted_value) {
1536         if ($this->description)
1537             $n = "\n";
1538         if ($posted_value == '')
1539             return "${n}//" . $this->_config_format('0');
1540         else
1541             return "${n}" . $this->_config_format($posted_value);
1542     }
1543 }
1544
1545 class list_variable
1546 extends _variable {
1547     function _get_config_line($posted_value) {
1548         // split the phrase by any number of commas or space characters,
1549         // which include " ", \r, \t, \n and \f
1550         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
1551         $list_values = join("|", $list_values);
1552         return _variable::_get_config_line($list_values);
1553     }
1554     function get_html() {
1555         $list_values = explode("|", $this->default_value);
1556         $rows = max(3, count($list_values) +1);
1557         $list_values = join("\n", $list_values);
1558         $ta = $this->get_config_item_header();
1559         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
1560         $ta .= $list_values . "</textarea>";
1561         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1562         return $ta;
1563     }
1564 }
1565
1566 class array_variable
1567 extends _variable {
1568     function _config_format($value) {
1569         return sprintf("\$%s = array(%s);", $this->get_config_item_name(), $value);
1570     }
1571     function _get_config_line($posted_value) {
1572         // split the phrase by any number of commas or space characters,
1573         // which include " ", \r, \t, \n and \f
1574         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
1575         if (!empty($list_values)) {
1576             $list_values = "'".join("', '", $list_values)."'";
1577             return "\n" . $this->_config_format($list_values);
1578         } else
1579             return "\n//" . $this->_config_format('');
1580     }
1581     function get_html() {
1582         $list_values = join("\n", $this->default_value);
1583         $rows = max(3, count($this->default_value) +1);
1584         $ta = $this->get_config_item_header();
1585         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
1586         $ta .= $list_values . "</textarea>";
1587         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1588         return $ta;
1589     }
1590
1591 }
1592
1593 class _ini_set
1594 extends _variable {
1595     function value() {
1596         global $HTTP_POST_VARS;
1597         if ($v = $HTTP_POST_VARS[$this->config_item_name])
1598             return $v;
1599         else {
1600             return ini_get($this->get_config_item_name);
1601         }
1602     }
1603     function _config_format($value) {
1604         return sprintf("ini_set('%s', '%s');", $this->get_config_item_name(), $value);
1605     }
1606     function _get_config_line($posted_value) {
1607         if ($posted_value && ! $posted_value == $this->default_value)
1608             return "\n" . $this->_config_format($posted_value);
1609         else
1610             return "\n//" . $this->_config_format($this->default_value);
1611     }
1612 }
1613
1614 class boolean_define
1615 extends _define {
1616     function _get_config_line($posted_value) {
1617         if ($this->description)
1618             $n = "\n";
1619         return "${n}" . $this->_config_format($posted_value);
1620     }
1621     function _config_format($value) {
1622         if (strtolower(trim($value)) == 'false')
1623             $value = false;
1624         return sprintf("define('%s', %s);", $this->get_config_item_name(),
1625                        (bool)$value ? 'true' : 'false');
1626     }
1627     function get_html() {
1628         $output = $this->get_config_item_header();
1629         $output .= '<select name="' . $this->get_config_item_name() . "\" {$this->jscheck}>\n";
1630         /* The first option is the default */
1631         list($option, $label) = each($this->default_value);
1632         $output .= "  <option value=\"$option\" selected='selected'>$label</option>\n";
1633         /* There can usually, only be two options, there can be
1634          * three options in the case of a boolean_define_commented_optional */
1635         while (list($option, $label) = each($this->default_value)) 
1636           $output .= "  <option value=\"$option\">$label</option>\n";
1637         $output .= "</select>\n";
1638         return $output;
1639     }
1640 }
1641
1642 class boolean_define_optional
1643 extends boolean_define {
1644     function _config_format($value) {
1645         $name = $this->get_config_item_name();
1646         return "if (!defined('$name')) " . boolean_define::_config_format($value);
1647     }
1648 }
1649
1650 class boolean_define_commented
1651 extends boolean_define {
1652     function _get_config_line($posted_value) {
1653         if ($this->description)
1654             $n = "\n";
1655         list($default_value, $label) = each($this->default_value);
1656         if ($posted_value == $default_value)
1657             return "${n}//" . $this->_config_format($posted_value);
1658         else if ($posted_value == '')
1659             return "${n}//" . $this->_config_format('false');
1660         else
1661             return "${n}" . $this->_config_format($posted_value);
1662     }
1663 }
1664
1665 class boolean_define_commented_optional
1666 extends boolean_define_commented {
1667     function _config_format($value) {
1668         $name = $this->get_config_item_name();
1669         return "if (!defined('$name')) " . boolean_define_commented::_config_format($value);
1670     }
1671 }
1672
1673 class part
1674 extends _variable {
1675     function value () { return; }
1676     function get_config($posted_value) {
1677         $d = stripHtml($this->_get_description());
1678         global $SEPARATOR;
1679         return "\n".$SEPARATOR . str_replace("\n", "\n// ", $d) ."\n$this->default_value";
1680     }
1681     function get_instructions($title) {
1682         $group_name = preg_replace("/\W/","",$title);
1683         $i = "<tr class='header' id='$group_name'>\n<td class=\"part\" width=\"100%\" colspan=\"2\" bgcolor=\"#eeaaaa\">\n";
1684         $i .= "<h2>" . $title . "</h2>\n    " . nl2p($this->_get_description()) ."\n";
1685         $i .= "<p><a href=\"javascript:toggle_group('$group_name')\" id=\"{$group_name}_text\">Hide options.</a></p>";
1686         return  $i ."</td>\n";
1687     }
1688     function get_html() {
1689         return "";
1690     }
1691 }
1692
1693 // html utility functions
1694 function nl2p($text) {
1695   preg_match_all("@\s*(<pre>.*?</pre>|<dl>.*?</dl>|.*?(?=\n\n|<pre>|<dl>|$))@s",
1696                  $text, $m, PREG_PATTERN_ORDER);
1697
1698   $text = '';
1699   foreach ($m[1] as $par) {
1700     if (!($par = trim($par)))
1701       continue;
1702     if (!preg_match('/^<(pre|dl)>/', $par))
1703       $par = "<p>$par</p>";
1704     $text .= $par;
1705   }
1706   return $text;
1707 }
1708
1709 function stripHtml($text) {
1710         $d = str_replace("<pre>", "", $text);
1711         $d = str_replace("</pre>", "", $d);
1712         $d = str_replace("<dl>", "", $d);
1713         $d = str_replace("</dl>", "", $d);
1714         $d = str_replace("<dt>", "", $d);
1715         $d = str_replace("</dt>", "", $d);
1716         $d = str_replace("<dd>", "", $d);
1717         $d = str_replace("</dd>", "", $d);
1718         $d = str_replace("<p>", "", $d);
1719         $d = str_replace("</p>", "", $d);
1720         //restore html entities into characters
1721         // http://www.php.net/manual/en/function.htmlentities.php
1722         $trans = get_html_translation_table (HTML_ENTITIES);
1723         $trans = array_flip ($trans);
1724         $d = strtr($d, $trans);
1725         return $d;
1726 }
1727
1728 /**
1729  * Seed the random number generator.
1730  *
1731  * better_srand() ensures the randomizer is seeded only once.
1732  * 
1733  * How random do you want it? See:
1734  * http://www.php.net/manual/en/function.srand.php
1735  * http://www.php.net/manual/en/function.mt-srand.php
1736  */
1737 function better_srand($seed = '') {
1738     static $wascalled = FALSE;
1739     if (!$wascalled) {
1740         if ($seed === '') {
1741             list($usec,$sec)=explode(" ",microtime());
1742             if ($usec > 0.1) 
1743                 $seed = (double) $usec * $sec;
1744             else // once in a while use the combined LCG entropy
1745                 $seed = (double) 1000000 * substr(uniqid("",true),13);
1746         }
1747         if (function_exists('mt_srand')) {
1748             mt_srand($seed); // mersenne twister
1749         } else {
1750             srand($seed);    
1751         }
1752         $wascalled = TRUE;
1753     }
1754 }
1755
1756 function rand_ascii($length = 1) {
1757     better_srand();
1758     $s = "";
1759     for ($i = 1; $i <= $length; $i++) {
1760         // return only typeable 7 bit ascii, avoid quotes
1761         if (function_exists('mt_rand'))
1762             // the usually bad glibc srand()
1763             $s .= chr(mt_rand(40, 126)); 
1764         else
1765             $s .= chr(rand(40, 126));
1766     }
1767     return $s;
1768 }
1769
1770 ////
1771 // Function to create better user passwords (much larger keyspace),
1772 // suitable for user passwords.
1773 // Sequence of random ASCII numbers, letters and some special chars.
1774 // Note: There exist other algorithms for easy-to-remember passwords.
1775 function random_good_password ($minlength = 5, $maxlength = 8) {
1776   $newpass = '';
1777   // assume ASCII ordering (not valid on EBCDIC systems!)
1778   $valid_chars = "!#%&+-.0123456789=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
1779   $start = ord($valid_chars);
1780   $end   = ord(substr($valid_chars,-1));
1781   better_srand();
1782   if (function_exists('mt_rand')) // mersenne twister
1783       $length = mt_rand($minlength, $maxlength);
1784   else  // the usually bad glibc rand()
1785       $length = rand($minlength, $maxlength);
1786   while ($length > 0) {
1787       if (function_exists('mt_rand'))
1788           $newchar = mt_rand($start, $end);
1789       else
1790           $newchar = rand($start, $end);
1791       if (! strrpos($valid_chars,$newchar) ) continue; // skip holes
1792       $newpass .= sprintf("%c",$newchar);
1793       $length--;
1794   }
1795   return($newpass);
1796 }
1797
1798 // debugging
1799 function printArray($a) {
1800     echo "<hr />\n<pre>\n";
1801     print_r($a);
1802     echo "\n</pre>\n<hr />\n";
1803 }
1804
1805 // end of class definitions
1806 /////////////////////////////
1807 // begin auto generation code
1808
1809 if (!function_exists('is_a'))
1810 {
1811   function is_a($object, $class)
1812   {
1813     $class = strtolower($class);
1814     return (get_class($object) == $class) or is_subclass_of($object, $class);
1815   }
1816 }
1817
1818
1819 if (@$HTTP_POST_VARS['action'] == 'make_config') {
1820
1821     $timestamp = date ('dS of F, Y H:i:s');
1822
1823     $config = "<?php
1824 /* This is a local configuration file for PhpWiki.
1825  * It was automatically generated by the configurator script
1826  * on the $timestamp.
1827  */
1828
1829 /*$copyright*/
1830
1831 /////////////////////////////////////////////////////////////////////
1832 /*$preamble*/
1833 ";
1834
1835     $posted = $GLOBALS['HTTP_POST_VARS'];
1836
1837     if (defined('DEBUG'))
1838         printArray($GLOBALS['HTTP_POST_VARS']);
1839
1840     foreach($properties as $option_name => $a) {
1841         $posted_value = $posted[$a->config_item_name];
1842         $config .= $properties[$option_name]->get_config($posted_value);
1843     }
1844
1845     if (defined('DEBUG')) {
1846         $diemsg = "The configurator.php is provided for testing purposes only.
1847 You can't use this file with your PhpWiki server yet!!";
1848         $config .= "\ndie(\"$diemsg\");\n";
1849     }
1850     $config .= $end;
1851
1852     /* We first check if the config-file exists. */
1853     if (file_exists($fs_config_file)) {
1854         /* We make a backup copy of the file */
1855         // $config_file = 'index-user.php';
1856         $new_filename = preg_replace('/\.php$/', time() . '.php', $fs_config_file);
1857         if (@copy($fs_config_file, $new_filename)) {
1858             $fp = @fopen($fs_config_file, 'w');
1859         }
1860     } else {
1861         $fp = @fopen($fs_config_file, 'w');
1862     }
1863
1864     if ($fp) {
1865         fputs($fp, $config);
1866         fclose($fp);
1867         echo "<p>The configuration was written to <code><b>$config_file</b></code>.</p>\n";
1868         if ($new_filename) {
1869             echo "<p>A backup was made to <code><b>$new_filename</b></code>.</p>\n";
1870         }
1871         echo "<p><strong>You must rename or copy this</strong> <code><b>$config_file</b></code> <strong>file to</strong> <code><b>index.php</b></code>.</p>\n";
1872     } else {
1873         echo "<p>A configuration file could <b>not</b> be written. You should copy the above configuration to a file, and manually save it as <code><b>index.php</b></code>.</p>\n";
1874     }
1875
1876     echo "<hr />\n<p>Here's the configuration file based on your answers:</p>\n";
1877     echo "<form method='get' action='$PHP_SELF'>\n";
1878     echo "<textarea id='config-output' readonly='readonly' style='width:100%;' rows='30' cols='100'>\n";
1879     echo htmlentities($config);
1880     echo "</textarea></form>\n";
1881     echo "<hr />\n";
1882
1883     echo "<p>To make any corrections, <a href=\"configurator.php\">edit the settings again</a>.</p>\n";
1884
1885 } else { // first time or create password
1886     $posted = $GLOBALS['HTTP_POST_VARS'];
1887     /* No action has been specified - we make a form. */
1888
1889     echo '
1890 <form action="configurator.php" method="post">
1891 <input type="hidden" name="action" value="make_config" />
1892 <table cellpadding="4" cellspacing="0">
1893 ';
1894
1895     while(list($property, $obj) = each($properties)) {
1896         echo $obj->get_instructions($property);
1897         if ($h = $obj->get_html()) {
1898             if (defined('DEBUG'))  $h = get_class($obj) . "<br />\n" . $h;
1899             echo "<td>".$h."</td>\n";
1900         }
1901         echo '</tr>';
1902     }
1903
1904     echo '
1905 </table>
1906 <p><input type="submit" value="Save ',$config_file,'" /> <input type="reset" value="Clear" /></p>
1907 </form>
1908 ';
1909 }
1910 ?>
1911 </body>
1912 </html>