Turning the FIXMEs into one-liners.
[squirrelmail.git] / src / configtest.php
CommitLineData
d1ae9d4c 1<?php
134e4174 2
30967a1e 3/**
d1ae9d4c 4 * SquirrelMail configtest script
5 *
4b5049de 6 * @copyright &copy; 2003-2007 The SquirrelMail Project Team
4b4abf93 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
30967a1e 8 * @version $Id$
9 * @package squirrelmail
10 * @subpackage config
d1ae9d4c 11 */
12
13/************************************************************
14 * NOTE: you do not need to change this script! *
15 * If it throws errors you need to adjust your config. *
16 ************************************************************/
17
ebd2391c 18/** This is the configtest page */
19define('PAGE_NAME', 'configtest');
20
df758744 21// This script could really use some restructuring as it has grown quite rapidly
22// but is not very 'clean'. Feel free to get some structure into this thing.
23
dda39a1a 24/** force verbose error reporting and turn on display of errors */
25error_reporting(E_ALL);
26ini_set('display_errors',1);
27
28/** Blockcopy from init.php. Cleans globals. */
29if ((bool) ini_get('register_globals') &&
30 strtolower(ini_get('register_globals'))!='off') {
31 /**
32 * Remove all globals that are not reserved by PHP
33 * 'value' and 'key' are used by foreach. Don't unset them inside foreach.
34 */
35 foreach ($GLOBALS as $key => $value) {
36 switch($key) {
37 case 'HTTP_POST_VARS':
38 case '_POST':
39 case 'HTTP_GET_VARS':
40 case '_GET':
41 case 'HTTP_COOKIE_VARS':
42 case '_COOKIE':
43 case 'HTTP_SERVER_VARS':
44 case '_SERVER':
45 case 'HTTP_ENV_VARS':
46 case '_ENV':
47 case 'HTTP_POST_FILES':
48 case '_FILES':
49 case '_REQUEST':
50 case 'HTTP_SESSION_VARS':
51 case '_SESSION':
52 case 'GLOBALS':
53 case 'key':
54 case 'value':
55 break;
56 default:
57 unset($GLOBALS[$key]);
58 }
59 }
60 // Unset variables used in foreach
61 unset($GLOBALS['key']);
62 unset($GLOBALS['value']);
63}
64
65
66/**
67 * Displays error messages and warnings
68 * @param string $str message
69 * @param boolean $fatal fatal error or only warning
70 */
3a196538 71function do_err($str, $fatal = TRUE) {
f084f987 72 global $IND, $warnings;
73 $level = $fatal ? 'FATAL ERROR:' : 'WARNING:';
3a196538 74 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
75 if($fatal) {
f084f987 76 echo '</body></html>';
77 exit;
3a196538 78 } else {
f084f987 79 $warnings++;
80 }
5b53b7e0 81}
82
5b53b7e0 83ob_implicit_flush();
30967a1e 84/** @ignore */
5b53b7e0 85define('SM_PATH', '../');
dda39a1a 86/** load minimal function set */
b37e457f 87require(SM_PATH . 'include/constants.php');
dda39a1a 88require(SM_PATH . 'functions/global.php');
89require(SM_PATH . 'functions/strings.php');
a895042a 90$SQM_INTERNAL_VERSION = explode('.', SM_VERSION, 3);
b37e457f 91$SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
5b53b7e0 92
dda39a1a 93/** set default value in order to block remote access */
d0184454 94$allow_remote_configtest=false;
95
dda39a1a 96/** Load all configuration files before output begins */
97
98/* load default configuration */
99require(SM_PATH . 'config/config_default.php');
100/* reset arrays in default configuration */
101$ldap_server = array();
102$plugins = array();
103$fontsets = array();
104$theme = array();
105$theme[0]['PATH'] = SM_PATH . 'themes/default_theme.php';
106$theme[0]['NAME'] = 'Default';
107$aTemplateSet = array();
108$aTemplateSet[0]['ID'] = 'default';
109$aTemplateSet[0]['NAME'] = 'Default';
110/* load site configuration */
5b53b7e0 111if (file_exists(SM_PATH . 'config/config.php')) {
dda39a1a 112 require(SM_PATH . 'config/config.php');
5b53b7e0 113}
dda39a1a 114/* load local configuration overrides */
115if (file_exists(SM_PATH . 'config/config_local.php')) {
116 require(SM_PATH . 'config/config_local.php');
117}
118
8459a9bb 119/** Load plugins */
120global $disable_plugins;
121$squirrelmail_plugin_hooks = array();
122if (!$disable_plugins && file_exists(SM_PATH . 'config/plugin_hooks.php')) {
123 require(SM_PATH . 'config/plugin_hooks.php');
124}
125
dda39a1a 126/** Warning counter */
127$warnings = 0;
128
129/** indent */
130$IND = str_repeat('&nbsp;',4);
c772f125 131
69792446 132/**
133 * get_location starts session and must be run before output is started.
134 */
135$test_location = get_location();
136
151562a7 137?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
138 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
d1ae9d4c 139<html>
140<head>
f084f987 141 <meta name="robots" content="noindex,nofollow">
142 <title>SquirrelMail configtest</title>
d1ae9d4c 143</head>
144<body>
145<h1>SquirrelMail configtest</h1>
146
147<p>This script will try to check some aspects of your SquirrelMail configuration
148and point you to errors whereever it can find them. You need to go run <tt>conf.pl</tt>
d18703d3 149in the <tt>config/</tt> directory first before you run this script.</p>
d1ae9d4c 150
151<?php
152
d1ae9d4c 153$included = array_map('basename', get_included_files() );
154if(!in_array('config.php', $included)) {
155 if(!file_exists(SM_PATH . 'config/config.php')) {
156 do_err('Config file '.SM_PATH . 'config/config.php does not exist!<br />'.
f084f987 157 'You need to run <tt>conf.pl</tt> first.');
d1ae9d4c 158 }
159 do_err('Could not read '.SM_PATH.'config/config.php! Check file permissions.');
160}
161if(!in_array('strings.php', $included)) {
162 do_err('Could not include '.SM_PATH.'functions/strings.php!<br />'.
f084f987 163 'Check permissions on that file.');
d1ae9d4c 164}
165
d0184454 166/* Block remote use of script */
167if (! $allow_remote_configtest) {
168 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER);
a15f9d93 169 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER);
170
171 if ((! isset($client_ip) || $client_ip!='127.0.0.1') &&
f084f987 172 (! isset($client_ip) || ! isset($server_ip) || $client_ip!=$server_ip)) {
f8a1ed5a 173 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
d0184454 174 }
175}
d1ae9d4c 176
b37e457f 177echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . SM_VERSION . "</b></td></tr>\n" .
f084f987 178 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
179 '<tr><td>Config file last modified:</td><td><b>' .
180 date ('d F Y H:i:s', filemtime(SM_PATH . 'config/config.php')) .
181 "</b></td></tr>\n</table>\n</p>\n\n";
d1ae9d4c 182
c3da9f50 183/* check $config_version */
65efa982 184if ($config_version!='1.5.0') {
c3da9f50 185 do_err('Configuration file version does not match required version. Please update your configuration file.');
186}
a15f9d93 187
a1912bbc 188
189/* checking PHP specs */
190
d1ae9d4c 191echo "Checking PHP configuration...<br />\n";
192
abd74f7d 193if(!check_php_version(4,1,0)) {
194 do_err('Insufficient PHP version: '. PHP_VERSION . '! Minimum required: 4.1.0');
d1ae9d4c 195}
196
3a196538 197echo $IND . 'PHP version ' . PHP_VERSION . ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
a1912bbc 198
0cc820f9 199echo $IND . 'display_errors: ' . ini_get('display_errors') . "<br />\n";
200
201echo $IND . 'error_reporting: ' . ini_get('error_reporting') . "<br />\n";
202
ccbde363 203$safe_mode = ini_get('safe_mode');
204if ($safe_mode) {
205 echo $IND . 'safe_mode: ' . $safe_mode;
206 if (empty($prefs_dsn) || empty($addrbook_dsn))
207 echo ' (<font color="red">double check data and attachment directory ownership, etc!</font>)';
dc528046 208 if (!empty($addrbook_dsn) || !empty($prefs_dsn) || !empty($addrbook_global_dsn))
ccbde363 209 echo ' (<font color="red">does PHP have access to database interface?</font>)';
210 echo "<br />\n";
211 $safe_mode_exec_dir = ini_get('safe_mode_exec_dir');
212 echo $IND . 'safe_mode_exec_dir: ' . $safe_mode_exec_dir . "<br />\n";
213}
214
a1912bbc 215/* register_globals check: test for boolean false and any string that is not equal to 'off' */
216
dc528046 217if ((bool) ini_get('register_globals') &&
a3b99374 218 strtolower(ini_get('register_globals'))!='off') {
b00dce9b 219 do_err('You have register_globals turned on. This is not an error, but it CAN be a security hazard. Consider turning register_globals off.', false);
c772f125 220}
a1912bbc 221
222
223/* variables_order check */
224
b00dce9b 225// FIXME(?): Hmm, how do we distinguish between when an ini setting is not available (ini_set() returns empty string) and when the administrator set the value to an empty string? The latter is sure to be highly rare, so for now, just assume that empty value means the setting isn't even available (could also check PHP version when this setting was implemented) although, we'll also warn the user if it is empty, with a non-fatal error
47fa8e9b 226$variables_order = strtoupper(ini_get('variables_order'));
227if (empty($variables_order))
b00dce9b 228 do_err('Your variables_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
47fa8e9b 229else if (strpos($variables_order, 'G') === FALSE
a1912bbc 230 || strpos($variables_order, 'P') === FALSE
231 || strpos($variables_order, 'C') === FALSE
47fa8e9b 232 || strpos($variables_order, 'S') === FALSE) {
b00dce9b 233 do_err('Your variables_order setting is insufficient for SquirrelMail to function. It needs at least "GPCS", but you have it set to "' . htmlspecialchars($variables_order) . '"', true);
a1912bbc 234} else {
235 echo $IND . "variables_order OK: $variables_order.<br />\n";
236}
237
238
47fa8e9b 239/* gpc_order check (removed from PHP as of v5.0) */
240
241if (!check_php_version(5)) {
b00dce9b 242 // FIXME(?): Hmm, how do we distinguish between when an ini setting is not available (ini_set() returns empty string) and when the administrator set the value to an empty string? The latter is sure to be highly rare, so for now, just assume that empty value means the setting isn't even available (could also check PHP version when this setting was implemented) although, we'll also warn the user if it is empty, with a non-fatal error
47fa8e9b 243 $gpc_order = strtoupper(ini_get('gpc_order'));
244 if (empty($gpc_order))
b00dce9b 245 do_err('Your gpc_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
47fa8e9b 246 else if (strpos($gpc_order, 'G') === FALSE
247 || strpos($gpc_order, 'P') === FALSE
248 || strpos($gpc_order, 'C') === FALSE) {
b00dce9b 249 do_err('Your gpc_order setting is insufficient for SquirrelMail to function. It needs to be set to "GPC", but you have it set to "' . htmlspecialchars($gpc_order) . '"', true);
47fa8e9b 250 } else {
251 echo $IND . "gpc_order OK: $gpc_order.<br />\n";
252 }
a1912bbc 253}
254
255
256/* check PHP extensions */
257
d1ae9d4c 258$php_exts = array('session','pcre');
259$diff = array_diff($php_exts, get_loaded_extensions());
260if(count($diff)) {
261 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
262}
263
d053c206 264echo $IND . "PHP extensions OK. Dynamic loading is ";
265
266if (!(bool)ini_get('enable_dl') || (bool)ini_get('safe_mode')) {
267 echo "disabled.<br />\n";
268} else {
269 echo "enabled.<br />\n";
270}
271
d1ae9d4c 272
8f186a2a 273/* dangerous php settings */
274/**
275 * mbstring.func_overload allows to replace original string and regexp functions
276 * with their equivalents from php mbstring extension. It causes problems when
d0184454 277 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
9211bcef 278 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
8f186a2a 279 * and .htaccess files (php 4.3.5).
280 */
281if (function_exists('mb_internal_encoding') &&
9211bcef 282 check_php_version(4,2,0) &&
8f186a2a 283 (int)ini_get('mbstring.func_overload')!=0) {
284 $mb_error='You have enabled mbstring overloading.'
285 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
286 do_err($mb_error);
287}
d1ae9d4c 288
99c1c0d6 289/**
290 * Do not use SquirrelMail with magic_quotes_* on.
291 */
430a19f3 292if ( (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime()) ||
293 (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) ||
99c1c0d6 294 ( (bool) ini_get('magic_quotes_sybase') && ini_get('magic_quotes_sybase') != 'off' )
295 ) {
296 $magic_quotes_warning='You have enabled any one of <tt>magic_quotes_runtime</tt>, '
297 .'<tt>magic_quotes_gpc</tt> or <tt>magic_quotes_sybase</tt> in your PHP '
298 .'configuration. We recommend all those settings to be off. SquirrelMail '
299 .'may work with them on, but when experiencing stray backslashes in your mail '
300 .'or other strange behaviour, it may be advisable to turn them off.';
301 do_err($magic_quotes_warning,false);
302}
303
dc528046 304if (ini_get('short_open_tag') == 0) {
305 $short_open_tag_warning = 'You have configured PHP not to allow short tags '
306 . '(<tt>short_open_tag=off</tt>). This shouldn\'t be a problem with '
307 . 'SquirrelMail or any plugin coded coded according to the '
308 . 'SquirrelMail Coding Guidelines, but if you experience problems with '
309 . 'PHP code being displayed in some of the pages and changing setting '
310 . 'to "on" solves the problem, please file a bug report against the '
311 . 'failing plugin. The correct contact information is most likely '
312 . 'to be found in the plugin documentation.';
313 do_err($short_open_tag_warning, false);
314}
99c1c0d6 315
d1ae9d4c 316/* checking paths */
317
318echo "Checking paths...<br />\n";
319
320if(!file_exists($data_dir)) {
d0184454 321 // data_dir is not that important in db_setups.
ccbde363 322 if (!empty($prefs_dsn)) {
d0184454 323 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
324 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
325 } else {
326 do_err("Data dir ($data_dir) does not exist!");
327 }
91e0dccc 328}
d0184454 329// don't check if errors
330if(!isset($data_dir_error) && !is_dir($data_dir)) {
ccbde363 331 if (!empty($prefs_dsn)) {
d0184454 332 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
333 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
334 } else {
335 do_err("Data dir ($data_dir) is not a directory!");
336 }
91e0dccc 337}
d4eaadbe 338// datadir should be executable - but no clean way to test on that
d0184454 339if(!isset($data_dir_error) && !is_writable($data_dir)) {
ccbde363 340 if (!empty($prefs_dsn)) {
d0184454 341 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
342 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
343 } else {
344 do_err("Data dir ($data_dir) is not writable!");
345 }
d1ae9d4c 346}
347
d0184454 348if (isset($data_dir_error)) {
349 echo " Some plugins might need access to data directory.<br />\n";
350} else {
351 // todo_ornot: actually write something and read it back.
352 echo $IND . "Data dir OK.<br />\n";
353}
d1ae9d4c 354
355if($data_dir == $attachment_dir) {
356 echo $IND . "Attachment dir is the same as data dir.<br />\n";
d0184454 357 if (isset($data_dir_error)) {
358 do_err($data_dir_error);
359 }
d1ae9d4c 360} else {
361 if(!file_exists($attachment_dir)) {
362 do_err("Attachment dir ($attachment_dir) does not exist!");
91e0dccc 363 }
d1ae9d4c 364 if (!is_dir($attachment_dir)) {
365 do_err("Attachment dir ($attachment_dir) is not a directory!");
91e0dccc 366 }
d1ae9d4c 367 if (!is_writable($attachment_dir)) {
368 do_err("I cannot write to attachment dir ($attachment_dir)!");
369 }
370 echo $IND . "Attachment dir OK.<br />\n";
371}
372
373
646b17e0 374echo "Checking plugins...<br />\n";
375
d1ae9d4c 376/* check plugins and themes */
d17b7894 377//FIXME: check requirements given in plugin _info() function, such as required PHP extensions, Pear packages, other plugins, SM version, etc see development docs for list of returned info from that function
378//FIXME: update this list with most recent contents of the Obsolete category - I think it has changed recently
f084f987 379$bad_plugins = array(
0880efc9 380 'attachment_common', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 381 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
0880efc9 382 'compose_new_window', // Integrated into SquirrelMail 1.4 core
383 'delete_move_next', // Integrated into SquirrelMail 1.5 core
eb7bd9b7 384 'disk_quota', // Obsolete: See Check Quota plugin
0880efc9 385 'email_priority', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 386 'emoticons', // Obsolete: See HTML Mail plugin
0880efc9 387 'focus_change', // Integrated into SquirrelMail 1.2 core
388 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
389 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
eb7bd9b7 390 'hancock', // Not Working: See Random Signature Taglines plugin
0880efc9 391 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
392 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
393 'motd', // Integrated into SquirrelMail 1.2 core
394 'paginator', // Integrated into SquirrelMail 1.2 core
395 'printer_friendly', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 396 'procfilter', // Obsolete: See Server Side Filter plugin
0880efc9 397 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
398 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
399 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
400 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
401 'sqclock', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 402 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
403 'tmda', // Obsolete: See TMDA Tools plugin
404 'vacation', // Obsolete: See Vacation Local plugin
0880efc9 405 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
406 'xmailer' // Integrated into SquirrelMail 1.2 core
f084f987 407 );
3a196538 408
5b53b7e0 409if (isset($plugins[0])) {
410 foreach($plugins as $plugin) {
411 if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
f084f987 412 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
5b53b7e0 413 } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
f084f987 414 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
415 } elseif (in_array($plugin, $bad_plugins)) {
416 do_err('You have enabled the <i>'.$plugin.'</i> plugin, which causes problems with this version of SquirrelMail. Please check the ReleaseNotes or other documentation for more information.', false);
417 }
d1ae9d4c 418 }
69792446 419 // load plugin functions
420 include_once(SM_PATH . 'functions/plugin.php');
421 // turn on output buffering in order to prevent output of new lines
422 ob_start();
423 foreach ($plugins as $name) {
424 use_plugin($name);
425 }
426 // get output and remove whitespace
427 $output = trim(ob_get_contents());
428 ob_end_clean();
429 // if plugins output more than newlines and spacing, stop script execution.
430 if (!empty($output)) {
d17b7894 431//FIXME: if the output buffer is checked INSIDE the foreach loop above, we can tell the user WHICH plugin has the problem - seems like a good idea
c13b8d16 432 $plugin_load_error = 'Some output is produced when plugins are loaded. Usually this means there is an error in one of the plugin setup or configuration files. The output was: '.htmlspecialchars($output);
69792446 433 do_err($plugin_load_error);
434 }
dc528046 435 /**
56f9bb83 436 * Print plugin versions
437 */
56f9bb83 438 echo $IND . "Plugin versions...<br />\n";
439 foreach ($plugins as $name) {
d95b10b3 440 $plugin_version = get_plugin_version($name);
daa0c5b8 441 $english_name = get_plugin_requirement($name, 'english_name');
442 echo $IND . $IND . (empty($english_name) ? $name . ' ' : $english_name . ' (' . $name . ') ') . (empty($plugin_version) ? '??' : $plugin_version) . "<br />\n";
2cbaf68d 443
dc528046 444 // check if this plugin has any other plugin
2cbaf68d 445 // dependencies and if they are satisfied
446 //
447 $failed_dependencies = check_plugin_dependencies($name);
f258865c 448 if ($failed_dependencies === SQ_INCOMPATIBLE) {
03a69f57 449 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
450 }
451 else if (is_array($failed_dependencies)) {
2cbaf68d 452 $missing_plugins = '';
fc6228e4 453 foreach ($failed_dependencies as $depend_name => $depend_requirements) {
454 $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
2cbaf68d 455 }
456 do_err($name . ' is missing some dependencies: ' . trim($missing_plugins, ', '), FALSE);
457 }
458
56f9bb83 459 }
69792446 460 /**
dc528046 461 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
6e515418 462 * message and return TRUE if there are any errors in its setup/configuration.
69792446 463 */
62fb877b 464 $plugin_err = boolean_hook_function('configtest', $null, 1);
69792446 465 if($plugin_err) {
466 do_err('Some plugin tests failed.');
467 } else {
468 echo $IND . "Plugins OK.<br />\n";
469 }
5b53b7e0 470} else {
471 echo $IND . "Plugins are not enabled in config.<br />\n";
d1ae9d4c 472}
d1ae9d4c 473foreach($theme as $thm) {
474 if(!file_exists($thm['PATH'])) {
475 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
476 } elseif(!is_readable($thm['PATH'])) {
477 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
478 }
479}
480
481echo $IND . "Themes OK.<br />\n";
482
07337c9b 483if ( $squirrelmail_default_language != 'en_US' ) {
484 $loc_path = SM_PATH .'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
485 if( ! file_exists( $loc_path ) ) {
f8a1ed5a 486 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 487 '</i> as your default language, but I cannot find this translation (should be '.
488 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
489 'separately from the main SquirrelMail package.', FALSE);
07337c9b 490 } elseif ( ! is_readable( $loc_path ) ) {
f8a1ed5a 491 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 492 '</i> as your default language, but I cannot read this translation (file '.
493 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
07337c9b 494 } else {
495 echo $IND . "Default language OK.<br />\n";
496 }
497} else {
498 echo $IND . "Default language OK.<br />\n";
499}
500
74530cf4 501echo $IND . "Base URL detected as: <tt>" . htmlspecialchars($test_location) .
502 "</tt> (location base " . (empty($config_location_base) ? 'autodetected' : 'set to <tt>' .
503 htmlspecialchars($config_location_base)."</tt>") . ")<br />\n";
23649466 504
a15f9d93 505/* check minimal requirements for other security options */
d1ae9d4c 506
a15f9d93 507/* imaps or ssmtp */
508if($use_smtp_tls == 1 || $use_imap_tls == 1) {
d1ae9d4c 509 if(!check_php_version(4,3,0)) {
510 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
511 }
512 if(!extension_loaded('openssl')) {
513 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
514 }
515}
a15f9d93 516/* starttls extensions */
1c4f110f 517if($use_smtp_tls === 2 || $use_imap_tls === 2) {
a15f9d93 518 if (! function_exists('stream_socket_enable_crypto')) {
519 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
520 }
521}
522/* digest-md5 */
523if ($smtp_auth_mech=='digest-md5' || $imap_auth_mech =='digest-md5') {
524 if (!extension_loaded('xml')) {
525 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
526 }
527}
528
529/* check outgoing mail */
d1ae9d4c 530
531echo "Checking outgoing mail service....<br />\n";
532
533if($useSendmail) {
534 // is_executable also checks for existance, but we want to be as precise as possible with the errors
535 if(!file_exists($sendmail_path)) {
536 do_err("Location of sendmail program incorrect ($sendmail_path)!");
91e0dccc 537 }
d1ae9d4c 538 if(!is_executable($sendmail_path)) {
539 do_err("I cannot execute the sendmail program ($sendmail_path)!");
540 }
541
542 echo $IND . "sendmail OK<br />\n";
543} else {
a15f9d93 544 $stream = fsockopen( ($use_smtp_tls==1?'tls://':'').$smtpServerAddress, $smtpPort,
f084f987 545 $errorNumber, $errorString);
d1ae9d4c 546 if(!$stream) {
547 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
f084f987 548 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
d1ae9d4c 549 }
550
551 // check for SMTP code; should be 2xx to allow us access
552 $smtpline = fgets($stream, 1024);
553 if(((int) $smtpline{0}) > 3) {
9c941728 554 do_err("Error connecting to SMTP server. Server error: ".
f084f987 555 htmlspecialchars($smtpline));
d1ae9d4c 556 }
557
a15f9d93 558 /* smtp starttls checks */
1c4f110f 559 if ($use_smtp_tls===2) {
a15f9d93 560 // if something breaks, script should close smtp connection on exit.
561
562 // say helo
563 fwrite($stream,"EHLO $client_ip\r\n");
564
565 $ehlo=array();
566 $ehlo_error = false;
567 while ($line=fgets($stream, 1024)){
568 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
f084f987 569 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
a15f9d93 570 if (!isset($match[3])) {
571 // simple one word extension
572 $ehlo[strtoupper($match[2])]='';
573 } else {
574 // ehlo-keyword + ehlo-param
575 $ehlo[strtoupper($match[2])]=trim($match[3]);
576 }
577 if ($match[1]==' ') {
578 $ret = $line;
579 break;
580 }
581 } else {
dc528046 582 //
a15f9d93 583 $ehlo_error = true;
584 $ehlo[]=$line;
585 break;
586 }
587 }
588 if ($ehlo_error) {
589 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
590 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
591 do_err('STARTTLS support is not declared by SMTP server.');
592 }
593
594 fwrite($stream,"STARTTLS\r\n");
595 $starttls_response=fgets($stream, 1024);
596 if ($starttls_response[0]!=2) {
597 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
598 .htmlspecialchars($starttls_response);
599 do_err($starttls_cmd_err);
600 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
601 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
602 } else {
603 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
604 }
605 // According to RFC we should second ehlo call here.
606 }
607
d1ae9d4c 608 fputs($stream, 'QUIT');
609 fclose($stream);
9c941728 610 echo $IND . 'SMTP server OK (<tt><small>'.
f084f987 611 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
d1ae9d4c 612
613 /* POP before SMTP */
614 if($pop_before_smtp) {
615 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
616 if (!$stream) {
9c941728 617 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
f084f987 618 . $err_no . ' : ' . htmlspecialchars($err_str));
d1ae9d4c 619 }
620
621 $tmp = fgets($stream, 1024);
622 if (substr($tmp, 0, 3) != '+OK') {
623 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
f084f987 624 . ' '.htmlspecialchars($tmp));
d1ae9d4c 625 }
626 fputs($stream, 'QUIT');
627 fclose($stream);
628 echo $IND . "POP-before-SMTP OK.<br />\n";
629 }
630}
631
df758744 632/**
633 * Check the IMAP server
634 */
d1ae9d4c 635echo "Checking IMAP service....<br />\n";
636
df758744 637/** Can we open a connection? */
a15f9d93 638$stream = fsockopen( ($use_imap_tls==1?'tls://':'').$imapServerAddress, $imapPort,
f084f987 639 $errorNumber, $errorString);
d1ae9d4c 640if(!$stream) {
70b71161 641 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
f084f987 642 "Server error: ($errorNumber) ".
643 htmlspecialchars($errorString));
d1ae9d4c 644}
645
df758744 646/** Is the first response 'OK'? */
d1ae9d4c 647$imapline = fgets($stream, 1024);
648if(substr($imapline, 0,4) != '* OK') {
f084f987 649 do_err('Error connecting to IMAP server. Server error: '.
650 htmlspecialchars($imapline));
d1ae9d4c 651}
652
df758744 653echo $IND . 'IMAP server ready (<tt><small>'.
9c941728 654 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
d1ae9d4c 655
df758744 656/** Check capabilities */
657fputs($stream, "A001 CAPABILITY\r\n");
a15f9d93 658$capline = '';
659while ($line=fgets($stream, 1024)){
f084f987 660 if (preg_match("/A001.*/",$line)) {
661 break;
662 } else {
663 $capline.=$line;
664 }
a15f9d93 665}
666
667/* don't display capabilities before STARTTLS */
1c4f110f 668if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
a15f9d93 669 do_err('Your server doesn\'t support STARTTLS.');
1c4f110f 670} elseif($use_imap_tls===2) {
a15f9d93 671 /* try starting starttls */
672 fwrite($stream,"A002 STARTTLS\r\n");
673 $starttls_line=fgets($stream, 1024);
674 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
675 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
f084f987 676 .htmlspecialchars($starttls_line);
a15f9d93 677 do_err($imap_starttls_err);
678 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
679 do_err('Failed to enable encryption on IMAP connection.');
680 } else {
681 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
682 }
683
684 // get new capability line
685 fwrite($stream,"A003 CAPABILITY\r\n");
686 $capline='';
687 while ($line=fgets($stream, 1024)){
688 if (preg_match("/A003.*/",$line)) {
689 break;
690 } else {
691 $capline.=$line;
692 }
693 }
694}
df758744 695
696echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
697
698if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
699 do_err('Your server doesn\'t allow plaintext logins. '.
f084f987 700 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
701 'in the SquirrelMail configuration.', FALSE);
df758744 702}
df758744 703
ceb7ad3c 704if (stristr($capline, 'XMAGICTRASH') !== false) {
705 $magic_trash = 'It looks like IMAP_MOVE_EXPUNGE_TO_TRASH option is turned on '
706 .'in your Courier IMAP configuration. Courier does not provide tools that '
707 .'allow to detect folder used for Trash or commands are not documented. '
708 .'SquirrelMail can\'t detect special trash folder. SquirrelMail manages '
709 .'all message deletion or move operations internally and '
710 .'IMAP_MOVE_EXPUNGE_TO_TRASH option can cause errors in message and '
711 .'folder management operations. Please turn off IMAP_MOVE_EXPUNGE_TO_TRASH '
712 .'option in Courier imapd configuration.';
713 do_err($magic_trash,false);
714}
715
0fa9bde7 716/* add warning about IMAP delivery */
717if (stristr($capline, 'XCOURIEROUTBOX') !== false) {
718 $courier_outbox = 'OUTBOX setting is enabled in your Courier imapd '
719 .'configuration. SquirrelMail uses standard SMTP protocol or sendmail '
720 .'binary to send emails. Courier IMAP delivery method is not supported'
721 .' and can create duplicate email messages.';
722 do_err($courier_outbox,false);
723}
724
df758744 725/** OK, close connection */
a15f9d93 726fputs($stream, "A004 LOGOUT\r\n");
df758744 727fclose($stream);
728
17fca61d 729echo "Checking internationalization (i18n) settings...<br />\n";
0ed3bdc3 730echo "$IND gettext - ";
731if (function_exists('gettext')) {
8f186a2a 732 echo 'Gettext functions are available.'
733 .' On some systems you must have appropriate system locales compiled.'
734 ."<br />\n";
fd72907b 735
736 /* optional setlocale() tests. Should work only on glibc systems. */
737 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET)) {
867fed37 738 include_once(SM_PATH . 'include/languages.php');
fd72907b 739 echo $IND . $IND . 'Testing translations:<br>';
740 foreach ($languages as $lang_code => $lang_data) {
741 /* don't test aliases */
742 if (isset($lang_data['NAME'])) {
743 /* locale can be $lang_code or $lang_data['LOCALE'] */
744 if (isset($lang_data['LOCALE'])) {
745 $setlocale = $lang_data['LOCALE'];
746 } else {
747 $setlocale = $lang_code;
748 }
749 /* prepare information about tested locales */
750 if (is_array($setlocale)) {
751 $display_locale = implode(', ',$setlocale);
752 $locale_count = count($setlocale);
753 } else {
754 $display_locale = $setlocale;
755 $locale_count = 1;
756 }
757 $tested_locales_msg = 'Tested '.htmlspecialchars($display_locale).' '
758 .($locale_count>1 ? 'locales':'locale'). '.';
759
760 echo $IND . $IND .$IND . $lang_data['NAME'].' (' .$lang_code. ') - ';
761 $retlocale = sq_setlocale(LC_ALL,$setlocale);
762 if (is_bool($retlocale)) {
763 echo '<font color="red">unsupported</font>. ';
764 echo $tested_locales_msg;
765 } else {
766 echo 'supported. '
767 .$tested_locales_msg
768 .' setlocale() returned "'.htmlspecialchars($retlocale).'"';
769 }
770 echo "<br />\n";
771 }
772 }
773 echo $IND . $IND . '<a href="configtest.php">Don\'t test translations</a>';
774 } else {
775 echo $IND . $IND . '<a href="configtest.php?testlocales=1">Test translations</a>. '
776 .'This test is not accurate and might work only on some systems.'
777 ."\n";
778 }
779 echo "<br />\n";
780 /* end of translation tests */
0ed3bdc3 781} else {
8f186a2a 782 echo 'Gettext functions are unavailable.'
783 .' SquirrelMail will use slower internal gettext functions.'
784 ."<br />\n";
0ed3bdc3 785}
786echo "$IND mbstring - ";
787if (function_exists('mb_detect_encoding')) {
788 echo "Mbstring functions are available.<br />\n";
789} else {
8f186a2a 790 echo 'Mbstring functions are unavailable.'
791 ." Japanese translation won't work.<br />\n";
0ed3bdc3 792}
793echo "$IND recode - ";
794if (function_exists('recode')) {
795 echo "Recode functions are available.<br />\n";
ba17b6c7 796} elseif (isset($use_php_recode) && $use_php_recode) {
0ed3bdc3 797 echo "Recode functions are unavailable.<br />\n";
798 do_err('Your configuration requires recode support, but recode support is missing.');
799} else {
800 echo "Recode functions are unavailable.<br />\n";
801}
802echo "$IND iconv - ";
803if (function_exists('iconv')) {
804 echo "Iconv functions are available.<br />\n";
ba17b6c7 805} elseif (isset($use_php_iconv) && $use_php_iconv) {
0ed3bdc3 806 echo "Iconv functions are unavailable.<br />\n";
807 do_err('Your configuration requires iconv support, but iconv support is missing.');
808} else {
809 echo "Iconv functions are unavailable.<br />\n";
810}
867fed37 811// same test as in include/init.php + date_default_timezone_set check
0ed3bdc3 812echo "$IND timezone - ";
867fed37 813if ( (!ini_get('safe_mode')) || function_exists('date_default_timezone_set') ||
f084f987 814 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
815 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
fd72907b 816 echo "Webmail users can change their time zone settings. \n";
0ed3bdc3 817} else {
fd72907b 818 echo "Webmail users can't change their time zone settings. \n";
4764a7ff 819}
fd72907b 820if (isset($_ENV['TZ'])) {
821 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
822} else {
823 echo 'Current time zone is '.date('T');
824}
825echo ".<br />\n";
d18703d3 826
4764a7ff 827// Pear DB tests
d18703d3 828echo "Checking database functions...<br />\n";
829if($addrbook_dsn || $prefs_dsn || $addrbook_global_dsn) {
134e4174 830 @include_once('DB.php');
831 if (class_exists('DB')) {
832 echo "$IND PHP Pear DB support is present.<br />\n";
833 $db_functions=array(
f084f987 834 'dbase' => 'dbase_open',
835 'fbsql' => 'fbsql_connect',
836 'interbase' => 'ibase_connect',
837 'informix' => 'ifx_connect',
838 'msql' => 'msql_connect',
839 'mssql' => 'mssql_connect',
840 'mysql' => 'mysql_connect',
841 'mysqli' => 'mysqli_connect',
842 'oci8' => 'ocilogon',
843 'odbc' => 'odbc_connect',
844 'pgsql' => 'pg_connect',
845 'sqlite' => 'sqlite_open',
846 'sybase' => 'sybase_connect'
847 );
134e4174 848
849 $dsns = array();
850 if($prefs_dsn) {
851 $dsns['preferences'] = $prefs_dsn;
852 }
853 if($addrbook_dsn) {
854 $dsns['addressbook'] = $addrbook_dsn;
855 }
856 if($addrbook_global_dsn) {
857 $dsns['global addressbook'] = $addrbook_global_dsn;
858 }
859
860 foreach($dsns as $type => $dsn) {
ba17b6c7 861 $aDsn = explode(':', $dsn);
862 $dbtype = array_shift($aDsn);
d053c206 863
134e4174 864 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
865 echo "$IND$dbtype database support present.<br />\n";
d053c206 866 } elseif(!(bool)ini_get('enable_dl') || (bool)ini_get('safe_mode')) {
867 do_err($dbtype.' database support not present!');
868 } else {
869 // Non-fatal error
870 do_err($dbtype.' database support not present or not configured!
871 Trying to dynamically load '.$dbtype.' extension.
872 Please note that it is advisable to not rely on dynamic loading of extensions.', FALSE);
873 }
134e4174 874
134e4174 875
d053c206 876 // now, test this interface:
134e4174 877
d053c206 878 $dbh = DB::connect($dsn, true);
879 if (DB::isError($dbh)) {
880 do_err('Database error: '. htmlspecialchars(DB::errorMessage($dbh)) .
881 ' in ' .$type .' DSN.');
d18703d3 882 }
d053c206 883 $dbh->disconnect();
884 echo "$IND$type database connect successful.<br />\n";
134e4174 885 }
886 } else {
8f186a2a 887 $db_error='Required PHP PEAR DB support is not available.'
888 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
dc528046 889 .' The include path is now: "<tt>' . ini_get('include_path') . '</tt>".';
8f186a2a 890 do_err($db_error);
134e4174 891 }
4764a7ff 892} else {
d18703d3 893 echo $IND."not using database functionality.<br />\n";
0ed3bdc3 894}
7562c55b 895
896// LDAP DB tests
897echo "Checking LDAP functions...<br />\n";
898if( empty($ldap_server) ) {
134e4174 899 echo $IND."not using LDAP functionality.<br />\n";
7562c55b 900} else {
d0184454 901 if ( !function_exists('ldap_connect') ) {
7562c55b 902 do_err('Required LDAP support is not available.');
903 } else {
134e4174 904 echo "$IND LDAP support present.<br />\n";
7562c55b 905 foreach ( $ldap_server as $param ) {
906
d0184454 907 $linkid = @ldap_connect($param['host'], (empty($param['port']) ? 389 : $param['port']) );
7562c55b 908
909 if ( $linkid ) {
f084f987 910 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
91e0dccc 911
7562c55b 912 if ( !empty($param['protocol']) &&
f084f987 913 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION, $param['protocol']) ) {
7562c55b 914 do_err('Unable to set LDAP protocol');
91e0dccc 915 }
7562c55b 916
917 if ( empty($param['binddn']) ) {
d0184454 918 $bind = @ldap_bind($linkid);
7562c55b 919 } else {
d0184454 920 $bind = @ldap_bind($param['binddn'], $param['bindpw']);
7562c55b 921 }
922
923 if ( $bind ) {
924 echo "$IND LDAP Bind Successful <br />";
925 } else {
926 do_err('Unable to Bind to LDAP Server');
927 }
91e0dccc 928
d0184454 929 @ldap_close($linkid);
7562c55b 930 } else {
931 do_err('Connection to LDAP failed');
932 }
933 }
934 }
935}
a2b193bc 936
3a196538 937echo '<hr width="75%" align="center">';
938echo '<h2 align="center">Summary</h2>';
939$footer = '<hr width="75%" align="center">';
940if ($warnings) {
b00dce9b 941 echo '<p>No fatal errors were found, but there was at least 1 warning. Please check the flagged issue(s) carefully, as correcting them may prevent erratic, undefined, or incorrect behavior (or flat out breakage).</p>';
f084f987 942 echo $footer;
3a196538 943} else {
f084f987 944 print <<< EOF
d1ae9d4c 945<p>Congratulations, your SquirrelMail setup looks fine to me!</p>
946
13721b47 947<p><a href="login.php">Login now</a></p>
d1ae9d4c 948
949</body>
3a196538 950</html>
951EOF;
f084f987 952 echo $footer;
3a196538 953}