| [ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 3 /** 4 * Error code for a missing driver configuration. 5 */ 6 define('HORDE_ERROR_DRIVER_CONFIG_MISSING', 1); 7 8 /** 9 * Error code for an incomplete driver configuration. 10 */ 11 define('HORDE_ERROR_DRIVER_CONFIG', 2); 12 13 /** 14 * The Util:: class provides generally useful methods of different kinds. 15 * 16 * $Horde: framework/Util/Util.php,v 1.388 2005/01/12 15:51:12 chuck Exp $ 17 * 18 * Copyright 1999-2005 Chuck Hagenbuch <chuck@horde.org> 19 * Copyright 1999-2005 Jon Parise <jon@horde.org> 20 * 21 * See the enclosed file COPYING for license information (LGPL). If you 22 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 23 * 24 * @author Chuck Hagenbuch <chuck@horde.org> 25 * @author Jon Parise <jon@horde.org> 26 * @since Horde 3.0 27 * @package Horde_Util 28 */ 29 class Util { 30 31 /** 32 * Returns an object's clone. 33 * 34 * @param object &$obj The object to clone. 35 * 36 * @return object The cloned object. 37 */ 38 function &cloneObject(&$obj) 39 { 40 if (version_compare(zend_version(), '2', '>')) { 41 return clone($obj); 42 } else { 43 $newObj = $obj; 44 return $newObj; 45 } 46 } 47 48 /** 49 * Buffers the output from a function call, like readfile() or 50 * highlight_string(), that prints the output directly, so that instead it 51 * can be returned as a string and used. 52 * 53 * @access public 54 * 55 * @param string $function The function to run. 56 * @param mixed $arg1 First argument to $function(). 57 * @param mixed $arg2 Second argument to $function(). 58 * @param mixed $arg... ... 59 * @param mixed $argN Nth argument to $function(). 60 * 61 * @return string The output of the function. 62 */ 63 function bufferOutput() 64 { 65 if (func_num_args() == 0) { 66 return false; 67 } 68 $eval = false; 69 $args = func_get_args(); 70 $function = array_shift($args); 71 if (is_array($function)) { 72 if (!is_callable($function)) { 73 return false; 74 } 75 } elseif (($function == 'include') || 76 ($function == 'include_once') || 77 ($function == 'require') || 78 ($function == 'require_once')) { 79 $eval = true; 80 } elseif (!function_exists($function) && 81 ($function != 'eval')) { 82 return false; 83 } 84 85 ob_start(); 86 if ($eval) { 87 eval($function . " '" . implode(',', $args) . "';"); 88 } elseif ($function == 'eval') { 89 eval($args[0]); 90 } else { 91 call_user_func_array($function, $args); 92 } 93 $output = ob_get_contents(); 94 ob_end_clean(); 95 96 return $output; 97 } 98 99 /** 100 * Checks to see if a value has been set by the script and not by GET, 101 * POST, or cookie input. The value being checked MUST be in the global 102 * scope. 103 * 104 * @access public 105 * 106 * @param string $varname The variable name to check. 107 * 108 * @return mixed Null if the var is in user input, the variable value 109 * otherwise. 110 */ 111 function nonInputVar($varname) 112 { 113 if (isset($_GET[$varname]) || 114 isset($_POST[$varname]) || 115 isset($_COOKIE[$varname])) { 116 return null; 117 } else { 118 return isset($GLOBALS[$varname]) ? $GLOBALS[$varname] : null; 119 } 120 } 121 122 /** 123 * Adds a name=value pair to the end of an URL, taking care of whether 124 * there are existing parameters and whether to use ?, & or & as the 125 * glue. All data will be urlencoded. 126 * 127 * @access public 128 * 129 * @param string $url The URL to modify 130 * @param mixed $parameter Either the name=value pair to add 131 * (DEPRECATED) -or- 132 * the name value -or- 133 * an array of name/value pairs. 134 * @param string $value If specified, the value part ($parameter is 135 * then assumed to just be the parameter name). 136 * @param boolean $encode If true, and we don't have argument separators 137 * yet, the argument separator gets encoded. 138 * 139 * @return string The modified URL. 140 * 141 * @since Horde 2.1 142 */ 143 function addParameter($url, $parameter, $value = null, $encode = true) 144 { 145 if (empty($parameter)) { 146 return $url; 147 } 148 149 if (!is_array($parameter)) { 150 /* This is deprecated should be removed in the future. */ 151 if (is_null($value)) { 152 @list($parameter, $value) = explode('=', $parameter, 2); 153 } 154 $add = array($parameter => $value); 155 } else { 156 $add = $parameter; 157 } 158 159 $arg = $encode ? '&' : '&'; 160 if (($pos = strpos($url, '?')) === false) { 161 $glue = '?'; 162 } else { 163 /* Check if the argument separator has been already 164 * htmlentities-ized in the URL. */ 165 $query = substr($url, $pos + 1); 166 if (preg_match('/=.*?&.*?=/', $query)) { 167 $arg = '&'; 168 $query = strtr($query, array_flip(get_html_translation_table(HTML_ENTITIES))); 169 } elseif (preg_match('/=.*?&.*?=/', $query)) { 170 $arg = '&'; 171 } 172 $pairs = explode($arg, $query); 173 $params = array(); 174 foreach ($pairs as $pair) { 175 $pair = explode('=', $pair, 2); 176 $params[$pair[0]] = count($pair) == 2 ? $pair[1] : ''; 177 } 178 $glue = $arg; 179 } 180 181 $url_params = array(); 182 foreach ($add as $parameter => $value) { 183 if (!isset($params[$parameter])) { 184 if (is_array($value)) { 185 foreach ($value as $val) { 186 $url_params[] = urlencode($parameter) . '[]=' . urlencode($val); 187 } 188 } else { 189 $url_params[] = urlencode($parameter) . '=' . urlencode($value); 190 } 191 } 192 } 193 194 if (count($url_params)) { 195 return $url . $glue . implode($arg, $url_params); 196 } else { 197 return $url; 198 } 199 } 200 201 /** 202 * Removes name=value pairs from a URL. 203 * 204 * @access public 205 * 206 * @param string $url The URL to modify. 207 * @param mixed $remove Either a single parameter to remove or an array 208 * of parameters to remove. 209 * 210 * @return string The modified URL. 211 * 212 * @since Horde 2.2 213 */ 214 function removeParameter($url, $remove) 215 { 216 if (!is_array($remove)) { 217 $remove = array($remove); 218 } 219 220 /* Return immediately if there are no parameters to remove. */ 221 if (($pos = strpos($url, '?')) === false) { 222 return $url; 223 } 224 225 $entities = false; 226 list($url, $query) = explode('?', $url, 2); 227 228 /* Check if the argument separator has been already 229 * htmlentities-ized in the URL. */ 230 if (preg_match('/=.*?&.*?=/', $query)) { 231 $entities = true; 232 $query = strtr($query, array_flip(get_html_translation_table(HTML_ENTITIES))); 233 } 234 235 /* Get the list of parameters. */ 236 $pairs = explode('&', $query); 237 $params = array(); 238 foreach ($pairs as $pair) { 239 $pair = explode('=', $pair, 2); 240 $params[$pair[0]] = count($pair) == 2 ? $pair[1] : ''; 241 } 242 243 /* Remove the parameters. */ 244 foreach ($remove as $param) { 245 unset($params[$param]); 246 } 247 248 if (!count($params)) { 249 return $url; 250 } 251 252 /* Flatten arrays. 253 * FIXME: should handle more than one array level somehow. */ 254 $add = array(); 255 foreach ($params as $key => $val) { 256 if (is_array($val)) { 257 foreach ($val as $v) { 258 $add[] = $key . '[]=' . $v; 259 } 260 } else { 261 $add[] = $key . '=' . $val; 262 } 263 } 264 265 $query = implode('&', $add); 266 if ($entities) { 267 $query = htmlentities($query); 268 } 269 270 return $url . '?' . $query; 271 } 272 273 /** 274 * Returns a url with the 'nocache' parameter added, if the browser is 275 * buggy and caches old URLs. 276 * 277 * @access public 278 * 279 * @param string $url The URL to modify. 280 * 281 * @return string The requested URI. 282 */ 283 function nocacheUrl($url) 284 { 285 static $rand_num; 286 287 require_once 'Horde/Browser.php'; 288 $browser = &Browser::singleton(); 289 290 /* We may need to set a dummy parameter 'nocache' since some 291 * browsers do not always honor the 'no-cache' header. */ 292 if ($browser->hasQuirk('cache_same_url')) { 293 if (!isset($rand_num)) { 294 $rand_num = base_convert(microtime(), 10, 36); 295 } 296 return Util::addParameter($url, 'nocache', $rand_num); 297 } else { 298 return $url; 299 } 300 } 301 302 /** 303 * Returns a hidden form input containing the session name and id. 304 * 305 * @access public 306 * 307 * @param boolean $append_session 0 = only if needed, 1 = always. 308 * 309 * @return string The hidden form input, if needed/requested. 310 */ 311 function formInput($append_session = 0) 312 { 313 if ($append_session == 1 || 314 !isset($_COOKIE[session_name()])) { 315 return '<input type="hidden" name="' . htmlspecialchars(session_name()) . '" value="' . htmlspecialchars(session_id()) . "\" />\n"; 316 } else { 317 return ''; 318 } 319 } 320 321 /** 322 * Prints a hidden form input containing the session name and id. 323 * 324 * @access public 325 * 326 * @param boolean $append_session 0 = only if needed, 1 = always. 327 */ 328 function pformInput($append_session = 0) 329 { 330 echo Util::formInput($append_session); 331 } 332 333 /** 334 * If magic_quotes_gpc is in use, run stripslashes() on $var. 335 * 336 * @access public 337 * 338 * @param string &$var The string to un-quote, if necessary. 339 * 340 * @return string $var, minus any magic quotes. 341 */ 342 function dispelMagicQuotes(&$var) 343 { 344 static $magic_quotes; 345 346 if (!isset($magic_quotes)) { 347 $magic_quotes = get_magic_quotes_gpc(); 348 } 349 350 if ($magic_quotes) { 351 if (!is_array($var)) { 352 $var = stripslashes($var); 353 } else { 354 array_walk($var, array('Util', 'dispelMagicQuotes')); 355 } 356 } 357 358 return $var; 359 } 360 361 /** 362 * Gets a form variable from GET or POST data, stripped of magic quotes if 363 * necessary. If the variable is somehow set in both the GET data and the 364 * POST data, the value from the POST data will be returned and the GET 365 * value will be ignored. 366 * 367 * @access public 368 * 369 * @param string $var The name of the form variable to look for. 370 * @param string $default The value to return if the variable is not 371 * there. 372 * 373 * @return string The cleaned form variable, or $default. 374 */ 375 function getFormData($var, $default = null) 376 { 377 return (($val = Util::getPost($var)) !== null) 378 ? $val : Util::getGet($var, $default); 379 } 380 381 /** 382 * Gets a form variable from GET data, stripped of magic quotes if 383 * necessary. This function will NOT return a POST variable. 384 * 385 * @access public 386 * 387 * @param string $var The name of the form variable to look for. 388 * @param string $default The value to return if the variable is not 389 * there. 390 * 391 * @return string The cleaned form variable, or $default. 392 * 393 * @since Horde 2.2 394 */ 395 function getGet($var, $default = null) 396 { 397 return (isset($_GET[$var])) 398 ? Util::dispelMagicQuotes($_GET[$var]) 399 : $default; 400 } 401 402 /** 403 * Gets a form variable from POST data, stripped of magic quotes if 404 * necessary. This function will NOT return a GET variable. 405 * 406 * @access public 407 * 408 * @param string $var The name of the form variable to look for. 409 * @param string $default The value to return if the variable is not 410 * there. 411 * 412 * @return string The cleaned form variable, or $default. 413 * 414 * @since Horde 2.2 415 */ 416 function getPost($var, $default = null) 417 { 418 return (isset($_POST[$var])) 419 ? Util::dispelMagicQuotes($_POST[$var]) 420 : $default; 421 } 422 423 /** 424 * Determines the location of the system temporary directory. 425 * 426 * @access public 427 * 428 * @return string A directory name which can be used for temp files. 429 * Returns false if one could not be found. 430 */ 431 function getTempDir() 432 { 433 /* First, try PHP's upload_tmp_dir directive. */ 434 $tmp = ini_get('upload_tmp_dir'); 435 436 /* Otherwise, try to determine the TMPDIR environment 437 * variable. */ 438 if (empty($tmp)) { 439 $tmp = getenv('TMPDIR'); 440 } 441 442 /* If we still cannot determine a value, then cycle through a 443 * list of preset possibilities. */ 444 $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp', 445 'c:\windows\temp', 'c:\winnt\temp'); 446 while (empty($tmp) && count($tmp_locations)) { 447 $tmp_check = array_shift($tmp_locations); 448 if (@is_dir($tmp_check)) { 449 $tmp = $tmp_check; 450 } 451 } 452 453 /* If it is still empty, we have failed, so return false; 454 * otherwise return the directory determined. */ 455 return empty($tmp) ? false : $tmp; 456 } 457 458 /** 459 * Creates a temporary filename for the lifetime of the script, and 460 * (optionally) register it to be deleted at request shutdown. 461 * 462 * @param string $prefix Prefix to make the temporary name more 463 * recognizable. 464 * @param boolean $delete Delete the file at the end of the request? 465 * @param string $dir Directory to create the temporary file in. 466 * @param boolean $secure If deleting file, should we securely delete the 467 * file? 468 * 469 * @return string Returns the full path-name to the temporary file. 470 * Returns false if a temp file could not be created. 471 */ 472 function getTempFile($prefix = '', $delete = true, $dir = '', $secure = false) 473 { 474 if (empty($dir) || !is_dir($dir)) { 475 $tmp_dir = Util::getTempDir(); 476 } else { 477 $tmp_dir = $dir; 478 } 479 480 if (empty($tmp_dir)) { 481 return false; 482 } 483 484 $tmp_file = tempnam($tmp_dir, $prefix); 485 486 /* If the file was created, then register it for deletion and return */ 487 if (empty($tmp_file)) { 488 return false; 489 } else { 490 if ($delete) { 491 Util::deleteAtShutdown($tmp_file, true, $secure); 492 } 493 return $tmp_file; 494 } 495 } 496 497 /** 498 * Creates a temporary directory in the system's temporary directory. 499 * 500 * @access public 501 * 502 * @param boolean $delete Delete the temporary directory at the end of 503 * the request? 504 * @param string $temp_dir Use this temporary directory as the directory 505 * where the temporary directory will be created. 506 * 507 * @return string The pathname to the new temporary directory. 508 * Returns false if directory not created. 509 */ 510 function createTempDir($delete = true, $temp_dir = null) 511 { 512 if (is_null($temp_dir)) { 513 $temp_dir = Util::getTempDir(); 514 } 515 516 if (empty($temp_dir)) { 517 return false; 518 } 519 520 /* Get the first 8 characters of a random string to use as a temporary 521 directory name. */ 522 do { 523 $temp_dir .= '/' . substr(base_convert(mt_rand() . microtime(), 10, 36), 0, 8); 524 } while (file_exists($temp_dir)); 525 526 $old_umask = umask(0000); 527 if (!mkdir($temp_dir, 0700)) { 528 $temp_dir = false; 529 } elseif ($delete) { 530 Util::deleteAtShutdown($temp_dir); 531 } 532 umask($old_umask); 533 534 return $temp_dir; 535 } 536 537 /** 538 * Removes given elements at request shutdown. 539 * 540 * If called with a filename will delete that file at request shutdown; if 541 * called with a directory will remove that directory and all files in that 542 * directory at request shutdown. 543 * 544 * If called with no arguments, return all elements to be deleted (this 545 * should only be done by Util::_deleteAtShutdown). 546 * 547 * The first time it is called, it initializes the array and registers 548 * Util::_deleteAtShutdown() as a shutdown function - no need to do so 549 * manually. 550 * 551 * The second parameter allows the unregistering of previously registered 552 * elements. 553 * 554 * @access public 555 * 556 * @param string $filename The filename to be deleted at the end of the 557 * request. 558 * @param boolean $register If true, then register the element for 559 * deletion, otherwise, unregister it. 560 * @param boolean $secure If deleting file, should we securely delete 561 * the file? 562 */ 563 function deleteAtShutdown($filename = false, $register = true, 564 $secure = false) 565 { 566 static $dirs, $files, $securedel; 567 568 /* Initialization of variables and shutdown functions. */ 569 if (is_null($dirs)){ 570 $dirs = array(); 571 $files = array(); 572 $securedel = array(); 573 register_shutdown_function(array('Util', '_deleteAtShutdown')); 574 } 575 576 if ($filename) { 577 if ($register) { 578 if (@is_dir($filename)) { 579 $dirs[$filename] = true; 580 } else { 581 $files[$filename] = true; 582 } 583 if ($secure) { 584 $securedel[$filename] = true; 585 } 586 } else { 587 unset($dirs[$filename]); 588 unset($files[$filename]); 589 unset($securedel[$filename]); 590 } 591 } else { 592 return array($dirs, $files, $securedel); 593 } 594 } 595 596 /** 597 * Deletes registered files at request shutdown. 598 * 599 * This function should never be called manually; it is registered as a 600 * shutdown function by Util::deleteAtShutdown() and called automatically 601 * at the end of the request. It will retrieve the list of folders and 602 * files to delete from Util::deleteAtShutdown()'s static array, and then 603 * iterate through, deleting folders recursively. 604 * 605 * Contains code from gpg_functions.php. 606 * Copyright (c) 2002-2003 Braverock Ventures 607 * 608 * @access private 609 */ 610 function _deleteAtShutdown() 611 { 612 $registered = Util::deleteAtShutdown(); 613 $dirs = $registered[0]; 614 $files = $registered[1]; 615 $secure = $registered[2]; 616 617 foreach ($files as $file => $val) { 618 /* Delete files */ 619 if ($val && @file_exists($file)) { 620 /* Should we securely delete the file by overwriting the 621 data with a random string? */ 622 if (isset($secure[$file])) { 623 $random_str = ''; 624 for ($i = 0; $i < filesize($file); $i++) { 625 $random_str .= chr(mt_rand(0, 255)); 626 } 627 $fp = fopen($file, 'r+'); 628 fwrite($fp, $random_str); 629 fclose($fp); 630 } 631 @unlink($file); 632 } 633 } 634 635 foreach ($dirs as $dir => $val) { 636 /* Delete directories */ 637 if ($val && @file_exists($dir)) { 638 /* Make sure directory is empty. */ 639 $dir_class = dir($dir); 640 while (false !== ($entry = $dir_class->read())) { 641 if ($entry != '.' && $entry != '..') { 642 @unlink($dir . '/' . $entry); 643 } 644 } 645 $dir_class->close(); 646 @rmdir($dir); 647 } 648 } 649 } 650 651 /** 652 * Outputs javascript code to close the current window. 653 * 654 * @access public 655 * 656 * @param string $code Any addtional javascript code to run before 657 * closing the window. 658 */ 659 function closeWindowJS($code = '') 660 { 661 echo '<script language="JavaScript" type="text/javascript">' . $code . 662 'window.close();</script>'; 663 } 664 665 /** 666 * Caches the result of extension_loaded() calls. 667 * 668 * @access private 669 * 670 * @param string $ext The extension name. 671 * 672 * @return boolean Is the extension loaded? 673 */ 674 function extensionExists($ext) 675 { 676 static $cache = array(); 677 678 if (!isset($cache[$ext])) { 679 $cache[$ext] = extension_loaded($ext); 680 } 681 682 return $cache[$ext]; 683 } 684 685 /** 686 * Tries to load a PHP extension, behaving correctly for all operating 687 * systems. 688 * 689 * @param string $ext The extension to load. 690 * 691 * @return boolean True if the extension is now loaded, false if not. 692 * True can mean that the extension was already loaded, 693 * OR was loaded dynamically. 694 */ 695 function loadExtension($ext) 696 { 697 /* If $ext is already loaded, our work is done. */ 698 if (Util::extensionExists($ext)) { 699 return true; 700 } 701 702 /* See if we can call dl() at all, by the current ini settings. */ 703 if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { 704 return false; 705 } 706 707 if (substr(PHP_OS, 0, 3) == 'WIN') { 708 $suffix = 'dll'; 709 } else { 710 switch (PHP_OS) { 711 case 'HP-UX': 712 $suffix = 'sl'; 713 break; 714 715 case 'AIX': 716 $suffix = 'a'; 717 break; 718 719 case 'OSX': 720 $suffix = 'bundle'; 721 break; 722 723 default: 724 $suffix = 'so'; 725 } 726 } 727 728 return @dl($ext . '.' . $suffix) || @dl('php_' . $ext . '.' . $suffix); 729 } 730 731 /** 732 * Checks if all necessary parameters for a driver's configuration are set 733 * and returns a PEAR_Error if something is missing. 734 * 735 * @param array $params The configuration array with all parameters. 736 * @param array $fields An array with mandatory parameter names for this 737 * driver. 738 * @param string $name The clear text name of the driver. If not 739 * specified, the application name will be used. 740 * @param array $info A hash containing detailed information about the 741 * driver. Will be passed as the userInfo to the 742 * PEAR_Error. 743 */ 744 function assertDriverConfig($params, $fields, $name, $info = array()) 745 { 746 $info = array_merge($info, 747 array('params' => $params, 748 'fields' => $fields, 749 'name' => $name)); 750 751 if (!is_array($params) || !count($params)) { 752 require_once 'PEAR.php'; 753 return PEAR::throwError(sprintf(_("No configuration information specified for %s."), $name), 754 HORDE_ERROR_DRIVER_CONFIG_MISSING, 755 $info); 756 } 757 758 foreach ($fields as $field) { 759 if (!isset($params[$field])) { 760 require_once 'PEAR.php'; 761 return PEAR::throwError(sprintf(_("Required '%s' not specified in configuration."), $field, $name), 762 HORDE_ERROR_DRIVER_CONFIG, 763 $info); 764 } 765 } 766 } 767 768 /** 769 * Returns a format string to be used by strftime(). 770 * 771 * @param string $format A format string as used by date(). 772 * 773 * @return string A format string as similar as possible to $format. 774 */ 775 function date2strftime($format) 776 { 777 $dateSymbols = array('a', 'A', 'd', 'D', 'F', 'g', 'G', 'h', 'H', 'i', 'j', 'l', 'm', 'M', 'n', 'r', 's', 'T', 'w', 'W', 'y', 'Y', 'z', 'm/d/Y', 'M', "\n", 'g:i a', 'G:i', "\t", 'H:i:s', '%'); 778 $strftimeSymbols = array('%p', '%p', '%d', '%a', '%B', '%I', '%H', '%I', '%H', '%M', '%e', '%A', '%m', '%b', '%m', '%a, %e %b %Y %T %Z', '%S', '%Z', '%w', '%V', '%y', '%Y', '%j', '%D', '%h', '%n', '%r', '%R', '%t', '%T', '%%'); 779 780 $result = ''; 781 for ($pos = 0; $pos < strlen($format);) { 782 for ($symbol = 0; $symbol < count($dateSymbols); $symbol++) { 783 if (strpos($format, $dateSymbols[$symbol], $pos) === $pos) { 784 $result .= $strftimeSymbols[$symbol]; 785 $pos += strlen($dateSymbols[$symbol]); 786 continue 2; 787 } 788 } 789 $result .= substr($format, $pos, 1); 790 $pos++; 791 } 792 793 return $result; 794 } 795 796 /** 797 * Returns a format string to be used by date(). 798 * 799 * @param string $format A format string as used by strftime(). 800 * 801 * @return string A format string as similar as possible to $format. 802 */ 803 function strftime2date($format) 804 { 805 $dateSymbols = array('a', 'A', 'd', 'D', 'F', 'g', 'G', 'h', 'H', 'i', 'j', 'l', 'm', 'M', 'n', 'r', 's', 'T', 'w', 'W', 'y', 'Y', 'z', 'm/d/Y', 'M', "\n", 'g:i a', 'G:i', "\t", 'H:i:s', '%'); 806 $strftimeSymbols = array('%p', '%p', '%d', '%a', '%B', '%I', '%H', '%I', '%H', '%M', '%e', '%A', '%m', '%b', '%m', '%a, %e %b %Y %T %Z', '%S', '%Z', '%w', '%V', '%y', '%Y', '%j', '%D', '%h', '%n', '%r', '%R', '%t', '%T', '%%'); 807 808 return str_replace($strftimeSymbols, $dateSymbols, $format); 809 } 810 811 } 812 813 if (!function_exists('_')) { 814 function _($string) 815 { 816 return $string; 817 } 818 819 function bindtextdomain() 820 { 821 } 822 823 function textdomain() 824 { 825 } 826 827 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |