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