1<?php 2/* 3 +-----------------------------------------------------------------------+ 4 | This file is part of the Roundcube Webmail client | 5 | | 6 | Copyright (C) The Roundcube Dev Team | 7 | | 8 | Licensed under the GNU General Public License version 3 or | 9 | any later version with exceptions for skins & plugins. | 10 | See the README file for a full license statement. | 11 +-----------------------------------------------------------------------+ 12 | Author: Thomas Bruederli <roundcube@gmail.com> | 13 +-----------------------------------------------------------------------+ 14*/ 15 16if (!class_exists('rcmail_install', false) || !isset($RCI)) { 17 die("Not allowed! Please open installer/index.php instead."); 18} 19 20?> 21 22<h3>Check config file</h3> 23<?php 24 25if ($read_config = is_readable(RCUBE_CONFIG_DIR . 'defaults.inc.php')) { 26 $config = $RCI->load_config_file(RCUBE_CONFIG_DIR . 'defaults.inc.php'); 27 if (!empty($config)) { 28 $RCI->pass('defaults.inc.php'); 29 } 30 else { 31 $RCI->fail('defaults.inc.php', 'Syntax error'); 32 } 33} 34else { 35 $RCI->fail('defaults.inc.php', 'Unable to read default config file?'); 36} 37 38echo '<br />'; 39 40if ($read_config = is_readable(RCUBE_CONFIG_DIR . 'config.inc.php')) { 41 $config = $RCI->load_config_file(RCUBE_CONFIG_DIR . 'config.inc.php'); 42 if (!empty($config)) { 43 $RCI->pass('config.inc.php'); 44 } 45 else { 46 $RCI->fail('config.inc.php', 'Syntax error'); 47 } 48} 49else { 50 $RCI->fail('config.inc.php', 'Unable to read file. Did you create the config file?'); 51} 52 53echo '<br />'; 54 55if ($RCI->configured && ($messages = $RCI->check_config())) { 56 if (is_array($messages['replaced'])) { 57 echo '<h3 class="warning">Replaced config options</h3>'; 58 echo '<p class="hint">The following config options have been replaced or renamed. '; 59 echo 'Please update them accordingly in your config files.</p>'; 60 61 echo '<ul class="configwarnings">'; 62 foreach ($messages['replaced'] as $msg) { 63 echo html::tag('li', null, html::span('propname', $msg['prop']) . 64 ' was replaced by ' . html::span('propname', $msg['replacement'])); 65 } 66 echo '</ul>'; 67 } 68 69 if (is_array($messages['obsolete'])) { 70 echo '<h3>Obsolete config options</h3>'; 71 echo '<p class="hint">You still have some obsolete or inexistent properties set. This isn\'t a problem but should be noticed.</p>'; 72 73 echo '<ul class="configwarnings">'; 74 foreach ($messages['obsolete'] as $msg) { 75 echo html::tag('li', null, html::span('propname', $msg['prop']) 76 . (!empty($msg['explain']) ? ': ' . $msg['explain'] : '')); 77 } 78 echo '</ul>'; 79 } 80 81 echo '<p class="suggestion">OK, lazy people can download the updated config file here: '; 82 echo html::a(['href' => './?_mergeconfig=1'], 'config.inc.php') . ' '; 83 echo "</p>"; 84 85 if (is_array($messages['dependencies'])) { 86 echo '<h3 class="warning">Dependency check failed</h3>'; 87 echo '<p class="hint">Some of your configuration settings require other options to be configured or additional PHP modules to be installed</p>'; 88 89 echo '<ul class="configwarnings">'; 90 foreach ($messages['dependencies'] as $msg) { 91 echo html::tag('li', null, html::span('propname', $msg['prop']) . ': ' . $msg['explain']); 92 } 93 echo '</ul>'; 94 } 95} 96 97?> 98 99<h3>Check if directories are writable</h3> 100<p>Roundcube may need to write/save files into these directories</p> 101<?php 102 103$dirs[] = !empty($RCI->config['temp_dir']) ? $RCI->config['temp_dir'] : 'temp'; 104if ($RCI->config['log_driver'] != 'syslog') { 105 $dirs[] = $RCI->config['log_dir'] ? $RCI->config['log_dir'] : 'logs'; 106} 107 108foreach ($dirs as $dir) { 109 $dirpath = rcube_utils::is_absolute_path($dir) ? $dir : INSTALL_PATH . $dir; 110 if (is_writable(realpath($dirpath))) { 111 $RCI->pass($dir); 112 $pass = true; 113 } 114 else { 115 $RCI->fail($dir, 'not writeable for the webserver'); 116 } 117 echo '<br />'; 118} 119 120if (empty($pass)) { 121 echo '<p class="hint">Use <tt>chmod</tt> or <tt>chown</tt> to grant write privileges to the webserver</p>'; 122} 123 124?> 125 126<h3>Check DB config</h3> 127<?php 128 129$db_working = false; 130if ($RCI->configured) { 131 if (!empty($RCI->config['db_dsnw'])) { 132 $DB = rcube_db::factory($RCI->config['db_dsnw'], '', false); 133 $DB->set_debug((bool)$RCI->config['sql_debug']); 134 $DB->db_connect('w'); 135 136 if (!($db_error_msg = $DB->is_error())) { 137 $RCI->pass('DSN (write)'); 138 echo '<br />'; 139 $db_working = true; 140 } 141 else { 142 $RCI->fail('DSN (write)', $db_error_msg); 143 echo '<p class="hint">Make sure that the configured database exists and that the user has write privileges<br />'; 144 echo 'DSN: ' . rcube::Q($RCI->config['db_dsnw']) . '</p>'; 145 } 146 } 147 else { 148 $RCI->fail('DSN (write)', 'not set'); 149 } 150} 151else { 152 $RCI->fail('DSN (write)', 'Could not read config file'); 153} 154 155// initialize db with schema found in /SQL/* 156if ($db_working && !empty($_POST['initdb'])) { 157 if (!$RCI->init_db($DB)) { 158 $db_working = false; 159 echo '<p class="warning">Please try to initialize the database manually as described in the INSTALL guide. 160 Make sure that the configured database exists and that the user as write privileges</p>'; 161 } 162} 163else if ($db_working && !empty($_POST['updatedb'])) { 164 if (!$RCI->update_db($_POST['version'])) { 165 echo '<p class="warning">Database schema update failed.</p>'; 166 } 167} 168 169// test database 170if ($db_working) { 171 $db_read = $DB->query("SELECT count(*) FROM " . $DB->quote_identifier($RCI->config['db_prefix'] . 'users')); 172 if ($DB->is_error()) { 173 $RCI->fail('DB Schema', "Database not initialized"); 174 echo '<form action="index.php?_step=3" method="post">' 175 . '<p><input type="submit" name="initdb" value="Initialize database" /></p>' 176 . '</form>'; 177 178 $db_working = false; 179 } 180 else if ($err = $RCI->db_schema_check($DB, $update = !empty($_POST['updatedb']))) { 181 $RCI->fail('DB Schema', "Database schema differs"); 182 echo '<ul style="margin:0"><li>' . join("</li>\n<li>", $err) . "</li></ul>"; 183 184 $select = $RCI->versions_select(['name' => 'version']); 185 $select->add('0.9 or newer', ''); 186 187 echo '<form action="index.php?_step=3" method="post">' 188 . '<p class="suggestion">You should run the update queries to get the schema fixed.' 189 . '<br/><br/>Version to update from: ' . $select->show('') 190 . ' <input type="submit" name="updatedb" value="Update" /></p>' 191 . '</form>'; 192 193 $db_working = false; 194 } 195 else { 196 $RCI->pass('DB Schema'); 197 echo '<br />'; 198 } 199} 200 201// more database tests 202if ($db_working) { 203 // Using transactions to workaround SQLite bug (#7064) 204 if ($DB->db_provider == 'sqlite') { 205 $DB->startTransaction(); 206 } 207 208 // write test 209 $insert_id = md5(uniqid()); 210 $db_write = $DB->query("INSERT INTO " . $DB->quote_identifier($RCI->config['db_prefix'] . 'session') 211 . " (`sess_id`, `changed`, `ip`, `vars`) VALUES (?, ".$DB->now().", '127.0.0.1', 'foo')", $insert_id); 212 213 if ($db_write) { 214 $RCI->pass('DB Write'); 215 $DB->query("DELETE FROM " . $DB->quote_identifier($RCI->config['db_prefix'] . 'session') 216 . " WHERE `sess_id` = ?", $insert_id); 217 } 218 else { 219 $RCI->fail('DB Write', $RCI->get_error()); 220 } 221 echo '<br />'; 222 223 // Transaction end 224 if ($DB->db_provider == 'sqlite') { 225 $DB->rollbackTransaction(); 226 } 227 228 // check timezone settings 229 $tz_db = 'SELECT ' . $DB->unixtimestamp($DB->now()) . ' AS tz_db'; 230 $tz_db = $DB->query($tz_db); 231 $tz_db = $DB->fetch_assoc($tz_db); 232 $tz_db = (int) $tz_db['tz_db']; 233 $tz_local = (int) time(); 234 $tz_diff = $tz_local - $tz_db; 235 236 // sometimes db and web servers are on separate hosts, so allow a 30 minutes delta 237 if (abs($tz_diff) > 1800) { 238 $RCI->fail('DB Time', "Database time differs {$tz_diff}s from PHP time"); 239 } 240 else { 241 $RCI->pass('DB Time'); 242 } 243} 244 245?> 246 247<h3>Test filetype detection</h3> 248 249<?php 250 251if ($errors = $RCI->check_mime_detection()) { 252 $RCI->fail('Fileinfo/mime_content_type configuration'); 253 if (!empty($RCI->config['mime_magic'])) { 254 echo '<p class="hint">Try setting the <tt>mime_magic</tt> config option to <tt>null</tt>.</p>'; 255 } 256 else { 257 echo '<p class="hint">Check the <a href="http://www.php.net/manual/en/function.finfo-open.php">Fileinfo functions</a> of your PHP installation.<br/>'; 258 echo 'The path to the magic.mime file can be set using the <tt>mime_magic</tt> config option in Roundcube.</p>'; 259 } 260} 261else { 262 $RCI->pass('Fileinfo/mime_content_type configuration'); 263 echo "<br/>"; 264} 265 266 267if ($errors = $RCI->check_mime_extensions()) { 268 $RCI->fail('Mimetype to file extension mapping'); 269 echo '<p class="hint">Please set a valid path to your webserver\'s mime.types file to the <tt>mime_types</tt> config option.<br/>'; 270 echo 'If you can\'t find such a file, download it from <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types">svn.apache.org</a>.</p>'; 271} 272else { 273 $RCI->pass('Mimetype to file extension mapping'); 274 echo "<br/>"; 275} 276 277$smtp_hosts = $RCI->get_hostlist('smtp_server'); 278if (!empty($smtp_hosts)) { 279 $smtp_host_field = new html_select(['name' => '_smtp_host', 'id' => 'smtp_server']); 280 $smtp_host_field->add($smtp_hosts, $smtp_hosts); 281} 282else { 283 $smtp_host_field = new html_inputfield(['name' => '_smtp_host', 'id' => 'smtp_server']); 284} 285 286$user = $RCI->getprop('smtp_user', '(none)'); 287$pass = $RCI->getprop('smtp_pass', '(none)'); 288 289if ($user == '%u') { 290 $user_field = new html_inputfield(['name' => '_smtp_user', 'id' => 'smtp_user']); 291 $user = $user_field->show(isset($_POST['_smtp_user']) ? $_POST['_smtp_user'] : ''); 292} 293else { 294 $user = html::quote($user); 295} 296if ($pass == '%p') { 297 $pass_field = new html_passwordfield(['name' => '_smtp_pass', 'id' => 'smtp_pass']); 298 $pass = $pass_field->show(); 299} 300else { 301 $pass = html::quote($pass); 302} 303 304?> 305 306<form action="index.php?_step=3" method="post"> 307 308<h3>Test SMTP config</h3> 309 310<p> 311<table> 312<tbody> 313 <tr> 314 <td><label for="smtp_server">Server</label></td> 315 <td><?php echo $smtp_host_field->show(isset($_POST['_smtp_host']) ? $_POST['_smtp_host'] : ''); ?></td> 316 </tr> 317 <tr> 318 <td><label for="smtp_port">Port</label></td> 319 <td><?php echo rcube::Q($RCI->getprop('smtp_port')); ?></td> 320 </tr> 321 <tr> 322 <td><label for="smtp_user">Username</label></td> 323 <td><?php echo $user; ?></td> 324 </tr> 325 <tr> 326 <td><label for="smtp_pass">Password</label></td> 327 <td><?php echo $pass; ?></td> 328 </tr> 329</tbody> 330</table> 331</p> 332 333<?php 334 335$from_field = new html_inputfield(['name' => '_from', 'id' => 'sendmailfrom']); 336$to_field = new html_inputfield(['name' => '_to', 'id' => 'sendmailto']); 337 338if (isset($_POST['sendmail'])) { 339 340 echo '<p>Trying to send email...<br />'; 341 342 $smtp_host = trim($_POST['_smtp_host']); 343 $smtp_port = $RCI->getprop('smtp_port'); 344 345 $from = rcube_utils::idn_to_ascii(trim($_POST['_from'])); 346 $to = rcube_utils::idn_to_ascii(trim($_POST['_to'])); 347 348 if ( 349 preg_match('/^' . $RCI->email_pattern . '$/i', $from) 350 && preg_match('/^' . $RCI->email_pattern . '$/i', $to) 351 ) { 352 $headers = [ 353 'From' => $from, 354 'To' => $to, 355 'Subject' => 'Test message from Roundcube', 356 ]; 357 358 $body = 'This is a test to confirm that Roundcube can send email.'; 359 360 // send mail using configured SMTP server 361 $CONFIG = $RCI->config; 362 363 if (!empty($_POST['_smtp_user'])) { 364 $CONFIG['smtp_user'] = $_POST['_smtp_user']; 365 } 366 if (!empty($_POST['_smtp_pass'])) { 367 $CONFIG['smtp_pass'] = $_POST['_smtp_pass']; 368 } 369 370 $mail_object = new Mail_mime(); 371 $send_headers = $mail_object->headers($headers); 372 $head = $mail_object->txtHeaders($send_headers); 373 374 $SMTP = new rcube_smtp(); 375 $SMTP->connect($smtp_host, $smtp_port, $CONFIG['smtp_user'], $CONFIG['smtp_pass']); 376 377 $status = $SMTP->send_mail($headers['From'], $headers['To'], $head, $body); 378 $smtp_response = $SMTP->get_response(); 379 380 if ($status) { 381 $RCI->pass('SMTP send'); 382 } 383 else { 384 $RCI->fail('SMTP send', join('; ', $smtp_response)); 385 } 386 } 387 else { 388 $RCI->fail('SMTP send', 'Invalid sender or recipient'); 389 } 390 391 echo '</p>'; 392} 393 394?> 395 396<table> 397<tbody> 398 <tr> 399 <td><label for="sendmailfrom">Sender</label></td> 400 <td><?php echo $from_field->show(isset($_POST['_from']) ? $_POST['_from'] : ''); ?></td> 401 </tr> 402 <tr> 403 <td><label for="sendmailto">Recipient</label></td> 404 <td><?php echo $to_field->show(isset($_POST['_to']) ? $_POST['_to'] : ''); ?></td> 405 </tr> 406</tbody> 407</table> 408 409<p><input type="submit" name="sendmail" value="Send test mail" /></p> 410 411</form> 412 413<form action="index.php?_step=3" method="post"> 414 415<h3>Test IMAP config</h3> 416 417<?php 418 419$default_hosts = $RCI->get_hostlist(); 420if (!empty($default_hosts)) { 421 $host_field = new html_select(['name' => '_host', 'id' => 'imaphost']); 422 $host_field->add($default_hosts, $default_hosts); 423} 424else { 425 $host_field = new html_inputfield(['name' => '_host', 'id' => 'imaphost']); 426} 427 428$user_field = new html_inputfield(['name' => '_user', 'id' => 'imapuser']); 429$pass_field = new html_passwordfield(['name' => '_pass', 'id' => 'imappass']); 430 431?> 432 433<table> 434<tbody> 435 <tr> 436 <td><label for="imaphost">Server</label></td> 437 <td><?php echo $host_field->show(isset($_POST['_host']) ? $_POST['_host'] : ''); ?></td> 438 </tr> 439 <tr> 440 <td>Port</td> 441 <td><?php echo $RCI->getprop('default_port'); ?></td> 442 </tr> 443 <tr> 444 <td><label for="imapuser">Username</label></td> 445 <td><?php echo $user_field->show(isset($_POST['_user']) ? $_POST['_user'] : ''); ?></td> 446 </tr> 447 <tr> 448 <td><label for="imappass">Password</label></td> 449 <td><?php echo $pass_field->show(); ?></td> 450 </tr> 451</tbody> 452</table> 453 454<?php 455 456if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user'])) { 457 458 echo '<p>Connecting to ' . rcube::Q($_POST['_host']) . '...<br />'; 459 460 $imap_host = trim($_POST['_host']); 461 $imap_port = $RCI->getprop('default_port'); 462 $imap_ssl = false; 463 $a_host = parse_url($imap_host); 464 465 if ($a_host['host']) { 466 $imap_host = $a_host['host']; 467 $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], ['ssl','imaps','tls'])) ? $a_host['scheme'] : null; 468 if (isset($a_host['port'])) { 469 $imap_port = $a_host['port']; 470 } 471 else if ($imap_ssl && $imap_ssl != 'tls' && (!$imap_port || $imap_port == 143)) { 472 $imap_port = 993; 473 } 474 } 475 476 $imap_host = rcube_utils::idn_to_ascii($imap_host); 477 $imap_user = rcube_utils::idn_to_ascii($_POST['_user']); 478 479 $imap = new rcube_imap; 480 $imap->set_options([ 481 'auth_type' => $RCI->getprop('imap_auth_type'), 482 'debug' => $RCI->getprop('imap_debug'), 483 'socket_options' => $RCI->getprop('imap_conn_options'), 484 ]); 485 486 if ($imap->connect($imap_host, $imap_user, $_POST['_pass'], $imap_port, $imap_ssl)) { 487 $RCI->pass('IMAP connect', 'SORT capability: ' . ($imap->get_capability('SORT') ? 'yes' : 'no')); 488 $imap->close(); 489 } 490 else { 491 $RCI->fail('IMAP connect', $RCI->get_error()); 492 } 493} 494 495?> 496 497<p><input type="submit" name="imaptest" value="Check login" /></p> 498 499</form> 500 501<hr /> 502 503<p class="warning"> 504 505After completing the installation and the final tests please <b>remove</b> the whole 506installer folder from the document root of the webserver or make sure that 507<tt>enable_installer</tt> option in <tt>config.inc.php</tt> is disabled.<br /> 508<br /> 509 510These files may expose sensitive configuration data like server passwords and encryption keys 511to the public. Make sure you cannot access this installer from your browser. 512 513</p> 514