r3230 - 0.17.8: pre-release adjustments
[racktables] / install.php
CommitLineData
0e7f2155 1<?php
5b4523dc 2
d3372430
DO
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.
5b4523dc 6
0e7f2155
DO
7$stepfunc[1] = 'not_already_installed';
8$stepfunc[2] = 'platform_is_ok';
9$stepfunc[3] = 'init_config';
96e102b2
DO
10$stepfunc[4] = 'init_database_static';
11$stepfunc[5] = 'init_database_dynamic';
12$stepfunc[6] = 'congrats';
13$dbxlink = NULL;
0e7f2155
DO
14
15if (isset ($_REQUEST['step']))
16 $step = $_REQUEST['step'];
17else
18 $step = 1;
19
20if ($step > count ($stepfunc))
21{
22 require 'inc/init.php';
790a60e8
DO
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}");
0e7f2155
DO
34 exit;
35}
36$title = "RackTables installation: step ${step} of " . count ($stepfunc);
3fb336f6 37require_once ('inc/dictionary.php');
0e7f2155 38?>
f48dc2cc
DO
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">
0e7f2155 41<head><title><?php echo $title; ?></title>
21fd978f 42<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
f48dc2cc
DO
43<link rel=stylesheet type='text/css' href=pi.css />
44</head>
45<body>
0e7f2155 46<center>
f48dc2cc 47<?php
f92287f4
DO
48echo "<h1>${title}</h1><p>";
49
50echo "</p><form method=post>\n";
51$testres = $stepfunc[$step] ();
52if ($testres)
53{
54 $next_step = $step + 1;
ae067ef3 55 echo "<br><input type=submit value='proceed'>";
f92287f4
DO
56}
57else
58{
59 $next_step = $step;
ae067ef3 60 echo "<br><input type=submit value='retry'>";
f92287f4
DO
61}
62echo "<input type=hidden name=step value='${next_step}'>\n";
63
64?>
65</form>
66</center>
67</body>
68</html>
69
70<?php
0e7f2155
DO
71// Check if the software is already installed.
72function not_already_installed()
f48dc2cc 73{
80138748 74 @include ('inc/secret.php');
f92287f4
DO
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 {
43f06d53 82 echo 'There seem to be no existing installation here, I am going to setup one now.<br>';
f92287f4
DO
83 return TRUE;
84 }
f48dc2cc
DO
85}
86
e4675d3a
DO
87function 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
0e7f2155
DO
99// Check for PHP extensions.
100function platform_is_ok ()
f48dc2cc 101{
0e7f2155
DO
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
f48dc2cc 109 {
0e7f2155
DO
110 echo '<td class=msg_error>not found';
111 $nerrs++;
112 }
113 echo '</td></tr>';
f48dc2cc 114
0e7f2155
DO
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>';
f48dc2cc 124
e4675d3a
DO
125 $nerrs += extension_issues ('sha1', 'hash function');
126 $nerrs += extension_issues ('preg_match', 'PCRE extension');
127 $nerrs += extension_issues ('ereg', 'POSIX Regex extension');
f48dc2cc 128
0e7f2155
DO
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>';
f48dc2cc 135
e4675d3a 136 $nerrs += extension_issues ('gd_info', 'GD extension');
f48dc2cc 137
01539ac3 138 echo '<tr><td>HTTP scheme</td>';
fff18256 139 if (!empty($_SERVER['HTTPS']) and $_SERVER['HTTPS'] != 'off')
01539ac3
DO
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
e4675d3a 145 $nerrs += extension_issues ('mb_strlen', 'Multibyte string extension');
9ddee5ea
DO
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
0e7f2155
DO
156 echo "</table>\n";
157 return !$nerrs;
158}
f48dc2cc 159
0e7f2155
DO
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.
165function init_config ()
166{
80138748 167 if (!is_writable ('inc/secret.php'))
f92287f4 168 {
80138748
DO
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>";
9b16b1f1 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. ';
029563a4 172 echo 'SELinux may be turned back on with "setenforce 1" command.';
f92287f4
DO
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";
ae067ef3
DO
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>";
f92287f4
DO
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>";
ae067ef3 192 echo "<td><input type=text name=mysql_db id=mysql_db value=racktables_db></td></tr>\n";
f92287f4 193 echo "<tr><td><label for=mysql_username>username:</label></td>";
ae067ef3 194 echo "<td><input type=text name=mysql_username value=racktables_user></td></tr>\n";
f92287f4
DO
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 }
e1ae3fb4
AD
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
80138748 230 $conf = fopen ('inc/secret.php', 'w+');
f92287f4
DO
231 if ($conf === FALSE)
232 {
80138748 233 echo "Error: failed to open inc/secret.php for writing";
f92287f4
DO
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");
e0dcbf1e 241 fwrite ($conf, "\$db_password = '" . $_REQUEST['mysql_password'] . "';\n\n");
2a622048
DO
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://racktables.org/trac/wiki/RackTablesUserAuthentication
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
272ENDOFTEXT
273);
f92287f4
DO
274 fwrite ($conf, "?>\n");
275 fclose ($conf);
276 echo "The configuration file has been written successfully.<br>";
0e7f2155 277 return TRUE;
f48dc2cc
DO
278}
279
96e102b2
DO
280function connect_to_db ()
281{
80138748 282 require ('inc/secret.php');
96e102b2
DO
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
294function init_database_static ()
0e7f2155 295{
01539ac3
DO
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 }
0e7f2155 309 echo 'Initializing the database...<br>';
96e102b2 310 echo '<table border=1>';
b2bdfd89
DO
311 echo "<tr><th>file</th><th>queries</th><th>errors</th></tr>";
312 $errlist = array();
3fb336f6 313 foreach (array ('structure', 'dictbase') as $part)
f92287f4 314 {
96e102b2
DO
315 $filename = "install/init-${part}.sql";
316 echo "<tr><td>${filename}</td>";
317 $f = fopen ("install/init-${part}.sql", 'r');
96e102b2
DO
318 if ($f === FALSE)
319 {
320 echo "Failed to open install/init-${part}.sql for reading";
321 return FALSE;
322 }
b2bdfd89 323 $longq = '';
96e102b2
DO
324 while (!feof ($f))
325 {
326 $line = fgets ($f);
327 if (ereg ('^--', $line))
328 continue;
b2bdfd89 329 $longq .= $line;
96e102b2
DO
330 }
331 fclose ($f);
b2bdfd89 332 $nq = $nerrs = 0;
5fe42ae4 333 foreach (preg_split ("/;\s*\n/", $longq) as $query)
96e102b2 334 {
5fe42ae4 335 $query = trim($query);
96e102b2
DO
336 if (empty ($query))
337 continue;
338 $nq++;
b2bdfd89
DO
339 if ($dbxlink->exec ($query) === FALSE)
340 {
341 $nerrs++;
342 $errlist[] = $query;
343 }
96e102b2 344 }
b2bdfd89 345 echo "<td>${nq}</td><td>${nerrs}</td></tr>\n";
f92287f4 346 }
3fb336f6
DO
347 // (re)load dictionary by pure PHP means w/o any external file
348 echo "<tr><th>dictionary</th>";
349 $nq = $nerrs = 0;
3fb336f6 350 $dictq = array();
ca3d68bd
DO
351 foreach (reloadDictionary() as $query)
352 {
353 $nq++;
354 if ($dbxlink->exec ($query) === FALSE)
3fb336f6 355 {
ca3d68bd
DO
356 $nerrs++;
357 $errlist[] = $query;
3fb336f6 358 }
ca3d68bd 359 }
3fb336f6
DO
360 echo "<td>${nq}</td><td>${nerrs}</td></tr>\n";
361
96e102b2 362 echo '</table>';
b2bdfd89
DO
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 }
0e7f2155
DO
371 return TRUE;
372}
f48dc2cc 373
96e102b2
DO
374function init_database_dynamic ()
375{
376 connect_to_db();
377 global $dbxlink;
43f06d53 378 if (!isset ($_REQUEST['password']) or empty ($_REQUEST['password']))
96e102b2
DO
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 }
43f06d53 391 return FALSE;
96e102b2
DO
392 }
393 else
394 {
93bdb7ba
DO
395 // Never send cleartext password over the wire.
396 $hash = sha1 ($_REQUEST['password']);
79b8ad1e 397 $query = "INSERT INTO `UserAccount` (`user_id`, `user_name`, `user_password_hash`, `user_realname`) " .
93bdb7ba 398 "VALUES (1,'admin','${hash}','RackTables Administrator')";
43f06d53
DO
399 $result = $dbxlink->exec ($query);
400 echo "Administrator password has been set successfully.<br>";
401 return TRUE;
96e102b2 402 }
96e102b2
DO
403}
404
0e7f2155 405function congrats ()
f48dc2cc 406{
01539ac3
DO
407 echo 'Congratulations! RackTables installation is complete. After pressing Proceed you will ';
408 echo 'enter the system. Authenticate with <strong>admin</strong> username.<br>';
409 echo "RackTables web-site runs some <a href='http://racktables.org/trac/wiki'>wiki</a> pages ";
410 echo "and <a href='http://racktables.org/trac/report/1'>a bug tracker</a>.<br>We have also got ";
411 echo "a <a href='http://www.freelists.org/list/racktables-users'>mailing list</a> for users. Have fun.<br>";
0e7f2155 412 return TRUE;
f48dc2cc
DO
413}
414
415?>