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) {
25 $level = $fatal ?
'FATAL ERROR:' : 'WARNING:';
26 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
28 echo '</body></html>';
35 $IND = str_repeat(' ',4);
39 define('SM_PATH', '../');
41 /* set default value in order to block remote access to script */
42 $allow_remote_configtest=false;
45 * Load config before output begins. functions/strings.php depends on
46 * functions/globals.php. functions/global.php needs to be run before
47 * any html output starts. If config.php is missing, error will be displayed
50 if (file_exists(SM_PATH
. 'config/config.php')) {
51 include(SM_PATH
. 'config/config.php');
52 include(SM_PATH
. 'functions/strings.php');
54 ?
><!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
55 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
58 <meta name
="robots" content
="noindex,nofollow">
59 <title
>SquirrelMail configtest
</title
>
62 <h1
>SquirrelMail configtest
</h1
>
64 <p
>This script will
try to check some aspects of your SquirrelMail configuration
65 and point you to errors whereever it can find them
. You need to go run
<tt
>conf
.pl
</tt
>
66 in the
<tt
>config
/</tt
> directory first before you run this script
.</p
>
70 $included = array_map('basename', get_included_files() );
71 if(!in_array('config.php', $included)) {
72 if(!file_exists(SM_PATH
. 'config/config.php')) {
73 do_err('Config file '.SM_PATH
. 'config/config.php does not exist!<br />'.
74 'You need to run <tt>conf.pl</tt> first.');
76 do_err('Could not read '.SM_PATH
.'config/config.php! Check file permissions.');
78 if(!in_array('strings.php', $included)) {
79 do_err('Could not include '.SM_PATH
.'functions/strings.php!<br />'.
80 'Check permissions on that file.');
83 /* Block remote use of script */
84 if (! $allow_remote_configtest) {
85 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER
);
86 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER
);
88 if ((! isset($client_ip) ||
$client_ip!='127.0.0.1') &&
89 (! isset($client_ip) ||
! isset($server_ip) ||
$client_ip!=$server_ip)) {
90 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
93 /* checking PHP specs */
95 echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . $version . "</b></td></tr>\n" .
96 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
97 '<tr><td>Config file last modified:</td><td><b>' .
98 date ('d F Y H:i:s', filemtime(SM_PATH
. 'config/config.php')) .
99 "</b></td></tr>\n</table>\n</p>\n\n";
101 /* check $config_version */
102 if ($config_version!='1.4.0') {
103 do_err('Configuration file version does not match required version. Please update your configuration file.');
106 echo "Checking PHP configuration...<br />\n";
108 if(!check_php_version(4,1,0)) {
109 do_err('Insufficient PHP version: '. PHP_VERSION
. '! Minimum required: 4.1.0');
112 echo $IND . 'PHP version ' . PHP_VERSION
. ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
114 $php_exts = array('session','pcre');
115 $diff = array_diff($php_exts, get_loaded_extensions());
117 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
120 echo $IND . "PHP extensions OK.<br />\n";
122 /* dangerous php settings */
124 * mbstring.func_overload allows to replace original string and regexp functions
125 * with their equivalents from php mbstring extension. It causes problems when
126 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
127 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
128 * and .htaccess files (php 4.3.5).
130 if (function_exists('mb_internal_encoding') &&
131 check_php_version(4,2,0) &&
132 (int)ini_get('mbstring.func_overload')!=0) {
133 $mb_error='You have enabled mbstring overloading.'
134 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
140 echo "Checking paths...<br />\n";
142 if(!file_exists($data_dir)) {
143 // data_dir is not that important in db_setups.
144 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
145 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
146 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
148 do_err("Data dir ($data_dir) does not exist!");
151 // don't check if errors
152 if(!isset($data_dir_error) && !is_dir($data_dir)) {
153 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
154 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
155 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
157 do_err("Data dir ($data_dir) is not a directory!");
160 // datadir should be executable - but no clean way to test on that
161 if(!isset($data_dir_error) && !is_writable($data_dir)) {
162 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
163 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
164 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
166 do_err("Data dir ($data_dir) is not writable!");
170 if (isset($data_dir_error)) {
171 echo " Some plugins might need access to data directory.<br />\n";
173 // todo_ornot: actually write something and read it back.
174 echo $IND . "Data dir OK.<br />\n";
177 if($data_dir == $attachment_dir) {
178 echo $IND . "Attachment dir is the same as data dir.<br />\n";
179 if (isset($data_dir_error)) {
180 do_err($data_dir_error);
183 if(!file_exists($attachment_dir)) {
184 do_err("Attachment dir ($attachment_dir) does not exist!");
186 if (!is_dir($attachment_dir)) {
187 do_err("Attachment dir ($attachment_dir) is not a directory!");
189 if (!is_writable($attachment_dir)) {
190 do_err("I cannot write to attachment dir ($attachment_dir)!");
192 echo $IND . "Attachment dir OK.<br />\n";
196 /* check plugins and themes */
197 $bad_plugins = array('view_as_html','folder_preferences');
199 if (isset($plugins[0])) {
200 foreach($plugins as $plugin) {
201 if(!file_exists(SM_PATH
.'plugins/'.$plugin)) {
202 do_err('You have enabled the <i>'.$plugin.'</i> plugin but I cannot find it.', FALSE);
203 } elseif (!is_readable(SM_PATH
.'plugins/'.$plugin.'/setup.php')) {
204 do_err('You have enabled the <i>'.$plugin.'</i> plugin but I cannot read its setup.php file.', FALSE);
205 } elseif (in_array($plugin, $bad_plugins)) {
206 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);
209 echo $IND . "Plugins OK.<br />\n";
211 echo $IND . "Plugins are not enabled in config.<br />\n";
213 foreach($theme as $thm) {
214 if(!file_exists($thm['PATH'])) {
215 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
216 } elseif(!is_readable($thm['PATH'])) {
217 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
221 echo $IND . "Themes OK.<br />\n";
223 if ( $squirrelmail_default_language != 'en_US' ) {
224 $loc_path = SM_PATH
.'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
225 if( ! file_exists( $loc_path ) ) {
226 do_err('You have set <i>' . $squirrelmail_default_language .
227 '</i> as your default language, but I cannot find this translation (should be '.
228 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
229 'separately from the main SquirrelMail package.', FALSE);
230 } elseif ( ! is_readable( $loc_path ) ) {
231 do_err('You have set <i>' . $squirrelmail_default_language .
232 '</i> as your default language, but I cannot read this translation (file '.
233 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
235 echo $IND . "Default language OK.<br />\n";
238 echo $IND . "Default language OK.<br />\n";
241 echo $IND . "Base URL detected as: <tt>" . htmlspecialchars(get_location()) . "</tt><br />\n";
243 /* check minimal requirements for other security options */
246 if($use_smtp_tls == 1 ||
$use_imap_tls == 1) {
247 if(!check_php_version(4,3,0)) {
248 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
250 if(!extension_loaded('openssl')) {
251 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
254 /* starttls extensions */
255 if($use_smtp_tls == 2 ||
$use_imap_tls == 2) {
256 if (! function_exists('stream_socket_enable_crypto')) {
257 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
261 if ($smtp_auth_mech=='digest-md5' ||
$imap_auth_mech =='digest-md5') {
262 if (!extension_loaded('xml')) {
263 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
267 /* check outgoing mail */
269 echo "Checking outgoing mail service....<br />\n";
272 // is_executable also checks for existance, but we want to be as precise as possible with the errors
273 if(!file_exists($sendmail_path)) {
274 do_err("Location of sendmail program incorrect ($sendmail_path)!");
276 if(!is_executable($sendmail_path)) {
277 do_err("I cannot execute the sendmail program ($sendmail_path)!");
280 echo $IND . "sendmail OK<br />\n";
282 $stream = fsockopen( ($use_smtp_tls==1?
'tls://':'').$smtpServerAddress, $smtpPort,
283 $errorNumber, $errorString);
285 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
286 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
289 // check for SMTP code; should be 2xx to allow us access
290 $smtpline = fgets($stream, 1024);
291 if(((int) $smtpline{0}) > 3) {
292 do_err("Error connecting to SMTP server. Server error: ".
293 htmlspecialchars($smtpline));
296 /* smtp starttls checks */
297 if ($use_smtp_tls==2) {
298 // if something breaks, script should close smtp connection on exit.
301 fwrite($stream,"EHLO $client_ip\r\n");
305 while ($line=fgets($stream, 1024)){
306 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
307 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
308 if (!isset($match[3])) {
309 // simple one word extension
310 $ehlo[strtoupper($match[2])]='';
312 // ehlo-keyword + ehlo-param
313 $ehlo[strtoupper($match[2])]=trim($match[3]);
315 if ($match[1]==' ') {
327 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
328 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
329 do_err('STARTTLS support is not declared by SMTP server.');
332 fwrite($stream,"STARTTLS\r\n");
333 $starttls_response=fgets($stream, 1024);
334 if ($starttls_response[0]!=2) {
335 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
336 .htmlspecialchars($starttls_response);
337 do_err($starttls_cmd_err);
338 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
339 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
341 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
343 // According to RFC we should second ehlo call here.
346 fputs($stream, 'QUIT');
348 echo $IND . 'SMTP server OK (<tt><small>'.
349 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
351 /* POP before SMTP */
352 if($pop_before_smtp) {
353 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
355 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
356 . $err_no . ' : ' . htmlspecialchars($err_str));
359 $tmp = fgets($stream, 1024);
360 if (substr($tmp, 0, 3) != '+OK') {
361 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
362 . ' '.htmlspecialchars($tmp));
364 fputs($stream, 'QUIT');
366 echo $IND . "POP-before-SMTP OK.<br />\n";
371 * Check the IMAP server
373 echo "Checking IMAP service....<br />\n";
375 /** Can we open a connection? */
376 $stream = fsockopen( ($use_imap_tls==1?
'tls://':'').$imapServerAddress, $imapPort,
377 $errorNumber, $errorString);
379 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
380 "Server error: ($errorNumber) ".
381 htmlspecialchars($errorString));
384 /** Is the first response 'OK'? */
385 $imapline = fgets($stream, 1024);
386 if(substr($imapline, 0,4) != '* OK') {
387 do_err('Error connecting to IMAP server. Server error: '.
388 htmlspecialchars($imapline));
391 echo $IND . 'IMAP server ready (<tt><small>'.
392 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
394 /** Check capabilities */
395 fputs($stream, "A001 CAPABILITY\r\n");
397 while ($line=fgets($stream, 1024)){
398 if (preg_match("/A001.*/",$line)) {
405 /* don't display capabilities before STARTTLS */
406 if ($use_imap_tls==2 && stristr($capline, 'STARTTLS') === false) {
407 do_err('Your server doesn\'t support STARTTLS.');
408 } elseif($use_imap_tls==2) {
409 /* try starting starttls */
410 fwrite($stream,"A002 STARTTLS\r\n");
411 $starttls_line=fgets($stream, 1024);
412 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
413 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
414 .htmlspecialchars($starttls_line);
415 do_err($imap_starttls_err);
416 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT
)) {
417 do_err('Failed to enable encryption on IMAP connection.');
419 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
422 // get new capability line
423 fwrite($stream,"A003 CAPABILITY\r\n");
425 while ($line=fgets($stream, 1024)){
426 if (preg_match("/A003.*/",$line)) {
434 echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
436 if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
437 do_err('Your server doesn\'t allow plaintext logins. '.
438 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
439 'in the SquirrelMail configuration.', FALSE);
442 /** OK, close connection */
443 fputs($stream, "A004 LOGOUT\r\n");
446 echo "Checking internationalization (i18n) settings...<br />\n";
447 echo "$IND gettext - ";
448 if (function_exists('gettext')) {
449 echo 'Gettext functions are available.'
450 .' On some systems you must have appropriate system locales compiled.'
453 echo 'Gettext functions are unavailable.'
454 .' SquirrelMail will use slower internal gettext functions.'
457 echo "$IND mbstring - ";
458 if (function_exists('mb_detect_encoding')) {
459 echo "Mbstring functions are available.<br />\n";
461 echo 'Mbstring functions are unavailable.'
462 ." Japanese translation won't work.<br />\n";
464 echo "$IND recode - ";
465 if (function_exists('recode')) {
466 echo "Recode functions are available.<br />\n";
467 } elseif (isset($use_php_recode) && $use_php_recode) {
468 echo "Recode functions are unavailable.<br />\n";
469 do_err('Your configuration requires recode support, but recode support is missing.');
471 echo "Recode functions are unavailable.<br />\n";
473 echo "$IND iconv - ";
474 if (function_exists('iconv')) {
475 echo "Iconv functions are available.<br />\n";
476 } elseif (isset($use_php_iconv) && $use_php_iconv) {
477 echo "Iconv functions are unavailable.<br />\n";
478 do_err('Your configuration requires iconv support, but iconv support is missing.');
480 echo "Iconv functions are unavailable.<br />\n";
482 // same test as in include/validate.php
483 echo "$IND timezone - ";
484 if ( (!ini_get('safe_mode')) ||
485 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
486 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
487 echo "Webmail users can change their time zone settings.<br />\n";
489 echo "Webmail users can't change their time zone settings.<br />\n";
494 echo "Checking database functions...<br />\n";
495 if($addrbook_dsn ||
$prefs_dsn ||
$addrbook_global_dsn) {
496 @include_once
('DB.php');
497 if (class_exists('DB')) {
498 echo "$IND PHP Pear DB support is present.<br />\n";
500 'dbase' => 'dbase_open',
501 'fbsql' => 'fbsql_connect',
502 'interbase' => 'ibase_connect',
503 'informix' => 'ifx_connect',
504 'msql' => 'msql_connect',
505 'mssql' => 'mssql_connect',
506 'mysql' => 'mysql_connect',
507 'mysqli' => 'mysqli_connect',
508 'oci8' => 'ocilogon',
509 'odbc' => 'odbc_connect',
510 'pgsql' => 'pg_connect',
511 'sqlite' => 'sqlite_open',
512 'sybase' => 'sybase_connect'
517 $dsns['preferences'] = $prefs_dsn;
520 $dsns['addressbook'] = $addrbook_dsn;
522 if($addrbook_global_dsn) {
523 $dsns['global addressbook'] = $addrbook_global_dsn;
526 foreach($dsns as $type => $dsn) {
527 $aDsn = explode(':', $dsn);
528 $dbtype = array_shift($aDsn);
529 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
530 echo "$IND$dbtype database support present.<br />\n";
532 // now, test this interface:
534 $dbh = DB
::connect($dsn, true);
535 if (DB
::isError($dbh)) {
536 do_err('Database error: '. htmlspecialchars(DB
::errorMessage($dbh)) .
537 ' in ' .$type .' DSN.');
540 echo "$IND$type database connect successful.<br />\n";
543 do_err($dbtype.' database support not present!');
547 $db_error='Required PHP PEAR DB support is not available.'
548 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
549 .' The include path is now:<tt>' . ini_get('include_path') . '</tt>.';
553 echo $IND."not using database functionality.<br />\n";
557 echo "Checking LDAP functions...<br />\n";
558 if( empty($ldap_server) ) {
559 echo $IND."not using LDAP functionality.<br />\n";
561 if ( !function_exists('ldap_connect') ) {
562 do_err('Required LDAP support is not available.');
564 echo "$IND LDAP support present.<br />\n";
565 foreach ( $ldap_server as $param ) {
567 $linkid = @ldap_connect
($param['host'], (empty($param['port']) ?
389 : $param['port']) );
570 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
572 if ( !empty($param['protocol']) &&
573 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION
, $param['protocol']) ) {
574 do_err('Unable to set LDAP protocol');
577 if ( empty($param['binddn']) ) {
578 $bind = @ldap_bind
($linkid);
580 $bind = @ldap_bind
($param['binddn'], $param['bindpw']);
584 echo "$IND LDAP Bind Successful <br />";
586 do_err('Unable to Bind to LDAP Server');
589 @ldap_close
($linkid);
591 do_err('Connection to LDAP failed');
597 echo '<hr width="75%" align="center">';
598 echo '<h2 align="center">Summary</h2>';
599 $footer = '<hr width="75%" align="center">';
601 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>';
605 <p
>Congratulations
, your SquirrelMail setup looks fine to me
!</p
>
607 <p
><a href
="login.php">Login now
</a
></p
>