1<?php 2 3/** 4 * SquirrelMail Compatibility Plugin 5 * Copyright (c) 2004-2009 Paul Lesniewski <paul@squirrelmail.org> 6 * Licensed under the GNU GPL. For full terms see the file COPYING. 7 * 8 * SquirrelMail developers, see below under "SQUIRRELMAIL DEVELOPER 9 * NOTES" for information about how the include files are maintained 10 * 11 * @package plugins 12 * @subpackage compatibility 13 * 14 */ 15 16 17 18 // change this to TRUE to disable plugin config test functionality 19 // which will increase performance (minimally) 20 // 21 $disable_config_check = FALSE; 22 23 24 // --------------------------------------- 25 26 27 global $compatibility_sm_path, $compatibility_disable_config_check; 28 $compatibility_disable_config_check = $disable_config_check; 29 30 31 // we don't want to do any defining constants ourselves to stay 32 // as non-intrusive as possible, so just our own variable 33 // 34 if (defined('SM_PATH')) 35 $compatibility_sm_path = SM_PATH; 36 else 37 $compatibility_sm_path = '../'; 38 39 40 // Some uses of this plugin (such as vlogin) were somehow calling the 41 // functions here before having included the functions in global.php, 42 // resulting in fatal errors when called below. Thus, the need for 43 // the following includes 44 // 45 46 // we also need to include the validate file first 47 // thing so we don't lose the ability to display themes, 48 // but we cannot include this file unless we are being 49 // called from a plugin request, thus this if statement 50 // 51/* 52 if ( strpos(getcwd(), 'plugins') ) 53 { 54 if (file_exists($compatibility_sm_path . 'include/validate.php')) 55 include_once($compatibility_sm_path . 'include/validate.php'); 56 else if (file_exists($compatibility_sm_path . 'src/validate.php')) 57 include_once($compatibility_sm_path . 'src/validate.php'); 58 } 59 60 61 include_once($compatibility_sm_path . 'functions/strings.php'); 62 63 64 if (file_exists($compatibility_sm_path . 'functions/global.php')) 65 include_once($compatibility_sm_path . 'functions/global.php'); 66 else if (file_exists($compatibility_sm_path . 'src/global.php')) 67 include_once($compatibility_sm_path . 'src/global.php'); 68*/ 69 70 71 72 // legacy support for previous versions of compatibility plugin 73 // 74//see below 75// function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0') 76// { return check_sm_version($a, $b, $c); } 77 function compatibility_check_php_version ($a = '0', $b = '0', $c = '0') 78 { return check_php_version($a, $b, $c); } 79 function compatibility_sqsession_register ($var, $name) 80 { sqsession_register ($var, $name); } 81 function compatibility_sqsession_unregister ($name) 82 { sqsession_unregister($name); } 83 function compatibility_sqsession_is_active() 84 { sqsession_is_active(); } 85 function compatibility_sqsession_is_registered ($name) 86 { return sqsession_is_registered($name); } 87 function compatibility_sqextractGlobalVar ($name) 88 { global $$name; sqgetGlobalVar($name, $$name); } 89 90 91 92 // now include everything that current SM version is missing 93 // 94 load_legacy_support(); 95 96 97 98 99 /** 100 * Checks SquirrelMail version, returns TRUE if SquirrelMail 101 * version is at least a.b.c. 102 * 103 * @param $a int Major version number 104 * @param $b int Minor version number 105 * @param $c int Revision number 106 * 107 * @return boolean TRUE if SquirrelMail version matches at 108 * least a.b.c, FALSE otherwise. 109 * 110 */ 111 function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0') 112 { 113 if (function_exists('check_sm_version')) 114 return check_sm_version($a, $b, $c); 115 116 if (defined('SM_VERSION')) 117 $version = SM_VERSION; 118 else 119 global $version; 120 121 list($aa, $bb, $cc) = preg_split('/\./', $version, 3); 122 $cc = intval($cc); 123 124 if(!is_numeric($cc)) 125 list($cc, $info) = explode(' ', $cc, 2); 126 127 return ($aa > $a) 128 || (($aa == $a) && ($bb > $b)) 129 || (($aa == $a) && ($bb == $b) && ($cc >= $c)); 130 } 131 132 133 134 /** 135 * Includes needed files with updated API for legacy 136 * SquirrelMail installations 137 * 138 */ 139 function load_legacy_support() 140 { 141 142 global $compatibility_sm_path; 143 144 // SQUIRRELMAIL DEVELOPER NOTES 145 // 146 // The array below should be updated with every release of 147 // SquirrelMail, along with adding needed directories in the 148 // includes for this plugin. 149 // 150 // Code that was added as of a certain version should be put 151 // in the include file in the directory corresponding to that 152 // same version number in order to make it available to older 153 // versions. When including files here, that file will be 154 // included for all versions prior. 155 // 156 // If some code was added to the newest codebase for two different 157 // release series, for example, a function called "sq_new_function()" 158 // that was added in both 1.4.10 as well as 1.5.2, please add 159 // the function to only the higher version (1.5.2 in this case), 160 // and add additional logic to the way it is included: 161 // 162 // if ((!compatibility_check_sm_version(1, 4, 10) 163 // || (compatibility_check_sm_version(1, 5, 0) 164 // && !compatibility_check_sm_version(1, 5, 2))) 165 // && !function_exists('sq_new_function')) 166 // { 167 // function sq_new_function() 168 // { 169 // echo "HELLO WORLD"; 170 // } 171 // } 172 // 173 // NOTE: In-between version includes should simply be put in the 174 // lowest version include file for the new release series 175 // (e.g., anything in the 1.5.0 include file will be loaded 176 // for all 1.4.x versions, and of course, not for 1.5.0). 177 // The following in-between include file system is thus not 178 // needed, but leaving code and documentation about how it 179 // works just for edification: 180 // 181 // In-between include directories should be named as such: 182 // "1.4.x-to-1.5.0" where the latter version string must 183 // correspond to a real SquirrelMail version and the versions 184 // must be separated by the string "-to-" 185 // 186 // Order in this array is significant, please keep newest releases 187 // at top of this list, ordered downward from there... 188 // 189 // These have to be hard-coded since there is no way to know if this 190 // plugin is being used in series 1.2.x, 1.3.x, 1.4.x, 1.5.x, etc. 191 // 192 $compatibility_versions = array( 193 '1.5.2', '1.5.1', '1.5.0', 194 // in-between includes not needed: 195 //'1.4.x-to-1.5.0', 196 '1.4.20', '1.4.19', '1.4.18', '1.4.17', '1.4.16', '1.4.15', '1.4.14', 197 '1.4.13', '1.4.12', '1.4.11', '1.4.10', '1.4.9', '1.4.8', '1.4.7', 198 '1.4.6', '1.4.5', '1.4.4', '1.4.3', '1.4.2', '1.4.1', '1.4.0', 199 // skipping 1.3.x, not supported for now 200 // in-between includes not needed: 201 //'1.2.x-to-1.4.0', 202 '1.2.11', '1.2.10', '1.2.9', '1.2.8', '1.2.7', 203 // if you are running anything older than this, I feel really, really sorry for you 204 ); 205 206 207 // loop through all versions in our list, including files 208 // for all versions newer than the one being run here and now 209 // 210 $last_csv_version_string = ''; 211 $last_version_string = ''; 212 for ($count = 0; !empty($compatibility_versions[$count]); $count++) 213 { 214 215 $version_string = $compatibility_versions[$count]; 216 217 218/* ----- see above; in-between includes not needed... 219 // in-between version files: set version string to the higher 220 // version so that all versions in the release series below 221 // it will see it 222 // 223 if (($pos = strpos($version_string, '-to-')) !== FALSE) 224 $csv_version_string = str_replace('.', ', ', substr($version_string, $pos + 4)); 225 226 227 // normal conversion to CSV values 228 // 229 else 230----- */ 231 // note that we could split $version_string by '.' instead and not use eval below 232 $csv_version_string = str_replace('.', ', ', $version_string); 233 234 235 if ($count == 0) 236 { 237 if (eval('if (compatibility_check_sm_version(' . $csv_version_string . ')) return TRUE; else return FALSE;')) 238 return; 239 $last_csv_version_string = $csv_version_string; 240 $last_version_string = $version_string; 241 continue; 242 } 243 244 245 if (eval('if (file_exists($compatibility_sm_path . \'plugins/compatibility/includes/' 246 . $last_version_string . '/global.php\')) include_once($compatibility_sm_path . \'plugins/compatibility/includes/' 247 . $last_version_string . '/global.php\'); if (compatibility_check_sm_version(' 248 . $csv_version_string . ')) return TRUE;')) 249 return; 250 251 $last_csv_version_string = $csv_version_string; 252 $last_version_string = $version_string; 253 254 } 255 256 } 257 258 259 260/** 261 * Allows a plugin to push itself (or another plugin) to the top 262 * or bottom of the plugin order for a certain hook. It also 263 * allows for positioning immediately before or after another 264 * plugin. 265 * 266 * NOTE that this function will only be useful when called from 267 * certain points in the code context, such as from a very early 268 * hook like 'config_override' (which has been changed to 269 * 'prefs_backend'), and may not work reliably for reordering 270 * hooks that are already in execution. 271 * 272 * @param string $plugin_name The name of the plugin to reposition. 273 * @param string $hook_name The name of the hook wherein the 274 * repositioning happens. 275 * @param boolean $before If the repositioning should be at the 276 * top of the plugin list (or before the 277 * $relative_plugin plugin). When FALSE, 278 * repositioning goes to the bottom of 279 * the plugin list or after $relative_plugin 280 * (OPTIONAL; default is TRUE). 281 * @param string $relative_plugin The name of a plugin that the repositioning 282 * should be relative to. If not given, 283 * the target plugin is just moved to the 284 * extreme front or back of the whole plugin 285 * list (OPTIONAL; default not used). 286 * 287 * @return boolean TRUE when repositioning succeeds, FALSE otherwise 288 * (for instance, it might fail if the target plugin 289 * is not already registered on the target hook, or 290 * $relative_plugin is not also found on the target hook). 291 * 292 */ 293function reposition_plugin_on_hook($plugin_name, $hook_name, $before=TRUE, 294 $relative_plugin='') 295{ 296 297 global $squirrelmail_plugin_hooks, $plugins; 298 299 300 // make sure plugin is already registered on the target hook 301 // 302 if (is_array($squirrelmail_plugin_hooks[$hook_name]) 303 && !empty($squirrelmail_plugin_hooks[$hook_name][$plugin_name])) 304 { 305 306 // move relative to another plugin? 307 // 308 $relative_plugin_function = FALSE; 309 if (!empty($relative_plugin)) 310 { 311 if (empty($squirrelmail_plugin_hooks[$hook_name][$relative_plugin])) 312 return FALSE; 313 314 $relative_plugin_function = $squirrelmail_plugin_hooks[$hook_name][$relative_plugin]; 315 } 316 317 318 // grab target plugin's function callback for this hook 319 // 320 $plugin_function = $squirrelmail_plugin_hooks[$hook_name][$plugin_name]; 321 322 323 // reordering an associative array can only be done 324 // by rebuilding by hand as far as I know 325 // 326 $new_hook_array = array(); 327 if ($before && !$relative_plugin_function) 328 $new_hook_array[$plugin_name] = $plugin_function; 329 foreach ($squirrelmail_plugin_hooks[$hook_name] as $plugin => $function) 330 { 331 332 if ($plugin == $plugin_name) 333 continue; 334 335 // move relative to another plugin? 336 // 337 if ($plugin == $relative_plugin && !empty($relative_plugin)) 338 { 339 if ($before) 340 { 341 $new_hook_array[$plugin_name] = $plugin_function; 342 $new_hook_array[$relative_plugin] = $relative_plugin_function; 343 } 344 else 345 { 346 $new_hook_array[$relative_plugin] = $relative_plugin_function; 347 $new_hook_array[$plugin_name] = $plugin_function; 348 } 349 continue; 350 } 351 352 $new_hook_array[$plugin] = $function; 353 354 } 355 if (!$before && !$relative_plugin_function) 356 $new_hook_array[$plugin_name] = $plugin_function; 357 358 359 360 // now replace the plugins for the target hook 361 // 362 $squirrelmail_plugin_hooks[$hook_name] = $new_hook_array; 363 364 return TRUE; 365 366 } 367 368 369 // plugin not found on target hook 370 // 371 return FALSE; 372 373} 374 375 376 377/** 378 * Dynamically enables a plugin to the SquirrelMail environment. 379 * 380 * @param string $plugin_name The name of the plugin to add. 381 * @param mixed $args The current plugin function argument, 382 * which must be exactly as received by 383 * the plugin function that is calling 384 * this code (OPTIONAL; default empty). 385 * @param boolean $dont_execute When adding plugins that are registered 386 * on the same hook that is currently being 387 * executed, the registered function for 388 * the new plugins will be manually run, 389 * however, setting this flag to TRUE will 390 * prevent that from happening (plugins 391 * will be registered, but never executed) 392 * (OPTIONAL; default is FALSE). 393 * 394 */ 395function add_plugin($plugin_name, $args='', $dont_execute=FALSE) 396{ 397 398 global $squirrelmail_plugin_hooks, $plugins; 399 400 // changing the hook function array whilst in the 401 // middle of iterating thru it for the same hook 402 // doesn't always work, so we'll see if the hook 403 // currently being executed has had its function 404 // list changed; if so, we will execute the added 405 // hook functions ourselves 406 // 407 $hook_name = get_current_hook_name($args); 408 409 410 // used below for determining if any plugins 411 // were added to currently running hook 412 // 413 if (!empty($hook_name) 414 && !empty($squirrelmail_plugin_hooks[$hook_name]) 415 && is_array($squirrelmail_plugin_hooks[$hook_name])) 416 $original_hook_functions = $squirrelmail_plugin_hooks[$hook_name]; 417 else 418 $original_hook_functions = array(); 419 420 421 // add plugin to global plugin array 422 // 423 $plugins[] = $plugin_name; 424 425 426 // enable plugin -- emulate code from use_plugin() function 427 // in SquirrelMail core, because in 1.5.2, it no longer 428 // called "squirrelmail_plugin_init_<plugin_name>", which 429 // NEEDS to be called here. 430 // 431 if (file_exists(SM_PATH . "plugins/$plugin_name/setup.php")) 432 { 433 434 include_once(SM_PATH . "plugins/$plugin_name/setup.php"); 435 436 $function = "squirrelmail_plugin_init_$plugin_name"; 437 if (function_exists($function)) 438 $function(); 439 440 } 441 442 443 // now get any new plugins for the current hook 444 // and run their hooks 445 // 446 if (!$dont_execute && !empty($hook_name)) 447 { 448 449 if (!empty($squirrelmail_plugin_hooks[$hook_name]) 450 && is_array($squirrelmail_plugin_hooks[$hook_name])) 451 $new_hook_functions = array_diff($squirrelmail_plugin_hooks[$hook_name], 452 $original_hook_functions); 453 else 454 $new_hook_functions = array(); 455 456 foreach ($new_hook_functions as $function) 457 if (function_exists($function)) 458//FIXME: is $args always how plugins are called, even in 1.4.x? 459 $function($args); 460 461 } 462 463} 464 465 466 467/** 468 * Dynamically disables a plugin from the SquirrelMail environment. 469 * 470 * @param string $plugin_name The name of the plugin to remove. 471 * 472 */ 473function remove_plugin($plugin_name) 474{ 475 476 global $squirrelmail_plugin_hooks, $plugins; 477 478 $plugin_key = array_search($plugin_name, $plugins); 479 if (!is_null($plugin_key) && $plugin_key !== FALSE) 480 { 481 unset($plugins[$plugin_key]); 482 if (is_array($squirrelmail_plugin_hooks)) 483 foreach (array_keys($squirrelmail_plugin_hooks) as $hookName) 484 { 485 unset($squirrelmail_plugin_hooks[$hookName][$plugin_name]); 486 } 487 } 488 489} 490 491 492 493/** 494 * Determines what plugin hook is currently executing, 495 * if any, in a SquirrelMail version-independent fashion. 496 * 497 * @param mixed $args The current plugin function argument, 498 * which must be exactly as received by 499 * the plugin function that is calling 500 * this code. 501 * 502 * @return string The name of the currently executing plugin 503 * hook, or an empty string if either no hook 504 * is running or the hook name could not be 505 * determined. 506 * 507 */ 508function get_current_hook_name($args='') 509{ 510 511 if (check_sm_version(1, 5, 1)) 512 { 513 global $currentHookName; 514 if (!empty($currentHookName)) 515 return $currentHookName; 516 } 517 518 519//TODO: should we ALWAYS backtrace instead of assuming that $args[0] is the hook name? 520 if (!empty($args[0]) && is_string($args[0])) 521 return $args[0]; 522 else 523 { 524 525 // plugin args not given or didn't have a hook 526 // name in them, so try backtracing instead 527 // 528 $backtrace = debug_backtrace(); 529 foreach ($backtrace as $trace) 530 if ($trace['function'] == 'do_hook' 531 || $trace['function'] == 'do_hook_function' 532 || $trace['function'] == 'concat_hook_function' 533 || $trace['function'] == 'boolean_hook_function') 534 return $trace['args'][0]; 535 536 // nothing found at all 537 // 538 return ''; 539 540 } 541 542} 543 544 545 546/** 547 * Load configuration file 548 * 549 * Convenience function for plugins that loads a configuration 550 * file (or files). If the file(s) is(are) not found, an error 551 * is displayed and execution stops (function won't return). 552 * If multiple configuration files are given, ALL of them are 553 * included (unless $load_only_one is TRUE), if they exist, in 554 * the order given. Only one of them needs to be found to avert 555 * triggering an error. 556 * 557 * Note that configuration files are loaded in the order given, 558 * so the caller should place the file that should have the 559 * final overrides as the LAST in the given list, unless using 560 * $load_only_one, in which case the most important configuration 561 * file should probably come first. 562 * 563 * Non-functional on login_before hook. 564TODO - re-verify that the above is true 565 * 566 * @param string $plugin_name The name of the plugin as 567 * it is known to SquirrelMail, 568 * that is, it is the name 569 * of the plugin directory 570 * @param mixed $config_files An array of files that will 571 * be included IN THE ORDER that 572 * they are given in the 573 * array. Can also be given as 574 * a string if only one config 575 * file is being loaded. Files 576 * should be specified relative 577 * to the calling plugin's 578 * directory, such as: 579 * 'config.php' 580 * or: 581 * '../../config/my_plugin_config.php' 582 * or: 583 * array('data/config.php', 'data/admins.php') 584 * It is also possible to give a 585 * full/direct path to a 586 * configuration file by placing 587 * a forward slash at the 588 * beginning of the file: 589 * array('/var/lib/squirrelmail/config/myplugin.conf') 590 * @param boolean $return_errors When TRUE, any errors encountered 591 * will cause this function to return 592 * FALSE; otherwise, errors are 593 * handled herein by showing an error 594 * to the user and exiting (OPTIONAL; 595 * default is FALSE). 596 * @param boolean $load_only_one When TRUE, this function will stop 597 * after it has successfully loaded 598 * one configuration file, starting 599 * with the first one given for 600 * $config_files. When FALSE, all 601 * configuration files will be loaded 602 * such that the last one can override 603 * all others ("cascading") (OPTIONAL; 604 * default is FALSE). 605 * 606 * @return mixed If no errors are found, TRUE is returned; if an error 607 * was found and $return_errors is TRUE, FALSE is returned. 608 * If $return_errors is FALSE and an error is found, this 609 * function will never return. 610 * 611 */ 612function load_config($plugin_name, $config_files, 613 $return_errors=FALSE, $load_only_one=FALSE) 614{ 615 616 global $compatibility_sm_path; 617 618 619 // if only one config file given as string 620 // 621 if (!is_array($config_files)) $config_files = array($config_files); 622 623 624 // loop through files, attempting to include them 625 // 626 $file_count = 1; 627 foreach ($config_files as $file) 628 { 629 630 if (strpos($file, '/') === 0) 631 $plugin_path = $file; 632 else 633 $plugin_path = $compatibility_sm_path . 'plugins/' . $plugin_name . '/' . $file; 634 635 // store inclusion results to be checked below 636 // 637 ${'config' . $file_count} = @include_once($plugin_path); 638 639 // if we only need one configuration file, stop 640 // here if we successfully loaded this config file 641 // 642 if ($load_only_one && ${'config' . $file_count}) 643 return TRUE; 644 645 $file_count++; 646 647 } 648 649 650 // now check to see if we got at least one successful inclusion 651 // 652 $success = FALSE; 653 for ($i = 1; $i < $file_count; $i++) 654 if (${'config' . $i}) 655 { 656 $success = TRUE; 657 break; 658 } 659 660 661 // error... 662 // 663 if (!$success) 664 { 665 666 if ($return_errors) return FALSE; 667 668// TODO: when used in configtest hook (and others??), this function (sq_change_text_domain()) is not known yet... but usually $return_errors should be turned on for that hook 669 sq_change_text_domain('compatibility'); 670 $error_msg = _("Administrative error:") . '<br />' 671 . sprintf(_("The plugin %s has not been set up correctly."), 672 '"<strong>' . $plugin_name . '</strong>"') 673 . '<br />' 674 . _("Please read the README or INSTALL files that came with the plugin."); 675 sq_change_text_domain('squirrelmail'); 676 include_once($compatibility_sm_path . 'functions/display_messages.php'); 677 global $color; 678 plain_error_message($error_msg, $color); 679 exit; 680 } 681 682 return TRUE; 683 684} 685 686 687 688/** 689 * Validate Plugin Setup Utility 690 * 691 * Checks a plugin to see if the user has installed it 692 * correctly by checking for the existence of the given 693 * files (all relative from the plugin's directory) 694 * 695 * @param string $pluginName The name of the plugin as 696 * it is known to SquirrelMail, 697 * that is, it is the name 698 * of the plugin directory. 699 * @param array $configFiles An array of any files that the 700 * user should have set up for 701 * this plugin, for example: 702 * array('config.php') 703 * or: 704 * array('data/config.php', 'data/admins.php') 705 * where all files will be 706 * referenced from the plugin's 707 * main directory. 708 * It is also possible to give a 709 * full/direct path to a 710 * configuration file by placing 711 * a forward slash at the 712 * beginning of the file: 713 * array('/var/lib/squirrelmail/config/myplugin.conf') 714 * @param boolean $return_errors When true, any errors encountered 715 * will cause this function to return 716 * either FALSE or a string describing 717 * the error; otherwise, errors are 718 * handled herein by showing an error 719 * to the user and exiting (OPTIONAL; 720 * default is FALSE). 721 * 722 * @return mixed If no errors are found, TRUE is returned; if an error 723 * was found and $return_errors is TRUE, either FALSE or 724 * a string describing the error is returned. If $return_errors 725 * is FALSE and an error is found, this function will never 726 * return. 727 * 728 */ 729function check_plugin_setup($pluginName, $configFiles, $return_errors=FALSE) 730{ 731 732 global $compatibility_disable_config_check; 733 if ($compatibility_disable_config_check) return; 734 735 736 global $compatibility_sm_path; 737 738 739 // check one at a time... 740 // 741 foreach ($configFiles as $configFile) 742 { 743 744 if (strpos($configFile, '/') === 0) 745 $plugin_path = $configFile; 746 else 747 $plugin_path = $compatibility_sm_path . 'plugins/' . $pluginName . '/' . $configFile; 748 749 if (!file_exists($plugin_path)) 750 { 751 752 //if ($return_errors) return FALSE; 753 754 sq_change_text_domain('compatibility'); 755 756 if ($return_errors) 757 { 758 $error_msg = sprintf(_("The file %s is missing from plugin %s."), 759 '"<strong>' . $configFile . '</strong>"', 760 '"<strong>' . $pluginName . '</strong>"'); 761 sq_change_text_domain('squirrelmail'); 762 return $error_msg; 763 } 764 765 $error_msg = _("Administrative error:") . '<br />' 766 . sprintf(_("The plugin %s has not been set up correctly."), 767 '"<strong>' . $pluginName . '</strong>"') 768 . '<br />' 769 . sprintf(_("The file %s is missing."), 770 '"<strong>' . $configFile . '</strong>"') 771 . '<br />' 772 . _("Please read the README or INSTALL files that came with the plugin."); 773 sq_change_text_domain('squirrelmail'); 774 include_once($compatibility_sm_path . 'functions/display_messages.php'); 775 global $color; 776 plain_error_message($error_msg, $color); 777 exit; 778 779 } 780 781 } 782 783 return TRUE; 784 785} 786 787 788 789/** 790 * Test if a given file contains a given string. 791 * 792 * This can be used, for example, by plugins during the configtest hook 793 * that want to verify if a certain patch to the SquirrelMail core has 794 * been applied or not. 795 * 796 * The string is searched for using a regular expression to allow for 797 * more complex searches than direct string comparision. The $string 798 * parameter may contain regular expression syntax if desired. 799 * 800 * @param string $file The file to search (usually a full path). 801 * @param string $string The string to search for (can include regular 802 * expression syntax if desired - any special 803 * regular expression meta characters need to 804 * be escaped unless they are being used as such). 805 * @param boolean $quiet When TRUE and $file cannot be found or opened, 806 * this function returns FALSE, otherwise it 807 * will complain and exit (never return) (OPTIONAL; 808 * default is FALSE). 809 * 810 * @return boolean TRUE when $string was found or FALSE when it was not. 811 * When $quiet is TRUE, FALSE is also returned if the 812 * target file could not be located, opened or read. 813 * 814 */ 815function check_file_contents($file, $string, $quiet=FALSE) 816{ 817 818 if (check_php_version(4, 3, 0)) 819 { 820 $contents = file_get_contents($file); 821 if (!$contents) 822 if ($quiet) return FALSE; 823 else 824 { 825 echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!'; 826 exit; 827 } 828 } 829 else 830 { 831 $temp_contents = file($file); 832 if (!$temp_contents || !is_array($temp_contents)) 833 if ($quiet) return FALSE; 834 else 835 { 836 echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!'; 837 exit; 838 } 839 $contents = ''; 840 foreach ($temp_contents as $line) 841 $contents .= $line; 842 } 843 844 845 return preg_match('/' . $string . '/', $contents); 846 847} 848 849 850 851/** 852 * Returns the difference in times. Some small 853 * amount of precision might be lost in the + 854 * operations, but nothing serious. 855 * 856 * This is only a convenience function for plugin 857 * authors fine tuning performance and may not 858 * work on some operating systems. 859 * 860 * @param string $start The microtime() results for 861 * the start point. 862 * @param string $end The microtime() results for 863 * the end point (OPTIONAL; 864 * if empty defaults to the 865 * time NOW). 866 * 867 * @return float The difference between start and 868 * end points. 869 * 870 */ 871function sm_microtime_diff($start, $end=0) 872{ 873 874 if (empty($end)) $end = microtime(); 875 876 return (substr($end, 11) - substr($start, 11)) 877 + (substr($end, 0, 9) - substr($start, 0, 9)); 878 879} 880 881 882 883