Source for file jConfigCompiler.class.php

Documentation is available at jConfigCompiler.class.php

  1. <?php
  2. /**
  3. @package      jelix
  4. @subpackage   core
  5. @author       Laurent Jouanneau
  6. @contributor  Thibault Piront (nuKs), Christophe Thiriot, Philippe Schelté
  7. @copyright    2006-2011 Laurent Jouanneau
  8. @copyright    2007 Thibault Piront, 2008 Christophe Thiriot, 2008 Philippe Schelté
  9. @link         http://www.jelix.org
  10. @licence      GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  11. */
  12.  
  13. /**
  14.  * jConfigCompiler merge two ini file in a single array and store it in a temporary file
  15.  * This is a static class
  16.  * @package  jelix
  17.  * @subpackage core
  18.  * @static
  19.  */
  20. class jConfigCompiler {
  21.  
  22.     static protected $commonConfig;
  23.  
  24.     private function __construct ()}
  25.  
  26.     /**
  27.      * read the given ini file, for the current entry point, or for the entrypoint given
  28.      * in $pseudoScriptName. Merge it with the content of defaultconfig.ini.php
  29.      * It also calculates some options.
  30.      * If you are in a CLI script but you want to load a configuration file for a web entry point
  31.      * or vice-versa, you need to indicate the $pseudoScriptName parameter with the name of the entry point
  32.      * @param string $configFile the config file name
  33.      * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  34.      *                                else should be false, these extra informations are
  35.      *                                not needed to run the application
  36.      * @param boolean $isCli  indicate if the configuration to read is for a CLI script or no
  37.      * @param string $pseudoScriptName the name of the entry point, relative to the base path,
  38.      *               corresponding to the readed configuration
  39.      * @return object an object which contains configuration values
  40.      */
  41.     static public function read($configFile$allModuleInfo false$isCli false$pseudoScriptName=''){
  42.  
  43.         $tempPath jApp::tempBasePath();
  44.         $configPath jApp::configPath();
  45.  
  46.         if($tempPath=='/'){
  47.             // if it equals to '/', this is because realpath has returned false in the application.init.php
  48.             // so this is because the path doesn't exist.
  49.             throw new Exception('Application temp directory doesn\'t exist !'3);
  50.         }
  51.  
  52.         if(!is_writable($tempPath)){
  53.             throw new Exception('Application temp base directory ('.$tempPath.') is not writable'4);
  54.         }
  55.  
  56.         self::$commonConfig jIniFile::read($configPath.'defaultconfig.ini.php',true);
  57.  
  58.         $config jIniFile::read(JELIX_LIB_CORE_PATH.'defaultconfig.ini.php');
  59.  
  60.         if (self::$commonConfig{
  61.             self::_mergeConfig($configself::$commonConfig);
  62.         }
  63.  
  64.         if($configFile !='defaultconfig.ini.php'){
  65.             if(!file_exists($configPath.$configFile))
  66.                 throw new Exception("Config file $configFile is missing !"5);
  67.             iffalse === ($userConfig parse_ini_file($configPath.$configFile,true)))
  68.                 throw new Exception("Syntax error in the config file $configFile !"6);
  69.             self::_mergeConfig($config$userConfig);
  70.         }
  71.         $config = (object) $config;
  72.  
  73.         self::prepareConfig($config$allModuleInfo$isCli$pseudoScriptName);
  74.         self::$commonConfig  null;
  75.         return $config;
  76.     }
  77.  
  78.     /**
  79.      * Identical to read(), but also stores the result in a temporary file
  80.      * @param string $configFile the config file name
  81.      * @param boolean $isCli 
  82.      * @param string $pseudoScriptName 
  83.      * @return object an object which contains configuration values
  84.      */
  85.     static public function readAndCache($configFile$isCli null$pseudoScriptName ''{
  86.  
  87.         if ($isCli === null)
  88.             $isCli (PHP_SAPI == 'cli');
  89.  
  90.         $config self::read($configFilefalse$isCli$pseudoScriptName);
  91.         $tempPath jApp::tempPath();
  92.         jFile::createDir($tempPath);
  93.  
  94.         if(BYTECODE_CACHE_EXISTS){
  95.             $filename=$tempPath.str_replace('/','~',$configFile).'.conf.php';
  96.             if ($f @fopen($filename'wb')) {
  97.                 fwrite($f'<?php $config = '.var_export(get_object_vars($config),true).";\n?>");
  98.                 fclose($f);
  99.             else {
  100.                 throw new Exception('(24)Error while writing config cache file '.$filename);
  101.             }
  102.         }else{
  103.             jIniFile::write(get_object_vars($config)$tempPath.str_replace('/','~',$configFile).'.resultini.php'";<?php die('');?>\n");
  104.         }
  105.         return $config;
  106.     }
  107.  
  108.     /**
  109.      * fill some config properties with calculated values
  110.      * @param object $config  the config object
  111.      * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  112.      *                                else should be false, these extra informations are
  113.      *                                not needed to run the application
  114.      * @param boolean $isCli  indicate if the configuration to read is for a CLI script or no
  115.      * @param string $pseudoScriptName the name of the entry point, relative to the base path,
  116.      *               corresponding to the readed configuration
  117.      */
  118.     static protected function prepareConfig($config$allModuleInfo$isCli$pseudoScriptName){
  119.  
  120.         $config->isWindows (DIRECTORY_SEPARATOR === '\\');
  121.         if(trim$config->startAction== ''{
  122.             $config->startAction ':';
  123.         }
  124.  
  125.         if ($config->domainName == "" && isset($_SERVER['SERVER_NAME']))
  126.             $config->domainName $_SERVER['SERVER_NAME'];
  127.  
  128.         $config->_allBasePath array();
  129.  
  130.         self::getPaths($config->urlengine$pseudoScriptName$isCli);
  131.         self::_loadModuleInfo($config$allModuleInfo);
  132.         self::_loadPluginsPathList($config);
  133.  
  134.         $coordplugins array();
  135.         foreach ($config->coordplugins as $name=>$conf{
  136.             if (!isset($config->_pluginsPathList_coord[$name])) {
  137.                 throw new Exception("Error in the main configuration. The coord plugin $name doesn't exist!"7);
  138.             }
  139.             if ($conf{
  140.                 if ($conf != '1' && !file_exists(jApp::configPath($conf))) {
  141.                     throw new Exception("Error in the main configuration. Configuration file '$conf' for coord plugin $name doesn't exist!"8);
  142.                 }
  143.                 $coordplugins[$name$conf;
  144.             }
  145.         }
  146.         $config->coordplugins $coordplugins;
  147.  
  148.         self::_initResponsesPath($config->responses);
  149.         self::_initResponsesPath($config->_coreResponses);
  150.  
  151.         if (trim($config->timeZone=== ''{
  152.             $tz ini_get('date.timezone');
  153.             if ($tz != '')
  154.                 $config->timeZone $tz;
  155.             else
  156.                 $config->timeZone "Europe/Paris";
  157.         }
  158.  
  159.         if($config->sessions['storage'== 'files'){
  160.             $config->sessions['files_path'str_replace(array('lib:','app:')array(LIB_PATHjApp::appPath())$config->sessions['files_path']);
  161.         }
  162.  
  163.         $config->sessions['_class_to_load'array();
  164.         if ($config->sessions['loadClasses'!= ''{
  165.             $list preg_split('/ *, */',$config->sessions['loadClasses']);
  166.             foreach($list as $sel{
  167.                 if(preg_match("/^([a-zA-Z0-9_\.]+)~([a-zA-Z0-9_\.\\/]+)$/"$sel$m)){
  168.                     if (!isset($config->_modulesPathList[$m[1]])) {
  169.                         throw new Exception('Error in config files, loadClasses: '.$m[1].' is not a valid or activated module');
  170.                     }
  171.  
  172.                     if( ($p=strrpos($m[2]'/')) !== false){
  173.                         $className substr($m[2],$p+1);
  174.                         $subpath substr($m[2],0,$p+1);
  175.                     }else{
  176.                         $className $m[2];
  177.                         $subpath ='';
  178.                     }
  179.  
  180.                     $path $config->_modulesPathList[$m[1]].'classes/'.$subpath.$className.'.class.php';
  181.  
  182.                     if (!file_exists($path|| strpos($subpath,'..'!== false {
  183.                         throw new Exception('Error in config files, loadClasses, bad class selector: '.$sel);
  184.                     }
  185.                     $config->sessions['_class_to_load'][$path;
  186.                 }
  187.                 else
  188.                     throw new Exception('Error in config files, loadClasses, bad class selector: '.$sel);
  189.             }
  190.         }
  191.  
  192.         /*if(preg_match("/^([a-zA-Z]{2})(?:_([a-zA-Z]{2}))?$/",$config->locale,$m)){
  193.             if(!isset($m[2])){
  194.                 $m[2] = $m[1];
  195.             }
  196.             $config->defaultLang = strtolower($m[1]);
  197.             $config->defaultCountry = strtoupper($m[2]);
  198.             $config->locale = $config->defaultLang.'_'.$config->defaultCountry;
  199.         }else{
  200.             throw new Exception("Syntax error in the locale parameter in config file $configFile !", 14);
  201.         }*/
  202.     }
  203.  
  204.     /**
  205.      * Analyse and check the "lib:" and "app:" path.
  206.      * @param object $config  the config object
  207.      * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  208.      *                                else should be false, these extra informations are
  209.      *                                not needed to run the application
  210.      */
  211.     static protected function _loadModuleInfo($config$allModuleInfo{
  212.  
  213.         $installerFile jApp::configPath('installer.ini.php');
  214.  
  215.         if ($config->disableInstallers{
  216.             $installation array ();
  217.         }
  218.         else if (!file_exists($installerFile)) {
  219.             if ($allModuleInfo)
  220.                 $installation array ();
  221.             else
  222.                 throw new Exception("installer.ini.php doesn't exist! You must install your application.\n"9);
  223.         }
  224.         else
  225.             $installation parse_ini_file($installerFile,true);
  226.  
  227.         $section $config->urlengine['urlScriptId'];
  228.  
  229.         if (!isset($installation[$section]))
  230.             $installation[$sectionarray();
  231.  
  232.         $list preg_split('/ *, */',$config->modulesPath);
  233.         if (isset(self::$commonConfig['modulesPath']))
  234.             $list array_merge($listpreg_split('/ *, */',self::$commonConfig['modulesPath']));
  235.         array_unshift($listJELIX_LIB_PATH.'core-modules/');
  236.         $pathChecked array();
  237.  
  238.         foreach($list as $k=>$path){
  239.             if(trim($path== ''continue;
  240.             $p str_replace(array('lib:','app:')array(LIB_PATHjApp::appPath())$path);
  241.             if (!file_exists($p)) {
  242.                 throw new Exception('The path, '.$path.' given in the jelix config, doesn\'t exist !'10);
  243.             }
  244.             if (substr($p,-1!='/')
  245.                 $p.='/';
  246.             if (in_array($p$pathChecked))
  247.                 continue;
  248.             $pathChecked[$p;
  249.  
  250.              // don't include the core-modules into the list of base path. this list is to verify
  251.              // if modules have been modified into repositories
  252.             if ($k!=&& $config->compilation['checkCacheFiletime'])
  253.                 $config->_allBasePath[]=$p;
  254.  
  255.             if ($handle opendir($p)) {
  256.                 while (false !== ($f readdir($handle))) {
  257.                     if ($f[0!= '.' && is_dir($p.$f)) {
  258.  
  259.                         if ($config->disableInstallers)
  260.                             $installation[$section][$f.'.installed'1;
  261.                         else if (!isset($installation[$section][$f.'.installed']))
  262.                             $installation[$section][$f.'.installed'0;
  263.  
  264.                         if ($f == 'jelix'{
  265.                             $config->modules['jelix.access'2// the jelix module should always be public
  266.                         }
  267.                         else {
  268.                             if ($config->enableAllModules{
  269.                                 if ($config->disableInstallers
  270.                                     || $installation[$section][$f.'.installed']
  271.                                     || $allModuleInfo)
  272.                                     $config->modules[$f.'.access'2;
  273.                                 else
  274.                                     $config->modules[$f.'.access'0;
  275.                             }
  276.                             else if (!isset($config->modules[$f.'.access'])) {
  277.                                 // no given access in defaultconfig and ep config
  278.                                 $config->modules[$f.'.access'0;
  279.                             }
  280.                             else if($config->modules[$f.'.access'== 0){
  281.                                 // we want to activate the module if it is not activated
  282.                                 // for the entry point, but is declared activated
  283.                                 // in the default config file. In this case, it means
  284.                                 // that it is activated for an other entry point,
  285.                                 // and then we want the possibility to retrieve its
  286.                                 // urls, at least
  287.                                 if (isset(self::$commonConfig['modules'][$f.'.access'])
  288.                                     && self::$commonConfig['modules'][$f.'.access'0)
  289.                                     $config->modules[$f.'.access'3;
  290.                             }
  291.                             else if (!$installation[$section][$f.'.installed']{
  292.                                 // module is not installed.
  293.                                 // outside installation mode, we force the access to 0
  294.                                 // so the module is unusable until it is installed
  295.                                 if (!$allModuleInfo)
  296.                                     $config->modules[$f.'.access'0;
  297.                             }
  298.                         }
  299.  
  300.                         if (!isset($installation[$section][$f.'.dbprofile']))
  301.                             $config->modules[$f.'.dbprofile''default';
  302.                         else
  303.                             $config->modules[$f.'.dbprofile'$installation[$section][$f.'.dbprofile'];
  304.  
  305.                         if ($allModuleInfo{
  306.                             if (!isset($installation[$section][$f.'.version']))
  307.                                 $installation[$section][$f.'.version''';
  308.  
  309.                             if (!isset($installation[$section][$f.'.dataversion']))
  310.                                 $installation[$section][$f.'.dataversion''';
  311.  
  312.                             if (!isset($installation['__modules_data'][$f.'.contexts']))
  313.                                 $installation['__modules_data'][$f.'.contexts''';
  314.  
  315.                             $config->modules[$f.'.version'$installation[$section][$f.'.version'];
  316.                             $config->modules[$f.'.dataversion'$installation[$section][$f.'.dataversion'];
  317.                             $config->modules[$f.'.installed'$installation[$section][$f.'.installed'];
  318.  
  319.                             $config->_allModulesPathList[$f]=$p.$f.'/';
  320.                         }
  321.  
  322.                         if ($config->modules[$f.'.access'== 3{
  323.                             $config->_externalModulesPathList[$f]=$p.$f.'/';
  324.                         }
  325.                         elseif ($config->modules[$f.'.access'])
  326.                             $config->_modulesPathList[$f]=$p.$f.'/';
  327.                     }
  328.                 }
  329.                 closedir($handle);
  330.             }
  331.         }
  332.     }
  333.  
  334.     /**
  335.      * Analyse plugin paths
  336.      * @param object $config the config container
  337.      */
  338.     static protected function _loadPluginsPathList($config{
  339.         $list preg_split('/ *, */',$config->pluginsPath);
  340.         array_unshift($listJELIX_LIB_PATH.'plugins/');
  341.         foreach($list as $k=>$path){
  342.             if(trim($path== ''continue;
  343.             $p str_replace(array('lib:','app:')array(LIB_PATHjApp::appPath())$path);
  344.             if(!file_exists($p)){
  345.                 trigger_error('The path, '.$path.' given in the jelix config, doesn\'t exists !',E_USER_ERROR);
  346.                 exit;
  347.             }
  348.             if(substr($p,-1!='/')
  349.                 $p.='/';
  350.  
  351.             if ($handle opendir($p)) {
  352.                 while (false !== ($f readdir($handle))) {
  353.                     if ($f[0!= '.' && is_dir($p.$f)) {
  354.                         if($subdir opendir($p.$f)){
  355.                             if($k!=&& $config->compilation['checkCacheFiletime'])
  356.                                $config->_allBasePath[]=$p.$f.'/';
  357.                             while (false !== ($subf readdir($subdir))) {
  358.                                 if ($subf[0!= '.' && is_dir($p.$f.'/'.$subf)) {
  359.                                     if($f == 'tpl'){
  360.                                         $prop '_tplpluginsPathList_'.$subf;
  361.                                         $config->{$prop}[$p.$f.'/'.$subf.'/';
  362.                                     }else{
  363.                                         $prop '_pluginsPathList_'.$f;
  364.                                         $config->{$prop}[$subf$p.$f.'/'.$subf.'/';
  365.                                     }
  366.                                 }
  367.                             }
  368.                             closedir($subdir);
  369.                         }
  370.                     }
  371.                 }
  372.                 closedir($handle);
  373.             }
  374.         }
  375.     }
  376.  
  377.     /**
  378.      * calculate miscelaneous path, depending of the server configuration and other informations
  379.      * in the given array : script path, script name, documentRoot ..
  380.      * @param array $urlconf  urlengine configuration. scriptNameServerVariable, basePath,
  381.      *  jelixWWWPath, jqueryPath and entrypointExtension should be present
  382.      */
  383.     static public function getPaths(&$urlconf$pseudoScriptName =''$isCli false{
  384.         // retrieve the script path+name.
  385.         // for cli, it will be the path from the directory were we execute the script (given to the php exec).
  386.         // for web, it is the path from the root of the url
  387.  
  388.         if ($pseudoScriptName{
  389.             $urlconf['urlScript'$pseudoScriptName;
  390.         }
  391.         else {
  392.             if($urlconf['scriptNameServerVariable'== ''{
  393.                 $urlconf['scriptNameServerVariable'self::findServerName($urlconf['entrypointExtension']$isCli);
  394.             }
  395.             $urlconf['urlScript'$_SERVER[$urlconf['scriptNameServerVariable']];
  396.         }
  397.         $lastslash strrpos ($urlconf['urlScript']'/');
  398.  
  399.         // now we separate the path and the name of the script, and then the basePath
  400.         if ($isCli{
  401.             if ($lastslash === false{
  402.                 $urlconf['urlScriptPath'($pseudoScriptNamejApp::appPath('/scripts/')getcwd().'/');
  403.                 $urlconf['urlScriptName'$urlconf['urlScript'];
  404.             }
  405.             else {
  406.                 $urlconf['urlScriptPath'getcwd().'/'.substr ($urlconf['urlScript']0$lastslash ).'/';
  407.                 $urlconf['urlScriptName'substr ($urlconf['urlScript']$lastslash+1);
  408.             }
  409.             $basepath $urlconf['urlScriptPath'];
  410.             $snp $urlconf['urlScriptName'];
  411.             $urlconf['urlScript'$basepath.$snp;
  412.         }
  413.         else {
  414.             $urlconf['urlScriptPath'substr ($urlconf['urlScript']0$lastslash ).'/';
  415.             $urlconf['urlScriptName'substr ($urlconf['urlScript']$lastslash+1);
  416.  
  417.             $basepath $urlconf['basePath'];
  418.             if ($basepath == ''{
  419.                 // for beginners or simple site, we "guess" the base path
  420.                 $basepath $localBasePath $urlconf['urlScriptPath'];
  421.             }
  422.             else {
  423.                 if ($basepath != '/'{
  424.                     if($basepath[0!= '/'$basepath='/'.$basepath;
  425.                     if(substr($basepath,-1!= '/'$basepath.='/';
  426.                 }
  427.  
  428.                 if ($pseudoScriptName{
  429.                     // with pseudoScriptName, we aren't in a true context, we could be in a cli context
  430.                     // (the installer), and we want the path like when we are in a web context.
  431.                     // $pseudoScriptName is supposed to be relative to the basePath
  432.                     $urlconf['urlScriptPath'substr($basepath,0,-1).$urlconf['urlScriptPath'];
  433.                     $urlconf['urlScript'$urlconf['urlScriptPath'].$urlconf['urlScriptName'];
  434.                 }
  435.                 $localBasePath $basepath;
  436.                 if ($urlconf['backendBasePath']{
  437.                     $localBasePath $urlconf['backendBasePath'];
  438.                     // we have to change urlScriptPath. it may contains the base path of the backend server
  439.                     // we should replace this base path by the basePath of the frontend server
  440.                     if (strpos($urlconf['urlScriptPath']$urlconf['backendBasePath']=== 0{
  441.                         $urlconf['urlScriptPath'$basepath.substr$urlconf['urlScriptPath']strlen($urlconf['backendBasePath']));
  442.                     }
  443.                     else  {
  444.                         $urlconf['urlScriptPath'$basepath.substr($urlconf['urlScriptPath']1);
  445.                     }
  446.  
  447.                 }elseif(strpos($urlconf['urlScriptPath']$basepath!== 0{
  448.                     throw new Exception('Jelix Error: basePath ('.$basepath.') in config file doesn\'t correspond to current base path. You should setup it to '.$urlconf['urlScriptPath']);
  449.                 }
  450.             }
  451.  
  452.             $urlconf['basePath'$basepath;
  453.  
  454.             if($urlconf['jelixWWWPath'][0!= '/')
  455.                 $urlconf['jelixWWWPath'$basepath.$urlconf['jelixWWWPath'];
  456.             if($urlconf['jqueryPath'][0!= '/')
  457.                 $urlconf['jqueryPath'$basepath.$urlconf['jqueryPath'];
  458.             $snp substr($urlconf['urlScript'],strlen($localBasePath));
  459.  
  460.             if ($localBasePath == '/')
  461.                 $urlconf['documentRoot'jApp::wwwPath();
  462.             else if(strpos(jApp::wwwPath()$localBasePath=== false{
  463.                 if (isset($_SERVER['DOCUMENT_ROOT']))
  464.                     $urlconf['documentRoot'$_SERVER['DOCUMENT_ROOT'];
  465.                 else
  466.                     $urlconf['documentRoot'jApp::wwwPath();
  467.             }
  468.             else
  469.                 $urlconf['documentRoot'substr(jApp::wwwPath()0(strlen($localBasePath)));
  470.         }
  471.  
  472.         $pos strrpos($snp$urlconf['entrypointExtension']);
  473.         if($pos !== false){
  474.             $snp substr($snp,0,$pos);
  475.         }
  476.         $urlconf['urlScriptId'$snp;
  477.         $urlconf['urlScriptIdenc'rawurlencode($snp);
  478.     }
  479.  
  480.     static public function findServerName($ext '.php'$isCli false{
  481.         $varname '';
  482.         $extlen strlen($ext);
  483.  
  484.         if(strrpos($_SERVER['SCRIPT_NAME']$ext=== (strlen($_SERVER['SCRIPT_NAME']$extlen)
  485.            || $isCli{
  486.             return 'SCRIPT_NAME';
  487.         }else if (isset($_SERVER['REDIRECT_URL'])
  488.                   && strrpos$_SERVER['REDIRECT_URL']$ext=== (strlen$_SERVER['REDIRECT_URL']-$extlen)) {
  489.             return 'REDIRECT_URL';
  490.         }else if (isset($_SERVER['ORIG_SCRIPT_NAME'])
  491.                   && strrpos$_SERVER['ORIG_SCRIPT_NAME']$ext=== (strlen$_SERVER['ORIG_SCRIPT_NAME']$extlen)) {
  492.             return 'ORIG_SCRIPT_NAME';
  493.         }
  494.         throw new Exception('In config file the parameter urlengine:scriptNameServerVariable is empty and Jelix doesn\'t find
  495.             the variable in $_SERVER which contains the script name. You must see phpinfo and setup this parameter in your config file.'11);
  496.     }
  497.  
  498.     /**
  499.      * get all physical paths of responses file
  500.      */
  501.     static private function _initResponsesPath(&$list){
  502.         $copylist $list// because we modify $list and then it will search for "foo.path" responses...
  503.         foreach($copylist as $type=>$class){
  504.             if(file_exists($path=JELIX_LIB_CORE_PATH.'response/'.$class.'.class.php')){
  505.                 $list[$type.'.path']=$path;
  506.             }elseif(file_exists($path=jApp::appPath('responses/'.$class.'.class.php'))){
  507.                 $list[$type.'.path']=$path;
  508.             }else{
  509.                 throw new Exception('Configuration Error: the class file of the response type "'.$type.'" is not found ('.$path.')',12);
  510.             }
  511.         }
  512.     }
  513.  
  514.     /**
  515.      * merge two array which are the result of a parse_ini_file call
  516.      * @param array $array the main array
  517.      * @param array $tomerge the array to merge in the first one
  518.      */
  519.     static private function _mergeConfig(&$array$tomerge){
  520.  
  521.         foreach($tomerge as $k=>$v){
  522.             if(!isset($array[$k])){
  523.                 $array[$k$v;
  524.                 continue;
  525.             }
  526.             if($k[1== '_')
  527.                 continue;
  528.             if(is_array($v)){
  529.                 $array[$karray_merge($array[$k]$v);
  530.             }else{
  531.                 $array[$k$v;
  532.             }
  533.         }
  534.  
  535.     }
  536. }

Documentation generated on Mon, 19 Sep 2011 14:12:02 +0200 by phpDocumentor 1.4.3