dc835dc418646d6f7d0952cf93dfb022a8cab907
[pear] / HTML / FlexyFramework.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
4 // | PHP Version 4                                                        |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2002 The PHP Group                                |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license,      |
9 // | that is bundled with this package in the file LICENSE, and is        |
10 // | available at through the world-wide-web at                           |
11 // | http://www.php.net/license/2_02.txt.                                 |
12 // | If you did not receive a copy of the PHP license and are unable to   |
13 // | obtain it through the world-wide-web, please send a note to          |
14 // | license@php.net so we can mail you a copy immediately.               |
15 // +----------------------------------------------------------------------+
16 // | Authors:  Alan Knowles <alan@akbkhome.com>                           |
17 // +----------------------------------------------------------------------+
18 //
19 // $Id: FlexyFramework.php,v 1.8 2003/02/22 01:52:50 alan Exp $
20 //
21 //  Description
22 //  A Page (URL) to Object Mapper
23 //  Cleaned up version.. - for use on new projects -- not BC!! beware!!!
24
25
26 //-----------------------------------------------------------
27 // Debian APACHE - some idiot disabled AcceptPathInfo - it needs adding back.
28 //-----------------------------------------------------------
29
30  
31  
32 // Initialize Static Options
33 require_once 'PEAR.php';
34 require_once 'HTML/FlexyFramework/Page.php';  
35 require_once 'HTML/FlexyFramework/Error.php';
36 // better done here..
37 require_once 'DB/DataObject.php';
38
39 // To be removed ?? or made optional or something..
40  
41
42 // remove E_ANAL  
43  
44 error_reporting(E_ALL & ~E_STRICT );
45 //ini_set('display_errors','off');
46 //ini_set('log_errors','off');
47
48 //PEAR::setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_ERROR);
49
50
51
52
53 /**
54 * The URL to Object Mapper
55 *
56 * Usage:
57 * Create a index.php and add these lines.
58 *  
59 * ini_set("include_path", "/path/to/application"); 
60 * require_once 'HTML/FlexyFramework.php';
61 * HTML_FlexyFramework::factory(array("dir"=>"/where/my/config/dir/is");
62 *
63 *
64 * the path could include pear's path, if you dont install all the pear 
65 * packages into the development directory.
66 *
67 * It attempts to load a the config file from the includepath, 
68 * looks for ConfigData/default.ini
69 * or ConfigData/{hostname}.ini
70 * if your file is called staging.php rather than index.php 
71 * it will try staging.ini
72 *
73 */
74  
75 class HTML_FlexyFramework {
76     
77     /**
78      * Confirgurable items..
79      * If we set them to 'true', they must be set, otherwise they are optional.
80      */
81     var $project; // base class name
82     var $database; // set to true even if nodatabase=true
83     
84     // optional
85     var $debug = false;
86     var $enable = false; // modules
87     var $disable = false; // modules or permissions
88     var $appName = false;
89     var $appNameShort = false; // appname (which has templates)
90     var $version = false; // give it a version name. (appended to compile dir)
91     var $nodatabase = false; // set to true to block db config and testing.
92     var $fatalAction = false; // page to redirct to on failure. (eg. databse down etc.)
93     var $charset = false; // default UTF8
94     var $dataObjectsCache = true;  // use dataobjects ini cache.. - let's try this as the default behaviour...
95     var $dataObjectsCacheExpires = 72000; // 20 hours..
96     var $languages = false; // language settings -- see _handlelanguage
97     var $projectExtends = false; // if this is an array, it's a fallback of 'Projects' that can be called
98     
99
100     
101     // derived.
102     var $cli = false; // from cli 
103     var $run = false; // from cli
104     var $enableArray = false; // from enable.
105     var $classPrefix = false; // from prject.
106     var $baseDir = false ; // (directory+project)
107     var $rootDir = false ; // (directory that index.php is in!)
108     
109     var $baseURL = false;
110     var $rootURL = false ; // basename($baseURL)
111     
112     var $page = false; // active page..
113     var $timer = false; // the debug timer
114     var $calls = false; // the number of calls made to run!
115     var $start = false; // the start tiem.
116     
117     var $baseRequest = '';
118     var $ext; // the striped extention.
119     
120     var $dataObjectsOriginalIni = ''; // 1 houre..
121     
122     // used to be $_GLOBALS[__CLASS__]
123     
124     static $singleton; 
125     
126     
127     /**
128      * 
129      * Constructor - with assoc. array of props as option
130      * called by index.php usually, and runs the app code,
131      *
132      * uses 'universal construcor' format, so the argument relates directly to properties of this object.
133      * 
134      */
135     
136     
137     function __construct($config)
138     {
139         if (isset(self::$singleton)) {
140             trigger_error("FlexyFramework Construct called twice!", E_ERROR);
141         }
142         
143         self::$singleton = $this;
144         
145         $this->calls = 0;
146
147         $m = explode(' ',microtime());
148         $this->start = $m[0] + $m[1];
149         
150         $config = $this->loadModuleConfig($config);
151         
152         foreach($config as $k=>$v) {
153             $this->$k = $v;
154         }
155         $this->_parseConfig();
156         
157         // echo '<PRE>'; print_r($this);exit;
158         if ($this->cli) {
159             $args = $_SERVER['argv'];
160             array_shift($args );
161             array_shift($args );
162             $this->_run($this->run,false,$args);
163             return;
164         }
165     
166         // handle apache mod_rewrite..
167         // it looks like this might not work anymore..
168         
169         /*
170          *
171 <IfModule mod_rewrite.c>
172 RewriteEngine On
173 RewriteBase /
174 RewriteRule ^/web.hpasite/index\.local.php$ - [L]
175 RewriteCond %{REQUEST_FILENAME} !-f
176 RewriteCond %{REQUEST_FILENAME} !-d
177 RewriteRule ^(.+)$ /web.hpasite/index.local.php [L,NC,E=URL:$1]
178 </IfModule>
179 */ 
180         
181         if (!empty($_SERVER['REDIRECT_STATUS'])  && !empty($_SERVER['REDIRECT_URL'])) {
182           // phpinfo();exit;
183             $sn = $_SERVER['SCRIPT_NAME'];
184             $sublen = strlen(substr($sn , 0,  strlen($sn) - strlen(basename($sn)) -1));
185             //var_dump(array($sn,$subdir,basename($sn)));exit;
186           
187             //var_dump($_SERVER['SCRIPT_NAME'] . substr($_SERVER['REDIRECT_URL'],$sublen));
188             $this->_run($_SERVER['SCRIPT_NAME'] .  substr($_SERVER['REDIRECT_URL'], $sublen),false);
189             return ;
190         }
191         // eg... /web.hpasite/index.local.php/Projects
192          $this->_run($_SERVER['REQUEST_URI'],false);
193             
194         
195     }
196     /**
197      * This is the standard way to get information about the application settings.
198      * $ff = HTML_FlexyFramework::get();
199      * if ($ff->SomeVar[...])....
200      *
201      */
202     static function get()
203     {
204         return self::$singleton;
205     }
206     /*
207      * looks for files in the path and load up the default values for config?
208      */
209     function loadModuleConfig($cfg)
210     {
211         if (empty($cfg['enable'])) {
212             return $cfg;
213         }
214         $proj = $cfg['project'];
215         $rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
216
217         foreach(explode(',',$cfg['enable']) as $m) {
218             $cls = $proj.'_'. $m . '_Config';
219
220             if (!file_exists($rootDir . '/'.str_replace('_','/', $cls). '.php')) {
221                 continue;
222             }
223             require_once str_replace('_','/', $cls). '.php';
224             $c = new $cls();
225             if (method_exists($c,'init')) {
226                 $cfg = $c->init($this,$cfg);
227             }
228         }
229         return $cfg;
230     }
231     
232   
233     /**
234      * parse the configuration set by the constructor.
235      * 
236      *
237      */
238   
239     function _parseConfig()
240     {
241         
242         // make sure required values are set.. (anything that is not defaulted to false..)
243         foreach(get_class_vars(__CLASS__) as $k =>$v) {
244             if ($v === false && !isset($this->$k)) {
245                 die("$k is not set");
246             }
247         }
248         
249         
250         // enable modules.
251         if (!empty($this->enable)) {
252             $this->enableArray = explode(',', $this->enable);
253             
254             if (!in_array('Core',$this->enableArray ) &&
255                 !in_array('Core', explode(',', $this->disable ? $this->disable : '')))
256             {
257                 $this->enable = 'Core,'. $this->enable ;
258                 $this->enableArray = explode(',', $this->enable);
259             }
260         }
261         // are we running cli?
262         $this->cli = php_sapi_name() == 'cli'; 
263         
264         // will these work ok with cli?
265         $bits = explode(basename($_SERVER["SCRIPT_FILENAME"]), $_SERVER["SCRIPT_NAME"]);
266         if (!$this->cli) {
267             $bits[0] = str_replace('%2F','/',urlencode($bits[0]));
268             $this->baseURL = $bits[0] . basename($_SERVER["SCRIPT_FILENAME"]);
269             // however this is not correct if we are using rewrite..
270             if (!empty($_SERVER['REDIRECT_STATUS'])  && !empty($_SERVER['REDIRECT_URL'])) {
271                 $this->baseURL = substr($bits[0],0,-1); // without the trailing '/' ??
272                 $this->rootURL = $bits[0] == '/' ? '' : $bits[0];
273                 //$this->baseURL = $this->baseURL == '' ? '/' : $this->baseURL;
274                 
275             }
276             //phpinfo();exit;
277             // is this bit used??
278             //if (empty($_SERVER['SCRIPT_NAME'])) {
279                 
280             //    $this->baseURL = ''; // ??? this is if we replace top level...
281             //}
282         }
283         // if cli - you have to have set baseURL...
284         
285         
286         $this->rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
287         $this->baseDir = $this->rootDir .'/'. $this->project;
288         if (empty($this->rootURL)) {
289             $this->rootURL = dirname($this->baseURL); 
290             $this->rootURL = ($this->rootURL == '/') ? '' : $this->rootURL;
291         }
292          
293       
294         //var_dump($this->baseURL);
295         
296         if (!isset($this->database) && isset($this->DB_DataObject['database'])) {
297             $this->database = $this->DB_DataObject['database'];
298         }
299         
300          $this->classPrefix   = str_replace('/', '_', $this->project) . '_';
301         
302         // list the available options..
303         if ($this->cli && empty($_SERVER['argv'][1])) {
304             require_once 'HTML/FlexyFramework/Cli.php';
305             $fcli = new HTML_FlexyFramework_Cli($this);
306             $fcli->cliHelp();
307             exit;
308         }
309         
310         
311         // see if it's a framework assignment.
312         $ishelp = false;
313         if ($this->cli) {
314             require_once 'HTML/FlexyFramework/Cli.php';
315             $fcli = new HTML_FlexyFramework_Cli($this);
316             $res = $fcli->parseDefaultOpts();
317             if ($res === true) {
318                 $ishelp = true;
319             }
320              
321         }
322         
323         
324         $this->run = $this->cli ? $_SERVER['argv'][1] : false;
325      
326         
327         $this->_parseConfigDataObjects();
328         if ($this->dataObjectsCache && !$this->nodatabase) {
329             $this->_configDataObjectsCache();
330         }
331         
332         $this->_parseConfigTemplate();
333         $this->_parseConfigMail();
334  
335         //echo '<PRE>';print_r($this);exit;
336         
337         $this->_exposeToPear();
338                 
339
340         $this->_validateEnv();
341         
342         if ($ishelp) {
343             return;
344         }
345
346         $this->_validateDatabase();
347  
348         $this->_validateTemplate();
349         
350     }
351     /**
352      *
353      *
354      *'languages' => array(
355             'param' => '_lang',
356             'avail' => array('en','zh_HK', 'zh_CN'),
357             'default' => 'en',
358             'cookie' => 'TalentPricing_lang',
359             'localemap' => array(
360                 'en' => 'en_US.utf8',
361                 'zh_HK' => 'zh_TW.utf8',
362                 'zh_CN' => 'zh_CN.utf8',
363             )
364         ),
365     */
366     
367     function _handleLanguages($request)
368     {
369         if (
370             empty($this->languages) ||
371             (
372                     !isset($this->languages['cookie']) && !isset($this->languages['default'])
373             )
374         ) {
375             return;
376         }
377         
378         $cfg = $this->languages;
379         
380         $default = $cfg['default'];
381         
382         if(!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])){
383             
384             $brower_langs = explode(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
385             
386             foreach ($brower_langs as $bl) {
387                 $l = preg_replace('/;(.*)/', '', $bl);
388                 
389                 $l = str_replace('-', '_', $l);
390                 
391                 if(!in_array($l, $cfg['avail'])){
392                     continue;
393                 }
394                 
395                 $default = $l;
396                 break;
397             }
398         }
399            
400         $lang = isset($_COOKIE[$cfg['cookie']]) ?  $_COOKIE[$cfg['cookie']] : $default;
401
402         // handle languages in request..
403         $bits = explode('/', $request);
404         $redirect_to = false;
405         if (count($bits) && in_array($bits[0],$cfg['avail'])) {
406             // redirect..
407             $lang = array_shift($bits);
408             $redirect_to = implode('/', $bits);
409         }
410         
411          
412         
413         if (isset($_REQUEST[$cfg['param']])) {
414             $lang = $_REQUEST[$cfg['param']];
415         }
416     
417         if (!in_array($lang, $cfg['avail'])) {
418             $lang = $cfg['default'];
419         }
420         if (isset($cfg['localemap'][$lang])) {
421             setlocale(LC_ALL, $cfg['localemap'][$lang]);
422         }
423         setcookie($cfg['cookie'], $lang, 0, '/');
424         
425         $this->locale = $lang;
426         
427         if (!empty($this->HTML_Template_Flexy)) {
428             $this->HTML_Template_Flexy['locale'] = $lang;   //set a language for template engine
429         }
430         if ($redirect_to !== false) {
431             header('Location: ' . $this->rootURL . '/'.$redirect_to );
432             exit;
433          
434         }
435     }
436     
437     function parseDefaultLanguage($http_accept, $deflang = "en") 
438     {
439         if(isset($http_accept) && strlen($http_accept) > 1)  {
440            # Split possible languages into array
441            $x = explode(",",$http_accept);
442            
443            foreach ($x as $val) {
444               #check for q-value and create associative array. No q-value means 1 by rule
445               if(preg_match("/(.*);q=([0-1]{0,1}.\d{0,4})/i",$val,$matches))
446                  $lang[$matches[1]] = (float)$matches[2];
447               else
448                  $lang[$val] = 1.0;
449            }
450            
451            #return default language (highest q-value)
452            $qval = 0.0;
453            foreach ($lang as $key => $value) {
454               if ($value > $qval) {
455                  $qval = (float)$value;
456                  $deflang = $key;
457               }
458            }
459         }
460         return strtolower($deflang);
461      }
462     
463     /**
464      * overlay array properties..
465      */
466     
467     function applyIf($prop, $ar)
468     {
469         if (!isset($this->$prop)) {
470             $this->$prop = $ar;
471             return;
472         }
473         // add only things that where not set!!!.
474         $this->$prop = array_merge($ar,$this->$prop);
475         
476         return;
477         //foreach($ar as $k=>$v) {
478         //    if (!isset($this->$prop->$k)) {
479          //       $this->$prop->$k = $v;
480           //  }
481        // }
482     }
483     
484     /**
485      * DataObject cache 
486      * - if turned on (dataObjectsCache = true) then 
487      *  a) ini file points to a parsed version of the structure.
488      *  b) links.ini is a merged version of the configured link files.
489      * 
490      * This only will force a generation if no file exists at all.. - after that it has to be called manually 
491      * from the core page.. - which uses the Expires time to determine if regeneration is needed..
492      * 
493      * 
494      */
495     
496     function _configDataObjectsCache()
497     {
498         // cli works under different users... it may cause problems..
499         $this->debug(__METHOD__);
500         if (function_exists('posix_getpwuid')) {
501             $uinfo = posix_getpwuid( posix_getuid () ); 
502             $user = $uinfo['name'];
503         } else {
504             $user = getenv('USERNAME'); // windows.
505         }
506         
507         
508
509         $iniCache = ini_get('session.save_path') .'/' . 
510                'dbcfg-' . $user . '/'. str_replace('/', '_', $this->project) ;
511         
512         
513         if ($this->appNameShort) {
514             $iniCache .= '_' . $this->appNameShort;
515         }
516         if ($this->version) {
517             $iniCache .= '.' . $this->version;
518         }
519         if ($this->database === false) {
520             return;
521         }
522         
523         $dburl = parse_url($this->database);
524         if (!empty($dburl['path'])) {
525             $iniCache .= '-'.ltrim($dburl['path'],'/');
526         }
527         
528         $iniCache .= '.ini';
529         $this->debug(__METHOD__ . " : ini cache : $iniCache");
530         
531         $dburl = parse_url($this->database);
532         $dbini = 'ini_'. basename($dburl['path']);
533         $this->debug(__METHOD__ . " : ini file : $dbini");
534         //override ini setting... - store original..
535         if (isset($this->DB_DataObject[$dbini])) {
536             $this->dataObjectsOriginalIni = $this->DB_DataObject[$dbini];
537             ///print_r($this->DB_DataObject);exit;
538         }
539         // 
540         
541         
542         
543         $this->DB_DataObject[$dbini] =   $iniCache;
544         // we now have the configuration file name..
545         
546         
547         if (!file_exists($iniCache) || empty( $this->dataObjectsCacheExpires)) {
548             $this->debug(__METHOD__ . ':calling generate do cache');
549             $this->generateDataobjectsCache(true);
550             return;
551         }
552      
553         
554         
555     }
556     /**
557      *  _generateDataobjectsCache:
558      * 
559      * create xxx.ini and xxx.links.ini 
560      * 
561      * @arg force (boolean) force generation - default false;
562      * 
563      */
564      
565     function generateDataobjectsCache($force = false)
566     {
567         //$this->debug('generateDataobjectsCache: force=' . ($force ? 'yes' : 'no'));
568         if (!$this->dataObjectsCache) { // does not use dataObjects Caching..
569             $this->debug('generateDataobjectsCache: dataObjectsCache - empty');
570             return;
571         }
572         
573         $dburl = parse_url($this->database);
574         $dbini = 'ini_'. basename($dburl['path']);
575         
576         
577         $iniCache = $this->DB_DataObject[$dbini];
578         $this->debug('generateDataobjectsCache:' .dirname($iniCache).'/*.ini');
579         if ($force && file_exists($iniCache)) {
580             
581             $files = glob(dirname($iniCache).'/*.ini');
582             foreach($files as $f) {
583                 unlink($f);
584             }
585             clearstatcache();
586         }
587         $this->debug('generateDataobjectsCache: DONE ini delete');
588         
589         $iniCacheTmp = $iniCache . '.tmp' .md5(rand());  // random to stop two processes using the same file.
590         // has it expired..
591         $force = ($force ? $force : !file_exists($iniCache)) || !$this->dataObjectsCacheExpires;
592         // $this->debug('generateDataobjectsCache: after check : force=' . ($force ? 'yes' : 'no'));
593          // not force or not expired, do not bother..
594         if (!$force) {
595             if ((filemtime($iniCache) + $this->dataObjectsCacheExpires) >time()) {
596                 return;
597             }
598         }
599         
600         
601         
602          //echo "GENERATE?";
603         
604         // force quoting of column names..
605         // unless it forced off..
606         if (!isset($this->DB_DataObject['quote_identifiers_tableinfo'] )) { 
607             $this->DB_DataObject['quote_identifiers_tableinfo'] = true;
608         }
609         if (!file_exists(dirname($iniCache))) {
610             if (!mkdir(dirname($iniCache),0700, true)) {
611                 die("Failed to make cache directory : $iniCache\n");
612             }
613         }
614         
615         $this->DB_DataObject[$dbini] = $iniCacheTmp;
616         
617         $dl = DB_DataObject::DebugLevel();
618         $this->_exposeToPear(); // this will reset the debug level...
619         DB_DataObject::DebugLevel($dl);
620         
621         $this->debug('generateDataobjectsCache: running generator');
622         // DB_DataObject::debugLevel(1);      
623         require_once 'HTML/FlexyFramework/Generator.php';
624         $generator = new HTML_FlexyFramework_Generator();
625         $generator->start();
626         $this->debug('generateDataobjectsCache: done generator');
627
628         HTML_FlexyFramework_Generator::writeCache($iniCacheTmp, $iniCache); 
629         // reset the cache to the correct lcoation.
630         $this->DB_DataObject[$dbini] = $iniCache;
631         
632          
633
634         $this->_exposeToPear();
635         DB_DataObject::DebugLevel($dl);
636
637         //$GLOBALS['_DB_DATAOBJECT']['INI'][$this->database] =   parse_ini_file($iniCache, true);
638         //$GLOBALS['_DB_DATAOBJECT']['SEQUENCE']
639         // clear any dataobject cache..
640          
641         
642         //die("done");
643         
644     }
645     /**
646      * DataObject Configuration:
647      * Always in Project/DataObjects
648      * unless enableArray is available...
649      * 
650      * 
651      * 
652      */
653     function _parseConfigDataObjects()
654     {
655         if ($this->nodatabase && !$this->database) {
656             return;
657         }
658         $dburl = parse_url($this->database);
659         $dbini = 'ini_'. basename($dburl['path']);
660                 
661         $dbinis =  array(); //array(dirname(__FILE__) . '/Pman/DataObjects/pman.ini');
662         $dbreq =  array(); //array( dirname(__FILE__) . '/Pman/DataObjects/');
663         $dbcls =  array(); //array('Pman_DataObjects_');
664
665         $project = explode('/',$this->project)[0]; 
666         
667         if (!empty($this->enableArray)) {
668                 
669             $tops = array_merge( array($project), empty($this->projectExtends) ? array() : $this->projectExtends);
670             
671             foreach($tops as $td) {
672                     
673                 $bd = $this->rootDir .'/'.$td;
674                 foreach($this->enableArray as $m) {
675                     // look in Pman/MODULE/DataObjects/*
676                      if (file_exists($bd.'/'.$m.'/DataObjects')) {
677                         $dbinis[] = $bd.'/'.$m.'/DataObjects/'. strtolower($project).'.ini';
678                         $dbcls[] = $td.'_'. $m . '_DataObjects_';
679                         $dbreq[] = $bd.'/'.$m.'/DataObjects';
680                         continue;
681                     }
682                     // look in MODULE/DataObjects ?? DO WE SUPPORT THIS ANYMORE???
683                     if (file_exists($bd.'/../'.$m.'/DataObjects')) {
684                         $dbinis[] = $bd.'/../'.$m.'/DataObjects/'. strtolower($project).'.ini';
685                         $dbcls[] = $td. '_DataObjects_';
686                         $dbreq[] = $bd.'/../'.$m.'/DataObjects';
687                     }
688                         
689                         
690                       
691                 }
692             }     
693         } else {
694             
695             if (isset($this->DB_DataObject['schema_location'])) {
696                 $dbinis[] = $this->DB_DataObject['schema_location'] .'/'.basename($dburl['path']).'.ini';
697             } else {
698                 $dbinis[] = $this->baseDir.'/DataObjects/'.basename($dburl['path']).'.ini';
699             }
700             // non modular.
701             
702             $dbcls[] = $project .'_DataObjects_';
703             $dbreq[] = $this->baseDir.'/DataObjects';
704         }
705             
706         
707         $this->applyIf('DB_DataObject', array(   
708         
709             'class_location' =>  implode(PATH_SEPARATOR,$dbreq),
710             'class_prefix' =>  implode(PATH_SEPARATOR,$dbcls),
711             'database'        => $this->database,    
712             ///'require_prefix' => 
713          //   'schema_location' => dirname(__FILE__) . '/Pman/DataObjects/',
714              $dbini=> implode(PATH_SEPARATOR,$dbinis),
715          
716            //   'debug' => 5,
717         ));
718       //  print_r($this->DB_DataObject);exit;
719     }
720     /**
721      Set up thetemplate
722      * 
723      */
724     function _parseConfigTemplate()
725     {
726         
727         // compile.
728         if (function_exists('posix_getpwuid')) {
729             $uinfo = posix_getpwuid( posix_getuid () ); 
730          
731             $user = $uinfo['name'];
732         } else {
733             $user = getenv('USERNAME'); // windows.
734         }
735         
736         $compileDir = ini_get('session.save_path') .'/' . 
737             $user . '_compiled_templates_' . $this->project;
738         
739         if ($this->appNameShort) {
740             $compileDir .= '_' . $this->appNameShort;
741         }
742         if ($this->version) {
743             $compileDir .= '.' . $this->version;
744         }
745         
746         // templates. -- all this should be cached!!!
747         $src = array();
748          
749         
750         if ($this->appNameShort && !in_array('Core', explode(',', $this->disable ? $this->disable : ''))) {
751             // in app based version, template directory is in Core
752             
753             $src = array(  
754                 $this->baseDir . '/Core/templates'
755             );
756         }
757         
758         if(!empty($this->projectExtends)){
759             foreach ($this->projectExtends as $e){
760                 $add = $this->rootDir . '/' . $e .'/templates';
761                 if (!in_array($add,$src) && file_exists($add)) {
762                     $src[] = $add;
763                 }
764             }
765         }
766         
767         $src[] = $this->baseDir . '/templates';
768         
769         
770         
771         if (!empty($this->enableArray)) {
772              
773             
774             foreach($this->enableArray as $m) {
775                 $add = $this->baseDir . '/' . $m .'/templates';
776                 if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
777                     $src[] = $add;
778                 }
779                 
780             }
781             if (!empty($this->projectExtends)  )  {
782                 foreach ($this->projectExtends as $extend){
783                     foreach($this->enableArray as $m) {
784                         $add = $this->rootDir . '/' . $extend . '/' . $m .'/templates';
785                         if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
786                             $src[] = $add;
787                         }
788                     }
789                 }
790     
791             }
792         }
793          
794         
795         if ($this->appNameShort) {
796             $src[] =  $this->baseDir . '/'. $this->appNameShort. '/templates';
797         }
798         
799         // images may come from multiple places: - if we have multiple template directories.?
800         // how do we deal with this..?
801         // images/ << should always be mapped to master!
802         // for overridden appdir ones we will have to se rootURL etc.
803         
804         $url_rewrite = 'images/:'. $this->rootURL . '/'. $this->project. '/templates/images/';
805         
806         $this->applyIf('HTML_Template_Flexy', array(
807             'templateDir' => implode(PATH_SEPARATOR, $src),
808             'compileDir' => $compileDir,
809             'multiSource' => true,
810             'forceCompile' => 0,
811             'url_rewrite' => $url_rewrite,
812             'filters' => 'Php,SimpleTags', /// for non-tokenizer version?
813             'debug' => $this->debug ? 1 : 0,
814             'useTokenizer' => 1,
815              
816             
817         
818         
819         ));
820     } 
821     
822     function _parseConfigMail()
823     {
824         $this->applyIf('HTML_Template_Flexy', array(
825            'debug' => 0,
826            'driver' => 'smtp',
827            'host' => 'localhost',
828            'port' => 25,
829         ));
830     }
831     function _exposeToPear()
832     {
833         $cls = array_keys(get_class_vars(__CLASS__));
834         $base = array();
835         
836         // anything that get's set, that's not in our default properties
837         // is assumed to be an option set .
838         foreach(get_object_vars($this) as $k=>$v) {
839             if (in_array($k,$cls)) {
840                 $base[$k] = $v;
841                 continue;
842             }
843             $options = &PEAR::getStaticProperty($k,'options');
844             $options = $v;
845         }
846         $options = &PEAR::getStaticProperty('HTML_FlexyFramework','options');
847         $options = $base;
848          //   apply them..
849     }
850     
851     
852     function _validateEnv() 
853     {
854         /* have I been initialized */
855         
856         
857         if (get_magic_quotes_gpc() && !$this->cli) {
858             $this->fatalError(
859                 "magic quotes is enabled add the line<BR>
860                    php_value magic_quotes_gpc 0<BR>
861                    to your .htaccess file <BR>
862                    (Apache has to be configured to &quot;AllowOverride Options AuthConfig&quot; for the directory)
863                    ");
864                 
865         }
866         // set up error handling - 
867         $this->error = new HTML_FlexyFramework_Error();
868         
869         /// fudge work around bugs in PEAR::setErrorHandling(,)
870         $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_CALLBACK;
871         $GLOBALS['_PEAR_default_error_options'] = array($this->error,'raiseError');
872         
873         
874         
875         if ($this->debug) {
876             require_once 'Benchmark/Timer.php'; 
877             $this->timer = new BenchMark_Timer(true);
878             register_shutdown_function(function() { echo $this->timer->getOutput(); });
879         }
880
881     }
882     
883     function _validateDatabase()
884     {
885         //echo "<PRE>"; print_r($this);
886
887         if ($this->nodatabase) {
888             return;
889         }
890         $options = &PEAR::getStaticProperty('DB_DataObject','options');
891         $dd = empty($options['dont_die']) ? false : true;
892         $options['dont_die'] = true;
893         
894         // database is the only setting - we dont support mult databses?
895           
896             
897         $x = new DB_Dataobject;
898         $x->_database = $this->database;
899         if (PEAR::isError($err = $x->getDatabaseConnection())) {
900                                 
901
902                 $this->fatalError("Configuration or Database Error: could not connect to Database, <BR>
903                     Please check the value given to HTML_FlexyFramework, or run with debug on!<BR>
904                      <BR> ".$err->toString());
905         }
906         // reset dont die!
907         $options['dont_die'] = $dd ;
908         
909         
910     }
911     function _validateTemplate()
912     {
913         // check that we have a writeable directory for flexy's compiled templates.
914         
915         if (empty($this->HTML_Template_Flexy['compileDir'])) {
916             return;
917         }
918         
919         if ( !file_exists($this->HTML_Template_Flexy['compileDir']))  {
920             mkdir($this->HTML_Template_Flexy['compileDir'], 0700);
921             @mkdir($this->HTML_Template_Flexy['compileDir'], 0700, true);
922             clearstatcache();
923              
924             if ( !file_exists($this->HTML_Template_Flexy['compileDir']))  {
925             
926                 $this->fatalError("Configuration Error: you specified a directory that does not exist for<BR>
927                     HTML_Template_Flexy => compileDir  {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
928                 );
929             }
930         }
931         
932         if (!is_writeable($this->HTML_Template_Flexy['compileDir'])) {
933             $this->fatalError("Configuration Error: Please make sure the template cache directory is writeable<BR>
934                     eg. <BR>
935                     chmod 700 {$this->HTML_Template_Flexy['compileDir']}<BR>
936                     chgrp apache_user  {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
937             );
938         }
939         //echo "<PRE>";print_R($config);
940         
941         
942          
943           
944         
945         
946     }
947   
948   
949    
950         
951     
952     
953     /**
954     * Quality Redirector
955     *
956     * Usage in a page.:
957     * HTML_FlexyFramework::run('someurl/someother',array('somearg'=>'xxx'));
958     * ...do clean up...
959     * exit; <- dont cary on!!!!
960     *
961     * You should really
962     * 
963     * @param   string           redirect to url 
964     * @param   array Args Optional      any data you want to send to the next page..
965     * 
966     *
967     * @return   false
968     * @access   public
969     * @static
970     */
971   
972     
973     static function run($request,$args=array()) 
974     {
975         self::$singleton->_run($request,true,$args);
976         return false;
977     }
978     
979     
980     /**
981     * The main execution loop
982     *
983     * recursivly self called if redirects (eg. return values from page start methods)
984     * 
985     * @param   string from $_REQUEST or redirect from it'self.
986     * @param   boolean isRedirect  = is the request a redirect 
987     *
988     *
989     * @return   false || other    false indicates no page was served!
990     * @access   public|private
991     * @see      see also methods.....
992     */
993   
994     function _run($request,$isRedirect = false,$args = array()) 
995     {
996         
997         // clean the request up.
998         $this->calls++;
999         
1000         if ($this->calls > 5) {
1001             // to many redirections...
1002             trigger_error("FlexyFramework:: too many redirects - backtrace me!",E_USER_ERROR);
1003             exit;
1004         }
1005         
1006         $newRequest = $this->_getRequest($request,$isRedirect);
1007         
1008          
1009         // find the class/file to load
1010         list($classname,$subRequest) = $this->requestToClassName($newRequest,FALSE);
1011         
1012         
1013         $this->debug("requestToClassName return = CLASSNAME: $classname SUB REQUEST: $subRequest");
1014         
1015         // assume that this was handled by getclassname ?????
1016         if (!$classname) {
1017             return false;
1018         }
1019         
1020         // make page data/object accessable at anypoint in time using  this
1021         // not sure if this is used anymore - or even works..?
1022         $classobj = &PEAR::getStaticProperty('HTML_FlexyFramework', 'page');
1023         
1024         $classobj =  new  $classname();  // normally do not have constructors.
1025         
1026         
1027         $classobj->baseURL = $this->baseURL;
1028         $classobj->rootURL = $this->rootURL;
1029         $classobj->rootDir = $this->rootDir;
1030         $classobj->bootLoader  = $this;
1031         $classobj->request = $newRequest;
1032         $classobj->timer = &$this->timer;
1033         
1034         $this->page = $classobj;
1035         if ($this->cli && !$isRedirect ) { // redirect always just takes redirect args..
1036             require_once 'HTML/FlexyFramework/Cli.php';
1037             $fcli = new HTML_FlexyFramework_Cli($this);
1038             $nargs = $fcli->cliParse($classname);
1039             $args = $nargs === false ? $args : $nargs; /// replace if found.
1040             $classobj->cli_args = $nargs;
1041         }
1042         
1043         // echo '<PRE>'; print_r($this);exit;
1044         // echo "CHECK GET AUTH?";
1045         if (!method_exists($classobj, 'getAuth')) {
1046         //    echo "NO GET AUTH?";
1047             $this->fatalError("class $classname does not have a getAuth Method");
1048             return false;
1049         }
1050         
1051         /* check auth on the page */
1052         if (is_string($redirect = $classobj->getAuth())) {
1053             $this->debug("GOT AUTH REDIRECT".$redirect);
1054             return $this->_run($redirect,TRUE);
1055         }
1056         // used HTML_FlexyFramework::run();
1057                  
1058
1059         if ($redirect === false) {
1060             $this->debug("GOT AUTH FALSE");    
1061             return false; /// Access deined!!! - 
1062         }
1063      
1064         // allow the page to implement caching (for the full page..)
1065         // although normally it should implement caching on the outputBody() method.
1066         
1067         if (method_exists($classobj,"getCache")) {
1068             if ($result = $classobj->getCache()) {
1069                 return $result;
1070             }
1071         }
1072         /* allow redirect from start */
1073         if (method_exists($classobj,"start")) {
1074             if (is_string($redirect = $classobj->start($subRequest,$isRedirect,$args)))  {
1075                 $this->debug("REDIRECT $redirect <BR>");
1076                 return $this->_run($redirect,TRUE);
1077             }
1078             if ($redirect === false) {
1079                 return false;
1080             }
1081         }
1082                 
1083
1084          // used HTML_FlexyFramework::run();
1085         
1086         /* load the modules 
1087          * Modules are common page components like navigation headers etc.
1088          * that can have dynamic code.
1089          * Code has been removed now..
1090          */
1091         
1092         
1093         if ($this->timer) {
1094             $this->timer->setMarker("After $request loadModules Modules"); 
1095         }
1096         
1097         /* output it  - (our base page does not implement output for cli. */
1098         
1099         if ( method_exists($classobj,'output')) {
1100             $classobj->output(); 
1101         }
1102         
1103         
1104         if ($this->timer) {
1105             $this->timer->setMarker("After $request output"); 
1106             $this->timer->stop(); //?? really - yes...
1107            
1108             
1109         }
1110         
1111         if ($this->cli) {
1112             return true;
1113         }
1114         
1115         
1116         exit; /// die here...
1117         
1118     }
1119     
1120     /**
1121     * map the request into an object and run the page.
1122     *
1123     * The core of the work is done here.
1124     * 
1125     * 
1126     * @param   request  the request string
1127     * @param   boolean isRedirect - indicates that it should not attempt to strip the .../index.php from the request.
1128     * 
1129     * @access  private
1130     */
1131   
1132     function _getRequest($request, $isRedirect) 
1133     {
1134         
1135          
1136         if ($this->cli) {
1137             return $request;
1138         }
1139         
1140         $startRequest = $request;
1141         $request =@ array_shift(explode('?', $request));
1142         $this->debug("INPUT REQUEST $request<BR>");
1143         if (!$isRedirect) {
1144             // check that request forms contains baseurl????
1145             if (!empty($_SERVER['REDIRECT_STATUS'])  && !empty($_SERVER['REDIRECT_URL'])) {
1146                // phpinfo();exit;
1147                 $sn = $_SERVER['SCRIPT_NAME'];
1148                 $sublen = strlen(substr($sn , 0,  strlen($sn) - strlen(basename($sn)) -1 ));
1149                  //var_dump(array($sn,$subdir,basename($sn)));exit;
1150                 $subreq =  $_SERVER['SCRIPT_NAME'];
1151                 $request = substr($_SERVER['REDIRECT_URL'],$sublen);
1152                 
1153                  
1154             } else {
1155                   
1156              
1157                 $subreq = substr($request,0, strlen($this->baseURL));
1158                 if ($subreq != substr($this->baseURL,0,strlen($subreq))) {
1159                     $this->fatalError(
1160                         "Configuration error: Got base of $subreq which does not 
1161                             match configuration of: $this->baseURL} ");
1162                 }
1163                 $request = substr($request,strlen($this->baseURL));
1164                 
1165             }
1166             
1167              
1168         }
1169        // var_Dump(array('req'=>$request,'subreq'=>$subreq));
1170         
1171         // strip front
1172         // echo "REQUEST WAS: $request<BR>";
1173         // $request = preg_replace('/^'.preg_quote($base_url,'/').'/','',trim($request));
1174         // echo "IS NOW: $request<BR>";
1175         // strip end
1176         // strip valid html stuff
1177         //$request = preg_replace('/\/[.]+/','',$request);
1178         
1179
1180         $request = preg_replace('/^[\/]*/','',$request);
1181         $request = preg_replace('/\?.*$/','',$request);
1182         $request = preg_replace('/[\/]*$/','',$request);
1183         $this->baseRequest = $request;
1184         $request = str_replace('&','',$request); // any other invalid characters???
1185         $request = preg_replace('/\.([a-z]+)$/','',$request);
1186         $this->ext = substr($this->baseRequest , strlen($request));
1187         
1188         // REDIRECT ROO to index.php! for example..
1189         
1190         if (!$request && !$isRedirect) {
1191             if ($this->baseURL && (strlen($startRequest) < strlen($this->baseURL))) {
1192                 // needs to handle https + port
1193                 $http = ((!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"]  == 'on')) ? 'https' : 'http';
1194                 $sp = '';
1195                 if (!empty($_SERVER['SERVER_PORT'])) {
1196                     if ((($http == 'http') && ($_SERVER['SERVER_PORT'] == 80)) || (($http == 'https') && ($_SERVER['SERVER_PORT'] == 443))) {
1197                         // standard ports..
1198                     } else {
1199                         $sp .= ':'.((int) $_SERVER['SERVER_PORT']);
1200                     }
1201                 }
1202                 $host = !empty($_SERVER["HTTP_X_FORWARDED_HOST"]) ? $_SERVER["HTTP_X_FORWARDED_HOST"] : $_SERVER["HTTP_HOST"];
1203                 header('Location: '.$http.'://'.$host .$sp . $this->baseURL);
1204  
1205                 exit;
1206             }
1207             $request = "";
1208         }
1209        // var_dump(array($startRequest,$request, $this->baseRequest));
1210         
1211         $this->debug("OUTPUT REQUEST $request<BR>");
1212         
1213         $this->_handleLanguages($request);
1214
1215         
1216         return $request;
1217     }
1218     
1219    
1220     
1221     
1222     /**
1223     * get the Class name and filename to load
1224     *
1225     * Parses the request and converts that into a File + Classname
1226     * if the class doesnt exist it will attempt to find a file below it, and
1227     * call that one with the data.
1228     * Used by the module loader to determine the location of the modules
1229     *   
1230     * @param   request  the request string
1231     * @param   boolean showError - if false, allows you to continue if the class doesnt exist.
1232     * 
1233     *
1234     * @return   array classname, filepath
1235     * @access   private
1236     * @static
1237     */
1238   
1239     function requestToClassName($request,$showError=TRUE) 
1240     {
1241        // if ($request == "error") {
1242        //     return array("HTML_FlexyFramework_Error","");
1243        // }
1244         
1245         // special classes ::
1246         if ($this->cli && in_array($request, array('DataObjects'))) {
1247             require_once 'HTML/FlexyFramework/'. $request . '.php';
1248             return array('HTML_FlexyFramework_'. $request,'');
1249         }
1250         
1251         
1252         $request_array=explode("/",$request);
1253         $original_request_array = $request_array;
1254         $sub_request_array = array();
1255         $l = count($request_array)-1;
1256         if ($l > 10) { // ?? configurable?
1257             //PEAR::raiseError("Request To Long");
1258             $this->fatalError("Request To Long - " . $request);
1259         }
1260
1261         
1262         $classname='';
1263         // tidy up request array
1264         
1265         if ($request_array) {
1266             foreach(array_keys($request_array) as $i) {
1267                 $request_array[$i] = preg_replace('/[^a-z0-9]/i','_',urldecode($request_array[$i]));
1268             }
1269         }
1270         //echo "<PRE>"; print_r($request_array);
1271         // technically each module should do a check here... similar to this..
1272         
1273         
1274         for ($i=$l;$i >-1;$i--) {
1275             $location = implode('/',$request_array) . ".php";
1276             if ($location == '.php') {
1277                 $this->debug("SKIP first path check, as request str is empty");
1278                 break;
1279             }
1280             
1281             $this->debug("baseDIR = {$this->baseDir}");
1282             
1283             $floc = "{$this->baseDir}/$location";
1284             $this->debug("CHECK LOCATION = $location");
1285             
1286             
1287             
1288             if (!empty($location) && $location != '.php' && @file_exists($floc )) {             // hide? error???
1289                 require_once $floc ;
1290                 $classname = $this->classPrefix . implode('_',$request_array);
1291                 $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1292                 break;
1293             } 
1294             
1295             // in here check the 'projectExtends' versions..?
1296             
1297             if(!empty($this->projectExtends)){
1298                 $this->debug("Trying project Extends<BR>");
1299                 $has_extend_class = false;
1300                 
1301                 foreach ($this->projectExtends as $e){
1302                     $floc = "{$this->rootDir}/{$e}/$location";
1303                     $this->debug("Trying file: $floc");
1304                     if (!empty($location) && @file_exists($floc)) {             // hide? error???
1305                         require_once $floc ;
1306                         $classname = $e . '_' . implode('_',$request_array);
1307                         $has_extend_class = true;
1308                         $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1309                         break;
1310                     } 
1311                 }
1312                 
1313                 if(!empty($has_extend_class)){
1314                     break;
1315                 }
1316                 
1317             }
1318             
1319             
1320             $this->debug("$floc  - !!FOUND NOT FILE!!");
1321             
1322             $sub_request_array[] = $original_request_array[$i];
1323             unset($request_array[$i]);
1324             unset($original_request_array[$i]);
1325         }
1326          
1327         // is this really needed here!
1328         
1329         $classname = preg_replace('/[^a-z0-9]/i','_',$classname);
1330         $this->debug("CLASSNAME is '$classname'");
1331         // got it ok.
1332         if ($classname && class_exists($classname)) {
1333             $this->debug("using $classname");
1334             //print_r($sub_request_array);
1335             return array($classname,implode('/',array_reverse($sub_request_array)));
1336         }
1337         // stop looping..
1338         if ($showError) {
1339             $this->fatalError("INVALID REQUEST: \n $request FILE:".$this->baseDir. "/{$location}  CLASS:{$classname}");
1340             
1341         } 
1342         
1343         
1344         $this->debug("Try base {$this->baseDir}.php");   
1345         // try {project name}.php
1346         // this used to be silenced @ - if this fails we are usually pretty fried..
1347         
1348         if (file_exists($this->baseDir.'.php')) {
1349             
1350             
1351             $classname = str_replace('/', '_', $this->project); //   basename($this->baseDir);
1352             
1353             $this->debug("FOUND {$this->baseDir} requring and checking class $classname");   
1354             require_once $this->baseDir.'.php';
1355             $this->debug("require success");
1356             
1357             if (!class_exists($classname)) {
1358                 $this->fatalError( "{$this->baseDir}.php did not contain class $classname");
1359             }
1360         }
1361         // got projectname.php
1362         if ($classname && class_exists($classname)) {
1363             $this->debug("using $classname");
1364             //print_r($sub_request_array);
1365              
1366             return array($classname,implode('/',array_reverse($sub_request_array)));
1367         }    
1368             
1369         
1370         $this->fatalError( "can not find {$this->baseDir}.php"); // dies..
1371               
1372      
1373     }
1374     
1375     /**
1376     * ensure Single CLi process 
1377     * usage:
1378     * HTML_FlexyFramework::ensureSingle(__FILE__, $this);
1379     * @param string filename of running class
1380     * @param object class
1381     */
1382       
1383     static function ensureSingle($sig, $class) 
1384     {
1385         //echo "check single: $sig / ". get_class($class) ."\n";
1386         $ff = HTML_FlexyFramework::get();
1387         if (function_exists('posix_getpwuid')) {
1388             $uinfo = posix_getpwuid( posix_getuid () ); 
1389             $user = $uinfo['name'];
1390         } else {
1391             $user = getenv('USERNAME'); // windows.
1392         }
1393         $fdir = ini_get('session.save_path') .'/' . 
1394                 $user . '_cli_' . $ff->project ;
1395      
1396         
1397         if (!file_exists($fdir)) {
1398             mkdir($fdir, 0777);
1399         }
1400         
1401         $lock = $fdir.'/'. md5($sig) . '.' . get_class($class);
1402         //echo "check single: lock : $lock\n";
1403         if (!file_exists($lock)) {
1404             file_put_contents($lock, getmypid());
1405             //echo "check single: lock : DOES NOT EXIST\n";
1406             return true;
1407         }
1408         $oldpid = file_get_contents($lock);
1409         if (!file_exists('/proc/' . $oldpid)) {
1410             
1411             file_put_contents($lock, getmypid());
1412           //  echo "check single: lock : PROC NOT EXIST\n";
1413             return true;
1414         }
1415         // file exists, but process might not be the same..
1416         $name = array_pop(explode('_', get_class($class)));
1417         $cmd = file_get_contents('/proc/' . $oldpid.'/cmdline');
1418         if (!preg_match('/php/i',$cmd) || !preg_match('/'.$name.'/i',$cmd)) {
1419             file_put_contents($lock, getmypid());
1420             //echo "check single: lock : CMDLINE !have PHP \n";
1421             return true;
1422         }
1423         die("process " . $sig . " already running\n");
1424         
1425     }
1426     /**
1427      * removes the lock for the applicaiton - use with care...
1428      *
1429      *
1430      */
1431     static function ensureSingleClear($sig, $class)
1432     {
1433         $ff = HTML_FlexyFramework::get();
1434         if (function_exists('posix_getpwuid')) {
1435             $uinfo = posix_getpwuid( posix_getuid () ); 
1436             $user = $uinfo['name'];
1437         } else {
1438             $user = getenv('USERNAME'); // windows.
1439         }
1440         $fdir = ini_get('session.save_path') .'/' . 
1441                 $user . '_cli_' . $ff->project ;
1442      
1443         
1444         if (!file_exists($fdir)) {
1445             mkdir($fdir, 0777);
1446         }
1447         $lock = $fdir.'/'. md5($sig);
1448         if (!file_exists($lock)) {
1449             
1450             return true;
1451         }
1452         unlink($lock);;
1453     }
1454     
1455     
1456     /**
1457     * Debugging 
1458     * 
1459     * @param   string  text to output.
1460     * @access   public
1461     */
1462   
1463     function debug($output) {
1464        
1465         if (empty($this->debug)) {  
1466             return;
1467         }
1468         echo $this->cli ? 
1469               "HTML_FlexyFramework::debug  - ".$output."\n" 
1470             : "<B>HTML_FlexyFramework::debug</B> - ".$output."<BR>\n";
1471     
1472     }
1473     /**
1474     * Raises a fatal error. - normally only used when setting up to help get the config right.
1475     * 
1476     * can redirect to fatal Action page.. - hoepfully not issued before basic vars are set up..
1477     * 
1478     * @param   string  text to output.
1479     * @access   public
1480     */
1481     
1482     function fatalError($msg,$showConfig = 0) 
1483     {
1484         
1485         
1486          if ($this->fatalAction) {
1487             HTML_FlexyFramework::run($this->fatalAction,$msg);
1488             exit;
1489         }
1490         
1491         echo $this->cli ? $msg ."\n" : "<H1>$msg</H1>configuration information<PRE>";
1492         if ($showConfig) {
1493             
1494             print_r($this);
1495         }
1496         $ff = HTML_FlexyFramework::get();
1497         $ff->debug($msg);
1498         exit;
1499     }    
1500 }
1501
1502