web/lib/Zend/Config/Ini.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Config
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Ini.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  */
       
    21 
       
    22 
       
    23 /**
       
    24  * @see Zend_Config
       
    25  */
       
    26 require_once 'Zend/Config.php';
       
    27 
       
    28 
       
    29 /**
       
    30  * @category   Zend
       
    31  * @package    Zend_Config
       
    32  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    33  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    34  */
       
    35 class Zend_Config_Ini extends Zend_Config
       
    36 {
       
    37     /**
       
    38      * String that separates nesting levels of configuration data identifiers
       
    39      *
       
    40      * @var string
       
    41      */
       
    42     protected $_nestSeparator = '.';
       
    43 
       
    44     /**
       
    45      * String that separates the parent section name
       
    46      *
       
    47      * @var string
       
    48      */
       
    49     protected $_sectionSeparator = ':';
       
    50 
       
    51     /**
       
    52      * Whether to skip extends or not
       
    53      *
       
    54      * @var boolean
       
    55      */
       
    56     protected $_skipExtends = false;
       
    57 
       
    58     /**
       
    59      * Loads the section $section from the config file $filename for
       
    60      * access facilitated by nested object properties.
       
    61      *
       
    62      * If the section name contains a ":" then the section name to the right
       
    63      * is loaded and included into the properties. Note that the keys in
       
    64      * this $section will override any keys of the same
       
    65      * name in the sections that have been included via ":".
       
    66      *
       
    67      * If the $section is null, then all sections in the ini file are loaded.
       
    68      *
       
    69      * If any key includes a ".", then this will act as a separator to
       
    70      * create a sub-property.
       
    71      *
       
    72      * example ini file:
       
    73      *      [all]
       
    74      *      db.connection = database
       
    75      *      hostname = live
       
    76      *
       
    77      *      [staging : all]
       
    78      *      hostname = staging
       
    79      *
       
    80      * after calling $data = new Zend_Config_Ini($file, 'staging'); then
       
    81      *      $data->hostname === "staging"
       
    82      *      $data->db->connection === "database"
       
    83      *
       
    84      * The $options parameter may be provided as either a boolean or an array.
       
    85      * If provided as a boolean, this sets the $allowModifications option of
       
    86      * Zend_Config. If provided as an array, there are two configuration
       
    87      * directives that may be set. For example:
       
    88      *
       
    89      * $options = array(
       
    90      *     'allowModifications' => false,
       
    91      *     'nestSeparator'      => '->'
       
    92      *      );
       
    93      *
       
    94      * @param  string        $filename
       
    95      * @param  string|null   $section
       
    96      * @param  boolean|array $options
       
    97      * @throws Zend_Config_Exception
       
    98      * @return void
       
    99      */
       
   100     public function __construct($filename, $section = null, $options = false)
       
   101     {
       
   102         if (empty($filename)) {
       
   103             /**
       
   104              * @see Zend_Config_Exception
       
   105              */
       
   106             require_once 'Zend/Config/Exception.php';
       
   107             throw new Zend_Config_Exception('Filename is not set');
       
   108         }
       
   109 
       
   110         $allowModifications = false;
       
   111         if (is_bool($options)) {
       
   112             $allowModifications = $options;
       
   113         } elseif (is_array($options)) {
       
   114             if (isset($options['allowModifications'])) {
       
   115                 $allowModifications = (bool) $options['allowModifications'];
       
   116             }
       
   117             if (isset($options['nestSeparator'])) {
       
   118                 $this->_nestSeparator = (string) $options['nestSeparator'];
       
   119             }
       
   120             if (isset($options['skipExtends'])) {
       
   121                 $this->_skipExtends = (bool) $options['skipExtends'];
       
   122             }
       
   123         }
       
   124 
       
   125         $iniArray = $this->_loadIniFile($filename);
       
   126 
       
   127         if (null === $section) {
       
   128             // Load entire file
       
   129             $dataArray = array();
       
   130             foreach ($iniArray as $sectionName => $sectionData) {
       
   131                 if(!is_array($sectionData)) {
       
   132                     $dataArray = $this->_arrayMergeRecursive($dataArray, $this->_processKey(array(), $sectionName, $sectionData));
       
   133                 } else {
       
   134                     $dataArray[$sectionName] = $this->_processSection($iniArray, $sectionName);
       
   135                 }
       
   136             }
       
   137             parent::__construct($dataArray, $allowModifications);
       
   138         } else {
       
   139             // Load one or more sections
       
   140             if (!is_array($section)) {
       
   141                 $section = array($section);
       
   142             }
       
   143             $dataArray = array();
       
   144             foreach ($section as $sectionName) {
       
   145                 if (!isset($iniArray[$sectionName])) {
       
   146                     /**
       
   147                      * @see Zend_Config_Exception
       
   148                      */
       
   149                     require_once 'Zend/Config/Exception.php';
       
   150                     throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $filename");
       
   151                 }
       
   152                 $dataArray = $this->_arrayMergeRecursive($this->_processSection($iniArray, $sectionName), $dataArray);
       
   153 
       
   154             }
       
   155             parent::__construct($dataArray, $allowModifications);
       
   156         }
       
   157 
       
   158         $this->_loadedSection = $section;
       
   159     }
       
   160     
       
   161     /**
       
   162      * Load the INI file from disk using parse_ini_file(). Use a private error
       
   163      * handler to convert any loading errors into a Zend_Config_Exception
       
   164      * 
       
   165      * @param string $filename
       
   166      * @throws Zend_Config_Exception
       
   167      * @return array
       
   168      */
       
   169     protected function _parseIniFile($filename)
       
   170     {
       
   171         set_error_handler(array($this, '_loadFileErrorHandler'));
       
   172         $iniArray = parse_ini_file($filename, true); // Warnings and errors are suppressed
       
   173         restore_error_handler();
       
   174         
       
   175         // Check if there was a error while loading file
       
   176         if ($this->_loadFileErrorStr !== null) {
       
   177             /**
       
   178              * @see Zend_Config_Exception
       
   179              */
       
   180             require_once 'Zend/Config/Exception.php';
       
   181             throw new Zend_Config_Exception($this->_loadFileErrorStr);
       
   182         }
       
   183         
       
   184         return $iniArray;
       
   185     }
       
   186 
       
   187     /**
       
   188      * Load the ini file and preprocess the section separator (':' in the
       
   189      * section name (that is used for section extension) so that the resultant
       
   190      * array has the correct section names and the extension information is
       
   191      * stored in a sub-key called ';extends'. We use ';extends' as this can
       
   192      * never be a valid key name in an INI file that has been loaded using
       
   193      * parse_ini_file().
       
   194      *
       
   195      * @param string $filename
       
   196      * @throws Zend_Config_Exception
       
   197      * @return array
       
   198      */
       
   199     protected function _loadIniFile($filename)
       
   200     {
       
   201         $loaded = $this->_parseIniFile($filename);
       
   202         $iniArray = array();
       
   203         foreach ($loaded as $key => $data)
       
   204         {
       
   205             $pieces = explode($this->_sectionSeparator, $key);
       
   206             $thisSection = trim($pieces[0]);
       
   207             switch (count($pieces)) {
       
   208                 case 1:
       
   209                     $iniArray[$thisSection] = $data;
       
   210                     break;
       
   211 
       
   212                 case 2:
       
   213                     $extendedSection = trim($pieces[1]);
       
   214                     $iniArray[$thisSection] = array_merge(array(';extends'=>$extendedSection), $data);
       
   215                     break;
       
   216 
       
   217                 default:
       
   218                     /**
       
   219                      * @see Zend_Config_Exception
       
   220                      */
       
   221                     require_once 'Zend/Config/Exception.php';
       
   222                     throw new Zend_Config_Exception("Section '$thisSection' may not extend multiple sections in $filename");
       
   223             }
       
   224         }
       
   225 
       
   226         return $iniArray;
       
   227     }
       
   228 
       
   229     /**
       
   230      * Process each element in the section and handle the ";extends" inheritance
       
   231      * key. Passes control to _processKey() to handle the nest separator
       
   232      * sub-property syntax that may be used within the key name.
       
   233      *
       
   234      * @param  array  $iniArray
       
   235      * @param  string $section
       
   236      * @param  array  $config
       
   237      * @throws Zend_Config_Exception
       
   238      * @return array
       
   239      */
       
   240     protected function _processSection($iniArray, $section, $config = array())
       
   241     {
       
   242         $thisSection = $iniArray[$section];
       
   243 
       
   244         foreach ($thisSection as $key => $value) {
       
   245             if (strtolower($key) == ';extends') {
       
   246                 if (isset($iniArray[$value])) {
       
   247                     $this->_assertValidExtend($section, $value);
       
   248 
       
   249                     if (!$this->_skipExtends) {
       
   250                         $config = $this->_processSection($iniArray, $value, $config);
       
   251                     }
       
   252                 } else {
       
   253                     /**
       
   254                      * @see Zend_Config_Exception
       
   255                      */
       
   256                     require_once 'Zend/Config/Exception.php';
       
   257                     throw new Zend_Config_Exception("Parent section '$section' cannot be found");
       
   258                 }
       
   259             } else {
       
   260                 $config = $this->_processKey($config, $key, $value);
       
   261             }
       
   262         }
       
   263         return $config;
       
   264     }
       
   265 
       
   266     /**
       
   267      * Assign the key's value to the property list. Handles the
       
   268      * nest separator for sub-properties.
       
   269      *
       
   270      * @param  array  $config
       
   271      * @param  string $key
       
   272      * @param  string $value
       
   273      * @throws Zend_Config_Exception
       
   274      * @return array
       
   275      */
       
   276     protected function _processKey($config, $key, $value)
       
   277     {
       
   278         if (strpos($key, $this->_nestSeparator) !== false) {
       
   279             $pieces = explode($this->_nestSeparator, $key, 2);
       
   280             if (strlen($pieces[0]) && strlen($pieces[1])) {
       
   281                 if (!isset($config[$pieces[0]])) {
       
   282                     if ($pieces[0] === '0' && !empty($config)) {
       
   283                         // convert the current values in $config into an array
       
   284                         $config = array($pieces[0] => $config);
       
   285                     } else {
       
   286                         $config[$pieces[0]] = array();
       
   287                     }
       
   288                 } elseif (!is_array($config[$pieces[0]])) {
       
   289                     /**
       
   290                      * @see Zend_Config_Exception
       
   291                      */
       
   292                     require_once 'Zend/Config/Exception.php';
       
   293                     throw new Zend_Config_Exception("Cannot create sub-key for '{$pieces[0]}' as key already exists");
       
   294                 }
       
   295                 $config[$pieces[0]] = $this->_processKey($config[$pieces[0]], $pieces[1], $value);
       
   296             } else {
       
   297                 /**
       
   298                  * @see Zend_Config_Exception
       
   299                  */
       
   300                 require_once 'Zend/Config/Exception.php';
       
   301                 throw new Zend_Config_Exception("Invalid key '$key'");
       
   302             }
       
   303         } else {
       
   304             $config[$key] = $value;
       
   305         }
       
   306         return $config;
       
   307     }
       
   308 }