[ Index ]
 

Code source de Typo3 4.1.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/t3lib/ -> class.t3lib_loadmodules.php (source)

   1  <?php
   2  /***************************************************************
   3  *  Copyright notice
   4  *
   5  *  (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
   6  *  All rights reserved
   7  *
   8  *  This script is part of the TYPO3 project. The TYPO3 project is
   9  *  free software; you can redistribute it and/or modify
  10  *  it under the terms of the GNU General Public License as published by
  11  *  the Free Software Foundation; either version 2 of the License, or
  12  *  (at your option) any later version.
  13  *
  14  *  The GNU General Public License can be found at
  15  *  http://www.gnu.org/copyleft/gpl.html.
  16  *  A copy is found in the textfile GPL.txt and important notices to the license
  17  *  from the author is found in LICENSE.txt distributed with these scripts.
  18  *
  19  *
  20  *  This script is distributed in the hope that it will be useful,
  21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23  *  GNU General Public License for more details.
  24  *
  25  *  This copyright notice MUST APPEAR in all copies of the script!
  26  ***************************************************************/
  27  /**
  28   * This document provides a class that loads the modules for the TYPO3 interface.
  29   *
  30   * $Id: class.t3lib_loadmodules.php 1770 2006-10-25 10:27:07Z typo3 $
  31   * Modifications by Rene Fritz, 2001
  32   * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
  33   *
  34   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
  35   * @internal
  36   */
  37  /**
  38   * [CLASS/FUNCTION INDEX of SCRIPT]
  39   *
  40   *
  41   *
  42   *   79: class t3lib_loadModules
  43   *   99:     function load($modulesArray,$BE_USER='')
  44   *  370:     function checkExtensionModule($name)
  45   *  389:     function checkMod($name, $fullpath)
  46   *  471:     function checkModAccess($name,$MCONF)
  47   *  495:     function checkModWorkspace($name,$MCONF)
  48   *  519:     function parseModulesArray($arr)
  49   *  548:     function cleanName ($str)
  50   *  559:     function getRelativePath($baseDir,$destDir)
  51   *
  52   * TOTAL FUNCTIONS: 8
  53   * (This index is automatically created/updated by the extension "extdeveval")
  54   *
  55   */
  56  
  57  
  58  
  59  
  60  
  61  
  62  
  63  
  64  
  65  
  66  
  67  
  68  /**
  69   * Load Backend Interface modules
  70   *
  71   * Typically instantiated like this:
  72   *         $this->loadModules = t3lib_div::makeInstance('t3lib_loadModules');
  73   *         $this->loadModules->load($TBE_MODULES);
  74   *
  75   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
  76   * @package TYPO3
  77   * @subpackage t3lib
  78   */
  79  class t3lib_loadModules {
  80      var $modules = Array();        // After the init() function this array will contain the structure of available modules for the backend user.
  81      var $absPathArray = array();    // Array with paths pointing to the location of modules from extensions
  82  
  83      var $modListGroup = Array();        // this array will hold the elements that should go into the select-list of modules for groups...
  84      var $modListUser = Array();        // this array will hold the elements that should go into the select-list of modules for users...
  85  
  86      var $BE_USER = '';    // The backend user for use internally
  87      var $observeWorkspaces = FALSE;        // If set true, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
  88  
  89  
  90      /**
  91       * Init.
  92       * The outcome of the load() function will be a $this->modules array populated with the backend module structure available to the BE_USER
  93       * Further the global var $LANG will have labels and images for the modules loaded in an internal array.
  94       *
  95       * @param    array        $modulesArray should be the global var $TBE_MODULES, $BE_USER can optionally be set to an alternative Backend user object than the global var $BE_USER (which is the currently logged in user)
  96       * @param    object        Optional backend user object to use. If not set, the global BE_USER object is used.
  97       * @return    void
  98       */
  99  	function load($modulesArray,$BE_USER='')    {
 100              // Setting the backend user for use internally
 101          if (is_object($BE_USER))    {
 102              $this->BE_USER = $BE_USER;
 103          } else {
 104              $this->BE_USER = $GLOBALS['BE_USER'];
 105          }
 106  
 107              /*
 108  
 109               $modulesArray might look like this when entering this function.
 110               Notice the two modules added by extensions - they have a path attached
 111  
 112              Array
 113              (
 114                  [web] => list,info,perm,func
 115                  [file] => list
 116                  [doc] =>
 117                  [user] =>
 118                  [tools] => em,install,txphpmyadmin
 119                  [help] => about
 120                  [_PATHS] => Array
 121                      (
 122                          [tools_install] => /www/htdocs/typo3/32/coreinstall/typo3/ext/install/mod/
 123                          [tools_txphpmyadmin] => /www/htdocs/typo3/32/coreinstall/typo3/ext/phpmyadmin/modsub/
 124                      )
 125  
 126              )
 127  
 128               */
 129              //
 130          $this->absPathArray = $modulesArray['_PATHS'];
 131          unset($modulesArray['_PATHS']);
 132  
 133              /*
 134                  With the above data for modules the result of this function call will be:
 135  
 136                  Array
 137                  (
 138                      [web] => Array
 139                          (
 140                              [0] => list
 141                              [1] => info
 142                              [2] => perm
 143                              [3] => func
 144                          )
 145  
 146                      [file] => Array
 147                          (
 148                              [0] => list
 149                          )
 150  
 151                      [doc] => 1
 152                      [user] => 1
 153                      [tools] => Array
 154                          (
 155                              [0] => em
 156                              [1] => install
 157                              [2] => txphpmyadmin
 158                          )
 159  
 160                      [help] => Array
 161                          (
 162                              [0] => about
 163                          )
 164  
 165                  )
 166              */
 167          $theMods = $this->parseModulesArray($modulesArray);
 168  
 169              /*
 170                  Originally modules were found in typo3/mod/
 171                  User defined modules were found in ../typo3conf/
 172  
 173                  Today almost all modules reside in extensions and they are found by the _PATHS array of the incoming $TBE_MODULES array
 174              */
 175              // Setting paths for 1) core modules (old concept from mod/) and 2) user-defined modules (from ../typo3conf)
 176          $paths = array();
 177          $paths['defMods'] = PATH_typo3.'mod/';    // Path of static modules
 178          $paths['userMods'] = PATH_typo3.'../typo3conf/';  // local modules (maybe frontend specific)
 179  
 180              // Traverses the module setup and creates the internal array $this->modules
 181          foreach($theMods as $mods => $subMod)    {
 182              $path = NULL;
 183  
 184              $extModRelPath = $this->checkExtensionModule($mods);
 185              if ($extModRelPath)    {    // EXTENSION module:
 186                  $theMainMod = $this->checkMod($mods,PATH_site.$extModRelPath);
 187                  if (is_array($theMainMod) || $theMainMod!='notFound')    {
 188                      $path = 1;    // ... just so it goes on... submodules cannot be within this path!
 189                  }
 190              } else {    // 'CLASSIC' module
 191                      // Checking for typo3/mod/ module existence...
 192                  $theMainMod = $this->checkMod($mods,$paths['defMods'].$mods);
 193                  if (is_array($theMainMod) || $theMainMod!='notFound')    {
 194                      $path = $paths['defMods'];
 195                  } else {
 196                          // If not typo3/mod/ then it could be user-defined in typo3conf/ ...?
 197                      $theMainMod = $this->checkMod($mods,$paths['userMods'].$mods);
 198                      if (is_array($theMainMod) || $theMainMod!='notFound')    {
 199                          $path = $paths['userMods'];
 200                      }
 201                  }
 202              }
 203  
 204                  // if $theMainMod is not set (false) there is no access to the module !(?)
 205              if ($theMainMod && !is_null($path))    {
 206                  $this->modules[$mods] = $theMainMod;
 207  
 208                      // SUBMODULES - if any - are loaded (The 'doc' module cannot have submodules...)
 209                  if ($mods!='doc' && is_array($subMod))    {
 210                      foreach($subMod as $valsub)    {
 211                          $extModRelPath = $this->checkExtensionModule($mods.'_'.$valsub);
 212                          if ($extModRelPath)    {    // EXTENSION submodule:
 213                              $theTempSubMod = $this->checkMod($mods.'_'.$valsub,PATH_site.$extModRelPath);
 214                              if (is_array($theTempSubMod))    {    // default sub-module in either main-module-path, be it the default or the userdefined.
 215                                  $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
 216                              }
 217                          } else {    // 'CLASSIC' submodule
 218                                  // Checking for typo3/mod/xxx/ module existence...
 219  // FIXME what about $path = 1; from above and using $path as string here?
 220                              $theTempSubMod = $this->checkMod($mods.'_'.$valsub,$path.$mods.'/'.$valsub);
 221                              if (is_array($theTempSubMod))    {    // default sub-module in either main-module-path, be it the default or the userdefined.
 222                                  $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
 223                              } elseif ($path == $paths['defMods'])    {        // If the submodule did not exist in the default module path, then check if there is a submodule in the submodule path!
 224                                  $theTempSubMod = $this->checkMod($mods.'_'.$valsub,$paths['userMods'].$mods.'/'.$valsub);
 225                                  if (is_array($theTempSubMod))    {
 226                                      $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
 227                                  }
 228                              }
 229                          }
 230                      }
 231                  }
 232              } else {    // This must be done in order to fill out the select-lists for modules correctly!!
 233                  if ($mods!='doc' && is_array($subMod))    {
 234                      foreach($subMod as $valsub)    {
 235  // FIXME path can only be NULL here, or not?
 236                          $this->checkMod($mods.'_'.$valsub,$path.$mods.'/'.$valsub);
 237                      }
 238                  }
 239              }
 240          }
 241      /*
 242          At this point $this->modules should look like this:
 243          Only modules which were accessible to the $BE_USER is listed in this array.
 244  
 245          Array
 246          (
 247              [web] => Array
 248                  (
 249                      [name] => web
 250                      [script] => dummy.php
 251                      [defaultMod] => list
 252                      [sub] => Array
 253                          (
 254                              [list] => Array
 255                                  (
 256                                      [name] => web_list
 257                                      [script] => mod/web/list/../../../db_list.php
 258                                  )
 259  
 260                              [info] => Array
 261                                  (
 262                                      [name] => web_info
 263                                      [script] => mod/web/info/index.php
 264                                  )
 265  
 266                              [perm] => Array
 267                                  (
 268                                      [name] => web_perm
 269                                      [script] => mod/web/perm/index.php
 270                                  )
 271  
 272                              [func] => Array
 273                                  (
 274                                      [name] => web_func
 275                                      [script] => mod/web/func/index.php
 276                                  )
 277  
 278                          )
 279  
 280                  )
 281  
 282              [file] => Array
 283                  (
 284                      [name] => file
 285                      [script] => dummy.php
 286                      [sub] => Array
 287                          (
 288                              [list] => Array
 289                                  (
 290                                      [name] => file_list
 291                                      [script] => mod/file/list/../../../file_list.php
 292                                  )
 293  
 294                          )
 295  
 296                  )
 297  
 298              [doc] => Array
 299                  (
 300                      [name] => doc
 301                      [script] => mod/doc/../../alt_doc.php
 302                  )
 303  
 304              [user] => Array
 305                  (
 306                      [name] => user
 307                      [script] => dummy.php
 308                      [defaultMod] => task
 309                  )
 310  
 311              [tools] => Array
 312                  (
 313                      [name] => tools
 314                      [script] => dummy.php
 315                      [sub] => Array
 316                          (
 317                              [em] => Array
 318                                  (
 319                                      [name] => tools_em
 320                                      [script] => mod/tools/em/index.php
 321                                  )
 322  
 323                              [install] => Array
 324                                  (
 325                                      [name] => tools_install
 326                                      [script] => ext/install/mod/../../../install/index.php
 327                                  )
 328  
 329                              [txphpmyadmin] => Array
 330                                  (
 331                                      [name] => tools_txphpmyadmin
 332                                      [script] => ext/phpmyadmin/modsub/index.php
 333                                  )
 334  
 335                          )
 336  
 337                  )
 338  
 339              [help] => Array
 340                  (
 341                      [name] => help
 342                      [script] => dummy.php
 343                      [defaultMod] => welcome
 344                      [sub] => Array
 345                          (
 346                              [about] => Array
 347                                  (
 348                                      [name] => help_about
 349                                      [script] => mod/help/about/index.php
 350                                  )
 351  
 352                          )
 353  
 354                  )
 355  
 356          )
 357  
 358      */
 359  
 360  #debug($this->modules);
 361  #debug($GLOBALS['LANG']->moduleLabels);
 362      }
 363  
 364      /**
 365       * If the module name ($name) is a module from an extension (has path in $this->absPathArray) then that path is returned relative to PATH_site
 366       *
 367       * @param    string        Module name
 368       * @return    string        If found, the relative path from PATH_site
 369       */
 370  	function checkExtensionModule($name)    {
 371          global $TYPO3_LOADED_EXT;
 372  
 373          if (isset($this->absPathArray[$name]))    {
 374              return ereg_replace ('\/$', '', substr($this->absPathArray[$name],strlen(PATH_site)));
 375          }
 376      }
 377  
 378      /**
 379       * Here we check for the module.
 380       * Return values:
 381       *     'notFound':    If the module was not found in the path (no "conf.php" file)
 382       *     false:        If no access to the module (access check failed)
 383       *     array():    Configuration array, in case a valid module where access IS granted exists.
 384       *
 385       * @param    string        Module name
 386       * @param    string        Absolute path to module
 387       * @return    mixed        See description of function
 388       */
 389  	function checkMod($name, $fullpath)    {
 390          $modconf=Array();
 391          $path = ereg_replace ('/[^/.]+/\.\./', '/', $fullpath); // because 'path/../path' does not work
 392          if (@is_dir($path) && @file_exists($path.'/conf.php'))     {
 393              $MCONF = array();
 394              $MLANG = array();
 395              include($path.'/conf.php');    // The conf-file is included. This must be valid PHP.
 396              if (!$MCONF['shy'] && $this->checkModAccess($name,$MCONF) && $this->checkModWorkspace($name,$MCONF))    {
 397                  $modconf['name']=$name;
 398                      // language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
 399                  if (is_object($GLOBALS['LANG']))    {
 400                          // $MLANG['default']['tabs_images']['tab'] is for modules the reference to the module icon.
 401                          // Here the path is transformed to an absolute reference.
 402                      if ($MLANG['default']['tabs_images']['tab'])    {
 403  
 404                              // Initializing search for alternative icon:
 405                          $altIconKey = 'MOD:'.$name.'/'.$MLANG['default']['tabs_images']['tab'];        // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
 406                          $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div::resolveBackPath(PATH_typo3.$GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
 407  
 408                              // Setting icon, either default or alternative:
 409                          if ($altIconAbsPath && @is_file($altIconAbsPath))    {
 410                              $MLANG['default']['tabs_images']['tab']=$this->getRelativePath(PATH_typo3,$altIconAbsPath);
 411                          } else {
 412                                  // Setting default icon:
 413                              $MLANG['default']['tabs_images']['tab']=$this->getRelativePath(PATH_typo3,$fullpath.'/'.$MLANG['default']['tabs_images']['tab']);
 414                          }
 415  
 416                              // Finally, setting the icon with correct path:
 417                          if (substr($MLANG['default']['tabs_images']['tab'],0,3)=='../')    {
 418                              $MLANG['default']['tabs_images']['tab'] = PATH_site.substr($MLANG['default']['tabs_images']['tab'],3);
 419                          } else {
 420                              $MLANG['default']['tabs_images']['tab'] = PATH_typo3.$MLANG['default']['tabs_images']['tab'];
 421                          }
 422                      }
 423  
 424                          // If LOCAL_LANG references are used for labels of the module:
 425                      if ($MLANG['default']['ll_ref'])    {
 426                              // Now the 'default' key is loaded with the CURRENT language - not the english translation...
 427                          $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_labels_tablabel');
 428                          $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_labels_tabdescr');
 429                          $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_tabs_tab');
 430                          $GLOBALS['LANG']->addModuleLabels($MLANG['default'],$name.'_');
 431                      } else {    // ... otherwise use the old way:
 432                          $GLOBALS['LANG']->addModuleLabels($MLANG['default'],$name.'_');
 433                          $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang],$name.'_');
 434                      }
 435                  }
 436  
 437                      // Default script setup
 438                  if ($MCONF['script']==='_DISPATCH')    {
 439                      $modconf['script'] = 'mod.php?M='.rawurlencode($name);
 440                  } elseif ($MCONF['script'] && @file_exists($path.'/'.$MCONF['script']))    {
 441                      $modconf['script'] = $this->getRelativePath(PATH_typo3,$fullpath.'/'.$MCONF['script']);
 442                  } else {
 443                      $modconf['script'] = 'dummy.php';
 444                  }
 445                      // Default tab setting
 446                  if ($MCONF['defaultMod'])    {
 447                      $modconf['defaultMod'] = $MCONF['defaultMod'];
 448                  }
 449                      // Navigation Frame Script (GET params could be added)
 450                  if ($MCONF['navFrameScript']) {
 451                      $navFrameScript = explode('?', $MCONF['navFrameScript']);
 452                      $navFrameScript = $navFrameScript[0];
 453                      if (@file_exists($path.'/'.$navFrameScript))    {
 454                          $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3,$fullpath.'/'.$MCONF['navFrameScript']);
 455                      }
 456                  }
 457                      // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
 458                  if ($MCONF['navFrameScriptParam']) {
 459                      $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
 460                  }
 461              } else return false;
 462          } else $modconf = 'notFound';
 463          return $modconf;
 464      }
 465  
 466      /**
 467       * Returns true if the internal BE_USER has access to the module $name with $MCONF (based on security level set for that module)
 468       *
 469       * @param    string        Module name
 470       * @param    array        MCONF array (module configuration array) from the modules conf.php file (contains settings about what access level the module has)
 471       * @return    boolean        True if access is granted for $this->BE_USER
 472       */
 473  	function checkModAccess($name,$MCONF)    {
 474          if ($MCONF['access'])    {
 475              $access=strtolower($MCONF['access']);
 476                  // Checking if admin-access is required
 477              if (strstr($access,'admin'))    {    // If admin-permissions is required then return true if user is admin
 478                  if ($this->BE_USER->isAdmin())    {return true;}
 479              }
 480                  // This will add modules to the select-lists of user and groups
 481              if (strstr($access,'user'))    {    $this->modListUser[]=$name;        }
 482              if (strstr($access,'group'))    {    $this->modListGroup[]=$name;    }
 483                  // This checks if a user is permitted to access the module
 484              if ($this->BE_USER->isAdmin() || $this->BE_USER->check('modules',$name))    {return true;}    // If admin you can always access a module
 485  
 486          } else return true;    // If conf[access] is not set, then permission IS granted!
 487      }
 488  
 489      /**
 490       * Check if a module is allowed inside the current workspace for be user
 491       * Processing happens only if $this->observeWorkspaces is TRUE
 492       *
 493       * @param    string        Module name
 494       * @param    array        MCONF array (module configuration array) from the modules conf.php file (contains settings about workspace restrictions)
 495       * @return    boolean        True if access is granted for $this->BE_USER
 496       */
 497  	function checkModWorkspace($name,$MCONF)    {
 498          if ($this->observeWorkspaces)    {
 499              $status = TRUE;
 500              if ($MCONF['workspaces'])    {
 501                  $status = FALSE;
 502                  if (($this->BE_USER->workspace===0 && t3lib_div::inList($MCONF['workspaces'],'online')) ||
 503                      ($this->BE_USER->workspace===-1 && t3lib_div::inList($MCONF['workspaces'],'offline')) ||
 504                      ($this->BE_USER->workspace>0 && t3lib_div::inList($MCONF['workspaces'],'custom')))    {
 505                          $status = TRUE;
 506                  }
 507              } elseif ($this->BE_USER->workspace===-99)    {
 508                  $status = FALSE;
 509              }
 510              return $status;
 511          } else return TRUE;
 512      }
 513  
 514      /**
 515       * Parses the moduleArray ($TBE_MODULES) into a internally useful structure.
 516       * Returns an array where the keys are names of the module and the values may be true (only module) or an array (of submodules)
 517       *
 518       * @param    array        moduleArray ($TBE_MODULES)
 519       * @return    array        Output structure with available modules
 520       */
 521  	function parseModulesArray($arr)    {
 522          $theMods = Array();
 523          if (is_array($arr))    {
 524              foreach($arr as $mod => $subs)    {
 525                  $mod = $this->cleanName($mod);        // clean module name to alphanum
 526                  if ($mod)    {
 527                      if ($subs)    {
 528                          $subsArr = t3lib_div::trimExplode(',', $subs);
 529                          foreach($subsArr as $subMod)    {
 530                              $subMod = $this->cleanName($subMod);
 531                              if ($subMod)    {
 532                                  $theMods[$mod][] = $subMod;
 533                              }
 534                          }
 535                      } else {
 536                          $theMods[$mod] = 1;
 537                      }
 538                  }
 539              }
 540          }
 541          return $theMods;
 542      }
 543  
 544      /**
 545       * The $str is cleaned so that it contains alphanumerical characters only. Modules must only consist of these characters
 546       *
 547       * @param    string        String to clean up
 548       * @return    string
 549       */
 550  	function cleanName ($str)    {
 551          return preg_replace('/[^a-z0-9]/i','',$str);
 552      }
 553  
 554      /**
 555       * Get relative path for $destDir compared to $baseDir
 556       *
 557       * @param    string        Base directory
 558       * @param    string        Destination directory
 559       * @return    string        The relative path of destination compared to base.
 560       */
 561  	function getRelativePath($baseDir,$destDir){
 562              // By Rene Fritz
 563              // a special case , the dirs are equals
 564          if ($baseDir == $destDir){
 565              return './';
 566          }
 567  
 568          $baseDir = ereg_replace ('^/', '', $baseDir);     // remove beginning
 569          $destDir = ereg_replace ('^/', '', $destDir);
 570  
 571          $found = true;
 572          $slash_pos=0;
 573  
 574          do {
 575              $slash_pos = strpos ($destDir, '/');
 576              if (substr($destDir, 0, $slash_pos) == substr($baseDir, 0, $slash_pos)){
 577                  $baseDir = substr($baseDir, $slash_pos+1);
 578                  $destDir = substr($destDir, $slash_pos+1);
 579              } else {
 580                  $found = false;
 581              }
 582          } while($found == true);
 583  
 584          $slashes = strlen ($baseDir) - strlen (str_replace('/', '', $baseDir));
 585          for($i=0;$i < $slashes;$i++)    {
 586              $destDir = '../'.$destDir;
 587          }
 588          return $destDir;
 589      }
 590  }
 591  
 592  
 593  if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php'])    {
 594      include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php']);
 595  }
 596  ?>


Généré le : Sun Nov 25 17:13:16 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics