| [ Index ] |
|
Code source de eZ Publish 3.9.0 |
1 <?php 2 // 3 // $Id$ 4 // 5 // Definition of eZINI class 6 // 7 // Created on: <12-Feb-2002 14:06:45 bf> 8 // 9 // SOFTWARE NAME: eZ publish 10 // SOFTWARE RELEASE: 3.9.0 11 // BUILD VERSION: 17785 12 // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS 13 // SOFTWARE LICENSE: GNU General Public License v2.0 14 // NOTICE: > 15 // This program is free software; you can redistribute it and/or 16 // modify it under the terms of version 2.0 of the GNU General 17 // Public License as published by the Free Software Foundation. 18 // 19 // This program is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU General Public License for more details. 23 // 24 // You should have received a copy of version 2.0 of the GNU General 25 // Public License along with this program; if not, write to the Free 26 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 27 // MA 02110-1301, USA. 28 // 29 // 30 31 /*! 32 \class eZINI ezini.php 33 \ingroup eZUtils 34 \brief Reads and writes .ini style configuration files 35 36 The most common way of using it is. 37 \code 38 // include the file 39 include_once( "classes/ezinifile.php" ); 40 41 $ini = eZINI::instance( "site.ini" ); 42 43 // get a variable from the file. 44 $iniVar = $ini->variable( "BlockName", "Variable" ); 45 46 \endcode 47 48 The default ini file is site.ini but others can be passed to the instance() function 49 among with some others. It will create one unique instance for each ini file and rootdir, 50 this means that the next time instance() is used with the same parameters the same 51 object will be returned and no new parsing is required. 52 53 The class will by default try to create a cache file in var/cache/ini, however to change 54 this behaviour the static setIsCacheEnabled() function can be used, or use the $useCache 55 parameter in instance() for setting this for one object only. 56 57 The class will also handle charset conversion using eZTextCodec, to turn this behaviour 58 off use the static setIsTextCodecEnabled() function or set the $useTextCodec parameter 59 in instance() for a per object basis setting. 60 61 Normally the eZINI class will not give out much information about what it's doing, 62 it's only when errors occur that you'll see this. To enable internal debugging use 63 the static setIsDebugEnabled() function. The class will then give information about 64 which files are load, if cache files are used and when cache files are written. 65 */ 66 67 include_once 'lib/ezutils/classes/ezdebug.php'; 68 include_once ( 'lib/ezfile/classes/ezdir.php' ); 69 70 /*! 71 Has the date of the current cache code implementation as a timestamp, 72 if this changes(increases) the cache files will need to be recreated. 73 */ 74 // define( "EZ_INI_CACHE_CODE_DATE", 1043407541 ); 75 define( "EZ_INI_CACHE_CODE_DATE", 1043407542 ); 76 define( "EZ_INI_DEBUG_INTERNALS", false ); 77 78 class eZINI 79 { 80 /*! 81 Initialization of object; 82 */ 83 function eZINI( $fileName, $rootDir = "", $useTextCodec = null, $useCache = null, $useLocalOverrides = null, $directAccess = false, $addArrayDefinition = false ) 84 { 85 $this->Charset = "utf8"; 86 if ( $fileName == "" ) 87 $fileName = "site.ini"; 88 if ( $rootDir !== false && $rootDir == "" ) 89 $rootDir = "settings"; 90 if ( $useCache === null ) 91 $useCache = eZINI::isCacheEnabled(); 92 if ( eZINI::isNoCacheAdviced() ) 93 { 94 $useCache = false; 95 } 96 if ( $useTextCodec === null ) 97 $useTextCodec = eZINI::isTextCodecEnabled(); 98 99 $this->UseTextCodec = $useTextCodec; 100 $this->Codec = null; 101 $this->FileName = $fileName; 102 $this->RootDir = $rootDir; 103 $this->UseCache = $useCache; 104 $this->DirectAccess = $directAccess; 105 $this->UseLocalOverrides = $useLocalOverrides; 106 $this->AddArrayDefinition = $addArrayDefinition; 107 108 if ( $this->UseLocalOverrides == true ) 109 { 110 $this->LocalOverrideDirArray = $GLOBALS["eZINIOverrideDirList"]; 111 } 112 113 $this->load(); 114 } 115 116 /*! 117 \return the filename. 118 */ 119 function filename() 120 { 121 return $this->FileName; 122 } 123 124 /*! 125 \static 126 \return true if INI cache is enabled globally, the default value is true. 127 Change this setting with setIsCacheEnabled. 128 */ 129 function isCacheEnabled() 130 { 131 if ( !isset( $GLOBALS['eZINICacheEnabled'] ) ) 132 $GLOBALS['eZINICacheEnabled'] = true; 133 return $GLOBALS['eZINICacheEnabled']; 134 } 135 136 /*! 137 \return true if cache is not adviced to be used. 138 \note The no-cache-adviced flag might not be modified in time for site.ini and some other important files to be affected. 139 */ 140 function isNoCacheAdviced() 141 { 142 if ( !isset( $GLOBALS['eZSiteBasics'] ) ) 143 return false; 144 $siteBasics = $GLOBALS['eZSiteBasics']; 145 if ( !isset( $siteBasics['no-cache-adviced'] ) ) 146 return false; 147 return $siteBasics['no-cache-adviced']; 148 } 149 150 /*! 151 \static 152 Sets whether caching is enabled for INI files or not. This setting is global 153 and can be overriden in the instance() function. 154 */ 155 function setIsCacheEnabled( $cache ) 156 { 157 $GLOBALS['eZINICacheEnabled'] = $cache; 158 } 159 160 /*! 161 \static 162 \return true if debugging of internals is enabled, this will display 163 which files are loaded and when cache files are created. 164 Set the option with setIsDebugEnabled(). 165 */ 166 function isDebugEnabled() 167 { 168 if ( !isset( $GLOBALS['eZINIDebugInternalsEnabled'] ) ) 169 $GLOBALS['eZINIDebugInternalsEnabled'] = EZ_INI_DEBUG_INTERNALS; 170 return $GLOBALS['eZINIDebugInternalsEnabled']; 171 } 172 173 /*! 174 \static 175 Sets whether internal debugging is enabled or not. 176 */ 177 function setIsDebugEnabled( $debug ) 178 { 179 $GLOBALS['eZINIDebugInternalsEnabled'] = $debug; 180 } 181 182 /*! 183 \static 184 \return true if textcodecs is to be used, this will use the eZTextCodec class 185 in the eZI18N library for text conversion. 186 Set the option with setIsTextCodecEnabled(). 187 */ 188 function isTextCodecEnabled() 189 { 190 if ( !isset( $GLOBALS['eZINITextCodecEnabled'] ) ) 191 $GLOBALS['eZINITextCodecEnabled'] = true; 192 return $GLOBALS['eZINITextCodecEnabled']; 193 } 194 195 /*! 196 \static 197 Sets whether textcodec conversion is enabled or not. 198 */ 199 function setIsTextCodecEnabled( $codec ) 200 { 201 $GLOBALS['eZINITextCodecEnabled'] = $codec; 202 } 203 204 /*! 205 \static 206 Check wether a specified parameter in a specified section is set in a specified file 207 \param filename (optional) 208 \param directory (optional) 209 \param section name 210 \param parameter name 211 \return true if the the parameter is set. 212 */ 213 function parameterSet( $fileName = 'site.ini', $rootDir = 'settings', &$section, &$parameter ) 214 { 215 if ( !eZINI::exists( $fileName, $rootDir ) ) 216 return false; 217 218 $iniInstance =& eZINI::instance( $fileName, $rootDir, null, null, null, true ); 219 return $iniInstance->hasVariable( $section, $parameter ); 220 } 221 222 /*! 223 \static 224 \return true if the INI file \a $fileName exists in the root dir \a $rootDir. 225 $fileName defaults to site.ini and rootDir to settings. 226 */ 227 function exists( $fileName = "site.ini", $rootDir = "settings" ) 228 { 229 if ( $fileName == "" ) 230 $fileName = "site.ini"; 231 if ( $rootDir == "" ) 232 $rootDir = "settings"; 233 if ( file_exists( $rootDir . '/' . $fileName ) ) 234 return true; 235 else if ( file_exists( $rootDir . '/' . $fileName . '.append' ) ) 236 return true; 237 else if ( file_exists( $rootDir . '/' . $fileName . '.append.php' ) ) 238 return true; 239 return false; 240 } 241 242 /*! 243 Tries to load the ini file specified in the constructor or instance() function. 244 If cache files should be used and a cache file is found it loads that instead. 245 Set \a $reset to false if you don't want to reset internal data. 246 */ 247 function load( $reset = true ) 248 { 249 if ( $this->UseCache ) 250 { 251 $this->loadCache( $reset ); 252 } 253 else 254 { 255 $this->parse( false, false, $reset ); 256 } 257 } 258 259 /*! 260 Tries to load the ini file placement specified in the constructor or instance() function. 261 If cache files should be used and a cache file is found it loads that instead. 262 Set \a $reset to false if you don't want to reset internal data. 263 */ 264 function loadPlacement( $reset = true ) 265 { 266 if ( $this->UseCache ) 267 { 268 $this->loadCache( $reset, true ); 269 } 270 else 271 { 272 $this->parse( false, false, $reset, true ); 273 } 274 } 275 276 /*! 277 \private 278 Looks trough all known settings and override folders to find relevant INI files. 279 The result is a list with expanded paths to the files. 280 \return the expanded file list. 281 */ 282 function findInputFiles( &$inputFiles, &$iniFile ) 283 { 284 if ( $this->RootDir !== false ) 285 $iniFile = eZDir::path( array( $this->RootDir, $this->FileName ) ); 286 else 287 $iniFile = eZDir::path( array( $this->FileName ) ); 288 289 $inputFiles = array(); 290 291 if ( $this->FileName == 'override.ini' ) 292 { 293 eZExtension::prependExtensionSiteAccesses( false, $this, true, false, false ); 294 } 295 296 if ( file_exists( $iniFile ) ) 297 $inputFiles[] = $iniFile; 298 299 // try the same file name with '.append.php' replace with '.append' 300 if ( preg_match('/^(.+.append).php$/i', $iniFile, $matches ) && file_exists( $matches[1] ) ) 301 $inputFiles[] = $matches[1]; 302 303 if ( file_exists ( $iniFile . '.php' ) ) 304 $inputFiles[] = $iniFile . '.php'; 305 306 if ( $this->DirectAccess ) 307 { 308 if ( file_exists ( $iniFile . '.append' ) ) 309 $inputFiles[] = $iniFile . '.append'; 310 311 if ( file_exists ( $iniFile . '.append.php' ) ) 312 $inputFiles[] = $iniFile . '.append.php'; 313 } 314 else 315 { 316 $overrideDirs = $this->overrideDirs(); 317 foreach ( $overrideDirs as $overrideDirItem ) 318 { 319 $overrideDir = $overrideDirItem[0]; 320 $isGlobal = $overrideDirItem[1]; 321 if ( $isGlobal ) 322 $overrideFile = eZDir::path( array( $overrideDir, $this->FileName ) ); 323 else 324 $overrideFile = eZDir::path( array( $this->RootDir, $overrideDir, $this->FileName ) ); 325 if ( file_exists( $overrideFile . '.php' ) ) 326 { 327 $inputFiles[] = $overrideFile . '.php'; 328 } 329 if ( file_exists( $overrideFile ) ) 330 $inputFiles[] = $overrideFile; 331 332 if ( $isGlobal ) 333 $overrideFile = eZDir::path( array( $overrideDir, $this->FileName . '.append' ) ); 334 else 335 $overrideFile = eZDir::path( array( $this->RootDir, $overrideDir, $this->FileName . '.append' ) ); 336 if ( file_exists( $overrideFile . '.php' ) ) 337 { 338 $inputFiles[] = $overrideFile . '.php'; 339 } 340 if ( file_exists( $overrideFile ) ) 341 $inputFiles[] = $overrideFile; 342 } 343 } 344 } 345 346 /*! 347 \private 348 Will load a cached version of the ini file if it exists, 349 if not it will parse the original file and create the cache file. 350 */ 351 function loadCache( $reset = true, $placement = false ) 352 { 353 eZDebug::accumulatorStart( 'ini', 'ini_load', 'Load cache' ); 354 if ( $reset ) 355 $this->reset(); 356 $cachedDir = "var/cache/ini/"; 357 358 eZDebug::accumulatorStart( 'ini_find_files', 'ini_load', 'FindInputFiles' ); 359 $this->findInputFiles( $inputFiles, $iniFile ); 360 eZDebug::accumulatorStop( 'ini_find_files' ); 361 if ( count( $inputFiles ) == 0 ) 362 { 363 eZDebug::accumulatorStop( 'ini' ); 364 return false; 365 } 366 367 /* if ( strstr( end( $inputFiles ), 'settings/override/' ) ) 368 { 369 $overrideINIFile = array_pop( $inputFiles ); 370 }*/ 371 372 $md5_input = ''; 373 foreach ( $inputFiles as $inputFile ) 374 { 375 $md5_input .= $inputFile. "\n"; 376 } 377 if ( $this->UseTextCodec ) 378 { 379 include_once ( "lib/ezi18n/classes/eztextcodec.php" ); 380 $md5_input .= '-' . eZTextCodec::internalCharset(); 381 } 382 if ( $placement ) 383 { 384 $md5_input .= '-placement'; 385 } 386 $fileName = md5( $md5_input ) . ".php"; 387 $cachedFile = $cachedDir . $fileName; 388 if ( $placement ) 389 { 390 $this->PlacementCacheFile = $cachedFile; 391 } 392 else 393 { 394 $this->CacheFile = $cachedFile; 395 } 396 397 $inputTime = false; 398 // check for modifications 399 foreach ( $inputFiles as $inputFile ) 400 { 401 $fileTime = filemtime( $inputFile ); 402 if ( $inputTime === false or 403 $fileTime > $inputTime ) 404 $inputTime = $fileTime; 405 } 406 407 $loadCache = false; 408 $cacheTime = false; 409 $fileInfo = @stat( $cachedFile ); 410 if ( $fileInfo ) 411 { 412 $cacheTime = $fileInfo['mtime']; 413 $loadCache = true; 414 if ( $cacheTime < $inputTime ) 415 { 416 $loadCache = false; 417 } 418 } 419 420 $useCache = false; 421 if ( $loadCache ) 422 { 423 $useCache = true; 424 if ( eZINI::isDebugEnabled() ) 425 eZDebug::writeNotice( "Loading cache '$cachedFile' for file '" . $this->FileName . "'", "eZINI" ); 426 $charset = null; 427 $blockValues = array(); 428 include( $cachedFile ); 429 if ( !isset( $val ) or 430 !isset( $eZIniCacheCodeDate ) or 431 $eZIniCacheCodeDate != EZ_INI_CACHE_CODE_DATE ) 432 { 433 if ( eZINI::isDebugEnabled() ) 434 eZDebug::writeNotice( "Old structure in cache file used, recreating '$cachedFile' to new structure", "eZINI" ); 435 $this->reset(); 436 $useCache = false; 437 } 438 else 439 { 440 $this->Charset = $charset; 441 $this->ModifiedBlockValues = array(); 442 if ( $placement ) 443 { 444 $this->BlockValuesPlacement = $val; 445 } 446 else 447 { 448 $this->BlockValues = $val; 449 } 450 unset( $val ); 451 } 452 } 453 if ( !$useCache ) 454 { 455 eZDebug::accumulatorStart( 'ini_files_1', 'ini_load', 'Parse' ); 456 $this->parse( $inputFiles, $iniFile, false, $placement ); 457 eZDebug::accumulatorStop( 'ini_files_1' ); 458 eZDebug::accumulatorStart( 'ini_files_2', 'ini_load', 'Save Cache' ); 459 $cacheSaved = $this->saveCache( $cachedDir, $cachedFile, $placement ? $this->BlockValuesPlacement : $this->BlockValues ); 460 eZDebug::accumulatorStop( 'ini_files_2' ); 461 462 if ( $cacheSaved ) 463 { 464 // Write log message to storage.log 465 include_once ( 'lib/ezutils/classes/ezlog.php' ); 466 eZLog::writeStorageLog( $fileName, $cachedDir ); 467 } 468 } 469 470 eZDebug::accumulatorStop( 'ini' ); 471 } 472 473 /*! 474 \private 475 Stores the content of the INI object to the cache file \a $cachedFile. 476 */ 477 function saveCache( $cachedDir, $cachedFile, $data ) 478 { 479 if ( !file_exists( $cachedDir ) ) 480 { 481 include_once ( 'lib/ezfile/classes/ezdir.php' ); 482 if ( !eZDir::mkdir( $cachedDir, 0777, true ) ) 483 { 484 eZDebug::writeError( "Couldn't create cache directory $cachedDir, perhaps wrong permissions", "eZINI" ); 485 return false; 486 } 487 } 488 // save the data to a cached file 489 $fp = @fopen( $cachedFile, "w+" ); 490 if ( $fp === false ) 491 { 492 eZDebug::writeError( "Couldn't create cache file '$cachedFile', perhaps wrong permissions", "eZINI" ); 493 return false; 494 } 495 fwrite( $fp, "<?php\n\$eZIniCacheCodeDate = " . EZ_INI_CACHE_CODE_DATE . ";\n" ); 496 497 if ( $this->Codec ) 498 fwrite( $fp, "\$charset = \"".$this->Codec->RequestedOutputCharsetCode."\";\n" ); 499 else 500 fwrite( $fp, "\$charset = \"$this->Charset\";\n" ); 501 502 fwrite( $fp, "\$val = " . preg_replace( "@\n[\s]+@", '', var_export( $data, true ) ) . ";" ); 503 fwrite( $fp, "\n?>" ); 504 fclose( $fp ); 505 if ( eZINI::isDebugEnabled() ) 506 eZDebug::writeNotice( "Wrote cache file '$cachedFile'", "eZINI" ); 507 508 return true; 509 } 510 511 /*! 512 \private 513 Parses either the override ini file or the standard file and then the append 514 override file if it exists. 515 */ 516 function parse( $inputFiles = false, $iniFile = false, $reset = true, $placement = false ) 517 { 518 if ( $reset ) 519 $this->reset(); 520 if ( $inputFiles === false or 521 $iniFile === false ) 522 $this->findInputFiles( $inputFiles, $iniFile ); 523 524 foreach ( $inputFiles as $inputFile ) 525 { 526 if ( file_exists( $inputFile ) ) 527 { 528 $this->parseFile( $inputFile, $placement ); 529 } 530 } 531 } 532 533 /*! 534 \private 535 Will parse the INI file and store the variables in the variable $this->BlockValues 536 */ 537 function parseFile( $file, $placement = false ) 538 { 539 if ( eZINI::isDebugEnabled() ) 540 eZDebug::writeNotice( "Parsing file '$file'", 'eZINI' ); 541 542 include_once ( "lib/ezfile/classes/ezfile.php" ); 543 $contents = eZFile::getContents( $file ); 544 if ( $contents === false ) 545 { 546 eZDebug::writeError( "Failed opening file '$file' for reading", "eZINI" ); 547 return false; 548 } 549 550 $contents = str_replace( "\r", '', $contents ); 551 $endOfLine = strpos( $contents, "\n" ); 552 $line = substr( $contents, 0, $endOfLine ); 553 554 $currentBlock = ""; 555 if ( $line ) 556 { 557 // check for charset 558 if ( preg_match( "/#\?ini(.+)\?/", $line, $ini_arr ) ) 559 { 560 $args = explode( " ", trim( $ini_arr[1] ) ); 561 foreach ( $args as $arg ) 562 { 563 $vars = explode( '=', trim( $arg ) ); 564 if ( $vars[0] == "charset" ) 565 { 566 $val = $vars[1]; 567 if ( $val[0] == '"' and 568 strlen( $val ) > 0 and 569 $val[strlen($val)-1] == '"' ) 570 $val = substr( $val, 1, strlen($val) - 2 ); 571 $this->Charset = $val; 572 } 573 } 574 } 575 } 576 577 unset( $this->Codec ); 578 if ( $this->UseTextCodec ) 579 { 580 include_once ( "lib/ezi18n/classes/eztextcodec.php" ); 581 $this->Codec =& eZTextCodec::instance( $this->Charset, false, false ); 582 583 if ( $this->Codec ) 584 { 585 eZDebug::accumulatorStart( 'ini_conversion', false, 'INI string conversion' ); 586 $contents = $this->Codec->convertString( $contents ); 587 eZDebug::accumulatorStop( 'ini_conversion', false, 'INI string conversion' ); 588 } 589 } 590 else 591 $this->Codec = null; 592 593 foreach ( explode( "\n", $contents ) as $line ) 594 { 595 if ( $line == '' or $line[0] == '#' ) 596 continue; 597 if ( preg_match( "/^(.+)##.*/", $line, $regs ) ) 598 $line = $regs[1]; 599 if ( trim( $line ) == '' ) 600 continue; 601 // check for new block 602 if ( preg_match("#^\[(.+)\]\s*$#", $line, $newBlockNameArray ) ) 603 { 604 $newBlockName = trim( $newBlockNameArray[1] ); 605 $currentBlock = $newBlockName; 606 continue; 607 } 608 609 // check for variable 610 if ( preg_match("#^(\w+)\\[\\]$#", $line, $valueArray ) ) 611 { 612 $varName = trim( $valueArray[1] ); 613 614 if ( $placement ) 615 { 616 if ( isset( $this->BlockValuesPlacement[$currentBlock][$varName] ) && 617 !is_array( $this->BlockValuesPlacement[$currentBlock][$varName] ) ) 618 { 619 eZDebug::writeError( "Wrong operation on the ini setting array '$varName'", 'eZINI' ); 620 continue; 621 } 622 623 $this->BlockValuesPlacement[$currentBlock][$varName][] = $file; 624 } 625 else 626 { 627 $this->BlockValues[$currentBlock][$varName] = array(); 628 629 // In direct access mode we create empty elements at the beginning of an array 630 // in case it is redefined in this ini file. So when we will save it, definition 631 // will be created as well. 632 if ( $this->AddArrayDefinition ) 633 { 634 $this->BlockValues[$currentBlock][$varName][] = ""; 635 } 636 } 637 } 638 else if ( preg_match("#^([a-zA-Z0-9_-]+)(\\[([^\\]]*)\\])?=(.*)$#", $line, $valueArray ) ) 639 { 640 $varName = trim( $valueArray[1] ); 641 $varValue = $valueArray[4]; 642 643 if ( $valueArray[2] ) 644 { 645 if ( $valueArray[3] ) 646 { 647 $keyName = $valueArray[3]; 648 if ( $placement ) 649 { 650 $this->BlockValuesPlacement[$currentBlock][$varName][$keyName] = $file; 651 } 652 else 653 { 654 $this->BlockValues[$currentBlock][$varName][$keyName] = $varValue; 655 } 656 } 657 else 658 { 659 if ( $placement ) 660 { 661 $this->BlockValuesPlacement[$currentBlock][$varName][] = $file; 662 } 663 else 664 { 665 $this->BlockValues[$currentBlock][$varName][] = $varValue; 666 } 667 } 668 } 669 else 670 { 671 if ( $placement ) 672 { 673 $this->BlockValuesPlacement[$currentBlock][$varName] = $file; 674 } 675 else 676 { 677 $this->BlockValues[$currentBlock][$varName] = $varValue; 678 } 679 } 680 } 681 } 682 } 683 684 /*! 685 \removes the cache file if it exists. 686 */ 687 function resetCache() 688 { 689 if ( file_exists( $this->CacheFile ) ) 690 unlink( $this->CacheFile ); 691 if ( file_exists( $this->PlacementCacheFile ) ) 692 unlink( $this->PlacementCacheFile ); 693 } 694 695 696 /*! 697 Saves the file to disk. 698 If filename is given the file is saved with that name if not the current name is used. 699 If \a $useOverride is true then the file will be placed in the override directory, 700 if \a $useOverride is "append" it will append ".append" to the filename. 701 */ 702 function save( $fileName = false, $suffix = false, $useOverride = false, 703 $onlyModified = false, $useRootDir = true, $resetArrays = false ) 704 { 705 include_once ( 'lib/ezfile/classes/ezdir.php' ); 706 $lineSeparator = eZSys::lineSeparator(); 707 $pathArray = array(); 708 $dirArray = array(); 709 if ( $fileName === false ) 710 $fileName = $this->FileName; 711 if ( $useRootDir === true ) 712 { 713 $pathArray[] = $this->RootDir; 714 $dirArray[] = $this->RootDir; 715 } 716 else if ( is_string( $useRootDir ) ) 717 { 718 $pathArray[] = $useRootDir; 719 $dirArray[] = $useRootDir; 720 } 721 if ( $useOverride ) 722 { 723 $pathArray[] = 'override'; 724 $dirArray[] = 'override'; 725 } 726 if ( is_string( $useOverride ) and 727 $useOverride == "append" ) 728 $fileName .= ".append"; 729 if ( $suffix !== false ) 730 $fileName .= $suffix; 731 732 /* Try to guess which filename would fit better: 'xxx.apend' or 'xxx.append.php'. 733 * We choose 'xxx.append.php' in all cases except when 734 * 'xxx.append' exists already and 'xxx.append.php' does not exist. 735 */ 736 if( strstr( $fileName, '.append' ) ) 737 { 738 $fnAppend = ereg_replace( '\.php$', '', $fileName ); 739 $fnAppendPhp = $fnAppend.'.php'; 740 $fpAppend = eZDir::path( array_merge( $pathArray, $fnAppend ) ); 741 $fpAppendPhp = eZDir::path( array_merge( $pathArray, $fnAppendPhp ) ); 742 $fileName = ( file_exists( $fpAppend ) && !file_exists( $fpAppendPhp ) ) 743 ? $fnAppend : $fnAppendPhp; 744 } 745 746 $originalFileName = $fileName; 747 $backupFileName = $originalFileName . eZSys::backupFilename(); 748 $fileName .= '.tmp'; 749 750 $dirPath = eZDir::path( $dirArray ); 751 if ( !file_exists( $dirPath ) ) 752 eZDir::mkdir( $dirPath, octdec( '777' ), true ); 753 754 include_once ( 'lib/ezfile/classes/ezdir.php' ); 755 $filePath = eZDir::path( array_merge( $pathArray, $fileName ) ); 756 $originalFilePath = eZDir::path( array_merge( $pathArray, $originalFileName ) ); 757 $backupFilePath = eZDir::path( array_merge( $pathArray, $backupFileName ) ); 758 759 $fp = @fopen( $filePath, "w+"); 760 if ( !$fp ) 761 { 762 eZDebug::writeError( "Failed opening file '$filePath' for writing", "eZINI" ); 763 return false; 764 } 765 $writeOK = true; 766 $written = 0; 767 768 if ( $this->Codec ) 769 $written = fwrite( $fp, "<?php /* #?ini charset=\"" . $this->Codec->RequestedOutputCharsetCode . "\"?$lineSeparator$lineSeparator" ); 770 else 771 $written = fwrite( $fp, "<?php /* #?ini charset=\"" . $this->Charset . "\"?$lineSeparator$lineSeparator" ); 772 if ( $written === false ) 773 $writeOK = false; 774 $i = 0; 775 if ( $writeOK ) 776 { 777 foreach( array_keys( $this->BlockValues ) as $blockName ) 778 { 779 if ( $onlyModified ) 780 { 781 $groupHasModified = false; 782 if ( isset( $this->ModifiedBlockValues[$blockName] ) ) 783 { 784 foreach ( $this->ModifiedBlockValues[$blockName] as $modifiedValue ) 785 { 786 if ( $modifiedValue ) 787 $groupHasModified = true; 788 } 789 } 790 if ( !$groupHasModified ) 791 continue; 792 } 793 $written = 0; 794 if ( $i > 0 ) 795 $written = fwrite( $fp, "$lineSeparator" ); 796 if ( $written === false ) 797 { 798 $writeOK = false; 799 break; 800 } 801 $written = fwrite( $fp, "[$blockName]$lineSeparator" ); 802 if ( $written === false ) 803 { 804 $writeOK = false; 805 break; 806 } 807 foreach( array_keys( $this->BlockValues[$blockName] ) as $blockVariable ) 808 { 809 if ( $onlyModified ) 810 { 811 if ( !isset( $this->ModifiedBlockValues[$blockName][$blockVariable] ) or 812 !$this->ModifiedBlockValues[$blockName][$blockVariable] ) 813 continue; 814 } 815 $varKey = $blockVariable; 816 $varValue = $this->BlockValues[$blockName][$blockVariable]; 817 if ( is_array( $varValue ) ) 818 { 819 if ( count( $varValue ) > 0 ) 820 { 821 $customResetArray = ( isset( $this->BlockValues[$blockName]['ResetArrays'] ) and 822 $this->BlockValues[$blockName]['ResetArrays'] == 'false' ) 823 ? true 824 : false; 825 if ( $resetArrays and !$customResetArray ) 826 $written = fwrite( $fp, "$varKey" . "[]$lineSeparator" ); 827 foreach ( $varValue as $varArrayKey => $varArrayValue ) 828 { 829 if ( is_string( $varArrayKey ) ) 830 $written = fwrite( $fp, "$varKey" . "[$varArrayKey]=$varArrayValue$lineSeparator" ); 831 else 832 { 833 if ( $varArrayValue == NULL ) 834 $written = fwrite( $fp, "$varKey" . "[]$lineSeparator" ); 835 else 836 $written = fwrite( $fp, "$varKey" . "[]=$varArrayValue$lineSeparator" ); 837 } 838 if ( $written === false ) 839 break; 840 } 841 } 842 else 843 $written = fwrite( $fp, "$varKey" . "[]$lineSeparator" ); 844 } 845 else 846 { 847 $written = fwrite( $fp, "$varKey=$varValue$lineSeparator" ); 848 } 849 if ( $written === false ) 850 { 851 $writeOK = false; 852 break; 853 } 854 } 855 if ( !$writeOK ) 856 break; 857 ++$i; 858 } 859 } 860 if ( $writeOK ) 861 { 862 $written = fwrite( $fp, "*/ ?>" ); 863 if ( $written === false ) 864 $writeOK = false; 865 } 866 @fclose( $fp ); 867 if ( !$writeOK ) 868 { 869 unlink( $filePath ); 870 return false; 871 } 872 873 $siteConfig =& eZINI::instance( 'site.ini' ); 874 $filePermissions = $siteConfig->variable( 'FileSettings', 'StorageFilePermissions'); 875 @chmod( $filePath, octdec( $filePermissions ) ); 876 877 if ( file_exists( $backupFilePath ) ) 878 unlink( $backupFilePath ); 879 if ( file_exists( $originalFilePath ) ) 880 { 881 if ( !rename( $originalFilePath, $backupFilePath ) ) 882 return false; 883 } 884 if ( !rename( $filePath, $originalFilePath ) ) 885 { 886 rename( $backupFilePath, $originalFilePath ); 887 return false; 888 } 889 890 return true; 891 } 892 893 /*! 894 Removes all read data from .ini files. 895 */ 896 function reset() 897 { 898 $this->BlockValues = array(); 899 $this->ModifiedBlockValues = array(); 900 } 901 902 /*! 903 \return the root directory from where all .ini and override files are read. 904 905 This is set by the instance() or eZINI() functions. 906 */ 907 function rootDir() 908 { 909 return $this->RootDir; 910 } 911 912 /*! 913 \return the override directories, if no directories has been set "override" is returned. 914 915 The override directories are returned as an array of arrays. The first 916 value in the array is the override directory, the second is a boolean which 917 defines if the directory is relative to the rootDir() or not. If the second value 918 is false the override dir is relative, true means that the override dir is relative 919 to the eZ publish root directory. 920 The third value of the array will contain the identifier of the override, if it exists. 921 Identifiers are useful if you want to overwrite the current override setting. 922 */ 923 function overrideDirs() 924 { 925 if ( $this->UseLocalOverrides == true ) 926 $dirs =& $this->LocalOverrideDirArray; 927 else 928 $dirs =& $GLOBALS["eZINIOverrideDirList"]; 929 930 if ( !isset( $dirs ) or !is_array( $dirs ) ) 931 $dirs = array( array( "override", false, false ) ); 932 return $dirs; 933 } 934 935 /*! 936 Appends the override directory \a $dir to the override directory list. 937 If global dir is set top 938 */ 939 function prependOverrideDir( $dir, $globalDir = false, $identifier = false ) 940 { 941 if ( eZINI::isDebugEnabled() ) 942 eZDebug::writeNotice( "Changing override dir to '$dir'", "eZINI" ); 943 944 if ( $this->UseLocalOverrides == true ) 945 $dirs =& $this->LocalOverrideDirArray; 946 else 947 $dirs =& $GLOBALS["eZINIOverrideDirList"]; 948 949 if ( !isset( $dirs ) or !is_array( $dirs ) ) 950 $dirs = array( array( 'override', false, false ) ); 951 952 // Check if the override with the current identifier already exists 953 $overrideOverwritten = false; 954 if ( $identifier !== false ) 955 { 956 foreach ( array_keys( $dirs ) as $dirKey ) 957 { 958 if ( $dirs[$dirKey][2] == $identifier ) 959 { 960 $dirs[$dirKey][0] = $dir; 961 $dirs[$dirKey][1] = $globalDir; 962 $overrideOverwritten = true; 963 } 964 } 965 } 966 967 if ( $overrideOverwritten == false ) 968 $dirs = array_merge( array( array( $dir, $globalDir, $identifier ) ), $dirs ); 969 970 $this->CacheFile = false; 971 } 972 973 /*! 974 Appends the override directory \a $dir to the override directory list. 975 */ 976 function appendOverrideDir( $dir, $globalDir = false, $identifier = false ) 977 { 978 if ( eZINI::isDebugEnabled() ) 979 eZDebug::writeNotice( "Changing override dir to '$dir'", "eZINI" ); 980 981 if ( $this->UseLocalOverrides == true ) 982 $dirs =& $this->LocalOverrideDirArray; 983 else 984 $dirs =& $GLOBALS["eZINIOverrideDirList"]; 985 986 if ( !isset( $dirs ) or !is_array( $dirs ) ) 987 $dirs = array( 'override', false, false ); 988 989 // Check if the override with the current identifier already exists 990 $overrideOverwritten = false; 991 if ( $identifier !== false ) 992 { 993 foreach ( array_keys( $dirs ) as $dirKey ) 994 { 995 if ( $dirs[$dirKey][2] == $identifier ) 996 { 997 $dirs[$dirKey][0] = $dir; 998 $dirs[$dirKey][1] = $globalDir; 999 $overrideOverwritten = true; 1000 } 1001 } 1002 } 1003 1004 if ( $overrideOverwritten == false ) 1005 $dirs[] = array( $dir, $globalDir, $identifier = false ); 1006 $this->CacheFile = false; 1007 } 1008 1009 /*! 1010 Reads a variable from the ini file and puts it in the parameter \a $variable. 1011 \note \a $variable is not modified if the variable does not exist 1012 */ 1013 function assign( $blockName, $varName, &$variable ) 1014 { 1015 if ( $this->hasVariable( $blockName, $varName ) ) 1016 $variable = $this->variable( $blockName, $varName ); 1017 else 1018 return false; 1019 return true; 1020 } 1021 1022 /*! 1023 Reads a variable from the ini file. 1024 false is returned if the variable was not found. 1025 */ 1026 function variable( $blockName, $varName ) 1027 { 1028 $ret = false; 1029 if ( !isset( $this->BlockValues[$blockName] ) ) 1030 eZDebug::writeError( "Undefined group: '$blockName'", "eZINI" ); 1031 else if ( isset( $this->BlockValues[$blockName][$varName] ) ) 1032 $ret = $this->BlockValues[$blockName][$varName]; 1033 else 1034 eZDebug::writeError( "Undefined variable: '$varName' in group '$blockName'", "eZINI" ); 1035 1036 return $ret; 1037 } 1038 1039 /*! 1040 Reads multiple variables from the ini file. 1041 false is returned if the variable was not found. 1042 */ 1043 function variableMulti( $blockName, $varNames, $signatures = array() ) 1044 { 1045 $ret = array(); 1046 1047 if ( !isset( $this->BlockValues[$blockName] ) ) 1048 { 1049 eZDebug::writeError( "Undefined group: '$blockName'", "eZINI" ); 1050 return false; 1051 } 1052 foreach ( $varNames as $key => $varName ) 1053 { 1054 if ( isset( $this->BlockValues[$blockName][$varName] ) ) 1055 { 1056 $ret[$key] = $this->BlockValues[$blockName][$varName]; 1057 1058 if ( isset( $signatures[$key] ) ) 1059 { 1060 switch ( $signatures[$key] ) 1061 { 1062 case 'enabled': 1063 $ret[$key] = $this->BlockValues[$blockName][$varName] == 'enabled'; 1064 break; 1065 } 1066 } 1067 } 1068 else 1069 { 1070 $ret[] = null; 1071 } 1072 } 1073 1074 return $ret; 1075 } 1076 1077 /*! 1078 Checks if a variable is set. Returns true if the variable exists, false if not. 1079 */ 1080 function hasVariable( $blockName, $varName ) 1081 { 1082 return isset( $this->BlockValues[$blockName][$varName] ); 1083 } 1084 1085 /*! 1086 Check if a block/section is set. Returns true if the section/block is set, false if not 1087 */ 1088 function hasSection( $sectionName ) 1089 { 1090 return is_array( $this->BlockValues[$sectionName] ); 1091 } 1092 1093 /*! 1094 \return true if the variable \a $varName in group \a $blockName has been modified. 1095 */ 1096 function isVariableModified( $blockName, $varName ) 1097 { 1098 return ( isset( $this->ModifiedBlockValues[$blockName][$varName] ) and 1099 $this->ModifiedBlockValues[$blockName][$varName] ); 1100 } 1101 1102 /*! 1103 Reads a variable from the ini file. The variable 1104 will be returned as an array. ; is used as delimiter. 1105 */ 1106 function &variableArray( $blockName, $varName ) 1107 { 1108 $ret = $this->variable( $blockName, $varName ); 1109 if ( is_array( $ret ) ) 1110 { 1111 $arr = array(); 1112 foreach ( $ret as $retItem ) 1113 { 1114 $arr[] = explode( ";", $retItem ); 1115 } 1116 $ret = $arr; 1117 } 1118 else if ( $ret !== false ) 1119 $ret = explode( ";", $ret ); 1120 1121 return $ret; 1122 } 1123 1124 /*! 1125 Checks if group $blockName is set. Returns true if the group exists, false if not. 1126 */ 1127 function hasGroup( $blockName ) 1128 { 1129 return isSet( $this->BlockValues[$blockName] ); 1130 } 1131 1132 /*! 1133 Fetches a variable group and returns it as an associative array. 1134 */ 1135 function &group( $blockName ) 1136 { 1137 if ( !isset( $this->BlockValues[$blockName] ) ) 1138 { 1139 eZDebug::writeError( "Unknown group: '$origBlockName'", "eZINI" ); 1140 $ret = null; 1141 return $ret; 1142 } 1143 $ret = $this->BlockValues[$blockName]; 1144 1145 return $ret; 1146 } 1147 1148 function isSettingReadOnly( $fileName = false, $blockName = false, $settingName = false ) 1149 { 1150 if ( !$this->readOnlySettingsCheck() ) 1151 return true; 1152 1153 $ini =& eZINI::instance(); 1154 if ( !$ini->hasVariable( 'eZINISettings', 'ReadonlySettingList' ) ) 1155 return true; 1156 1157 $fileName = $fileName === false ? $ini->FileName : $fileName; 1158 $fileNameExploded = explode( '.', $fileName ); 1159 $realFileName = $fileNameExploded[0] . '.' . $fileNameExploded[1]; 1160 $blockName = $blockName === false ? '*' : $blockName; 1161 $settingName = $settingName === false ? '*' : $settingName; 1162 $currentSetting = $realFileName . '/' . $blockName . '/' . $settingName; 1163 1164 $settingList = $ini->variable( 'eZINISettings', 'ReadonlySettingList' ); 1165 $settingList[] = 'site.ini/eZINISettings/*'; 1166 1167 $result = !( in_array( $realFileName . '/*' , $settingList ) or 1168 in_array( $realFileName . '/' . $blockName . '/*' , $settingList ) or 1169 in_array( $realFileName . '/' . $blockName . '/' . $settingName , $settingList ) ); 1170 1171 return $result; 1172 } 1173 /*! 1174 Removes the group and all it's settings from the .ini file 1175 */ 1176 function removeGroup( $blockName ) 1177 { 1178 unset( $this->BlockValues[$blockName] ); 1179 unset( $this->BlockValuesPlacement[$blockName] ); 1180 } 1181 1182 function removeSetting( $blockName, $settingName ) 1183 { 1184 unset( $this->BlockValues[$blockName][$settingName] ); 1185 unset( $this->BlockValuesPlacement[$blockName][$settingName] ); 1186 if ( $this->BlockValues[$blockName] == null ) 1187 $this->removeGroup( $blockName ); 1188 } 1189 1190 /*! 1191 Fetches all defined groups and returns them as an associative array 1192 */ 1193 function &groups() 1194 { 1195 return $this->BlockValues; 1196 } 1197 1198 /*! 1199 Fetches all defined placements for every setting and returns them as an associative array 1200 */ 1201 function &groupPlacements() 1202 { 1203 if ( !$this->BlockValuesPlacement ) 1204 { 1205 $this->loadPlacement(); 1206 } 1207 return $this->BlockValuesPlacement; 1208 } 1209 1210 function &findSettingPlacement( $path ) 1211 { 1212 if ( is_array( $path ) && count( $path ) ) 1213 $path = $path[0]; 1214 $exploded = explode( '/', $path ); 1215 $directoryCount = count( $exploded ); 1216 switch ( $directoryCount ) 1217 { 1218 case 2: 1219 $placement = 'default'; 1220 break; 1221 case 3: 1222 $placement = 'override'; 1223 break; 1224 case 4: 1225 { 1226 $placement = 'siteaccess'; 1227 if ( $exploded[0] == 'extension' ) 1228 $placement = 'extension:' . $exploded[1]; 1229 } 1230 break; 1231 default: 1232 $placement = 'undefined'; 1233 break; 1234 } 1235 return $placement; 1236 } 1237 1238 function settingType( $settingValue ) 1239 { 1240 if ( is_array( $settingValue ) ) 1241 return 'array'; 1242 1243 if ( is_numeric( $settingValue ) ) 1244 return 'numeric'; 1245 1246 if ( $settingValue == 'true' or $settingValue == 'false' ) 1247 { 1248 return 'true/false'; 1249 } 1250 if ( $settingValue == 'enabled' or $settingValue == 'disabled' ) 1251 { 1252 return 'enable/disable'; 1253 } 1254 1255 return 'string'; 1256 } 1257 1258 /*! 1259 Sets all groups overwriting the current values 1260 */ 1261 function setGroups( $groupArray ) 1262 { 1263 $resultArray = array(); 1264 // Check for readOnly 1265 foreach ( $groupArray as $blockName => $blockVariables ) 1266 { 1267 foreach ( $blockVariables as $variableName => $variableValue ) 1268 { 1269 if ( !$this->isSettingReadOnly( $this->FileName, $blockName, $variableName ) ) 1270 continue; 1271 $resultArray[$blockName][$variableName] = $variableValue; 1272 } 1273 } 1274 $this->BlockValues = $resultArray; 1275 } 1276 1277 /*! 1278 Sets multiple variables from the array \a $variables. 1279 \param $variables Contains an associative array with groups as first key, 1280 variable names as second key and variable values as values. 1281 \code 1282 $ini->setVariables( array( 'SiteSettings' => array( 'SiteName' => 'mysite', 1283 'SiteURL' => 'http://mysite.com' ) ) ); 1284 \encode 1285 \sa setVariable 1286 */ 1287 function setVariables( $variables ) 1288 { 1289 foreach ( $variables as $blockName => $blockVariables ) 1290 { 1291 foreach ( $blockVariables as $variableName => $variableValue ) 1292 { 1293 $this->setVariable( $blockName, $variableName, $variableValue ); 1294 } 1295 } 1296 } 1297 1298 /*! 1299 Sets an INI file variable. 1300 \code 1301 $ini->setVariable( 'SiteSettings', 'SiteName', 'mysite' ); 1302 \endcode 1303 \sa setVariables 1304 */ 1305 function setVariable( $blockName, $variableName, $variableValue ) 1306 { 1307 if ( !$this->isSettingReadOnly( $this->filename(), $blockName, $variableName ) ) 1308 return false; 1309 1310 $this->BlockValues[$blockName][$variableName] = $variableValue; 1311 $this->ModifiedBlockValues[$blockName][$variableName] = true; 1312 } 1313 1314 /*! 1315 Returns BlockValues, which is a nicely named Array 1316 */ 1317 function getNamedArray() 1318 { 1319 return $this->BlockValues; 1320 } 1321 1322 /*! 1323 \static 1324 \return true if the ini file \a $fileName has been loaded yet. 1325 */ 1326 function isLoaded( $fileName = "site.ini", $rootDir = "settings", $useLocalOverrides = null ) 1327 { 1328 $isLoaded =& $GLOBALS["eZINIGlobalIsLoaded-$rootDir-$fileName-$useLocalOverrides"]; 1329 if ( !isset( $isLoaded ) ) 1330 return false; 1331 return $isLoaded; 1332 } 1333 1334 /*! 1335 \static 1336 Returns the current instance of the given .ini file 1337 If $useLocalOverrides is set to true you will get a copy of the current overrides, 1338 but changes to the override settings will not be global. 1339 Direct access is for accessing the filename directly in the specified path. .append and .append.php is automaticly added to filename 1340 \note Use create() if you need to get a unique copy which you can alter. 1341 */ 1342 function &instance( $fileName = "site.ini", $rootDir = "settings", $useTextCodec = null, $useCache = null, $useLocalOverrides = null, $directAccess = false, $addArrayDefinition = false ) 1343 { 1344 $impl =& $GLOBALS["eZINIGlobalInstance-$rootDir-$fileName-$useLocalOverrides"]; 1345 $isLoaded =& $GLOBALS["eZINIGlobalIsLoaded-$rootDir-$fileName-$useLocalOverrides"]; 1346 1347 $class = get_class( $impl ); 1348 if ( $class != "ezini" ) 1349 { 1350 $isLoaded = false; 1351 1352 $impl = new eZINI( $fileName, $rootDir, $useTextCodec, $useCache, $useLocalOverrides, $directAccess, $addArrayDefinition ); 1353 1354 $isLoaded = true; 1355 } 1356 return $impl; 1357 } 1358 1359 /*! 1360 Fetches the ini file \a $fileName and returns the INI object for it. 1361 \note This will not use the override system or read cache files, this is a direct fetch from one file. 1362 */ 1363 function &fetchFromFile( $fileName, $useTextCodec = null ) 1364 { 1365 $impl = new eZINI( $fileName, false, $useTextCodec, false, false, true ); 1366 return $impl; 1367 } 1368 1369 /*! 1370 \static 1371 Similar to instance() but will always create a new copy. 1372 */ 1373 function &create( $fileName = "site.ini", $rootDir = "settings", $useTextCodec = null, $useCache = null, $useLocalOverrides = null ) 1374 { 1375 $impl = new eZINI( $fileName, $rootDir, $useTextCodec, $useCache, $useLocalOverrides ); 1376 return $impl; 1377 } 1378 1379 /*! 1380 Sets ReadonlySettingsCheck variable. 1381 */ 1382 function setReadOnlySettingsCheck( $readOnly = true ) 1383 { 1384 $this->ReadOnlySettingsCheck = $readOnly; 1385 } 1386 1387 /*! 1388 \return ReadonlySettingsCheck variable. 1389 */ 1390 function readOnlySettingsCheck() 1391 { 1392 return $this->ReadOnlySettingsCheck; 1393 } 1394 /// \privatesection 1395 /// The charset of the ini file 1396 var $Charset; 1397 1398 /// Variable to store the textcodec. 1399 var $Codec; 1400 1401 /// Variable to store the ini file values. 1402 var $BlockValues; 1403 1404 /// Variable to store the setting placement (which file is the setting in). 1405 var $BlockValuesPlacement; 1406 1407 /// Variable to store whether variables are modified or not 1408 var $ModifiedBlockValues; 1409 1410 /// Stores the filename 1411 var $FileName; 1412 1413 /// The root of all ini files 1414 var $RootDir; 1415 1416 /// Whether to use the text codec when reading the ini file or not 1417 var $UseTextCodec; 1418 1419 /// Stores the path and filename of the value cache file 1420 var $CacheFile; 1421 1422 /// Stores the path and filename of the placement cache file 1423 var $PlacementCacheFile; 1424 1425 /// true if cache should be used 1426 var $UseCache; 1427 1428 /// true if the overrides should only be changed locally 1429 var $UseLocalOverrides; 1430 1431 /// Contains the override dirs, if in local mode 1432 var $LocalOverrideDirArray; 1433 1434 /// If \c true then all file loads are done directly on the filename. 1435 var $DirectAccess; 1436 1437 /// If \c true empty element will be created in the beginning of array if it is defined in this ini file. 1438 var $AddArrayDefinition; 1439 1440 /// If \c true eZINI will check each setting (before saving) for correspondence of settings in site.ini[eZINISetting].ReadonlySettingList 1441 var $ReadOnlySettingsCheck = true; 1442 1443 } 1444 1445 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sat Feb 24 10:30:04 2007 | par Balluche grâce à PHPXref 0.7 |