Handy place to show error reporting values - can use this as a tool for support requests
[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
a1912bbc 203/* register_globals check: test for boolean false and any string that is not equal to 'off' */
204
a3b99374 205if ((bool) ini_get('register_globals') &&
206 strtolower(ini_get('register_globals'))!='off') {
dda39a1a 207 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 208}
a1912bbc 209
210
211/* variables_order check */
212
213// FIXME(?): Hmm, how do we distinguish between when an ini setting is
214// not available (ini_set() returns empty string) and when
215// the administrator set the value to an empty string? The
216// latter is sure to be highly rare, so for now, just assume
217// that empty value means the setting isn't even available
218// (could also check PHP version when this setting was implemented)
47fa8e9b 219// although, we'll also warn the user if it is empty, with
220// a non-fatal error
221$variables_order = strtoupper(ini_get('variables_order'));
222if (empty($variables_order))
223 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);
224else if (strpos($variables_order, 'G') === FALSE
a1912bbc 225 || strpos($variables_order, 'P') === FALSE
226 || strpos($variables_order, 'C') === FALSE
47fa8e9b 227 || strpos($variables_order, 'S') === FALSE) {
228 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 229} else {
230 echo $IND . "variables_order OK: $variables_order.<br />\n";
231}
232
233
47fa8e9b 234/* gpc_order check (removed from PHP as of v5.0) */
235
236if (!check_php_version(5)) {
237 // FIXME(?): Hmm, how do we distinguish between when an ini setting is
238 // not available (ini_set() returns empty string) and when
239 // the administrator set the value to an empty string? The
240 // latter is sure to be highly rare, so for now, just assume
241 // that empty value means the setting isn't even available
242 // (could also check PHP version when this setting was implemented)
243 // although, we'll also warn the user if it is empty, with
244 // a non-fatal error
245 $gpc_order = strtoupper(ini_get('gpc_order'));
246 if (empty($gpc_order))
247 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);
248 else if (strpos($gpc_order, 'G') === FALSE
249 || strpos($gpc_order, 'P') === FALSE
250 || strpos($gpc_order, 'C') === FALSE) {
251 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);
252 } else {
253 echo $IND . "gpc_order OK: $gpc_order.<br />\n";
254 }
a1912bbc 255}
256
257
258/* check PHP extensions */
259
d1ae9d4c 260$php_exts = array('session','pcre');
261$diff = array_diff($php_exts, get_loaded_extensions());
262if(count($diff)) {
263 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
264}
265
17fca61d 266echo $IND . "PHP extensions OK.<br />\n";
d1ae9d4c 267
8f186a2a 268/* dangerous php settings */
269/**
270 * mbstring.func_overload allows to replace original string and regexp functions
271 * with their equivalents from php mbstring extension. It causes problems when
d0184454 272 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
9211bcef 273 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
8f186a2a 274 * and .htaccess files (php 4.3.5).
275 */
276if (function_exists('mb_internal_encoding') &&
9211bcef 277 check_php_version(4,2,0) &&
8f186a2a 278 (int)ini_get('mbstring.func_overload')!=0) {
279 $mb_error='You have enabled mbstring overloading.'
280 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
281 do_err($mb_error);
282}
d1ae9d4c 283
99c1c0d6 284/**
285 * Do not use SquirrelMail with magic_quotes_* on.
286 */
287if ( get_magic_quotes_runtime() || get_magic_quotes_gpc() ||
288 ( (bool) ini_get('magic_quotes_sybase') && ini_get('magic_quotes_sybase') != 'off' )
289 ) {
290 $magic_quotes_warning='You have enabled any one of <tt>magic_quotes_runtime</tt>, '
291 .'<tt>magic_quotes_gpc</tt> or <tt>magic_quotes_sybase</tt> in your PHP '
292 .'configuration. We recommend all those settings to be off. SquirrelMail '
293 .'may work with them on, but when experiencing stray backslashes in your mail '
294 .'or other strange behaviour, it may be advisable to turn them off.';
295 do_err($magic_quotes_warning,false);
296}
297
298
d1ae9d4c 299/* checking paths */
300
301echo "Checking paths...<br />\n";
302
303if(!file_exists($data_dir)) {
d0184454 304 // data_dir is not that important in db_setups.
305 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
306 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
307 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
308 } else {
309 do_err("Data dir ($data_dir) does not exist!");
310 }
91e0dccc 311}
d0184454 312// don't check if errors
313if(!isset($data_dir_error) && !is_dir($data_dir)) {
314 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
315 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
316 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
317 } else {
318 do_err("Data dir ($data_dir) is not a directory!");
319 }
91e0dccc 320}
d4eaadbe 321// datadir should be executable - but no clean way to test on that
d0184454 322if(!isset($data_dir_error) && !is_writable($data_dir)) {
323 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
324 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
325 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
326 } else {
327 do_err("Data dir ($data_dir) is not writable!");
328 }
d1ae9d4c 329}
330
d0184454 331if (isset($data_dir_error)) {
332 echo " Some plugins might need access to data directory.<br />\n";
333} else {
334 // todo_ornot: actually write something and read it back.
335 echo $IND . "Data dir OK.<br />\n";
336}
d1ae9d4c 337
338if($data_dir == $attachment_dir) {
339 echo $IND . "Attachment dir is the same as data dir.<br />\n";
d0184454 340 if (isset($data_dir_error)) {
341 do_err($data_dir_error);
342 }
d1ae9d4c 343} else {
344 if(!file_exists($attachment_dir)) {
345 do_err("Attachment dir ($attachment_dir) does not exist!");
91e0dccc 346 }
d1ae9d4c 347 if (!is_dir($attachment_dir)) {
348 do_err("Attachment dir ($attachment_dir) is not a directory!");
91e0dccc 349 }
d1ae9d4c 350 if (!is_writable($attachment_dir)) {
351 do_err("I cannot write to attachment dir ($attachment_dir)!");
352 }
353 echo $IND . "Attachment dir OK.<br />\n";
354}
355
356
646b17e0 357echo "Checking plugins...<br />\n";
358
d1ae9d4c 359/* check plugins and themes */
99a44bdc 360//FIXME: check requirements given in plugin _info() function, such
361// as required PHP extensions, Pear packages, other plugins, SM version, etc
362// see development docs for list of returned info from that function
f084f987 363$bad_plugins = array(
0880efc9 364 'attachment_common', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 365 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
0880efc9 366 'compose_new_window', // Integrated into SquirrelMail 1.4 core
367 'delete_move_next', // Integrated into SquirrelMail 1.5 core
eb7bd9b7 368 'disk_quota', // Obsolete: See Check Quota plugin
0880efc9 369 'email_priority', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 370 'emoticons', // Obsolete: See HTML Mail plugin
0880efc9 371 'focus_change', // Integrated into SquirrelMail 1.2 core
372 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
373 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
eb7bd9b7 374 'hancock', // Not Working: See Random Signature Taglines plugin
0880efc9 375 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
376 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
377 'motd', // Integrated into SquirrelMail 1.2 core
378 'paginator', // Integrated into SquirrelMail 1.2 core
379 'printer_friendly', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 380 'procfilter', // Obsolete: See Server Side Filter plugin
0880efc9 381 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
382 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
383 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
384 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
385 'sqclock', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 386 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
387 'tmda', // Obsolete: See TMDA Tools plugin
388 'vacation', // Obsolete: See Vacation Local plugin
0880efc9 389 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
390 'xmailer' // Integrated into SquirrelMail 1.2 core
f084f987 391 );
3a196538 392
5b53b7e0 393if (isset($plugins[0])) {
394 foreach($plugins as $plugin) {
395 if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
f084f987 396 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
5b53b7e0 397 } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
f084f987 398 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
399 } elseif (in_array($plugin, $bad_plugins)) {
400 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);
401 }
d1ae9d4c 402 }
69792446 403 // load plugin functions
404 include_once(SM_PATH . 'functions/plugin.php');
405 // turn on output buffering in order to prevent output of new lines
406 ob_start();
407 foreach ($plugins as $name) {
408 use_plugin($name);
409 }
410 // get output and remove whitespace
411 $output = trim(ob_get_contents());
412 ob_end_clean();
413 // if plugins output more than newlines and spacing, stop script execution.
414 if (!empty($output)) {
c13b8d16 415 $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 416 do_err($plugin_load_error);
417 }
56f9bb83 418 /**
419 * Print plugin versions
420 */
56f9bb83 421 echo $IND . "Plugin versions...<br />\n";
422 foreach ($plugins as $name) {
d95b10b3 423 $plugin_version = get_plugin_version($name);
daa0c5b8 424 $english_name = get_plugin_requirement($name, 'english_name');
425 echo $IND . $IND . (empty($english_name) ? $name . ' ' : $english_name . ' (' . $name . ') ') . (empty($plugin_version) ? '??' : $plugin_version) . "<br />\n";
2cbaf68d 426
427 // check if this plugin has any other plugin
428 // dependencies and if they are satisfied
429 //
430 $failed_dependencies = check_plugin_dependencies($name);
f258865c 431 if ($failed_dependencies === SQ_INCOMPATIBLE) {
03a69f57 432 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
433 }
434 else if (is_array($failed_dependencies)) {
2cbaf68d 435 $missing_plugins = '';
fc6228e4 436 foreach ($failed_dependencies as $depend_name => $depend_requirements) {
437 $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
2cbaf68d 438 }
439 do_err($name . ' is missing some dependencies: ' . trim($missing_plugins, ', '), FALSE);
440 }
441
56f9bb83 442 }
69792446 443 /**
97ae6d06 444 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
6e515418 445 * message and return TRUE if there are any errors in its setup/configuration.
69792446 446 */
62fb877b 447 $plugin_err = boolean_hook_function('configtest', $null, 1);
69792446 448 if($plugin_err) {
449 do_err('Some plugin tests failed.');
450 } else {
451 echo $IND . "Plugins OK.<br />\n";
452 }
5b53b7e0 453} else {
454 echo $IND . "Plugins are not enabled in config.<br />\n";
d1ae9d4c 455}
d1ae9d4c 456foreach($theme as $thm) {
457 if(!file_exists($thm['PATH'])) {
458 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
459 } elseif(!is_readable($thm['PATH'])) {
460 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
461 }
462}
463
464echo $IND . "Themes OK.<br />\n";
465
07337c9b 466if ( $squirrelmail_default_language != 'en_US' ) {
467 $loc_path = SM_PATH .'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
468 if( ! file_exists( $loc_path ) ) {
f8a1ed5a 469 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 470 '</i> as your default language, but I cannot find this translation (should be '.
471 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
472 'separately from the main SquirrelMail package.', FALSE);
07337c9b 473 } elseif ( ! is_readable( $loc_path ) ) {
f8a1ed5a 474 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 475 '</i> as your default language, but I cannot read this translation (file '.
476 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
07337c9b 477 } else {
478 echo $IND . "Default language OK.<br />\n";
479 }
480} else {
481 echo $IND . "Default language OK.<br />\n";
482}
483
74530cf4 484echo $IND . "Base URL detected as: <tt>" . htmlspecialchars($test_location) .
485 "</tt> (location base " . (empty($config_location_base) ? 'autodetected' : 'set to <tt>' .
486 htmlspecialchars($config_location_base)."</tt>") . ")<br />\n";
23649466 487
a15f9d93 488/* check minimal requirements for other security options */
d1ae9d4c 489
a15f9d93 490/* imaps or ssmtp */
491if($use_smtp_tls == 1 || $use_imap_tls == 1) {
d1ae9d4c 492 if(!check_php_version(4,3,0)) {
493 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
494 }
495 if(!extension_loaded('openssl')) {
496 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
497 }
498}
a15f9d93 499/* starttls extensions */
1c4f110f 500if($use_smtp_tls === 2 || $use_imap_tls === 2) {
a15f9d93 501 if (! function_exists('stream_socket_enable_crypto')) {
502 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
503 }
504}
505/* digest-md5 */
506if ($smtp_auth_mech=='digest-md5' || $imap_auth_mech =='digest-md5') {
507 if (!extension_loaded('xml')) {
508 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
509 }
510}
511
512/* check outgoing mail */
d1ae9d4c 513
514echo "Checking outgoing mail service....<br />\n";
515
516if($useSendmail) {
517 // is_executable also checks for existance, but we want to be as precise as possible with the errors
518 if(!file_exists($sendmail_path)) {
519 do_err("Location of sendmail program incorrect ($sendmail_path)!");
91e0dccc 520 }
d1ae9d4c 521 if(!is_executable($sendmail_path)) {
522 do_err("I cannot execute the sendmail program ($sendmail_path)!");
523 }
524
525 echo $IND . "sendmail OK<br />\n";
526} else {
a15f9d93 527 $stream = fsockopen( ($use_smtp_tls==1?'tls://':'').$smtpServerAddress, $smtpPort,
f084f987 528 $errorNumber, $errorString);
d1ae9d4c 529 if(!$stream) {
530 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
f084f987 531 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
d1ae9d4c 532 }
533
534 // check for SMTP code; should be 2xx to allow us access
535 $smtpline = fgets($stream, 1024);
536 if(((int) $smtpline{0}) > 3) {
9c941728 537 do_err("Error connecting to SMTP server. Server error: ".
f084f987 538 htmlspecialchars($smtpline));
d1ae9d4c 539 }
540
a15f9d93 541 /* smtp starttls checks */
1c4f110f 542 if ($use_smtp_tls===2) {
a15f9d93 543 // if something breaks, script should close smtp connection on exit.
544
545 // say helo
546 fwrite($stream,"EHLO $client_ip\r\n");
547
548 $ehlo=array();
549 $ehlo_error = false;
550 while ($line=fgets($stream, 1024)){
551 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
f084f987 552 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
a15f9d93 553 if (!isset($match[3])) {
554 // simple one word extension
555 $ehlo[strtoupper($match[2])]='';
556 } else {
557 // ehlo-keyword + ehlo-param
558 $ehlo[strtoupper($match[2])]=trim($match[3]);
559 }
560 if ($match[1]==' ') {
561 $ret = $line;
562 break;
563 }
564 } else {
565 //
566 $ehlo_error = true;
567 $ehlo[]=$line;
568 break;
569 }
570 }
571 if ($ehlo_error) {
572 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
573 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
574 do_err('STARTTLS support is not declared by SMTP server.');
575 }
576
577 fwrite($stream,"STARTTLS\r\n");
578 $starttls_response=fgets($stream, 1024);
579 if ($starttls_response[0]!=2) {
580 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
581 .htmlspecialchars($starttls_response);
582 do_err($starttls_cmd_err);
583 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
584 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
585 } else {
586 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
587 }
588 // According to RFC we should second ehlo call here.
589 }
590
d1ae9d4c 591 fputs($stream, 'QUIT');
592 fclose($stream);
9c941728 593 echo $IND . 'SMTP server OK (<tt><small>'.
f084f987 594 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
d1ae9d4c 595
596 /* POP before SMTP */
597 if($pop_before_smtp) {
598 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
599 if (!$stream) {
9c941728 600 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
f084f987 601 . $err_no . ' : ' . htmlspecialchars($err_str));
d1ae9d4c 602 }
603
604 $tmp = fgets($stream, 1024);
605 if (substr($tmp, 0, 3) != '+OK') {
606 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
f084f987 607 . ' '.htmlspecialchars($tmp));
d1ae9d4c 608 }
609 fputs($stream, 'QUIT');
610 fclose($stream);
611 echo $IND . "POP-before-SMTP OK.<br />\n";
612 }
613}
614
df758744 615/**
616 * Check the IMAP server
617 */
d1ae9d4c 618echo "Checking IMAP service....<br />\n";
619
df758744 620/** Can we open a connection? */
a15f9d93 621$stream = fsockopen( ($use_imap_tls==1?'tls://':'').$imapServerAddress, $imapPort,
f084f987 622 $errorNumber, $errorString);
d1ae9d4c 623if(!$stream) {
70b71161 624 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
f084f987 625 "Server error: ($errorNumber) ".
626 htmlspecialchars($errorString));
d1ae9d4c 627}
628
df758744 629/** Is the first response 'OK'? */
d1ae9d4c 630$imapline = fgets($stream, 1024);
631if(substr($imapline, 0,4) != '* OK') {
f084f987 632 do_err('Error connecting to IMAP server. Server error: '.
633 htmlspecialchars($imapline));
d1ae9d4c 634}
635
df758744 636echo $IND . 'IMAP server ready (<tt><small>'.
9c941728 637 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
d1ae9d4c 638
df758744 639/** Check capabilities */
640fputs($stream, "A001 CAPABILITY\r\n");
a15f9d93 641$capline = '';
642while ($line=fgets($stream, 1024)){
f084f987 643 if (preg_match("/A001.*/",$line)) {
644 break;
645 } else {
646 $capline.=$line;
647 }
a15f9d93 648}
649
650/* don't display capabilities before STARTTLS */
1c4f110f 651if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
a15f9d93 652 do_err('Your server doesn\'t support STARTTLS.');
1c4f110f 653} elseif($use_imap_tls===2) {
a15f9d93 654 /* try starting starttls */
655 fwrite($stream,"A002 STARTTLS\r\n");
656 $starttls_line=fgets($stream, 1024);
657 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
658 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
f084f987 659 .htmlspecialchars($starttls_line);
a15f9d93 660 do_err($imap_starttls_err);
661 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
662 do_err('Failed to enable encryption on IMAP connection.');
663 } else {
664 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
665 }
666
667 // get new capability line
668 fwrite($stream,"A003 CAPABILITY\r\n");
669 $capline='';
670 while ($line=fgets($stream, 1024)){
671 if (preg_match("/A003.*/",$line)) {
672 break;
673 } else {
674 $capline.=$line;
675 }
676 }
677}
df758744 678
679echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
680
681if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
682 do_err('Your server doesn\'t allow plaintext logins. '.
f084f987 683 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
684 'in the SquirrelMail configuration.', FALSE);
df758744 685}
df758744 686
ceb7ad3c 687if (stristr($capline, 'XMAGICTRASH') !== false) {
688 $magic_trash = 'It looks like IMAP_MOVE_EXPUNGE_TO_TRASH option is turned on '
689 .'in your Courier IMAP configuration. Courier does not provide tools that '
690 .'allow to detect folder used for Trash or commands are not documented. '
691 .'SquirrelMail can\'t detect special trash folder. SquirrelMail manages '
692 .'all message deletion or move operations internally and '
693 .'IMAP_MOVE_EXPUNGE_TO_TRASH option can cause errors in message and '
694 .'folder management operations. Please turn off IMAP_MOVE_EXPUNGE_TO_TRASH '
695 .'option in Courier imapd configuration.';
696 do_err($magic_trash,false);
697}
698
0fa9bde7 699/* add warning about IMAP delivery */
700if (stristr($capline, 'XCOURIEROUTBOX') !== false) {
701 $courier_outbox = 'OUTBOX setting is enabled in your Courier imapd '
702 .'configuration. SquirrelMail uses standard SMTP protocol or sendmail '
703 .'binary to send emails. Courier IMAP delivery method is not supported'
704 .' and can create duplicate email messages.';
705 do_err($courier_outbox,false);
706}
707
df758744 708/** OK, close connection */
a15f9d93 709fputs($stream, "A004 LOGOUT\r\n");
df758744 710fclose($stream);
711
17fca61d 712echo "Checking internationalization (i18n) settings...<br />\n";
0ed3bdc3 713echo "$IND gettext - ";
714if (function_exists('gettext')) {
8f186a2a 715 echo 'Gettext functions are available.'
716 .' On some systems you must have appropriate system locales compiled.'
717 ."<br />\n";
fd72907b 718
719 /* optional setlocale() tests. Should work only on glibc systems. */
720 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET)) {
867fed37 721 include_once(SM_PATH . 'include/languages.php');
fd72907b 722 echo $IND . $IND . 'Testing translations:<br>';
723 foreach ($languages as $lang_code => $lang_data) {
724 /* don't test aliases */
725 if (isset($lang_data['NAME'])) {
726 /* locale can be $lang_code or $lang_data['LOCALE'] */
727 if (isset($lang_data['LOCALE'])) {
728 $setlocale = $lang_data['LOCALE'];
729 } else {
730 $setlocale = $lang_code;
731 }
732 /* prepare information about tested locales */
733 if (is_array($setlocale)) {
734 $display_locale = implode(', ',$setlocale);
735 $locale_count = count($setlocale);
736 } else {
737 $display_locale = $setlocale;
738 $locale_count = 1;
739 }
740 $tested_locales_msg = 'Tested '.htmlspecialchars($display_locale).' '
741 .($locale_count>1 ? 'locales':'locale'). '.';
742
743 echo $IND . $IND .$IND . $lang_data['NAME'].' (' .$lang_code. ') - ';
744 $retlocale = sq_setlocale(LC_ALL,$setlocale);
745 if (is_bool($retlocale)) {
746 echo '<font color="red">unsupported</font>. ';
747 echo $tested_locales_msg;
748 } else {
749 echo 'supported. '
750 .$tested_locales_msg
751 .' setlocale() returned "'.htmlspecialchars($retlocale).'"';
752 }
753 echo "<br />\n";
754 }
755 }
756 echo $IND . $IND . '<a href="configtest.php">Don\'t test translations</a>';
757 } else {
758 echo $IND . $IND . '<a href="configtest.php?testlocales=1">Test translations</a>. '
759 .'This test is not accurate and might work only on some systems.'
760 ."\n";
761 }
762 echo "<br />\n";
763 /* end of translation tests */
0ed3bdc3 764} else {
8f186a2a 765 echo 'Gettext functions are unavailable.'
766 .' SquirrelMail will use slower internal gettext functions.'
767 ."<br />\n";
0ed3bdc3 768}
769echo "$IND mbstring - ";
770if (function_exists('mb_detect_encoding')) {
771 echo "Mbstring functions are available.<br />\n";
772} else {
8f186a2a 773 echo 'Mbstring functions are unavailable.'
774 ." Japanese translation won't work.<br />\n";
0ed3bdc3 775}
776echo "$IND recode - ";
777if (function_exists('recode')) {
778 echo "Recode functions are available.<br />\n";
ba17b6c7 779} elseif (isset($use_php_recode) && $use_php_recode) {
0ed3bdc3 780 echo "Recode functions are unavailable.<br />\n";
781 do_err('Your configuration requires recode support, but recode support is missing.');
782} else {
783 echo "Recode functions are unavailable.<br />\n";
784}
785echo "$IND iconv - ";
786if (function_exists('iconv')) {
787 echo "Iconv functions are available.<br />\n";
ba17b6c7 788} elseif (isset($use_php_iconv) && $use_php_iconv) {
0ed3bdc3 789 echo "Iconv functions are unavailable.<br />\n";
790 do_err('Your configuration requires iconv support, but iconv support is missing.');
791} else {
792 echo "Iconv functions are unavailable.<br />\n";
793}
867fed37 794// same test as in include/init.php + date_default_timezone_set check
0ed3bdc3 795echo "$IND timezone - ";
867fed37 796if ( (!ini_get('safe_mode')) || function_exists('date_default_timezone_set') ||
f084f987 797 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
798 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
fd72907b 799 echo "Webmail users can change their time zone settings. \n";
0ed3bdc3 800} else {
fd72907b 801 echo "Webmail users can't change their time zone settings. \n";
4764a7ff 802}
fd72907b 803if (isset($_ENV['TZ'])) {
804 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
805} else {
806 echo 'Current time zone is '.date('T');
807}
808echo ".<br />\n";
d18703d3 809
4764a7ff 810// Pear DB tests
d18703d3 811echo "Checking database functions...<br />\n";
812if($addrbook_dsn || $prefs_dsn || $addrbook_global_dsn) {
134e4174 813 @include_once('DB.php');
814 if (class_exists('DB')) {
815 echo "$IND PHP Pear DB support is present.<br />\n";
816 $db_functions=array(
f084f987 817 'dbase' => 'dbase_open',
818 'fbsql' => 'fbsql_connect',
819 'interbase' => 'ibase_connect',
820 'informix' => 'ifx_connect',
821 'msql' => 'msql_connect',
822 'mssql' => 'mssql_connect',
823 'mysql' => 'mysql_connect',
824 'mysqli' => 'mysqli_connect',
825 'oci8' => 'ocilogon',
826 'odbc' => 'odbc_connect',
827 'pgsql' => 'pg_connect',
828 'sqlite' => 'sqlite_open',
829 'sybase' => 'sybase_connect'
830 );
134e4174 831
832 $dsns = array();
833 if($prefs_dsn) {
834 $dsns['preferences'] = $prefs_dsn;
835 }
836 if($addrbook_dsn) {
837 $dsns['addressbook'] = $addrbook_dsn;
838 }
839 if($addrbook_global_dsn) {
840 $dsns['global addressbook'] = $addrbook_global_dsn;
841 }
842
843 foreach($dsns as $type => $dsn) {
ba17b6c7 844 $aDsn = explode(':', $dsn);
845 $dbtype = array_shift($aDsn);
134e4174 846 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
847 echo "$IND$dbtype database support present.<br />\n";
848
849 // now, test this interface:
850
851 $dbh = DB::connect($dsn, true);
852 if (DB::isError($dbh)) {
853 do_err('Database error: '. htmlspecialchars(DB::errorMessage($dbh)) .
f084f987 854 ' in ' .$type .' DSN.');
134e4174 855 }
856 $dbh->disconnect();
857 echo "$IND$type database connect successful.<br />\n";
858
859 } else {
ba17b6c7 860 do_err($dbtype.' database support not present!');
d18703d3 861 }
134e4174 862 }
863 } else {
8f186a2a 864 $db_error='Required PHP PEAR DB support is not available.'
865 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
866 .' The include path is now:<tt>' . ini_get('include_path') . '</tt>.';
867 do_err($db_error);
134e4174 868 }
4764a7ff 869} else {
d18703d3 870 echo $IND."not using database functionality.<br />\n";
0ed3bdc3 871}
7562c55b 872
873// LDAP DB tests
874echo "Checking LDAP functions...<br />\n";
875if( empty($ldap_server) ) {
134e4174 876 echo $IND."not using LDAP functionality.<br />\n";
7562c55b 877} else {
d0184454 878 if ( !function_exists('ldap_connect') ) {
7562c55b 879 do_err('Required LDAP support is not available.');
880 } else {
134e4174 881 echo "$IND LDAP support present.<br />\n";
7562c55b 882 foreach ( $ldap_server as $param ) {
883
d0184454 884 $linkid = @ldap_connect($param['host'], (empty($param['port']) ? 389 : $param['port']) );
7562c55b 885
886 if ( $linkid ) {
f084f987 887 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
91e0dccc 888
7562c55b 889 if ( !empty($param['protocol']) &&
f084f987 890 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION, $param['protocol']) ) {
7562c55b 891 do_err('Unable to set LDAP protocol');
91e0dccc 892 }
7562c55b 893
894 if ( empty($param['binddn']) ) {
d0184454 895 $bind = @ldap_bind($linkid);
7562c55b 896 } else {
d0184454 897 $bind = @ldap_bind($param['binddn'], $param['bindpw']);
7562c55b 898 }
899
900 if ( $bind ) {
901 echo "$IND LDAP Bind Successful <br />";
902 } else {
903 do_err('Unable to Bind to LDAP Server');
904 }
91e0dccc 905
d0184454 906 @ldap_close($linkid);
7562c55b 907 } else {
908 do_err('Connection to LDAP failed');
909 }
910 }
911 }
912}
a2b193bc 913
3a196538 914echo '<hr width="75%" align="center">';
915echo '<h2 align="center">Summary</h2>';
916$footer = '<hr width="75%" align="center">';
917if ($warnings) {
f084f987 918 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>';
919 echo $footer;
3a196538 920} else {
f084f987 921 print <<< EOF
d1ae9d4c 922<p>Congratulations, your SquirrelMail setup looks fine to me!</p>
923
13721b47 924<p><a href="login.php">Login now</a></p>
d1ae9d4c 925
926</body>
3a196538 927</html>
928EOF;
f084f987 929 echo $footer;
3a196538 930}