root/trunk/install.php

Revision 180, 26.3 kB (checked in by hannes, 1 week ago)

setting slightly different file permissions for .htaccess files, because some Apache installations seem to have problems otherwise...

Line 
1 <?php
2
3 /**
4  * Package: Spam Board 5
5  * File: install.php
6  * Description: script to initialize a new board
7  *
8  * Copyright (C) 2007, 2008 Hannes Schueller
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as
12  * published by the Free Software Foundation, version 3 of the
13  * License.
14  *
15  * This program 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 Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program (see LICENCE). If not,
22  * see <http://www.gnu.org/licenses/>.
23  **/
24
25 // number of the page which actually writes all the settings
26 $commitpage = 9;
27 $overviewpage = $commitpage - 1;
28
29 // global settings template (has a few defaults)
30 require_once('includes/config/settings.tmpl');
31
32 // import version number
33 require_once('includes/config/version.php');
34
35 // get formatting class
36 require_once('classes/misc/Format.php');
37 // initialize formatting object
38 $F = new Format();
39
40 // language file
41 require('includes/lang/' . $SETTINGS['language'] . '.php');
42
43 // input validation
44 require_once('includes/input.php');
45
46 // default page
47 if (!isset($INPUT['page']) || $INPUT['page'] == '') {
48     $INPUT['page'] = 1;
49 }
50
51 // check if the user wants to start over
52 if ($INPUT['submit'] == $LANG['Start_Over']) {
53     $INPUT['page'] = 1;
54     $SETUPDATA = Array();
55 } else {
56     $SETUPDATA = $_POST['SETUPDATA'];
57 }
58
59 // define next page number
60 $nextpage = $INPUT['page'] + 1;
61
62 // since this is important, define the order in which the password hashes should be suggested
63 $hashes_default = Array();
64 $hashes_default[0] = 'sha512';
65 $hashes_default[1] = 'ripemd320';
66 $hashes_default[2] = 'sha384';
67 $hashes_default[3] = 'ripemd256';
68 $hashes_default[4] = 'sha256';
69 $hashes_default[5] = 'ripemd160';
70 $hashes_default[6] = 'ripemd128';
71 $hashes_default[7] = 'sha1';
72 // available
73 $hashes = hash_algos();
74 for ($i = 7; $i <= 0; $i--) {
75     if (in_array($hashes_default[$i], $hashes)) {
76         // use this hash as default
77         $SETTINGS['hash'] = $hashes_default[$i];
78     }
79 }
80
81 // unlike all the other pages, this installer is a little simpler and prints output directly
82 print('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
83 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
84     <head>
85         <title>' . $LANG['Spam_Board_Installer'] . '</title>
86     </head>
87     <body>
88         <h1>' . $LANG['Spam_Board_Installer'] . '</h1>
89         <h2>' . $LANG['Page'] . ' ' . $INPUT['page'] . ' / ' . $commitpage . '</h2>
90         <form action="install.php" method="post">
91             <input type="hidden" name="page" value="' . $nextpage . '" />
92 ');
93
94 switch ($INPUT['page']) {
95     case $commitpage:
96         /* commit */
97         $ok = 1;
98         // set file permissions
99         if ($SETUPDATA['set_permissions'] == 1) {
100             if (@chmod('attachments', 0775)) {
101                 if (@chmod('db', 0770)) {
102                     if (@chmod('sessions', 0770)) {
103                         if (@chmod('images/avatars', 0775)) {
104                             if (@chmod('includes/config', 0770)) {
105                                 if (@chmod('includes/wrappers', 0770)) {
106                                     $ok = 1;
107                                 } else { $ok = 0; }
108                             } else { $ok = 0; }
109                         } else { $ok = 0; }
110                     } else { $ok = 0; }
111                 } else { $ok = 0; }
112             } else { $ok = 0; }
113             if ($ok == 1) {
114                 print($LANG['installer_permissions_success'] . '<br /><br />');
115             } else {
116                 print($LANG['error_installer_permissions']);
117             }
118         }
119         if ($ok == 1) {
120             // set up Apache URL rewriting
121             if ($SETUPDATA['url_rewriting'] == 1) {
122                 // create .htaccess
123                 if ($handle = @fopen('.htaccess', 'w')) {
124                     if (@fwrite($handle, "RewriteEngine On\n\nRewriteBase " . $SETUPDATA['webpath'] . "\n\nRewriteRule ^index\.php$ index.php [L]\nRewriteRule ^install\.php$ install.php [L]\nRewriteRule ^([a-z]+)\.php$ index.php?show=$1&%{QUERY_STRING} [L]\n\nOptions -Indexes\n")) {
125                         // set chmod
126                         @chmod('.htaccess', 0664);
127                     } else { $ok = 0; }
128                 } else { $ok = 0; }
129                 // create admin/.htaccess
130                 if ($handle = @fopen('admin/.htaccess', 'w')) {
131                     if (@fwrite($handle, "RewriteEngine On\n\nRewriteBase " . $SETUPDATA['webpath'] . "admin/\n\nRewriteRule ^index\.php$ index.php [L]\nRewriteRule ^([a-z]+)\.php$ index.php?show=$1&%{QUERY_STRING} [L]\n\nOptions -Indexes\n")) {
132                         // set chmod
133                         @chmod('admin/.htaccess', 0664);
134                     } else { $ok = 0; }
135                 } else { $ok = 0; }
136                 if ($ok == 1) {
137                     print($LANG['installer_rewriting_success'] . '<br /><br />');
138                 } else {
139                     print($LANG['error_installer_rewriting'] . '<br /><br />');
140                 }
141             }
142             if ($ok == 1) {
143                 /* write settings.php */
144                 // open settings file for write access
145                 if ($file = @fopen('includes/config/settings.php', 'w')) {
146                     // write settings
147                     fwrite($file, "<?php\n\n");
148                     fwrite($file, "/**\n * Package: Spam Board 5\n * File: includes/config/settings.php\n * Description: global board settings (usually modified through admin panel)\n **/\n\n");
149                     fwrite($file, "\$SETTINGS['maintainancemode'] = " . $SETTINGS['maintainancemode'] . "; // put the board into maintainance mode (1/0); only admins can use it then\n");
150                     fwrite($file, "\$SETTINGS['sqltype'] = '" . $SETUPDATA['sqltype'] . "'; // type of SQL database (e.g. SQLite)\n");
151                     fwrite($file, "\$SETTINGS['sqlhost'] = '" . $SETUPDATA['sqlhost'] . "'; // hostname for the SQL database (usually localhost)\n");
152                     fwrite($file, "\$SETTINGS['sqluser'] = '" . $SETUPDATA['sqluser'] . "'; // username for SQL\n");
153                     fwrite($file, "\$SETTINGS['sqlpassword'] = '" . $SETUPDATA['sqlpassword'] . "'; // password for SQL\n");
154                     fwrite($file, "\$SETTINGS['dbname'] = '" . $SETUPDATA['sqldatabase'] . "'; // name of the SQL database\n");
155                     fwrite($file, "\$SETTINGS['dbtableprefix'] = '" . $SETUPDATA['sqltableprefix'] . "'; // prefix of all the database tables\n");
156                     fwrite($file, "\$SETTINGS['fspath'] = '" . $SETUPDATA['fspath'] . "'; // full file system path to the forum root\n");
157                     fwrite($file, "\$SETTINGS['webpath'] = '" . $SETUPDATA['webpath'] . "'; // path to the forum from domain's root\n");
158                     fwrite($file, "\$SETTINGS['forumname'] = '" . $SETUPDATA['forumname'] . "'; // displayed in browser's title and used for outgoing e-mail\n");
159                     fwrite($file, "\$SETTINGS['slogan'] = '" . $SETUPDATA['slogan'] . "'; // displayed in browser's title\n");
160                     fwrite($file, "\$SETTINGS['forumlogo'] = '" . $SETUPDATA['forumlogo'] . "'; // has to be placed in the images directory\n");
161                     fwrite($file, "\$SETTINGS['sitename'] = '" . $SETUPDATA['sitename'] . "'; // name of the site the forum should link back to\n");
162                     fwrite($file, "\$SETTINGS['siteurl'] = '" . $SETUPDATA['siteurl'] . "'; // URL of the site the forum should link back to\n");
163                     fwrite($file, "\$SETTINGS['forumadmin'] = '" . $SETUPDATA['forumadmin'] . "'; // The admin's name. This'll be used to 'sign' all outgoing e-mail.\n");
164                     fwrite($file, "\$SETTINGS['forumadminemail'] = '" . $SETUPDATA['forumadminemail'] . "'; // e-mail address for outgoing mail\n");
165                     fwrite($file, "\$SETTINGS['topicsperpage'] = " . $SETTINGS['topicsperpage'] . "; // number of topics displayed per page\n");
166                     fwrite($file, "\$SETTINGS['postsperpage'] = " . $SETTINGS['postsperpage'] . "; // number of posts displayed per page\n");
167                     fwrite($file, "\$SETTINGS['maxavatarsize'] = " . $SETTINGS['maxavatarsize'] . "; // max. avatar width & height in pixels\n");
168                     fwrite($file, "\$SETTINGS['guestemail'] = " . $SETTINGS['guestemail'] . "; // show e-mail address field on post form for guests (1) or not (0)\n");
169                     fwrite($file, "\$SETTINGS['severalaccountspermail'] = " . $SETTINGS['severalaccountspermail'] . "; // allow registering more than one account per e-mail address (1/0)\n");
170                     fwrite($file, "\$SETTINGS['polls'] = " . $SETTINGS['polls'] . "; // polls on (1) or off (0)\n");
171                     fwrite($file, "\$SETTINGS['floodcontrol'] = " . $SETTINGS['floodcontrol'] . "; // number of seconds someone has to wait between two posts\n");
172                     fwrite($file, "\$SETTINGS['floodcontrol_search'] = " . $SETTINGS['floodcontrol_search'] . "; // number of seconds someone has to wait between two searches\n");
173                     fwrite($file, "\$SETTINGS['loginattempts'] = " . $SETTINGS['loginattempts'] . "; // number of failed login attempts by a user after which the board will try to lock him or her out for good (set to 0 to disable)\n");
174                     fwrite($file, "\$SETTINGS['maxuploadsize'] = " . $SETTINGS['maxuploadsize'] . "; // maximum file size of attachments in bytes\n");
175                     fwrite($file, "\$SETTINGS['uploadextensions'] = '" . $SETTINGS['uploadextensions'] . "'; // allowed file extensions for attachments (seperated by commas)\n");
176                     fwrite($file, "\$SETTINGS['ip_logging'] = " . $SETTINGS['ip_logging'] . "; // log IP address of every post (1) or not (0)\n");
177                     fwrite($file, "\$SETTINGS['language'] = '" . $SETTINGS['language'] . "'; // default board language\n");
178                     fwrite($file, "\$SETTINGS['url_rewriting'] = " . $SETUPDATA['url_rewriting'] . "; // URL rewriting through mod_rewrite (1) or not (0)\n");
179                     fwrite($file, "\$SETTINGS['timezone'] = '" . $SETTINGS['timezone'] . "'; // time offset compared to UTC\n");
180                     fwrite($file, "\$SETTINGS['encoding'] = '" . $SETTINGS['encoding'] . "'; // character encoding\n");
181                     fwrite($file, "\$SETTINGS['defaultstyle'] = '" . $SETTINGS['defaultstyle'] . "'; // default stylesheet of the board\n");
182                     fwrite($file, "\$SETTINGS['expire'] = " . $SETTINGS['expire'] . "; // cookie expiration in days\n");
183                     fwrite($file, "\$SETTINGS['debug'] = " . $SETTINGS['debug'] . "; // debug mode (0: off, 1: on, 2: admins only)\n");
184                     fwrite($file, "\$SETTINGS['hash'] = '" . $SETUPDATA['hash'] . "'; // hash algorithm used for the passwords\n");
185                     fwrite($file, '?>');
186                     // close file
187                     @fclose($file);
188                     // set chmod
189                     @chmod('includes/config/settings.php', 0660);
190                     // include new settings again
191                     require('includes/config/settings.php');
192                 } else { $ok = 0; }
193                 /* initialize crypto module */
194                 require('classes/misc/Password.php');
195                 $key = new Password();
196                 $key->generate(512);
197                 $padding = new Password();
198                 $padding->generate(512);
199                 // read template
200                 if ($template = @file_get_contents('includes/config/crypt.tmpl')) {
201                     // write into crypt.php
202                     if ($file = @fopen('includes/config/crypt.php', 'w')) {
203                         // write settings
204                         if (@fwrite($file, str_replace(Array('%key%', '%padding%'), Array($key->get(), $padding->get()), $template))) {
205                             @fclose($file);
206                             // set permissions
207                             @chmod('includes/config/crypt.php', 0660);
208                             // get new crypto settings
209                             require('includes/config/crypt.php');
210                         } else { $ok = 0; }
211                     } else { $ok = 0; }
212                 } else { $ok = 0; }
213                 /* copy other template files to their actual names */
214                 if (@copy('includes/config/bans.tmpl', 'includes/config/bans.php')) {
215                     @chmod('includes/config/bans.php', 0660);
216                 } else { $ok = 0; }
217                 if (@copy('includes/config/logins.tmpl', 'includes/config/logins.php')) {
218                     @chmod('includes/config/logins.php', 0660);
219                 } else { $ok = 0; }
220                 if (@copy('includes/config/memberstages.tmpl', 'includes/config/memberstages.php')) {
221                     @chmod('includes/config/memberstages.php', 0660);
222                 } else { $ok = 0; }
223                 if ($ok == 1) {
224                     print($LANG['installer_config_success'] . '<br /><br />');
225                 } else {
226                     print($LANG['error_installer_config']);
227                 }
228                 // set permissions for version.php
229                 @chmod('includes/config/version.php', 0660);
230                 // set permissions for bots.php
231                 @chmod('includes/config/bots.php', 0660);
232                 if ($ok == 1) {
233                     /* set up database */
234                     require('classes/misc/Connection.php');
235                     // create database file if needed
236                     if ($SETTINGS['sqltype'] == 'sqlite' && !is_file('db/' . $SETTINGS['dbname'])) {
237                         @touch('db/' . $SETTINGS['dbname']);
238                     }
239                     // open SQL connection
240                     if ($C = new Connection()) {
241                         // get table structure
242                         if ($db = @file_get_contents('db/' . $SETTINGS['sqltype'] . '.sql')) {
243                             // one SQL query at a time
244                             $db = explode(';', $db);
245                             foreach ($db as $query) {
246                                 $C->query(str_replace('%prefix%', $SETTINGS['dbtableprefix'], $query));
247                             }
248                             // finally, fill in default data
249                             if ($db = @file_get_contents('db/data.sql')) {
250                                 // one SQL query at a time
251                                 $db = explode(';', $db);
252                                 foreach ($db as $query) {
253                                     $C->query(str_replace('%prefix%', $SETTINGS['dbtableprefix'], $query));
254                                 }
255                             }
256                             // write the admin account
257                             $q = $C->prepare('INSERT INTO ' . $SETTINGS['dbtableprefix'] . 'members (membername, memberemail, memberavatar, memberpassword, registered, memberstatus) VALUES (:name, :email, :avatar, :password, :registered, :status)');
258                             $_t = new DateTime('now', new DateTimeZone('UTC'));
259                             $q->bindParam(':name', $SETUPDATA['forumadmin'], PDO::PARAM_STR);
260                             $q->bindParam(':email', $SETUPDATA['forumadminemail'], PDO::PARAM_STR);
261                             $q->bindValue(':avatar', 'images/spacer.gif', PDO::PARAM_STR);
262                             $q->bindValue(':password', '*', PDO::PARAM_STR);
263                             $q->bindParam(':registered', $_t->format('Y-m-d H:i:s'), PDO::PARAM_STR, 19);
264                             $q->bindValue(':status', 'Admin', PDO::PARAM_STR);
265                             $q->execute();
266                             // get id of admin
267                             $q = $C->prepare('SELECT MAX(memberid) AS id FROM ' . $SETTINGS['dbtableprefix'] . 'members');
268                             $q->execute();
269                             $row = $q->fetchObject();
270                             $q->closeCursor();
271                             // set actual password
272                             require('classes/misc/Member.php');
273                             Member::setPassword($row->id, $SETUPDATA['adminpassword']);
274                             // set group membership 'Admin'
275                             $q = $C->prepare('SELECT id FROM ' . $SETTINGS['dbtableprefix'] . 'usergroups WHERE name = :admin');
276                             $q->bindValue(':admin', 'Admin', PDO::PARAM_STR);
277                             $q->execute();
278                             $row2 = $q->fetchObject();
279                             $q->closeCursor();
280                             $q = $C->prepare('INSERT INTO ' . $SETTINGS['dbtableprefix'] . 'groupmemberships (member, usergroup) VALUES (:member, :group)');
281                             $q->bindParam(':member', $row->id, PDO::PARAM_INT, 12);
282                             $q->bindParam(':group', $row2->id, PDO::PARAM_INT, 12);
283                             $q->execute();
284                             // set group membership 'Member'
285                             $q = $C->prepare('SELECT id FROM ' . $SETTINGS['dbtableprefix'] . 'usergroups WHERE name = :member');
286                             $q->bindValue(':member', 'Member', PDO::PARAM_STR);
287                             $q->execute();
288                             $row2 = $q->fetchObject();
289                             $q->closeCursor();
290                             $q = $C->prepare('INSERT INTO ' . $SETTINGS['dbtableprefix'] . 'groupmemberships (member, usergroup) VALUES (:member, :group)');
291                             $q->bindParam(':member', $row->id, PDO::PARAM_INT, 12);
292                             $q->bindParam(':group', $row2->id, PDO::PARAM_INT, 12);
293                             $q->execute();
294                             // permissions
295                             if ($SETUPDATA['sqltype'] == 'sqlite') {
296                                 @chmod('db/' . $SETUPDATA['sqldatabase'], 0660);
297                             }
298
299                         } else { $ok = 0; }
300                     } else { $ok = 0; }
301                     if ($ok == 1) {
302                         print($LANG['installer_database_success'] . '<br /><br />');
303                         /* try securing sessions and db directories */
304                         if (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== FALSE) {
305                             // Apache -> .htaccess
306                             if ($file = @fopen('sessions/.htaccess', 'w')) {
307                                 // write settings
308                                 if (@fwrite($file, 'deny from all')) {
309                                     @fclose($file);
310                                     // set permissions
311                                     @chmod('sessions/.htaccess', 0664);
312                                 }
313                             }
314                             @copy('sessions/.htaccess', 'db/.htaccess');
315                             @copy('sessions/.htaccess', 'classes/.htaccess');
316                             @copy('sessions/.htaccess', 'admin/classes/.htaccess');
317                             @copy('sessions/.htaccess', 'includes/.htaccess');
318                             // exception: allow
319                             if ($file = @fopen('includes/styles/.htaccess', 'w')) {
320                                 // write settings
321                                 if (@fwrite($file, 'allow from all')) {
322                                     @fclose($file);
323                                     // set permissions
324                                     @chmod('includes/styles/.htaccess', 0664);
325                                 }
326                             }
327                             @copy('includes/styles/.htaccess', 'includes/js/.htaccess');
328                         } else {
329                             // other webservers...
330                         }
331                     } else {
332                         print($LANG['error_installer_database'] . '<br /><br />');
333                     }
334                 }
335             }
336         }
337         if ($ok == 1) {
338             /* test whether db and settings directories are accessable via HTTP */
339             $fp = @fsockopen($_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $errno, $errstr, 30);
340             if ($fp !== FALSE) {
341                 // db
342                 $req = 'GET ' . $SETTINGS['webpath'] . "db/spamboard.sql HTTP/1.1\r\n";
343                 $req .= 'Host: ' . $_SERVER['SERVER_NAME'] . "\r\n";
344                 $req .= "Connection: Close\r\n\r\n";
345                 fwrite($fp, $req);
346                 $reply = '';
347                 while (!feof($fp)) {
348                     $reply .= fgets($fp, 128);
349                 }
350                 fclose($fp);
351                 if (strpos($reply, '403 Forbidden') === FALSE) {
352