4 * SquirrelMail configtest script
6 * @copyright © 2003-2006 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 script could really use some restructuring as it has grown quite rapidly
19 // but is not very 'clean'. Feel free to get some structure into this thing.
22 function do_err($str, $fatal = TRUE) {
23 global $IND, $warnings;
24 $level = $fatal ?
'FATAL ERROR:' : 'WARNING:';
25 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
27 echo '</body></html>';
34 $IND = str_repeat(' ',4);
38 define('SM_PATH', '../');
40 /* set default value in order to block remote access to script */
41 $allow_remote_configtest=false;
44 * Load config before output begins. functions/strings.php depends on
45 * functions/globals.php. functions/global.php needs to be run before
46 * any html output starts. If config.php is missing, error will be displayed
49 if (file_exists(SM_PATH
. 'config/config.php')) {
50 include(SM_PATH
. 'config/config.php');
51 include(SM_PATH
. 'functions/strings.php');
53 ?
><!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
54 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
57 <meta name
="robots" content
="noindex,nofollow">
58 <title
>SquirrelMail configtest
</title
>
61 <h1
>SquirrelMail configtest
</h1
>
63 <p
>This script will
try to check some aspects of your SquirrelMail configuration
64 and point you to errors whereever it can find them
. You need to go run
<tt
>conf
.pl
</tt
>
65 in the
<tt
>config
/</tt
> directory first before you run this script
.</p
>
69 $included = array_map('basename', get_included_files() );
70 if(!in_array('config.php', $included)) {
71 if(!file_exists(SM_PATH
. 'config/config.php')) {
72 do_err('Config file '.SM_PATH
. 'config/config.php does not exist!<br />'.
73 'You need to run <tt>conf.pl</tt> first.');
75 do_err('Could not read '.SM_PATH
.'config/config.php! Check file permissions.');
77 if(!in_array('strings.php', $included)) {
78 do_err('Could not include '.SM_PATH
.'functions/strings.php!<br />'.
79 'Check permissions on that file.');
82 /* Block remote use of script */
83 if (! $allow_remote_configtest) {
84 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER
);
85 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER
);
87 if ((! isset($client_ip) ||
$client_ip!='127.0.0.1') &&
88 (! isset($client_ip) ||
! isset($server_ip) ||
$client_ip!=$server_ip)) {
89 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
92 /* checking PHP specs */
94 echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . $version . "</b></td></tr>\n" .
95 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
96 '<tr><td>Config file last modified:</td><td><b>' .
97 date ('d F Y H:i:s', filemtime(SM_PATH
. 'config/config.php')) .
98 "</b></td></tr>\n</table>\n</p>\n\n";
100 /* check $config_version */
101 if ($config_version!='1.4.0') {
102 do_err('Configuration file version does not match required version. Please update your configuration file.');
105 echo "Checking PHP configuration...<br />\n";
107 if(!check_php_version(4,1,0)) {
108 do_err('Insufficient PHP version: '. PHP_VERSION
. '! Minimum required: 4.1.0');
111 echo $IND . 'PHP version ' . PHP_VERSION
. ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
113 $php_exts = array('session','pcre');
114 $diff = array_diff($php_exts, get_loaded_extensions());
116 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
119 echo $IND . "PHP extensions OK.<br />\n";
121 /* dangerous php settings */
123 * mbstring.func_overload allows to replace original string and regexp functions
124 * with their equivalents from php mbstring extension. It causes problems when
125 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
126 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
127 * and .htaccess files (php 4.3.5).
129 if (function_exists('mb_internal_encoding') &&
130 check_php_version(4,2,0) &&
131 (int)ini_get('mbstring.func_overload')!=0) {
132 $mb_error='You have enabled mbstring overloading.'
133 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
139 echo "Checking paths...<br />\n";
141 if(!file_exists($data_dir)) {
142 // data_dir is not that important in db_setups.
143 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
144 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
145 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
147 do_err("Data dir ($data_dir) does not exist!");
150 // don't check if errors
151 if(!isset($data_dir_error) && !is_dir($data_dir)) {
152 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
153 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
154 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
156 do_err("Data dir ($data_dir) is not a directory!");
159 // datadir should be executable - but no clean way to test on that
160 if(!isset($data_dir_error) && !is_writable($data_dir)) {
161 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
162 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
163 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
165 do_err("Data dir ($data_dir) is not writable!");
169 if (isset($data_dir_error)) {
170 echo " Some plugins might need access to data directory.<br />\n";
172 // todo_ornot: actually write something and read it back.
173 echo $IND . "Data dir OK.<br />\n";
176 if($data_dir == $attachment_dir) {
177 echo $IND . "Attachment dir is the same as data dir.<br />\n";
178 if (isset($data_dir_error)) {
179 do_err($data_dir_error);
182 if(!file_exists($attachment_dir)) {
183 do_err("Attachment dir ($attachment_dir) does not exist!");
185 if (!is_dir($attachment_dir)) {
186 do_err("Attachment dir ($attachment_dir) is not a directory!");
188 if (!is_writable($attachment_dir)) {
189 do_err("I cannot write to attachment dir ($attachment_dir)!");
191 echo $IND . "Attachment dir OK.<br />\n";
195 /* check plugins and themes */
196 $bad_plugins = array(
197 'attachment_common', // Integrated into SquirrelMail 1.2 core
198 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
199 'compose_new_window', // Integrated into SquirrelMail 1.4 core
200 'delete_move_next', // Integrated into SquirrelMail 1.5 core
201 'disk_quota', // Obsolete: See Check Quota plugin
202 'email_priority', // Integrated into SquirrelMail 1.2 core
203 'emoticons', // Obsolete: See HTML Mail plugin
204 'focus_change', // Integrated into SquirrelMail 1.2 core
205 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
206 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
207 'hancock', // Not Working: See Random Signature Taglines plugin
208 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
209 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
210 'motd', // Integrated into SquirrelMail 1.2 core
211 'paginator', // Integrated into SquirrelMail 1.2 core
212 'printer_friendly', // Integrated into SquirrelMail 1.2 core
213 'procfilter', // Obsolete: See Server Side Filter plugin
214 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
215 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
216 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
217 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
218 'sqclock', // Integrated into SquirrelMail 1.2 core
219 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
220 'tmda', // Obsolete: See TMDA Tools plugin
221 'vacation', // Obsolete: See Vacation Local plugin
222 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
223 'xmailer' // Integrated into SquirrelMail 1.2 core
226 if (isset($plugins[0])) {
227 foreach($plugins as $plugin) {
228 if(!file_exists(SM_PATH
.'plugins/'.$plugin)) {
229 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
230 } elseif (!is_readable(SM_PATH
.'plugins/'.$plugin.'/setup.php')) {
231 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
232 } elseif (in_array($plugin, $bad_plugins)) {
233 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);
236 echo $IND . "Plugins OK.<br />\n";
238 echo $IND . "Plugins are not enabled in config.<br />\n";
240 foreach($theme as $thm) {
241 if(!file_exists($thm['PATH'])) {
242 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
243 } elseif(!is_readable($thm['PATH'])) {
244 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
248 echo $IND . "Themes OK.<br />\n";
250 if ( $squirrelmail_default_language != 'en_US' ) {
251 $loc_path = SM_PATH
.'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
252 if( ! file_exists( $loc_path ) ) {
253 do_err('You have set <i>' . $squirrelmail_default_language .
254 '</i> as your default language, but I cannot find this translation (should be '.
255 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
256 'separately from the main SquirrelMail package.', FALSE);
257 } elseif ( ! is_readable( $loc_path ) ) {
258 do_err('You have set <i>' . $squirrelmail_default_language .
259 '</i> as your default language, but I cannot read this translation (file '.
260 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
262 echo $IND . "Default language OK.<br />\n";
265 echo $IND . "Default language OK.<br />\n";
268 echo $IND . "Base URL detected as: <tt>" . htmlspecialchars(get_location()) . "</tt><br />\n";
270 /* check minimal requirements for other security options */
273 if($use_smtp_tls == 1 ||
$use_imap_tls == 1) {
274 if(!check_php_version(4,3,0)) {
275 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
277 if(!extension_loaded('openssl')) {
278 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
281 /* starttls extensions */
282 if($use_smtp_tls === 2 ||
$use_imap_tls === 2) {
283 if (! function_exists('stream_socket_enable_crypto')) {
284 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
288 if ($smtp_auth_mech=='digest-md5' ||
$imap_auth_mech =='digest-md5') {
289 if (!extension_loaded('xml')) {
290 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
294 /* check outgoing mail */
296 echo "Checking outgoing mail service....<br />\n";
299 // is_executable also checks for existance, but we want to be as precise as possible with the errors
300 if(!file_exists($sendmail_path)) {
301 do_err("Location of sendmail program incorrect ($sendmail_path)!");
303 if(!is_executable($sendmail_path)) {
304 do_err("I cannot execute the sendmail program ($sendmail_path)!");
307 echo $IND . "sendmail OK<br />\n";
309 $stream = fsockopen( ($use_smtp_tls==1?
'tls://':'').$smtpServerAddress, $smtpPort,
310 $errorNumber, $errorString);
312 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
313 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
316 // check for SMTP code; should be 2xx to allow us access
317 $smtpline = fgets($stream, 1024);
318 if(((int) $smtpline{0}) > 3) {
319 do_err("Error connecting to SMTP server. Server error: ".
320 htmlspecialchars($smtpline));
323 /* smtp starttls checks */
324 if ($use_smtp_tls===2) {
325 // if something breaks, script should close smtp connection on exit.
328 fwrite($stream,"EHLO $client_ip\r\n");
332 while ($line=fgets($stream, 1024)){
333 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
334 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
335 if (!isset($match[3])) {
336 // simple one word extension
337 $ehlo[strtoupper($match[2])]='';
339 // ehlo-keyword + ehlo-param
340 $ehlo[strtoupper($match[2])]=trim($match[3]);
342 if ($match[1]==' ') {
354 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
355 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
356 do_err('STARTTLS support is not declared by SMTP server.');
359 fwrite($stream,"STARTTLS\r\n");
360 $starttls_response=fgets($stream, 1024);
361 if ($starttls_response[0]!=2) {
362 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
363 .htmlspecialchars($starttls_response);
364 do_err($starttls_cmd_err);
365 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
366 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
368 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
370 // According to RFC we should second ehlo call here.
373 fputs($stream, 'QUIT');
375 echo $IND . 'SMTP server OK (<tt><small>'.
376 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
378 /* POP before SMTP */
379 if($pop_before_smtp) {
380 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
382 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
383 . $err_no . ' : ' . htmlspecialchars($err_str));
386 $tmp = fgets($stream, 1024);
387 if (substr($tmp, 0, 3) != '+OK') {
388 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
389 . ' '.htmlspecialchars($tmp));
391 fputs($stream, 'QUIT');
393 echo $IND . "POP-before-SMTP OK.<br />\n";
398 * Check the IMAP server
400 echo "Checking IMAP service....<br />\n";
402 /** Can we open a connection? */
403 $stream = fsockopen( ($use_imap_tls==1?
'tls://':'').$imapServerAddress, $imapPort,
404 $errorNumber, $errorString);
406 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
407 "Server error: ($errorNumber) ".
408 htmlspecialchars($errorString));
411 /** Is the first response 'OK'? */
412 $imapline = fgets($stream, 1024);
413 if(substr($imapline, 0,4) != '* OK') {
414 do_err('Error connecting to IMAP server. Server error: '.
415 htmlspecialchars($imapline));
418 echo $IND . 'IMAP server ready (<tt><small>'.
419 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
421 /** Check capabilities */
422 fputs($stream, "A001 CAPABILITY\r\n");
424 while ($line=fgets($stream, 1024)){
425 if (preg_match("/A001.*/",$line)) {
432 /* don't display capabilities before STARTTLS */
433 if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
434 do_err('Your server doesn\'t support STARTTLS.');
435 } elseif($use_imap_tls===2) {
436 /* try starting starttls */
437 fwrite($stream,"A002 STARTTLS\r\n");
438 $starttls_line=fgets($stream, 1024);
439 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
440 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
441 .htmlspecialchars($starttls_line);
442 do_err($imap_starttls_err);
443 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
444 do_err('Failed to enable encryption on IMAP connection.');
446 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
449 // get new capability line
450 fwrite($stream,"A003 CAPABILITY\r\n");
452 while ($line=fgets($stream, 1024)){
453 if (preg_match("/A003.*/",$line)) {
461 echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
463 if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
464 do_err('Your server doesn\'t allow plaintext logins. '.
465 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
466 'in the SquirrelMail configuration.', FALSE);
469 /** OK, close connection */
470 fputs($stream, "A004 LOGOUT\r\n");
473 echo "Checking internationalization (i18n) settings...<br />\n";
474 echo "$IND gettext - ";
475 if (function_exists('gettext')) {
476 echo 'Gettext functions are available.'
477 .' On some systems you must have appropriate system locales compiled.'
480 echo 'Gettext functions are unavailable.'
481 .' SquirrelMail will use slower internal gettext functions.'
484 echo "$IND mbstring - ";
485 if (function_exists('mb_detect_encoding')) {
486 echo "Mbstring functions are available.<br />\n";
488 echo 'Mbstring functions are unavailable.'
489 ." Japanese translation won't work.<br />\n";
491 echo "$IND recode - ";
492 if (function_exists('recode')) {
493 echo "Recode functions are available.<br />\n";
494 } elseif (isset($use_php_recode) && $use_php_recode) {
495 echo "Recode functions are unavailable.<br />\n";
496 do_err('Your configuration requires recode support, but recode support is missing.');
498 echo "Recode functions are unavailable.<br />\n";
500 echo "$IND iconv - ";
501 if (function_exists('iconv')) {
502 echo "Iconv functions are available.<br />\n";
503 } elseif (isset($use_php_iconv) && $use_php_iconv) {
504 echo "Iconv functions are unavailable.<br />\n";
505 do_err('Your configuration requires iconv support, but iconv support is missing.');
507 echo "Iconv functions are unavailable.<br />\n";
509 // same test as in include/validate.php
510 echo "$IND timezone - ";
511 if ( (!ini_get('safe_mode')) ||
512 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
513 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
514 echo "Webmail users can change their time zone settings.<br />\n";
516 echo "Webmail users can't change their time zone settings.<br />\n";
521 echo "Checking database functions...<br />\n";
522 if($addrbook_dsn ||
$prefs_dsn ||
$addrbook_global_dsn) {
523 @include_once
('DB.php');
524 if (class_exists('DB')) {
525 echo "$IND PHP Pear DB support is present.<br />\n";
527 'dbase' => 'dbase_open',
528 'fbsql' => 'fbsql_connect',
529 'interbase' => 'ibase_connect',
530 'informix' => 'ifx_connect',
531 'msql' => 'msql_connect',
532 'mssql' => 'mssql_connect',
533 'mysql' => 'mysql_connect',
534 'mysqli' => 'mysqli_connect',
535 'oci8' => 'ocilogon',
536 'odbc' => 'odbc_connect',
537 'pgsql' => 'pg_connect',
538 'sqlite' => 'sqlite_open',
539 'sybase' => 'sybase_connect'
544 $dsns['preferences'] = $prefs_dsn;
547 $dsns['addressbook'] = $addrbook_dsn;
549 if($addrbook_global_dsn) {
550 $dsns['global addressbook'] = $addrbook_global_dsn;
553 foreach($dsns as $type => $dsn) {
554 $aDsn = explode(':', $dsn);
555 $dbtype = array_shift($aDsn);
556 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
557 echo "$IND$dbtype database support present.<br />\n";
559 // now, test this interface:
561 $dbh = DB
::connect($dsn, true);
562 if (DB
::isError($dbh)) {
563 do_err('Database error: '. htmlspecialchars(DB
::errorMessage($dbh)) .
564 ' in ' .$type .' DSN.');
567 echo "$IND$type database connect successful.<br />\n";
570 do_err($dbtype.' database support not present!');
574 $db_error='Required PHP PEAR DB support is not available.'
575 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
576 .' The include path is now:<tt>' . ini_get('include_path') . '</tt>.';
580 echo $IND."not using database functionality.<br />\n";
584 echo "Checking LDAP functions...<br />\n";
585 if( empty($ldap_server) ) {
586 echo $IND."not using LDAP functionality.<br />\n";
588 if ( !function_exists('ldap_connect') ) {
589 do_err('Required LDAP support is not available.');
591 echo "$IND LDAP support present.<br />\n";
592 foreach ( $ldap_server as $param ) {
594 $linkid = @ldap_connect
($param['host'], (empty($param['port']) ?
389 : $param['port']) );
597 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
599 if ( !empty($param['protocol']) &&
600 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION
, $param['protocol']) ) {
601 do_err('Unable to set LDAP protocol');
604 if ( empty($param['binddn']) ) {
605 $bind = @ldap_bind
($linkid);
607 $bind = @ldap_bind
($param['binddn'], $param['bindpw']);
611 echo "$IND LDAP Bind Successful <br />";
613 do_err('Unable to Bind to LDAP Server');
616 @ldap_close
($linkid);
618 do_err('Connection to LDAP failed');
624 echo '<hr width="75%" align="center">';
625 echo '<h2 align="center">Summary</h2>';
626 $footer = '<hr width="75%" align="center">';
628 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>';
632 <p
>Congratulations
, your SquirrelMail setup looks fine to me
!</p
>
634 <p
><a href
="login.php">Login now
</a
></p
>