| [ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 /** 4 * Define HORDE_BASE, if it is not already set, and include the main 5 * Horde library, since we require it for this package to function. 6 */ 7 if (!defined('HORDE_BASE')) { 8 define('HORDE_BASE', dirname(__FILE__) . '/..'); 9 } 10 require_once HORDE_BASE . '/lib/core.php'; 11 12 /** 13 * Set the path to the templates needed for testing output. 14 */ 15 define('TEST_TEMPLATES', HORDE_BASE . '/templates/test/'); 16 17 /* If gettext is not loaded, define a dummy _() function so that 18 * including any file with gettext strings won't cause a fatal error, 19 * causing test.php to return a blank page. */ 20 if (!function_exists('_')) { 21 function _($s) { return $s; } 22 } 23 24 /** 25 * The Horde_Test:: class provides functions used in the test scripts 26 * used in the various applications (test.php). 27 * 28 * $Horde: horde/lib/Test.php,v 1.31.4.19 2006/03/28 12:31:13 jan Exp $ 29 * 30 * Copyright 1999-2006 Charles J. Hagenbuch <chuck@horde.org> 31 * Copyright 1999-2006 Jon Parise <jon@horde.org> 32 * Copyright 2002-2006 Brent J. Nordquist <bjn@horde.org> 33 * Copyright 2003-2006 Michael Slusarz <slusarz@bigworm.colorado.edu> 34 * 35 * See the enclosed file COPYING for license information (LGPL). If you 36 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 37 * 38 * @author Chuck Hagenbuch <chuck@horde.org> 39 * @author Jon Parise <jon@horde.org> 40 * @author Brent J. Nordquist <bjn@horde.org> 41 * @author Michael Slusarz <slusarz@bigworm.colorado.edu> 42 * @since Horde 3.0 43 * @package Horde_Test 44 */ 45 class Horde_Test { 46 47 /** 48 * Array that holds the list of Horde applications. 49 * (Loaded from config/registry.php) 50 * 51 * @var array 52 */ 53 var $applications = array(); 54 55 /** 56 * Cached results of getApplications(). 57 * 58 * @var array 59 */ 60 var $_appoutput = array(); 61 62 /** 63 * The PHP version of the system. 64 * 65 * @var array 66 */ 67 var $_phpver; 68 69 /** 70 * Constructor. 71 */ 72 function Horde_Test() 73 { 74 include_once HORDE_BASE . '/config/registry.php'; 75 ksort($this->applications); 76 77 /* Store the PHP version information. */ 78 $this->_phpver = $this->splitPHPVersion(phpversion()); 79 80 /* We want to be as verbose as possible here. */ 81 error_reporting(E_ALL); 82 83 /* Set character encoding. */ 84 header('Content-type: text/html; charset=utf-8'); 85 header('Vary: Accept-Language'); 86 } 87 88 /** 89 * Parse PHP version. 90 * 91 * @param string $version A PHP-style version string (X.X.X). 92 * 93 * @param array The parsed string. 94 * Keys: 'major', 'minor', 'subminor', 'class' 95 */ 96 function splitPHPVersion($version) 97 { 98 /* First pick off major version, and lower-case the rest. */ 99 if ((strlen($version) >= 3) && ($version[1] == '.')) { 100 $phpver['major'] = substr($version, 0, 3); 101 $version = substr(strtolower($version), 3); 102 } else { 103 $phpver['major'] = $version; 104 $phpver['class'] = 'unknown'; 105 return $phpver; 106 } 107 108 if ($version[0] == '.') { 109 $version = substr($version, 1); 110 } 111 112 /* Next, determine if this is 4.0b or 4.0rc; if so, there is no 113 minor, the rest is the subminor, and class is set to beta. */ 114 $s = strspn($version, '0123456789'); 115 if ($s == 0) { 116 $phpver['subminor'] = $version; 117 $phpver['class'] = 'beta'; 118 return $phpver; 119 } 120 121 /* Otherwise, this is non-beta; the numeric part is the minor, 122 the rest is either a classification (dev, cvs) or a subminor 123 version (rc<x>, pl<x>). */ 124 $phpver['minor'] = substr($version, 0, $s); 125 if ((strlen($version) > $s) && 126 (($version[$s] == '.') || ($version[$s] == '-'))) { 127 $s++; 128 } 129 $phpver['subminor'] = substr($version, $s); 130 if (($phpver['subminor'] == 'cvs') || 131 ($phpver['subminor'] == 'dev') || 132 (substr($phpver['subminor'], 0, 2) == 'rc')) { 133 unset($phpver['subminor']); 134 $phpver['class'] = 'dev'; 135 } else { 136 if (!$phpver['subminor']) { 137 unset($phpver['subminor']); 138 } 139 $phpver['class'] = 'release'; 140 } 141 142 return $phpver; 143 } 144 145 /** 146 * Check the list of PHP modules. 147 * 148 * @param array $modlist The module list. 149 * <pre> 150 * KEY: module name 151 * VALUE: Either the description or an array with the following entries: 152 * 'descrip' -- Module Description 153 * 'error' -- Error Message 154 * 'phpver' -- The PHP version above which to do the test 155 * </pre> 156 * 157 * @return string The HTML output. 158 */ 159 function phpModuleCheck($modlist) 160 { 161 $output = ''; 162 $output_array = array(); 163 164 foreach ($modlist as $key => $val) { 165 $error_msg = $mod_test = $status_out = $fatal = null; 166 $entry = array(); 167 168 if (is_array($val)) { 169 $descrip = $val['descrip']; 170 $fatal = !empty($val['fatal']); 171 if (isset($val['phpver']) && 172 (version_compare(phpversion(), $val['phpver']) == -1)) { 173 $mod_test = true; 174 $status_out = 'N/A'; 175 } 176 if (isset($val['error'])) { 177 $error_msg = $val['error']; 178 } 179 } else { 180 $descrip = $val; 181 } 182 183 if (is_null($status_out)) { 184 $mod_test = extension_loaded($key); 185 $status_out = $this->_status($mod_test, $fatal); 186 } 187 188 $entry[] = $descrip; 189 $entry[] = $status_out; 190 191 if (!is_null($error_msg) && !$mod_test) { 192 $entry[] = $error_msg; 193 if (!$fatal) { 194 $entry[] = 1; 195 } 196 } 197 198 $output .= $this->_outputLine($entry); 199 200 if ($fatal && !$mod_test) { 201 echo $output; 202 exit; 203 } 204 } 205 206 return $output; 207 } 208 209 /** 210 * Checks the list of PHP settings. 211 * 212 * @param array $modlist The settings list. 213 * <code> 214 * KEY: setting name 215 * VALUE: An array with the following entries: 216 * 'error' -- Error Message 217 * 'setting' -- Boolean - should the setting be on or off 218 * </code> 219 * 220 * @return string The HTML output. 221 */ 222 function phpSettingCheck($settings_list) 223 { 224 $output = ''; 225 226 foreach ($settings_list as $key => $val) { 227 $entry = array(); 228 $result = (ini_get($key) == $val['setting']); 229 230 $entry[] = $key . ' ' . (($val['setting'] === true) ? 'enabled' : 'disabled'); 231 $entry[] = $this->_status($result); 232 233 if (!$result) { 234 $entry[] = $val['error']; 235 } 236 237 $output .= $this->_outputLine($entry); 238 } 239 240 return $output; 241 } 242 243 /** 244 * Check the list of PEAR modules. 245 * 246 * @param array $pear_list The PEAR module list. 247 * <pre> 248 * KEY: PEAR class name 249 * VALUE: An array with the following entries: 250 * 'depends' -- This module depends on another module 251 * 'error' -- Error Message 252 * 'function' -- Reference to function to run if module is found 253 * 'path' -- The path to the PEAR module 254 * 'required' -- Is this PEAR module required? (boolean) 255 * </pre> 256 * 257 * @return string The HTML output. 258 */ 259 function PEARModuleCheck($pear_list) 260 { 261 $output = ''; 262 263 /* Turn tracking of errors on. */ 264 ini_set('track_errors', 1); 265 266 /* Print the include_path. */ 267 $output .= $this->_outputLine(array("<strong>PEAR Search Path (PHP's include_path)</strong>", ' <tt>' . ini_get('include_path') . '</tt>')); 268 269 /* Check for PEAR in general. */ 270 { 271 $entry = array(); 272 $entry[] = 'PEAR'; 273 @include_once 'PEAR.php'; 274 $entry[] = $this->_status(!isset($php_errormsg)); 275 if (isset($php_errormsg)) { 276 $entry[] = 'Check your PHP include_path setting to make sure it has the PEAR library directory.'; 277 $output .= $this->_outputLine($entry); 278 ini_restore('track_errors'); 279 return $output; 280 } 281 $output .= $this->_outputLine($entry); 282 } 283 284 /* Check for a recent PEAR version. */ 285 $entry = array(); 286 $newpear = $this->isRecentPEAR(); 287 $entry[] = 'Recent PEAR'; 288 $entry[] = $this->_status($newpear); 289 if (!$newpear) { 290 $entry[] = 'This version of PEAR is not recent enough. See the <a href="http://www.horde.org/pear/">Horde PEAR page</a> for details.'; 291 } 292 $output .= $this->_outputLine($entry); 293 294 /* Go through module list. */ 295 $succeeded = array(); 296 foreach ($pear_list as $key => $val) { 297 $entry = array(); 298 299 /* If this module depends on another module that we 300 * haven't succesfully found, fail the test. */ 301 if (!empty($val['depends']) && empty($succeeded[$val['depends']])) { 302 $result = false; 303 } else { 304 $result = @include_once $val['path']; 305 } 306 $error_msg = $val['error']; 307 if ($result && isset($val['function'])) { 308 $func_output = call_user_func($val['function']); 309 if ($func_output) { 310 $result = false; 311 $error_msg = $func_output; 312 } 313 } 314 $entry[] = $key; 315 $entry[] = $this->_status($result, !empty($val['required'])); 316 317 if ($result) { 318 $succeeded[$key] = true; 319 } else { 320 if (!empty($val['required'])) { 321 $error_msg .= ' THIS IS A REQUIRED MODULE!'; 322 } 323 $entry[] = $error_msg; 324 if (empty($val['required'])) { 325 $entry[] = 1; 326 } 327 } 328 329 $output .= $this->_outputLine($entry); 330 } 331 332 /* Restore previous value of 'track_errors'. */ 333 ini_restore('track_errors'); 334 335 return $output; 336 } 337 338 /** 339 * Check the list of required files 340 * 341 * @param array $file_list The file list. 342 * <pre> 343 * KEY: file path 344 * VALUE: The error message to use (null to use default message) 345 * </pre> 346 * 347 * @return string The HTML output. 348 */ 349 function requiredFileCheck($file_list) 350 { 351 $output = ''; 352 353 foreach ($file_list as $key => $val) { 354 $entry = array(); 355 $result = file_exists('./' . $key); 356 357 $entry[] = $key; 358 $entry[] = $this->_status($result); 359 360 if (!$result) { 361 if (empty($val)) { 362 $entry[] = 'The file <code>' . $key . '</code> appears to be missing. You probably just forgot to copy <code>' . $key . '.dist</code> over. While you do that, take a look at the settings and make sure they are appropriate for your site.'; 363 } else { 364 $entry[] = $val; 365 } 366 } 367 368 $output .= $this->_outputLine($entry); 369 } 370 371 return $output; 372 } 373 374 /** 375 * Displays an error screen with a list of all configuration files that 376 * are missing, together with a description what they do and how they are 377 * created. If a file can be automatically created from the defaults, then 378 * we do that instead and don't display an error. 379 * 380 * @param string $app The application name 381 * @param string $appBase The path to the application 382 * @param array $files An array with the "standard" configuration 383 * files that should be checked. Currently 384 * supported: 385 * - conf.php 386 * - prefs.php 387 * - mime_drivers.php 388 * @param array $additional An associative array containing more files (as 389 * keys) and error message (as values) if they 390 * don't exist. 391 */ 392 function configFilesMissing($app, $appBase, $files, $additional = array()) 393 { 394 /* Try to load a basic framework if we're testing an app other than 395 * the Horde base files. */ 396 if ($app != 'Horde') { 397 $GLOBALS['registry'] = &Registry::singleton(); 398 $GLOBALS['registry']->pushApp('horde', false); 399 } 400 401 if (!is_array($files)) { 402 $files = array($files); 403 } 404 $files = array_merge($files, array_keys($additional)); 405 406 /* Try to auto-create missing .dist files. */ 407 $indices = array_keys($files); 408 foreach ($indices as $index) { 409 if (is_readable($appBase . '/config/' . $files[$index])) { 410 unset($files[$index]); 411 } else { 412 if (@file_exists($appBase . '/config/' . $files[$index] . '.dist') && 413 @copy($appBase . '/config/' . $files[$index] . '.dist', $appBase . '/config/' . $files[$index])) { 414 unset($files[$index]); 415 } 416 } 417 } 418 419 /* Return if we have no missing files left. */ 420 if (!count($files)) { 421 return; 422 } 423 424 $descriptions = array_merge(array( 425 'conf.php' => sprintf('This is the main %s configuration file. ' . 426 'It contains paths and options for the %s ' . 427 'scripts. You need to login as an ' . 428 'administrator and create the file with ' . 429 'the web frontend under "Administration => ' . 430 'Setup".', 431 $app, $app, $appBase . '/config'), 432 'prefs.php' => sprintf('This file controls the default preferences ' . 433 'for %s, and also controls which preferences ' . 434 'users can alter.', $app), 435 'mime_drivers.php' => sprintf('This file controls local MIME ' . 436 'drivers for %s, specifically what ' . 437 'kinds of files are viewable and/or ' . 438 'downloadable.', $app), 439 'backends.php' => sprintf('This file controls what backends are ' . 440 'available from %s.', $app), 441 'sources.php' => sprintf('This file defines the list of available ' . 442 'sources for %s.', $app) 443 ), $additional); 444 445 /* If we know the user is an admin, give them a direct link to 446 * generate conf.php. In the future, should we try generating 447 * a basic conf.php automagically here? */ 448 if (Auth::isAdmin()) { 449 $setup_url = Horde::link(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . 450 '/admin/setup/config.php?app=' . String::lower($app))) . 451 'Configuration Web Interface' . '</a>'; 452 $descriptions['conf.php'] = 453 sprintf('This is the main %s configuration file. ' . 454 'Generate it by going to the %s.', 455 $app, $setup_url); 456 } 457 458 $title = sprintf('%s is not properly configured', $app); 459 $header = sprintf('Some of %s\'s configuration files are missing or unreadable', $app); 460 $footer = sprintf('Create these files from their .dist versions in %s and change them according to your needs.', $appBase . '/config'); 461 462 echo <<< HEADER 463 <html> 464 <head><title>$title</title></head> 465 <body style="background-color: white; color: black;"> 466 <h1>$header</h1> 467 HEADER; 468 469 foreach ($files as $file) { 470 if (empty($descriptions[$file])) { 471 continue; 472 } 473 $description = $descriptions[$file]; 474 echo <<< FILE 475 <h3>$file</h3><p>$description</p> 476 FILE; 477 } 478 479 echo <<< FOOTER 480 481 <h2>$footer</h2> 482 </body> 483 </html> 484 FOOTER; 485 exit; 486 } 487 488 /** 489 * Check the list of required Horde applications. 490 * 491 * @param array $app_list The application list. 492 * <pre> 493 * KEY: application name 494 * VALUE: An array with the following entries: 495 * 'error' -- Error Message 496 * 'version' -- The minimum version required 497 * </pre> 498 * 499 * @return string The HTML output. 500 */ 501 function requiredAppCheck($app_list) 502 { 503 $output = ''; 504 505 $apps = $this->applicationList(); 506 507 foreach ($app_list as $key => $val) { 508 $entry = array(); 509 $entry[] = $key; 510 511 if (!isset($apps[$key])) { 512 $entry[] = $this->_status(false); 513 $entry[] = $val['error']; 514 } else { 515 /* Strip '-cvs' and H3 (ver) from version string. */ 516 $appver = str_replace('-cvs', '', $apps[$key]->version); 517 $appver = preg_replace('/H3 \((.*)\)/', '$1', $appver); 518 if (version_compare($val['version'], $appver) === 1) { 519 $entry[] = $this->_status(false) . ' (Have version: ' . $apps[$key]->version . '; Need version: ' . $val['version'] . ')'; 520 $entry[] = $val['error']; 521 } else { 522 $entry[] = $this->_status(true) . ' (Version: ' . $apps[$key]->version . ')'; 523 } 524 } 525 $output .= $this->_outputLine($entry); 526 } 527 528 return $output; 529 } 530 531 /** 532 * Is this a 'recent' version of PEAR? 533 * 534 * @param boolean True if a recent version of PEAR. 535 */ 536 function isRecentPEAR() 537 { 538 @include_once 'PEAR.php'; 539 $pear_methods = get_class_methods('PEAR'); 540 return (is_array($pear_methods) && 541 (in_array('registershutdownfunc', $pear_methods) || 542 in_array('registerShutdownFunc', $pear_methods))); 543 } 544 545 /** 546 * Obtain information on the PHP version. 547 * 548 * @return object stdClass TODO 549 */ 550 function getPhpVersionInformation() 551 { 552 $output = &new stdClass; 553 $url = urlencode($_SERVER['PHP_SELF']); 554 $vers_check = true; 555 556 $testscript = $this->applications['horde']['webroot'] . '/test.php'; 557 $output->phpinfo = $testscript . '?mode=phpinfo&url=' . $url; 558 $output->extensions = $testscript . '?mode=extensions&url=' . $url; 559 $output->version = phpversion(); 560 $output->major = $this->_phpver['major']; 561 if (isset($this->_phpver['minor'])) { 562 $output->minor = $this->_phpver['minor']; 563 } 564 if (isset($this->_phpver['subminor'])) { 565 $output->subminor = $this->_phpver['subminor']; 566 } 567 $output->class = $this->_phpver['class']; 568 569 $output->status_color = 'red'; 570 if ($output->major < '4.3') { 571 $output->status = 'This version of PHP is not supported. You need to upgrade to a more recent version.'; 572 $vers_check = false; 573 } elseif (($output->major == '4.3') || 574 ($output->major == '4.4') || 575 ($output->major == '5.0') || 576 ($output->major == '5.1')) { 577 $output->status = 'You are running a supported version of PHP.'; 578 $output->status_color = 'green'; 579 } else { 580 $output->status = 'Wow, a mystical version of PHP from the future. Let <a href="mailto:dev@lists.horde.org">dev@lists.horde.org</a> know what version you have so we can fix this script.'; 581 $output->status_color = 'orange'; 582 } 583 584 if (!$vers_check) { 585 $output->version_check = 'Horde requires PHP 4.3.0 or greater.'; 586 } 587 588 return $output; 589 } 590 591 /** 592 * Get the application list. 593 * 594 * @return array List of stdClass objects. 595 * KEY: application name 596 * ELEMENT 'version': Version of application 597 * ELEMENT 'test': The location of the test script (if any) 598 */ 599 function applicationList() 600 { 601 if (!empty($this->_appoutput)) { 602 return $this->_appoutput; 603 } 604 605 foreach ($this->applications as $mod => $det) { 606 if (($det['status'] != 'heading') && 607 ($det['status'] != 'block') && 608 is_readable($det['fileroot'] . '/lib/version.php')) { 609 require_once $det['fileroot'] . '/lib/version.php'; 610 $version_constant = String::upper($mod) . '_VERSION'; 611 if (defined($version_constant)) { 612 $this->_appoutput[$mod] = &new stdClass; 613 $this->_appoutput[$mod]->version = constant($version_constant); 614 if (($mod != 'horde') && 615 @is_readable($det['fileroot'] . '/test.php')) { 616 $this->_appoutput[$mod]->test = $det['webroot'] . '/test.php'; 617 } 618 } 619 } 620 } 621 622 return $this->_appoutput; 623 } 624 625 /** 626 * Output the results of a status check. 627 * 628 * @access private 629 * 630 * @param boolean $bool The result of the status check. 631 * @param boolean $required Whether the checked item is required. 632 * 633 * @return string The HTML of the result of the status check. 634 */ 635 function _status($bool, $required = true) 636 { 637 if ($bool) { 638 return '<font color="green"><strong>Yes</strong></font>'; 639 } elseif ($required) { 640 return '<font color="red"><strong>No</strong></font>'; 641 } else { 642 return '<font color="orange"><strong>No</strong></font>'; 643 } 644 } 645 646 /** 647 * Internal output function. 648 * 649 * @access private 650 * 651 * @param array $entry 3 element array. 652 * <pre> 653 * 1st value: Header 654 * 2nd value: Test Result 655 * 3rd value: Error message (if present) 656 * 4th value: Error level (if present): 0 = error, 1 = warning 657 * </pre> 658 * 659 * @return string HTML output. 660 */ 661 function _outputLine($entry) 662 { 663 $output = '<li>' . array_shift($entry) . ': ' . array_shift($entry); 664 if (!empty($entry)) { 665 $msg = array_shift($entry); 666 $output .= '<br /><font color="' . (empty($entry) || !array_shift($entry) ? 'red' : 'orange') . '"><strong>' . $msg . '</strong></font>' . "\n"; 667 } 668 $output .= '</li>' . "\n"; 669 670 return $output; 671 } 672 673 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |