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