4 * SquirrelMail configtest script
6 * @copyright 2003-2010 The SquirrelMail Project Team
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 * @package squirrelmail
13 /************************************************************
14 * NOTE: you do not need to change this script! *
15 * If it throws errors you need to adjust your config. *
16 ************************************************************/
18 /** This is the configtest page */
19 define('PAGE_NAME', 'configtest');
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.
24 // force verbose error reporting and turn on display of errors, but not before
25 // getting their original values
26 $php_display_errors_original_value = ini_get('display_errors');
27 $php_error_reporting_original_value = ini_get('error_reporting');
28 error_reporting(E_ALL
);
29 ini_set('display_errors',1);
31 /** Blockcopy from init.php. Cleans globals. */
32 if ((bool) ini_get('register_globals') &&
33 strtolower(ini_get('register_globals'))!='off') {
35 * Remove all globals that are not reserved by PHP
36 * 'value' and 'key' are used by foreach. Don't unset them inside foreach.
38 foreach ($GLOBALS as $key => $value) {
40 case 'HTTP_POST_VARS':
44 case 'HTTP_COOKIE_VARS':
46 case 'HTTP_SERVER_VARS':
50 case 'HTTP_POST_FILES':
53 case 'HTTP_SESSION_VARS':
60 unset($GLOBALS[$key]);
63 // Unset variables used in foreach
64 unset($GLOBALS['key']);
65 unset($GLOBALS['value']);
70 * Displays error messages and warnings
71 * @param string $str message
72 * @param boolean $fatal fatal error or only warning
74 function do_err($str, $fatal = TRUE) {
75 global $IND, $warnings;
76 $level = $fatal ?
'FATAL ERROR:' : 'WARNING:';
77 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
79 echo '</body></html>';
88 define('SM_PATH', '../');
89 /** load minimal function set */
90 require(SM_PATH
. 'include/constants.php');
91 require(SM_PATH
. 'functions/global.php');
92 require(SM_PATH
. 'functions/strings.php');
93 require(SM_PATH
. 'functions/files.php');
94 $SQM_INTERNAL_VERSION = explode('.', SM_VERSION
, 3);
95 $SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
97 /** set default value in order to block remote access */
98 $allow_remote_configtest=false;
100 /** Load all configuration files before output begins */
102 /* load default configuration */
103 require(SM_PATH
. 'config/config_default.php');
104 /* reset arrays in default configuration */
105 $ldap_server = array();
109 $theme[0]['PATH'] = SM_PATH
. 'themes/default_theme.php';
110 $theme[0]['NAME'] = 'Default';
111 $aTemplateSet = array();
112 $aTemplateSet[0]['ID'] = 'default';
113 $aTemplateSet[0]['NAME'] = 'Default';
114 /* load site configuration */
115 if (file_exists(SM_PATH
. 'config/config.php')) {
116 require(SM_PATH
. 'config/config.php');
118 /* load local configuration overrides */
119 if (file_exists(SM_PATH
. 'config/config_local.php')) {
120 require(SM_PATH
. 'config/config_local.php');
124 * Include Compatibility plugin if available.
126 if (!$disable_plugins && file_exists(SM_PATH
. 'plugins/compatibility/functions.php'))
127 include_once(SM_PATH
. 'plugins/compatibility/functions.php');
130 global $disable_plugins;
131 $squirrelmail_plugin_hooks = array();
132 if (!$disable_plugins && file_exists(SM_PATH
. 'config/plugin_hooks.php')) {
133 require(SM_PATH
. 'config/plugin_hooks.php');
136 /** Warning counter */
140 $IND = str_repeat(' ',4);
143 * get_location starts session and must be run before output is started.
145 $test_location = get_location();
147 ?
><!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
148 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
151 <meta name
="robots" content
="noindex,nofollow">
152 <title
>SquirrelMail configtest
</title
>
155 <h1
>SquirrelMail configtest
</h1
>
157 <p
>This script will
try to check some aspects of your SquirrelMail configuration
158 and point you to errors whereever it can find them
. You need to go run
<tt
>conf
.pl
</tt
>
159 in the
<tt
>config
/</tt
> directory first before you run this script
.</p
>
163 $included = array_map('basename', get_included_files() );
164 if(!in_array('config.php', $included)) {
165 if(!file_exists(SM_PATH
. 'config/config.php')) {
166 do_err('Config file '.SM_PATH
. 'config/config.php does not exist!<br />'.
167 'You need to run <tt>conf.pl</tt> first.');
169 do_err('Could not read '.SM_PATH
.'config/config.php! Check file permissions.');
171 if(!in_array('strings.php', $included)) {
172 do_err('Could not include '.SM_PATH
.'functions/strings.php!<br />'.
173 'Check permissions on that file.');
176 /* Block remote use of script */
177 if (! $allow_remote_configtest) {
178 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER
);
179 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER
);
181 if ((! isset($client_ip) ||
$client_ip!='127.0.0.1') &&
182 (! isset($client_ip) ||
! isset($server_ip) ||
$client_ip!=$server_ip)) {
183 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
187 echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . SM_VERSION
. "</b></td></tr>\n" .
188 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
189 '<tr><td>Config file last modified:</td><td><b>' .
190 date ('d F Y H:i:s', filemtime(SM_PATH
. 'config/config.php')) .
191 "</b></td></tr>\n</table>\n</p>\n\n";
193 /* check $config_version */
194 if ($config_version!='1.5.0') {
195 do_err('Configuration file version does not match required version. Please update your configuration file.');
199 /* checking PHP specs */
201 echo "Checking PHP configuration...<br />\n";
203 if(!check_php_version(4,1,0)) {
204 do_err('Insufficient PHP version: '. PHP_VERSION
. '! Minimum required: 4.1.0');
207 echo $IND . 'PHP version ' . PHP_VERSION
. ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
209 echo $IND . 'display_errors: ' . $php_display_errors_original_value . " (overridden with 1 for this page only)<br />\n";
211 echo $IND . 'error_reporting: ' . $php_error_reporting_original_value . " (overridden with 2047 for this page only)<br />\n";
213 $safe_mode = ini_get('safe_mode');
215 //FIXME: should show that safe_mode is off when it is (this only shows the safe_mode setting when it's on) (also might be generally helpful to show things like open_basedir, too or even add phpinfo() output or a link to another script that has phpinfo()
216 echo $IND . 'safe_mode: ' . $safe_mode;
217 if (empty($prefs_dsn) ||
empty($addrbook_dsn))
218 echo ' (<font color="red">double check data and attachment directory ownership, etc!</font>)';
219 if (!empty($addrbook_dsn) ||
!empty($prefs_dsn) ||
!empty($addrbook_global_dsn))
220 echo ' (<font color="red">does PHP have access to database interface?</font>)';
222 $safe_mode_exec_dir = ini_get('safe_mode_exec_dir');
223 echo $IND . 'safe_mode_exec_dir: ' . $safe_mode_exec_dir . "<br />\n";
226 /* register_globals check: test for boolean false and any string that is not equal to 'off' */
228 if ((bool) ini_get('register_globals') &&
229 strtolower(ini_get('register_globals'))!='off') {
230 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);
234 /* variables_order check */
236 // 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
237 $variables_order = strtoupper(ini_get('variables_order'));
238 if (empty($variables_order))
239 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);
240 else if (strpos($variables_order, 'G') === FALSE
241 ||
strpos($variables_order, 'P') === FALSE
242 ||
strpos($variables_order, 'C') === FALSE
243 ||
strpos($variables_order, 'S') === FALSE) {
244 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);
246 echo $IND . "variables_order OK: $variables_order.<br />\n";
250 /* gpc_order check (removed from PHP as of v5.0) */
252 if (!check_php_version(5)) {
253 // 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
254 $gpc_order = strtoupper(ini_get('gpc_order'));
255 if (empty($gpc_order))
256 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);
257 else if (strpos($gpc_order, 'G') === FALSE
258 ||
strpos($gpc_order, 'P') === FALSE
259 ||
strpos($gpc_order, 'C') === FALSE) {
260 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);
262 echo $IND . "gpc_order OK: $gpc_order.<br />\n";
267 /* check PHP extensions */
269 $php_exts = array('session','pcre');
270 $diff = array_diff($php_exts, get_loaded_extensions());
272 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
275 echo $IND . "PHP extensions OK. Dynamic loading is ";
277 if (!(bool)ini_get('enable_dl') ||
(bool)ini_get('safe_mode')) {
278 echo "disabled.<br />\n";
280 echo "enabled.<br />\n";
284 /* dangerous php settings */
286 * mbstring.func_overload allows to replace original string and regexp functions
287 * with their equivalents from php mbstring extension. It causes problems when
288 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
289 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
290 * and .htaccess files (php 4.3.5).
292 if (function_exists('mb_internal_encoding') &&
293 check_php_version(4,2,0) &&
294 (int)ini_get('mbstring.func_overload')!=0) {
295 $mb_error='You have enabled mbstring overloading.'
296 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
301 * Do not use SquirrelMail with magic_quotes_* on.
303 if ( (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime
()) ||
304 (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc
()) ||
305 ( (bool) ini_get('magic_quotes_sybase') && ini_get('magic_quotes_sybase') != 'off' )
307 $magic_quotes_warning='You have enabled any one of <tt>magic_quotes_runtime</tt>, '
308 .'<tt>magic_quotes_gpc</tt> or <tt>magic_quotes_sybase</tt> in your PHP '
309 .'configuration. We recommend all those settings to be off. SquirrelMail '
310 .'may work with them on, but when experiencing stray backslashes in your mail '
311 .'or other strange behaviour, it may be advisable to turn them off.';
312 do_err($magic_quotes_warning,false);
315 if (ini_get('short_open_tag') == 0) {
316 $short_open_tag_warning = 'You have configured PHP not to allow short tags '
317 . '(<tt>short_open_tag=off</tt>). This shouldn\'t be a problem with '
318 . 'SquirrelMail or any plugin coded coded according to the '
319 . 'SquirrelMail Coding Guidelines, but if you experience problems with '
320 . 'PHP code being displayed in some of the pages and changing setting '
321 . 'to "on" solves the problem, please file a bug report against the '
322 . 'failing plugin. The correct contact information is most likely '
323 . 'to be found in the plugin documentation.';
324 do_err($short_open_tag_warning, false);
328 /* check who the web server is running as if possible */
330 if ($process_info = get_process_owner_info()) {
331 echo $IND . 'Web server is running as user: ' . $process_info['name'] . ' (' . $process_info['uid'] . ")<br />\n";
332 //echo $IND . 'Web server is running as effective user: ' . $process_info['ename'] . ' (' . $process_info['euid'] . ")<br />\n";
333 echo $IND . 'Web server is running as group: ' . $process_info['group'] . ' (' . $process_info['gid'] . ")<br />\n";
334 //echo $IND . 'Web server is running as effective group: ' . $process_info['egroup'] . ' (' . $process_info['egid'] . ")<br />\n";
340 echo "Checking paths...<br />\n";
342 if(!file_exists($data_dir)) {
343 // data_dir is not that important in db_setups.
344 if (!empty($prefs_dsn)) {
345 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
346 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
348 do_err("Data dir ($data_dir) does not exist!");
351 // don't check if errors
352 if(!isset($data_dir_error) && !is_dir($data_dir)) {
353 if (!empty($prefs_dsn)) {
354 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
355 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
357 do_err("Data dir ($data_dir) is not a directory!");
360 // datadir should be executable - but no clean way to test on that
361 if(!isset($data_dir_error) && !sq_is_writable($data_dir)) {
362 if (!empty($prefs_dsn)) {
363 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
364 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
366 do_err("Data dir ($data_dir) is not writable!");
370 if (isset($data_dir_error)) {
371 echo " Some plugins might need access to data directory.<br />\n";
373 // todo_ornot: actually write something and read it back.
374 echo $IND . "Data dir OK.<br />\n";
377 if($data_dir == $attachment_dir) {
378 echo $IND . "Attachment dir is the same as data dir.<br />\n";
379 if (isset($data_dir_error)) {
380 do_err($data_dir_error);
383 if(!file_exists($attachment_dir)) {
384 do_err("Attachment dir ($attachment_dir) does not exist!");
386 if (!is_dir($attachment_dir)) {
387 do_err("Attachment dir ($attachment_dir) is not a directory!");
389 if (!sq_is_writable($attachment_dir)) {
390 do_err("I cannot write to attachment dir ($attachment_dir)!");
392 echo $IND . "Attachment dir OK.<br />\n";
396 echo "Checking plugins...<br />\n";
398 /* check plugins and themes */
399 //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
400 //FIXME: update this list with most recent contents of the Obsolete category - I think it has changed recently
401 $bad_plugins = array(
402 'attachment_common', // Integrated into SquirrelMail 1.2 core
403 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
404 'compose_new_window', // Integrated into SquirrelMail 1.4 core
405 'delete_move_next', // Integrated into SquirrelMail 1.5 core
406 'disk_quota', // Obsolete: See Check Quota plugin
407 'email_priority', // Integrated into SquirrelMail 1.2 core
408 'emoticons', // Obsolete: See HTML Mail plugin
409 'focus_change', // Integrated into SquirrelMail 1.2 core
410 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
411 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
412 'hancock', // Not Working: See Random Signature Taglines plugin
413 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
414 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
415 'motd', // Integrated into SquirrelMail 1.2 core
416 'paginator', // Integrated into SquirrelMail 1.2 core
417 'printer_friendly', // Integrated into SquirrelMail 1.2 core
418 'procfilter', // Obsolete: See Server Side Filter plugin
419 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
420 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
421 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
422 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
423 'sqclock', // Integrated into SquirrelMail 1.2 core
424 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
425 'tmda', // Obsolete: See TMDA Tools plugin
426 'vacation', // Obsolete: See Vacation Local plugin
427 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
428 'xmailer' // Integrated into SquirrelMail 1.2 core
431 if (isset($plugins[0])) {
432 foreach($plugins as $plugin) {
433 if(!file_exists(SM_PATH
.'plugins/'.$plugin)) {
434 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
435 } elseif (!is_readable(SM_PATH
.'plugins/'.$plugin.'/setup.php')) {
436 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot locate or read its setup.php file.', FALSE);
437 } elseif (in_array($plugin, $bad_plugins)) {
438 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);
443 // load plugin functions
444 include_once(SM_PATH
. 'functions/plugin.php');
446 // turn on output buffering in order to prevent output of new lines
448 foreach ($plugins as $name) {
451 // get output and remove whitespace
452 $output = trim(ob_get_contents());
454 // if plugin outputs more than newlines and spacing, stop script execution.
455 if (!empty($output)) {
456 $plugin_load_error = 'Some output was produced when plugin <i>' . $name . '</i> was loaded. Usually this means there is an error in the plugin\'s setup or configuration file. The output was: '.htmlspecialchars($output);
457 do_err($plugin_load_error);
464 * Check the contents of the static plugin hooks array file against
465 * the plugin setup file, which may have changed in an upgrade, etc.
466 * This helps remind admins to re-run the configuration utility when
467 * a plugin has been changed or upgraded.
469 $static_squirrelmail_plugin_hooks = $squirrelmail_plugin_hooks;
470 $squirrelmail_plugin_hooks = array();
471 foreach ($plugins as $name) {
472 $function = "squirrelmail_plugin_init_$name";
473 if (function_exists($function)) {
476 // now iterate through each hook and make sure the
477 // plugin is registered on the correct ones in the
478 // static plugin configuration file
480 foreach ($squirrelmail_plugin_hooks as $hook_name => $hooked_plugins)
481 foreach ($hooked_plugins as $hooked_plugin => $hooked_function)
482 if ($hooked_plugin == $name
483 && (empty($static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin])
484 ||
$static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin] != $hooked_function))
485 do_err('The plugin <i>' . $name . '</i> is supposed to be registered on the <i>' . $hook_name . '</i> hook, but it is not. You need to re-run the configuration utility and re-save your configuration file.', FALSE);
488 $squirrelmail_plugin_hooks = $static_squirrelmail_plugin_hooks;
492 * Print plugin versions
494 echo $IND . "Plugin versions...<br />\n";
495 foreach ($plugins as $name) {
496 $plugin_version = get_plugin_version($name);
497 $english_name = get_plugin_requirement($name, 'english_name');
498 echo $IND . $IND . (empty($english_name) ?
$name . ' ' : $english_name . ' (' . $name . ') ') . (empty($plugin_version) ?
'??' : $plugin_version) . "<br />\n";
500 // check if this plugin has any other plugin
501 // dependencies and if they are satisfied
503 $failed_dependencies = check_plugin_dependencies($name);
504 if ($failed_dependencies === SQ_INCOMPATIBLE
) {
505 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
507 else if (is_array($failed_dependencies)) {
508 $missing_plugins = '';
509 $incompatible_plugins = '';
510 foreach ($failed_dependencies as $depend_name => $depend_requirements) {
511 if ($depend_requirements['version'] == SQ_INCOMPATIBLE
)
512 $incompatible_plugins .= ', ' . $depend_name;
514 $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ?
'must be activated' : 'need not be activated') . ')';
516 $error_string = (!empty($incompatible_plugins) ?
$name . ' cannot be activated at the same time as the following plugins: ' . trim($incompatible_plugins, ', ') : '')
517 . (!empty($missing_plugins) ?
(!empty($incompatible_plugins) ?
'. ' . $name . ' is also ' : $name . ' is ') . 'missing some dependencies: ' . trim($missing_plugins, ', ') : '');
518 do_err($error_string, FALSE);
525 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
526 * message and return TRUE if there are any errors in its setup/configuration.
528 $plugin_err = boolean_hook_function('configtest', $null, 1);
530 do_err('Some plugin tests failed.');
532 echo $IND . "Plugins OK.<br />\n";
535 echo $IND . "Plugins are not enabled in config.<br />\n";
537 foreach($theme as $thm) {
538 if(!file_exists($thm['PATH'])) {
539 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
540 } elseif(!is_readable($thm['PATH'])) {
541 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
545 echo $IND . "Themes OK.<br />\n";
547 if ( $squirrelmail_default_language != 'en_US' ) {
548 $loc_path = SM_PATH
.'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
549 if( ! file_exists( $loc_path ) ) {
550 do_err('You have set <i>' . $squirrelmail_default_language .
551 '</i> as your default language, but I cannot find this translation (should be '.
552 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
553 'separately from the main SquirrelMail package.', FALSE);
554 } elseif ( ! is_readable( $loc_path ) ) {
555 do_err('You have set <i>' . $squirrelmail_default_language .
556 '</i> as your default language, but I cannot read this translation (file '.
557 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
559 echo $IND . "Default language OK.<br />\n";
562 echo $IND . "Default language OK.<br />\n";
565 echo $IND . "Base URL detected as: <tt>" . htmlspecialchars($test_location) .
566 "</tt> (location base " . (empty($config_location_base) ?
'autodetected' : 'set to <tt>' .
567 htmlspecialchars($config_location_base)."</tt>") . ")<br />\n";
569 /* check minimal requirements for other security options */
572 if($use_smtp_tls == 1 ||
$use_imap_tls == 1) {
573 if(!check_php_version(4,3,0)) {
574 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
576 if(!extension_loaded('openssl')) {
577 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
580 /* starttls extensions */
581 if($use_smtp_tls === 2 ||
$use_imap_tls === 2) {
582 if (! function_exists('stream_socket_enable_crypto')) {
583 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
587 if ($smtp_auth_mech=='digest-md5' ||
$imap_auth_mech =='digest-md5') {
588 if (!extension_loaded('xml')) {
589 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
593 /* check outgoing mail */
595 echo "Checking outgoing mail service....<br />\n";
598 // is_executable also checks for existance, but we want to be as precise as possible with the errors
599 if(!file_exists($sendmail_path)) {
600 do_err("Location of sendmail program incorrect ($sendmail_path)!");
602 if(!is_executable($sendmail_path)) {
603 do_err("I cannot execute the sendmail program ($sendmail_path)!");
606 echo $IND . "sendmail OK<br />\n";
608 $stream = fsockopen( ($use_smtp_tls==1?
'tls://':'').$smtpServerAddress, $smtpPort,
609 $errorNumber, $errorString);
611 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
612 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
615 // check for SMTP code; should be 2xx to allow us access
616 $smtpline = fgets($stream, 1024);
617 if(((int) $smtpline{0}) > 3) {
618 do_err("Error connecting to SMTP server. Server error: ".
619 htmlspecialchars($smtpline));
622 /* smtp starttls checks */
623 if ($use_smtp_tls===2) {
624 // if something breaks, script should close smtp connection on exit.
627 // format EHLO argument correctly if needed
629 if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $client_ip))
630 $helohost = '[' . $client_ip . ']';
631 else // some day might add IPv6 here
632 $helohost = $client_ip;
636 fwrite($stream,"EHLO $helohost\r\n");
640 while ($line=fgets($stream, 1024)){
641 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
642 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
643 if (!isset($match[3])) {
644 // simple one word extension
645 $ehlo[strtoupper($match[2])]='';
647 // ehlo-keyword + ehlo-param
648 $ehlo[strtoupper($match[2])]=trim($match[3]);
650 if ($match[1]==' ') {
662 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
663 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
664 do_err('STARTTLS support is not declared by SMTP server.');
667 fwrite($stream,"STARTTLS\r\n");
668 $starttls_response=fgets($stream, 1024);
669 if ($starttls_response[0]!=2) {
670 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
671 .htmlspecialchars($starttls_response);
672 do_err($starttls_cmd_err);
673 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
674 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
676 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
678 // According to RFC we should second ehlo call here.
681 fputs($stream, 'QUIT');
683 echo $IND . 'SMTP server OK (<tt><small>'.
684 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
686 /* POP before SMTP */
687 if($pop_before_smtp) {
688 if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
689 $stream = fsockopen($pop_before_smtp_host, 110, $err_no, $err_str);
691 do_err("Error connecting to POP Server ($pop_before_smtp_host:110) "
692 . $err_no . ' : ' . htmlspecialchars($err_str));
695 $tmp = fgets($stream, 1024);
696 if (substr($tmp, 0, 3) != '+OK') {
697 do_err("Error connecting to POP Server ($pop_before_smtp_host:110)"
698 . ' '.htmlspecialchars($tmp));
700 fputs($stream, 'QUIT');
702 echo $IND . "POP-before-SMTP OK.<br />\n";
707 * Check the IMAP server
709 echo "Checking IMAP service....<br />\n";
711 /** Can we open a connection? */
712 $stream = fsockopen( ($use_imap_tls==1?
'tls://':'').$imapServerAddress, $imapPort,
713 $errorNumber, $errorString);
715 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
716 "Server error: ($errorNumber) ".
717 htmlspecialchars($errorString));
720 /** Is the first response 'OK'? */
721 $imapline = fgets($stream, 1024);
722 if(substr($imapline, 0,4) != '* OK') {
723 do_err('Error connecting to IMAP server. Server error: '.
724 htmlspecialchars($imapline));
727 echo $IND . 'IMAP server ready (<tt><small>'.
728 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
730 /** Check capabilities */
731 fputs($stream, "A001 CAPABILITY\r\n");
733 while ($line=fgets($stream, 1024)){
734 if (preg_match("/A001.*/",$line)) {
741 /* don't display capabilities before STARTTLS */
742 if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
743 do_err('Your server doesn\'t support STARTTLS.');
744 } elseif($use_imap_tls===2) {
745 /* try starting starttls */
746 fwrite($stream,"A002 STARTTLS\r\n");
747 $starttls_line=fgets($stream, 1024);
748 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
749 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
750 .htmlspecialchars($starttls_line);
751 do_err($imap_starttls_err);
752 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
753 do_err('Failed to enable encryption on IMAP connection.');
755 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
758 // get new capability line
759 fwrite($stream,"A003 CAPABILITY\r\n");
761 while ($line=fgets($stream, 1024)){
762 if (preg_match("/A003.*/",$line)) {
770 echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
772 if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
773 do_err('Your server doesn\'t allow plaintext logins. '.
774 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
775 'in the SquirrelMail configuration.', FALSE);
778 if (stristr($capline, 'XMAGICTRASH') !== false) {
779 $magic_trash = 'It looks like IMAP_MOVE_EXPUNGE_TO_TRASH option is turned on '
780 .'in your Courier IMAP configuration. Courier does not provide tools that '
781 .'allow to detect folder used for Trash or commands are not documented. '
782 .'SquirrelMail can\'t detect special trash folder. SquirrelMail manages '
783 .'all message deletion or move operations internally and '
784 .'IMAP_MOVE_EXPUNGE_TO_TRASH option can cause errors in message and '
785 .'folder management operations. Please turn off IMAP_MOVE_EXPUNGE_TO_TRASH '
786 .'option in Courier imapd configuration.';
787 do_err($magic_trash,false);
790 /* add warning about IMAP delivery */
791 if (stristr($capline, 'XCOURIEROUTBOX') !== false) {
792 $courier_outbox = 'OUTBOX setting is enabled in your Courier imapd '
793 .'configuration. SquirrelMail uses standard SMTP protocol or sendmail '
794 .'binary to send emails. Courier IMAP delivery method is not supported'
795 .' and can create duplicate email messages.';
796 do_err($courier_outbox,false);
799 /** OK, close connection */
800 fputs($stream, "A004 LOGOUT\r\n");
803 echo "Checking internationalization (i18n) settings...<br />\n";
804 echo "$IND gettext - ";
805 if (function_exists('gettext')) {
806 echo 'Gettext functions are available.'
807 .' On some systems you must have appropriate system locales compiled.'
810 /* optional setlocale() tests. Should work only on glibc systems. */
811 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET
)) {
812 include_once(SM_PATH
. 'include/languages.php');
813 echo $IND . $IND . 'Testing translations:<br>';
814 foreach ($languages as $lang_code => $lang_data) {
815 /* don't test aliases */
816 if (isset($lang_data['NAME'])) {
817 /* locale can be $lang_code or $lang_data['LOCALE'] */
818 if (isset($lang_data['LOCALE'])) {
819 $setlocale = $lang_data['LOCALE'];
821 $setlocale = $lang_code;
823 /* prepare information about tested locales */
824 if (is_array($setlocale)) {
825 $display_locale = implode(', ',$setlocale);
826 $locale_count = count($setlocale);
828 $display_locale = $setlocale;
831 $tested_locales_msg = 'Tested '.htmlspecialchars($display_locale).' '
832 .($locale_count>1 ?
'locales':'locale'). '.';
834 echo $IND . $IND .$IND . $lang_data['NAME'].' (' .$lang_code. ') - ';
835 $retlocale = sq_setlocale(LC_ALL
,$setlocale);
836 if (is_bool($retlocale)) {
837 echo '<font color="red">unsupported</font>. ';
838 echo $tested_locales_msg;
842 .' setlocale() returned "'.htmlspecialchars($retlocale).'"';
847 echo $IND . $IND . '<a href="configtest.php">Don\'t test translations</a>';
849 echo $IND . $IND . '<a href="configtest.php?testlocales=1">Test translations</a>. '
850 .'This test is not accurate and might work only on some systems.'
854 /* end of translation tests */
856 echo 'Gettext functions are unavailable.'
857 .' SquirrelMail will use slower internal gettext functions.'
860 echo "$IND mbstring - ";
861 if (function_exists('mb_detect_encoding')) {
862 echo "Mbstring functions are available.<br />\n";
864 echo 'Mbstring functions are unavailable.'
865 ." Japanese translation won't work.<br />\n";
867 echo "$IND recode - ";
868 if (function_exists('recode')) {
869 echo "Recode functions are available.<br />\n";
870 } elseif (isset($use_php_recode) && $use_php_recode) {
871 echo "Recode functions are unavailable.<br />\n";
872 do_err('Your configuration requires recode support, but recode support is missing.');
874 echo "Recode functions are unavailable.<br />\n";
876 echo "$IND iconv - ";
877 if (function_exists('iconv')) {
878 echo "Iconv functions are available.<br />\n";
879 } elseif (isset($use_php_iconv) && $use_php_iconv) {
880 echo "Iconv functions are unavailable.<br />\n";
881 do_err('Your configuration requires iconv support, but iconv support is missing.');
883 echo "Iconv functions are unavailable.<br />\n";
885 // same test as in include/init.php + date_default_timezone_set check
886 echo "$IND timezone - ";
887 if ( (!ini_get('safe_mode')) ||
function_exists('date_default_timezone_set') ||
888 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
889 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
890 echo "Webmail users can change their time zone settings. \n";
892 echo "Webmail users can't change their time zone settings. \n";
894 if (isset($_ENV['TZ'])) {
895 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
897 echo 'Current time zone is '.date('T');
902 echo "Checking database functions...<br />\n";
903 if($addrbook_dsn ||
$prefs_dsn ||
$addrbook_global_dsn) {
904 @include_once
('DB.php');
905 if (class_exists('DB')) {
906 echo "$IND PHP Pear DB support is present.<br />\n";
908 'dbase' => 'dbase_open',
909 'fbsql' => 'fbsql_connect',
910 'interbase' => 'ibase_connect',
911 'informix' => 'ifx_connect',
912 'msql' => 'msql_connect',
913 'mssql' => 'mssql_connect',
914 'mysql' => 'mysql_connect',
915 'mysqli' => 'mysqli_connect',
916 'oci8' => 'ocilogon',
917 'odbc' => 'odbc_connect',
918 'pgsql' => 'pg_connect',
919 'sqlite' => 'sqlite_open',
920 'sybase' => 'sybase_connect'
925 $dsns['preferences'] = $prefs_dsn;
928 $dsns['addressbook'] = $addrbook_dsn;
930 if($addrbook_global_dsn) {
931 $dsns['global addressbook'] = $addrbook_global_dsn;
934 foreach($dsns as $type => $dsn) {
935 $aDsn = explode(':', $dsn);
936 $dbtype = array_shift($aDsn);
938 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
939 echo "$IND$dbtype database support present.<br />\n";
940 } elseif(!(bool)ini_get('enable_dl') ||
(bool)ini_get('safe_mode')) {
941 do_err($dbtype.' database support not present!');
944 do_err($dbtype.' database support not present or not configured!
945 Trying to dynamically load '.$dbtype.' extension.
946 Please note that it is advisable to not rely on dynamic loading of extensions.', FALSE);
950 // now, test this interface:
952 $dbh = DB
::connect($dsn, true);
953 if (DB
::isError($dbh)) {
954 do_err('Database error: '. htmlspecialchars(DB
::errorMessage($dbh)) .
955 ' in ' .$type .' DSN.');
958 echo "$IND$type database connect successful.<br />\n";
961 $db_error='Required PHP PEAR DB support is not available.'
962 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
963 .' The include path is now: "<tt>' . ini_get('include_path') . '</tt>".';
967 echo $IND."not using database functionality.<br />\n";
971 echo "Checking LDAP functions...<br />\n";
972 if( empty($ldap_server) ) {
973 echo $IND."not using LDAP functionality.<br />\n";
975 if ( !function_exists('ldap_connect') ) {
976 do_err('Required LDAP support is not available.');
978 echo "$IND LDAP support present.<br />\n";
979 foreach ( $ldap_server as $param ) {
981 $linkid = @ldap_connect
($param['host'], (empty($param['port']) ?
389 : $param['port']) );
984 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
986 if ( !empty($param['protocol']) &&
987 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION
, $param['protocol']) ) {
988 do_err('Unable to set LDAP protocol');
991 if ( empty($param['binddn']) ) {
992 $bind = @ldap_bind
($linkid);
994 $bind = @ldap_bind
($linkid, $param['binddn'], $param['bindpw']);
998 echo "$IND LDAP Bind Successful <br />";
1000 do_err('Unable to Bind to LDAP Server');
1003 @ldap_close
($linkid);
1005 do_err('Connection to LDAP failed');
1011 echo '<hr width="75%" align="center">';
1012 echo '<h2 align="center">Summary</h2>';
1013 $footer = '<hr width="75%" align="center">';
1015 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>';
1019 <p
>Congratulations
, your SquirrelMail setup looks fine to me
!</p
>
1021 <p
><a href
="login.php">Login now
</a
></p
>