Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
ConfigTool.php
Go to the documentation of this file.
1 <?php
2 /*-------------------------------------------------------------------------------
3  * Xataface Web Application Framework
4  * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *-------------------------------------------------------------------------------
20  */
21 
31 require_once 'I18Nv2/I18Nv2.php';
32 
34 
35  var $configTypes = array('actions','fields','relationships','valuelists','tables','lang','metadata');
36  var $rawConfig = array();
37  var $config = array();
38  var $configLoaded = false;
39  var $iniLoaded = array();
40  var $configTableName = 'dataface__config';
41 
42  function Dataface_ConfigTool(){
43  $this->apc_load();
44  register_shutdown_function(array(&$this, 'apc_save'));
45  }
46 
50  var $nameLookup = array('actions'=>array(), 'fields'=>array(), 'table'=>array(), 'relationships'=>array(), 'valuelists'=>array(),'lang'=>array());
51 
52  public static function &getInstance(){
53  static $instance = 0;
54  if (!$instance ){
55  $instance = new Dataface_ConfigTool();
56  }
57  return $instance;
58  }
59 
66  function &loadConfig($type=null, $table=null){
67  $out =& $this->loadConfigFromINI($type, $table);
68  return $out;
69  }
70 
71 
79  function &loadConfigFromINI($type=null, $tablename='__global__'){
80  if ( !isset($tablename) ) $tablename = '__global__';
82  if ( $type == 'lang' ){
83  if ( isset($this->config[$type][$app->_conf['lang']][$tablename]) ){
84  return $this->config[$type][$app->_conf['lang']][$tablename];
85  }
86  } else {
87  if ( isset( $this->config[$type][$tablename] ) ){
88  return $this->config[$type][$tablename];
89  }
90  }
92  $paths = array();
93  $lpaths = array();
94  if ( $type === 'lang' ){
95 
96  if ( $tablename !== '__global__' ){
97  if ( !class_exists('Dataface_Table') ) import('Dataface/Table.php');
98  $lpaths[] = Dataface_Table::getBasePath($tablename).'/tables/'.basename($tablename).'/lang/'.basename($app->_conf['lang']).'.ini';
99 
100  } else {
101  $paths[] = DATAFACE_PATH.'/lang/'.basename($app->_conf['lang']).'.ini';
102  $lpaths[] = DATAFACE_SITE_PATH.'/lang/'.basename($app->_conf['lang']).'.ini';
103  }
104 
105  } else if ( $tablename !== '__global__' ){
106  //$paths = array(DATAFACE_SITE_PATH.'/tables/'.$tablename.'/'.$type.'.ini');
107  // Valuelists handle their own cascading because it involves loading
108  // the valuelist each time... and there may be opportunities to
109  // share between tables
110  if ( $type != 'valuelists' ) $paths[] = DATAFACE_PATH.'/'.basename($type).'.ini';
111  if ( $type != 'valuelists' ) $lpaths[] = DATAFACE_SITE_PATH.'/'.basename($type).'.ini';
112  $lpaths[] = Dataface_Table::getBasePath($tablename).'/tables/'.basename($tablename).'/'.basename($type).'.ini';
113 
114  } else {
115 
116  $paths[] = DATAFACE_PATH.'/'.basename($type).'.ini';
117  $lpaths[] = DATAFACE_SITE_PATH.'/'.basename($type).'.ini';
118  }
119 
120  // Add the ability to override settings in a module.
121  // Added Feb. 28, 2007 by Steve Hannah for version 0.6.14
122  if ( isset($app->_conf['_modules']) and count($app->_conf['_modules']) > 0 ){
123  foreach ( $app->_conf['_modules'] as $classname=>$path ){
124  $modpath = explode('_',$classname);
125  array_shift($modpath);
126  $modname = implode('_', $modpath);
127  if ( $type == 'lang' ){
128  $paths[] = DATAFACE_SITE_PATH.'/modules/'.basename($modname).'/lang/'.basename($app->_conf['lang']).'.ini';
129  $paths[] = DATAFACE_PATH.'/modules/'.basename($modname).'/lang/'.basename($app->_conf['lang']).'.ini';
130  } else {
131  $paths[] = DATAFACE_SITE_PATH.'/modules/'.basename($modname).'/'.basename($type).'.ini';
132  $paths[] = DATAFACE_PATH.'/modules/'.basename($modname).'/'.basename($type).'.ini';
133  }
134  }
135  }
136 
137  // Add the ability to override settings in the database.
138  // Added Feb. 27, 2007 by Steve Hannah for version 0.6.14
139  if ( @$app->_conf['enable_db_config'] and $type != 'permissions'){
140  if ( $type == 'lang' ){
141  if ( isset($tablename) ){
142  $lpaths[] = 'db:tables/'.basename($tablename).'/lang/'.basename($app->_conf['lang']);
143  } else {
144  $paths[] = 'db:lang/'.basename($app->_conf['lang']).'.ini';
145  }
146  } else {
147  if ( isset($tablename) ){
148  $paths[] = 'db:'.basename($type).'.ini';
149  $lpaths[] = 'db:tables/'.basename($tablename).'/'.basename($type).'.ini';
150  } else {
151  $paths[] = 'db:'.basename($type).'.ini';
152  }
153  }
154  }
155 
156  if ( !$tablename ){
157  $tablename = '__global__';
158 
159  }
160 
161  $paths = array_merge($paths, $lpaths);
162  //print_r($paths);
163  //print_r($lpaths);
164  if ( !isset( $this->config[$type][$tablename] ) ) $this->config[$type][$tablename] = array();
165  //import('Config.php');
166 
167  foreach ( $paths as $path ){
168  if ( !isset( $this->iniLoaded[$path] ) ){
169  $this->iniLoaded[$path] = true;
170 
171  if ( is_readable($path) || strstr($path,'db:') == $path ){
172 
173 
174  $config = $this->parse_ini_file($path, true);
175 
176  if ( isset( $config['charset'] ) and function_exists('iconv') ){
177  I18Nv2::recursiveIconv($config, $config['charset'], 'UTF-8');
178  }
179 
180 
181  if ( isset($config['__extends__']) ){
182  $config = array_merge_recursive_unique($this->loadConfigFromINI($type, $config['__extends__']), $config);
183  }
184 
185  $this->rawConfig[$path] =& $config;
186 
187  } else {
188  $config = array();
189  $this->rawConfig[$path] =& $config;
190  }
191  } else {
192  //echo "getting $path from raw config.";
193  //echo "$path already loaded:".implode(',', array_keys($this->iniLoaded));
194  $config =& $this->rawConfig[$path];
195  }
196 
197 
198  //echo "Conf for x".$path."x: ";
199  if ( !$config ) $config = array();
200 
201  foreach ( array_keys($config) as $entry ){
202  if ( $type == 'lang'){
203  $this->config[$type][$app->_conf['lang']][$tablename][$entry] =& $config[$entry];
204  } else {
205  $sep = null;
206  if ( strpos($entry, '>') !== false ){
207  $sep = '>';
208  }
209  if ( strpos($entry, ' extends ') !== false ){
210  $sep = ' extends ';
211  }
212  if ( $sep and is_array($config[$entry]) ){
213  list($newentry,$entryParents) = explode($sep, $entry);
214  $entryParents = array_map('trim',explode(',', $entryParents));
215  $newentry = trim($newentry);
216  $cout = array();
217  foreach ($entryParents as $entryParent){
218  if ( !isset($this->config[$type][$tablename][$entryParent]) ){
219  throw new Exception("Illegal extends. Parent not found: ".$entryParent." from rule: ".$entry." in ".$path);
220  }
221  $pconf =& $this->config[$type][$tablename][$entryParent];
222  if ( !is_array($pconf) ){
223  throw new Exception("Illegal extends. Parent is not a section. It is a scalar: ".$entryParent." from rule: ".$entry." in ".$path);
224 
225  }
226  foreach ($pconf as $pkey=>$pval){
227  $cout[$pkey] = $pval;
228  }
229  unset($pconf);
230 
231  }
232  $centry =& $config[$entry];
233  foreach ($centry as $ckey=>$cval){
234  $cout[$ckey] = $cval;
235  }
236  unset($centry);
237  unset($this->config[$type][$tablename][$entry]);
238  unset($this->config[$type][$tablename][$newentry]);
239  $this->config[$type][$tablename][$newentry] =& $cout;
240  unset($cout);
241 
242 
243  //$this->config[$type][$tablename][trim($newentry)] = array_merge($this->config[$type][$tablename][trim($entryParent)],$config[$entry]);
244  } else {
245  $this->config[$type][$tablename][$entry] =& $config[$entry];
246  }
247 
248  }
249  }
250 
251  unset($config);
252  }
253  if ( $type == 'lang' ){
254  return $this->config[$type][$app->_conf['lang']][$tablename];
255  } else {
256  return $this->config[$type][$tablename];
257  }
258 
259  }
260 
261  function apc_save(){
262  if ( function_exists('apc_store') and defined('DATAFACE_USE_CACHE') and DATAFACE_USE_CACHE ){
263  $res = apc_store($this->apc_hash().'$config', $this->config);
264  $res2 = apc_store($this->apc_hash().'$iniLoaded', $this->iniLoaded);
265 
266  }
267  }
268 
269  function apc_load(){
270  if ( function_exists('apc_fetch') and defined('DATAFACE_USE_CACHE') and DATAFACE_USE_CACHE ){
271  $this->config = apc_fetch($this->apc_hash().'$config');
272  $this->iniLoaded = apc_fetch($this->apc_hash().'$iniLoaded');
273  }
274  }
275 
276  function apc_hash(){
277  $appname = basename(DATAFACE_SITE_PATH);
278  return __FILE__.'-'.$appname;
279  }
280 
281 
282 
287  $tables_path = DATAFACE_SITE_PATH.'/tables';
288  $dir = dir($tables_path);
289  while ( false !== ( $entry = $dir->read() ) ){
290  if ( $entry === '.' || $entry === '..' ) continue;
291  $full_path = $tables_path.'/'.$entry;
292  if ( is_dir($full_path) ){
293  foreach ( $this->configTypes as $type ){
294  $this->loadConfigFromINI($type, $entry);
295  }
296  }
297  }
298  foreach ($this->configTypes as $type){
299  // load global properties.
300  $this->loadConfigFromINI($type, null);
301  }
302 
303  }
304 
305  function loadAllConfig(){
307  switch( strtolower($app->_conf['config_storage']) ){
308  case 'db':
309  case 'sql':
310  case 'database':
311  $this->loadConfigFromDB();
312  break;
313  case 'ini':
314  $this->loadAllConfigFromINI();
315  break;
316 
317  }
318 
319  }
320 
321 
322 
323  function parse_ini_file($path, $sections=false){
324  static $config = 0;
325  if ( !is_array($config) ){
326  $config = array();
327  }
328 
329 
330 
332  //echo "Checking for $path";
333  if ( strstr($path, 'db:') == $path ){
334  $path = substr($path, 3);
335  if ( !is_array($config) ){
336  $config = array();
337  if ( class_exists('Dataface_AuthenticationTool') ){
339  $username = $auth->getLoggedInUsername();
340  } else {
341  $username = null;
342  }
343 
344 
345  $sql = $this->buildConfigQuery($path, $username, $app->_conf['lang']);
346  $res = @mysql_query($sql, $app->db());
347  if (!$res ){
348  $this->createConfigTable();
349  $res = mysql_query($sql, $app->db());
350  }
351  if ( !$res ){
352  return $config;
353  }
354  while ( $row = mysql_fetch_assoc($res) ){
355  if ( !$row['section'] ){
356  $config[$row['file']][$row['key']] = $row['value'];
357  } else {
358  $config[$row['file']][$row['section']][$row['key']] = $row['value'];
359  }
360  }
361  @mysql_free_result($res);
362 
363 
364  }
365 
366  if ( !@$config[$path] ){
367 
368  return array();
369  }
370 
371  return $config[$path];
372 
373  } else {
374  if ( @$_GET['--refresh-apc'] or !(DATAFACE_EXTENSION_LOADED_APC && (filemtime($path) < apc_fetch($this->apc_hash().$path.'__mtime')) && ( $config[$path]=apc_fetch($this->apc_hash().$path) ) ) ){
375 
376 
377  //$config[$path] = parse_ini_file($path, $sections);
379  if ( DATAFACE_EXTENSION_LOADED_APC ){
380  apc_store($this->apc_hash().$path, $config[$path]);
381  apc_store($this->apc_hash().$path.'__mtime', time());
382  }
383  } else {
384  //
385  }
386 
387 
388  return $config[$path];
389 
390  }
391 
392  }
393 
394  function buildConfigQuery($path, $username, $lang, $where=null){
395  $sql = "select * from `".$this->configTableName."` where (`lang` IS NULL OR `lang` = '".$lang."') and ( `username` IS NULL";
396  if ( isset($username) ){
397  $sql .= " OR `username` = '".addslashes($username)."')";
398  } else {
399  $sql .= ')';
400  }
401  if ( isset($where) ) $sql .= ' and ('.$where.')';
402 
403 
404  $sql .= ' ORDER BY `priority`';
405  return $sql;
406  }
407 
408 
409  function createConfigTable(){
410  import('Dataface/ConfigTool/createConfigTable.function.php');
412  }
413 
414  function setConfigParam($file, $section, $key, $value, $username=null, $lang=null, $priority=5){
415  import('Dataface/ConfigTool/setConfigParam.function.php');
416  return Dataface_ConfigTool_setConfigParam($file, $section, $key, $value, $username, $lang, $priority);
417  }
418 
419  function clearConfigParam($file, $section, $key, $value, $username=null, $lang=null){
420  import('Dataface/ConfigTool/clearConfigParam.function.php');
421  return Dataface_ConfigTool_setConfigParam($file, $section, $key, $value, $username, $lang);
422  }
423 
424 }
425 
426 
427 
428 class INIParser {
429  private $keys = array();
430  private function replace_key($matches){
431  $this->keys[] = trim($matches[1]);
432  return 'keys'.(count($this->keys)-1).'=';
433  }
434 
435  private function replace_section($matches){
436  $this->keys[] = trim($matches[1]);
437  return '[keys'.(count($this->keys)-1).']';
438  }
439 
440  private function return_key($matches){
441  $index = intval($matches[1]);
442  if ( isset($this->keys[$index]) ){
443  return $this->keys[$index].'=';
444  } else {
445  return $matches[0];
446  }
447  }
448 
449 
450  private function refill_array($ini){
451  foreach ( $ini as $key=>$val){
452  if ( is_array($val) ){
453 
454  $val = $this->refill_array($val);
455 
456  } else {
457  $val = preg_replace_callback('/^keys(\d+)=/m', array($this, 'return_key'), $val);
458  }
459  $index = intval(substr($key, 4));
460  if ( isset($this->keys[$index]) ){
461  unset($ini[$key]);
462  $ini[$this->keys[$index]] = $val;
463  } else {
464  $ini[$key] = $val;
465  }
466  }
467  return $ini;
468  }
469 
470 
471  private function parse($file, $sections=false){
472  $this->keys = array();
473  $contents = file_get_contents($file);
474  $contents = preg_replace_callback('/^ *\[([^\]]+)\]/m', array($this, 'replace_section'), $contents);
475 
476  $contents = preg_replace_callback('/^([^\[=;"]+)(=)/m', array($this, 'replace_key'), $contents);
477  //echo $contents;
478  $ini = parse_ini_string($contents, $sections);
479  return $this->refill_array($ini);
480  }
481  public static function parse_ini_file($file, $sections=false){
482  if ( version_compare(PHP_VERSION, '5.3.0') >= 0 and version_compare(PHP_VERSION, '5.3.1') <= 0 ){
483  $p = new INIParser();
484  return $p->parse($file, $sections);
485  } else {
486  return parse_ini_file($file, $sections);
487  }
488  }
489 
490 }