r3231 - updated URLs
[racktables] / install.php
1 <?php
2
3 // This script is intended for execution through a web-browser, e.g.:
4 // https://example.com/racktables/install.php
5 // See README file for more information.
6
7 $stepfunc[1] = 'not_already_installed';
8 $stepfunc[2] = 'platform_is_ok';
9 $stepfunc[3] = 'init_config';
10 $stepfunc[4] = 'init_database_static';
11 $stepfunc[5] = 'init_database_dynamic';
12 $stepfunc[6] = 'congrats';
13 $dbxlink = NULL;
14
15 if (isset ($_REQUEST['step']))
16 $step = $_REQUEST['step'];
17 else
18 $step = 1;
19
20 if ($step > count ($stepfunc))
21 {
22 require 'inc/init.php';
23 $root = (empty($_SERVER['HTTPS']) or $_SERVER['HTTPS'] == 'off') ? 'http://' : 'https://';
24 $root .= isset ($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].($_SERVER['SERVER_PORT']=='80'?'':$_SERVER['SERVER_PORT']));
25 // "Since PHP 4.3.0, you will often get a slash or a dot back from
26 // dirname() in situations where the older functionality would have given
27 // you the empty string."
28 // "On Windows, both slash (/) and backslash (\) are used as directory
29 // separator character."
30 $root .= strtr (dirname ($_SERVER['PHP_SELF']), '\\', '/');
31 if (substr ($root, -1) != '/')
32 $root .= '/';
33 header ("Location: ${root}");
34 exit;
35 }
36 $title = "RackTables installation: step ${step} of " . count ($stepfunc);
37 require_once ('inc/dictionary.php');
38 ?>
39 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
40 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
41 <head><title><?php echo $title; ?></title>
42 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
43 <link rel=stylesheet type='text/css' href=pi.css />
44 </head>
45 <body>
46 <center>
47 <?php
48 echo "<h1>${title}</h1><p>";
49
50 echo "</p><form method=post>\n";
51 $testres = $stepfunc[$step] ();
52 if ($testres)
53 {
54 $next_step = $step + 1;
55 echo "<br><input type=submit value='proceed'>";
56 }
57 else
58 {
59 $next_step = $step;
60 echo "<br><input type=submit value='retry'>";
61 }
62 echo "<input type=hidden name=step value='${next_step}'>\n";
63
64 ?>
65 </form>
66 </center>
67 </body>
68 </html>
69
70 <?php
71 // Check if the software is already installed.
72 function not_already_installed()
73 {
74 @include ('inc/secret.php');
75 if (isset ($pdo_dsn))
76 {
77 echo 'Your configuration file exists and seems to hold necessary data already.<br>';
78 return FALSE;
79 }
80 else
81 {
82 echo 'There seem to be no existing installation here, I am going to setup one now.<br>';
83 return TRUE;
84 }
85 }
86
87 function extension_issues ($funcname, $extname)
88 {
89 echo "<tr><td>${extname}</td>";
90 if (function_exists ($funcname))
91 {
92 echo '<td class=msg_success>Ok</td></tr>';
93 return 0;
94 }
95 echo '<td class=msg_error>not found</td></tr>';
96 return 1;
97 }
98
99 // Check for PHP extensions.
100 function platform_is_ok ()
101 {
102 $nerrs = 0;
103 echo "<table border=1><tr><th>check item</th><th>result</th></tr>\n";
104
105 echo '<tr><td>PDO extension</td>';
106 if (class_exists ('PDO'))
107 echo '<td class=msg_success>Ok';
108 else
109 {
110 echo '<td class=msg_error>not found';
111 $nerrs++;
112 }
113 echo '</td></tr>';
114
115 echo '<tr><td>PDO-MySQL</td>';
116 if (defined ('PDO::MYSQL_ATTR_READ_DEFAULT_FILE'))
117 echo '<td class=msg_success>Ok';
118 else
119 {
120 echo '<td class=msg_error>not found';
121 $nerrs++;
122 }
123 echo '</td></tr>';
124
125 $nerrs += extension_issues ('sha1', 'hash function');
126 $nerrs += extension_issues ('preg_match', 'PCRE extension');
127 $nerrs += extension_issues ('ereg', 'POSIX Regex extension');
128
129 echo '<tr><td>SNMP extension</td>';
130 if (defined ('SNMP_NULL'))
131 echo '<td class=msg_success>Ok';
132 else
133 echo '<td class=msg_warning>Not found. Live SNMP tab will not function properly until the extension is installed.';
134 echo '</td></tr>';
135
136 $nerrs += extension_issues ('gd_info', 'GD extension');
137
138 echo '<tr><td>HTTP scheme</td>';
139 if (!empty($_SERVER['HTTPS']) and $_SERVER['HTTPS'] != 'off')
140 echo '<td class=msg_success>HTTPs';
141 else
142 echo '<td class=msg_warning>HTTP (all your passwords will be transmitted in cleartext)';
143 echo '</td></tr>';
144
145 $nerrs += extension_issues ('mb_strlen', 'Multibyte string extension');
146
147 echo '<tr><td>LDAP extension</td>';
148 if (defined ('LDAP_OPT_DEREF'))
149 echo '<td class=msg_success>Ok';
150 else
151 {
152 echo '<td class=msg_warning>not found, LDAP authentication will not work';
153 }
154 echo '</td></tr>';
155
156 echo "</table>\n";
157 return !$nerrs;
158 }
159
160 // Check that we can write to configuration file.
161 // If so, ask for DB connection paramaters and test
162 // the connection. Neither save the parameters nor allow
163 // going further until we succeed with the given
164 // credentials.
165 function init_config ()
166 {
167 if (!is_writable ('inc/secret.php'))
168 {
169 echo "The inc/secret.php file is not writable by web-server. Make sure it is.";
170 echo "The following commands should suffice:<pre>touch inc/secret.php\nchmod 666 inc/secret.php</pre>";
171 echo 'Fedora Linux with SELinux may require this file to be owned by specific user (apache) and/or executing "setenforce 0" for the time of installation. ';
172 echo 'SELinux may be turned back on with "setenforce 1" command.';
173 return FALSE;
174 }
175 if
176 (
177 !isset ($_REQUEST['save_config']) or
178 empty ($_REQUEST['mysql_host']) or
179 empty ($_REQUEST['mysql_db']) or
180 empty ($_REQUEST['mysql_username']) or
181 empty ($_REQUEST['mysql_password'])
182 )
183 {
184 echo "<input type=hidden name=save_config value=1>\n";
185 echo '<h3>Hint on setting up a database:</h3><pre>';
186 echo "mysql&gt; CREATE DATABASE racktables_db CHARACTER SET utf8 COLLATE utf8_general_ci;\n";
187 echo "mysql&gt; grant all privileges on racktables_db.* to racktables_user@localhost identified by 'MY_SECRET_PASSWORD';\n</pre>";
188 echo '<table>';
189 echo "<tr><td><label for=mysql_host>MySQL host:</label></td>";
190 echo "<td><input type=text name=mysql_host id=mysql_host value=localhost></td></tr>\n";
191 echo "<tr><td><label for=mysql_host>database:</label></td>";
192 echo "<td><input type=text name=mysql_db id=mysql_db value=racktables_db></td></tr>\n";
193 echo "<tr><td><label for=mysql_username>username:</label></td>";
194 echo "<td><input type=text name=mysql_username value=racktables_user></td></tr>\n";
195 echo "<tr><td><label for=mysql_password>password:</label></td>";
196 echo "<td><input type=password name=mysql_password></td></tr>\n";
197 echo '</table>';
198 return FALSE;
199 }
200 $pdo_dsn = 'mysql:host=' . $_REQUEST['mysql_host'] . ';dbname=' . $_REQUEST['mysql_db'];
201 try
202 {
203 $dbxlink = new PDO ($pdo_dsn, $_REQUEST['mysql_username'], $_REQUEST['mysql_password']);
204 }
205 catch (PDOException $e)
206 {
207 echo "<input type=hidden name=save_config value=1>\n";
208 echo '<table>';
209 echo "<tr><td><label for=mysql_host>MySQL host:</label></td>";
210 echo "<td><input type=text name=mysql_host id=mysql_host value='" . $_REQUEST['mysql_host'] . "'></td></tr>\n";
211 echo "<tr><td><label for=mysql_host>database:</label></td>";
212 echo "<td><input type=text name=mysql_db id=mysql_db value='" . $_REQUEST['mysql_db'] . "'></td></tr>\n";
213 echo "<tr><td><label for=mysql_username>username:</label></td>";
214 echo "<td><input type=text name=mysql_username value='" . $_REQUEST['mysql_username'] . "'></td></tr>\n";
215 echo "<tr><td><label for=mysql_password>password:</label></td>";
216 echo "<td><input type=password name=mysql_password value='" . $_REQUEST['mysql_password'] . "'></td></tr>\n";
217 echo "<tr><td colspan=2>The above parameters did not work. Check and try again.</td></tr>\n";
218 echo '</table>';
219 return FALSE;
220 }
221
222 // Make sure InnoDB is supported
223 require_once 'inc/database.php';
224 if (!isInnoDBSupported ($dbxlink))
225 {
226 echo 'Error: InnoDB support is disabled. See the README for details.';
227 return FALSE;
228 }
229
230 $conf = fopen ('inc/secret.php', 'w+');
231 if ($conf === FALSE)
232 {
233 echo "Error: failed to open inc/secret.php for writing";
234 return FALSE;
235 }
236 fwrite ($conf, "<?php\n/* This file has been generated automatically by RackTables installer.\n");
237 fwrite ($conf, " * you shouldn't normally edit it unless your database setup has changed.\n");
238 fwrite ($conf, " */\n");
239 fwrite ($conf, "\$pdo_dsn = '${pdo_dsn}';\n");
240 fwrite ($conf, "\$db_username = '" . $_REQUEST['mysql_username'] . "';\n");
241 fwrite ($conf, "\$db_password = '" . $_REQUEST['mysql_password'] . "';\n\n");
242 fwrite ($conf, <<<ENDOFTEXT
243 // Default setting is to authenticate users locally, but it is possible to
244 // employ existing LDAP or Apache userbase. Uncommenting below two lines MAY
245 // help in switching authentication to LDAP completely.
246 // More info: http://sourceforge.net/apps/mediawiki/racktables/index.php?title=RackTablesAdminGuide
247 #\$user_auth_src = 'ldap';
248 #\$require_local_account = FALSE;
249
250 // This is only necessary for 'ldap' authentication source
251 \$LDAP_options = array
252 (
253 'server' => 'some.server',
254 'domain' => 'some.domain',
255 # 'search_dn' => 'ou=people,O=YourCompany',
256 'search_attr' => 'uid',
257 # 'displayname_attrs' => 'givenname familyname',
258
259 // LDAP cache, values in seconds. Refresh, retry and expiry values are
260 // treated exactly as those for DNS SOA record. Example values 300-15-600:
261 // unconditionally remeber successful auth for 5 minutes, after that still
262 // permit user access, but try to revalidate username and password on the
263 // server (not more often, than once in 15 seconds). After 10 minutes of
264 // unsuccessful retries give up and deny access, so someone goes to fix
265 // LDAP server.
266 'cache_refresh' => 300,
267 'cache_retry' => 15,
268 'cache_expiry' => 600,
269 );
270
271
272 ENDOFTEXT
273 );
274 fwrite ($conf, "?>\n");
275 fclose ($conf);
276 echo "The configuration file has been written successfully.<br>";
277 return TRUE;
278 }
279
280 function connect_to_db ()
281 {
282 require ('inc/secret.php');
283 global $dbxlink;
284 try
285 {
286 $dbxlink = new PDO ($pdo_dsn, $db_username, $db_password);
287 }
288 catch (PDOException $e)
289 {
290 die ('Error connecting to the database');
291 }
292 }
293
294 function init_database_static ()
295 {
296 connect_to_db ();
297 global $dbxlink;
298 $result = $dbxlink->query ('show tables');
299 $tables = $result->fetchAll (PDO::FETCH_NUM);
300 $result->closeCursor();
301 unset ($result);
302 if (count ($tables))
303 {
304 echo 'Your database is already holding ' . count ($tables);
305 echo ' tables, so I will stop here and let you check it yourself.<br>';
306 echo 'There is some important data there probably.<br>';
307 return FALSE;
308 }
309 echo 'Initializing the database...<br>';
310 echo '<table border=1>';
311 echo "<tr><th>file</th><th>queries</th><th>errors</th></tr>";
312 $errlist = array();
313 foreach (array ('structure', 'dictbase') as $part)
314 {
315 $filename = "install/init-${part}.sql";
316 echo "<tr><td>${filename}</td>";
317 $f = fopen ("install/init-${part}.sql", 'r');
318 if ($f === FALSE)
319 {
320 echo "Failed to open install/init-${part}.sql for reading";
321 return FALSE;
322 }
323 $longq = '';
324 while (!feof ($f))
325 {
326 $line = fgets ($f);
327 if (ereg ('^--', $line))
328 continue;
329 $longq .= $line;
330 }
331 fclose ($f);
332 $nq = $nerrs = 0;
333 foreach (preg_split ("/;\s*\n/", $longq) as $query)
334 {
335 $query = trim($query);
336 if (empty ($query))
337 continue;
338 $nq++;
339 if ($dbxlink->exec ($query) === FALSE)
340 {
341 $nerrs++;
342 $errlist[] = $query;
343 }
344 }
345 echo "<td>${nq}</td><td>${nerrs}</td></tr>\n";
346 }
347 // (re)load dictionary by pure PHP means w/o any external file
348 echo "<tr><th>dictionary</th>";
349 $nq = $nerrs = 0;
350 $dictq = array();
351 foreach (reloadDictionary() as $query)
352 {
353 $nq++;
354 if ($dbxlink->exec ($query) === FALSE)
355 {
356 $nerrs++;
357 $errlist[] = $query;
358 }
359 }
360 echo "<td>${nq}</td><td>${nerrs}</td></tr>\n";
361
362 echo '</table>';
363 if (count ($errlist))
364 {
365 echo '<pre>The following queries failed:\n';
366 foreach ($errlist as $q)
367 echo "${q}\n\n";
368 echo '</pre>';
369 return FALSE;
370 }
371 return TRUE;
372 }
373
374 function init_database_dynamic ()
375 {
376 connect_to_db();
377 global $dbxlink;
378 if (!isset ($_REQUEST['password']) or empty ($_REQUEST['password']))
379 {
380 $result = $dbxlink->query ('select count(user_id) from UserAccount where user_id = 1');
381 $row = $result->fetch (PDO::FETCH_NUM);
382 $nrecs = $row[0];
383 $result->closeCursor();
384 if (!$nrecs)
385 {
386 echo '<table border=1>';
387 echo '<caption>Administrator password not set</caption>';
388 echo '<tr><td><input type=password name=password></td></tr>';
389 echo '</table>';
390 }
391 return FALSE;
392 }
393 else
394 {
395 // Never send cleartext password over the wire.
396 $hash = sha1 ($_REQUEST['password']);
397 $query = "INSERT INTO `UserAccount` (`user_id`, `user_name`, `user_password_hash`, `user_realname`) " .
398 "VALUES (1,'admin','${hash}','RackTables Administrator')";
399 $result = $dbxlink->exec ($query);
400 echo "Administrator password has been set successfully.<br>";
401 return TRUE;
402 }
403 }
404
405 function congrats ()
406 {
407 echo 'Congratulations! RackTables installation is complete. After pressing Proceed you will ';
408 echo 'enter the system. Authenticate with <strong>admin</strong> username.<br>RackTables project has a ';
409 echo "<a href='http://sourceforge.net/apps/mediawiki/racktables/index.php?title=RackTablesAdminGuide'>";
410 echo "wiki</a> and a ";
411 echo "<a href='http://www.freelists.org/list/racktables-users'>mailing list</a> for users. Have fun.<br>";
412 return TRUE;
413 }
414
415 ?>