2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
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 // +----------------------------------------------------------------------+
19 // $Id: FlexyFramework.php,v 1.8 2003/02/22 01:52:50 alan Exp $
22 // A Page (URL) to Object Mapper
23 // Cleaned up version.. - for use on new projects -- not BC!! beware!!!
26 //-----------------------------------------------------------
27 // Debian APACHE - some idiot disabled AcceptPathInfo - it needs adding back.
28 //-----------------------------------------------------------
32 // Initialize Static Options
33 require_once 'PEAR.php';
34 require_once 'HTML/FlexyFramework/Page.php';
35 require_once 'HTML/FlexyFramework/Error.php';
37 require_once 'DB/DataObject.php';
39 // To be removed ?? or made optional or something..
44 error_reporting(E_ALL & ~E_STRICT );
45 //ini_set('display_errors','off');
46 //ini_set('log_errors','off');
48 //PEAR::setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_ERROR);
54 * The URL to Object Mapper
57 * Create a index.php and add these lines.
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");
64 * the path could include pear's path, if you dont install all the pear
65 * packages into the development directory.
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
74 #[AllowDynamicProperties]
75 class HTML_FlexyFramework {
78 * Confirgurable items..
79 * If we set them to 'true', they must be set, otherwise they are optional.
81 var $project; // base class name
82 var $database; // set to true even if nodatabase=true
86 var $enable = false; // modules
87 var $disable = false; // modules or permissions
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 var $database_is_readonly = false;
103 var $cli = false; // from cli
104 var $run = false; // from cli
105 var $enableArray = false; // from enable.
106 var $classPrefix = false; // from prject.
107 var $baseDir = false ; // (directory+project)
108 var $rootDir = false ; // (directory that index.php is in!)
110 var $baseURL = false;
111 var $rootURL = false ; // basename($baseURL)
113 var $page = false; // active page..
114 var $timer = false; // the debug timer
115 var $calls = false; // the number of calls made to run!
116 var $start = false; // the start tiem.
118 var $baseRequest = '';
119 var $ext; // the striped extention.
121 var $dataObjectsOriginalIni = ''; // 1 houre..
123 // used to be $_GLOBALS[__CLASS__]
130 * Constructor - with assoc. array of props as option
131 * called by index.php usually, and runs the app code,
133 * uses 'universal construcor' format, so the argument relates directly to properties of this object.
138 function __construct($config)
140 if (isset(self::$singleton)) {
141 trigger_error("FlexyFramework Construct called twice!", E_ERROR);
144 self::$singleton = $this;
148 $m = explode(' ',microtime());
149 $this->start = $m[0] + $m[1];
151 $config = $this->loadModuleConfig($config);
153 foreach($config as $k=>$v) {
156 $this->_parseConfig();
158 // echo '<PRE>'; print_r($this);exit;
160 $args = $_SERVER['argv'];
163 $this->_run($this->run,false,$args);
167 // handle apache mod_rewrite..
168 // it looks like this might not work anymore..
172 <IfModule mod_rewrite.c>
175 RewriteRule ^/web.hpasite/index\.local.php$ - [L]
176 RewriteCond %{REQUEST_FILENAME} !-f
177 RewriteCond %{REQUEST_FILENAME} !-d
178 RewriteRule ^(.+)$ /web.hpasite/index.local.php [L,NC,E=URL:$1]
182 if (!empty($_SERVER['REDIRECT_STATUS']) && !empty($_SERVER['REDIRECT_URL'])) {
184 $sn = $_SERVER['SCRIPT_NAME'];
185 $sublen = strlen(substr($sn , 0, strlen($sn) - strlen(basename($sn)) -1));
186 //var_dump(array($sn,$subdir,basename($sn)));exit;
188 //var_dump($_SERVER['SCRIPT_NAME'] . substr($_SERVER['REDIRECT_URL'],$sublen));
189 $this->_run($_SERVER['SCRIPT_NAME'] . substr($_SERVER['REDIRECT_URL'], $sublen),false);
192 // eg... /web.hpasite/index.local.php/Projects
193 $this->_run($_SERVER['REQUEST_URI'],false);
198 * This is the standard way to get information about the application settings.
199 * $ff = HTML_FlexyFramework::get();
200 * if ($ff->SomeVar[...])....
203 static function get()
205 return self::$singleton;
208 * looks for files in the path and load up the default values for config?
210 function loadModuleConfig($cfg)
213 $proj = $cfg['project'];
214 $rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
216 $cls = $proj.'_Config';
220 if (file_exists($rootDir . '/'.str_replace('_','/', $cls). '.php')) {
221 require_once str_replace('_','/', $cls). '.php';
223 if (method_exists($c,'init')) {
224 $cfg = $c->init($this,$cfg);
227 if (empty($cfg['enable'])) {
230 foreach(explode(',',$cfg['enable']) as $m) {
231 $cls = $proj.'_'. $m . '_Config';
233 if (!file_exists($rootDir . '/'.str_replace('_','/', $cls). '.php')) {
236 require_once str_replace('_','/', $cls). '.php';
238 if (method_exists($c,'init')) {
239 $cfg = $c->init($this,$cfg);
247 * parse the configuration set by the constructor.
252 function _parseConfig()
255 // make sure required values are set.. (anything that is not defaulted to false..)
256 foreach(get_class_vars(__CLASS__) as $k =>$v) {
257 if ($v === false && !isset($this->$k)) {
258 die("$k is not set");
264 if (!empty($this->enable)) {
265 $this->enableArray = explode(',', $this->enable);
267 if (!in_array('Core',$this->enableArray ) &&
268 !in_array('Core', explode(',', $this->disable ? $this->disable : '')))
270 $this->enable = 'Core,'. $this->enable ;
271 $this->enableArray = explode(',', $this->enable);
274 // are we running cli?
275 $this->cli = php_sapi_name() == 'cli';
277 // will these work ok with cli?
278 $bits = explode(basename($_SERVER["SCRIPT_FILENAME"]), $_SERVER["SCRIPT_NAME"]);
280 $bits[0] = str_replace('%2F','/',urlencode($bits[0]));
281 $this->baseURL = $bits[0] . basename($_SERVER["SCRIPT_FILENAME"]);
282 // however this is not correct if we are using rewrite..
283 if (!empty($_SERVER['REDIRECT_STATUS']) && !empty($_SERVER['REDIRECT_URL'])) {
284 $this->baseURL = substr($bits[0],0,-1); // without the trailing '/' ??
285 $this->rootURL = $bits[0] == '/' ? '' : $bits[0];
286 //$this->baseURL = $this->baseURL == '' ? '/' : $this->baseURL;
290 // is this bit used??
291 //if (empty($_SERVER['SCRIPT_NAME'])) {
293 // $this->baseURL = ''; // ??? this is if we replace top level...
296 // if cli - you have to have set baseURL...
299 $this->rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
300 $this->baseDir = $this->rootDir .'/'. $this->project;
301 if (empty($this->rootURL)) {
302 $this->rootURL = dirname($this->baseURL);
303 $this->rootURL = ($this->rootURL == '/') ? '' : $this->rootURL;
307 //var_dump($this->baseURL);
309 if (!isset($this->database) && isset($this->DB_DataObject['database'])) {
310 $this->database = $this->DB_DataObject['database'];
313 $this->classPrefix = str_replace('/', '_', $this->project) . '_';
314 // list the available options..
315 if ($this->cli && empty($_SERVER['argv'][1])) {
316 require_once 'HTML/FlexyFramework/Cli.php';
317 $fcli = new HTML_FlexyFramework_Cli($this);
323 // see if it's a framework assignment.
326 require_once 'HTML/FlexyFramework/Cli.php';
327 $fcli = new HTML_FlexyFramework_Cli($this);
328 $res = $fcli->parseDefaultOpts();
336 $this->run = $this->cli ? $_SERVER['argv'][1] : false;
339 $this->_parseConfigDataObjects();
340 if ($this->dataObjectsCache && !$this->nodatabase) {
341 $this->_configDataObjectsCache();
344 $this->_parseConfigTemplate();
345 $this->_parseConfigMail();
347 //echo '<PRE>';print_r($this);exit;
349 $this->_exposeToPear();
352 $this->_validateEnv();
358 $this->_validateDatabase();
360 $this->_validateTemplate();
366 *'languages' => array(
368 'avail' => array('en','zh_HK', 'zh_CN'),
370 'cookie' => 'TalentPricing_lang',
371 'localemap' => array(
372 'en' => 'en_US.utf8',
373 'zh_HK' => 'zh_TW.utf8',
374 'zh_CN' => 'zh_CN.utf8',
379 function _handleLanguages($request)
382 empty($this->languages) ||
384 !isset($this->languages['cookie']) && !isset($this->languages['default'])
390 $cfg = $this->languages;
392 $default = $cfg['default'];
394 if(!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])){
396 $brower_langs = explode(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
398 foreach ($brower_langs as $bl) {
399 $l = preg_replace('/;(.*)/', '', $bl);
401 $l = str_replace('-', '_', $l);
403 if(!in_array($l, $cfg['avail'])){
412 $lang = isset($_COOKIE[$cfg['cookie']]) ? $_COOKIE[$cfg['cookie']] : $default;
414 // handle languages in request..
415 $bits = explode('/', $request);
416 $redirect_to = false;
417 if (count($bits) && in_array($bits[0],$cfg['avail'])) {
419 $lang = array_shift($bits);
420 $redirect_to = implode('/', $bits);
425 if (isset($_REQUEST[$cfg['param']])) {
426 $lang = $_REQUEST[$cfg['param']];
429 if (!in_array($lang, $cfg['avail'])) {
430 $lang = $cfg['default'];
432 if (isset($cfg['localemap'][$lang])) {
433 setlocale(LC_ALL, $cfg['localemap'][$lang]);
435 setcookie($cfg['cookie'], $lang, 0, '/');
437 $this->locale = $lang;
439 if (!empty($this->HTML_Template_Flexy)) {
440 $this->HTML_Template_Flexy['locale'] = $lang; //set a language for template engine
442 if ($redirect_to !== false) {
443 header('Location: ' . $this->rootURL . '/'.$redirect_to );
449 function parseDefaultLanguage($http_accept, $deflang = "en")
451 if(isset($http_accept) && strlen($http_accept) > 1) {
452 # Split possible languages into array
453 $x = explode(",",$http_accept);
455 foreach ($x as $val) {
456 #check for q-value and create associative array. No q-value means 1 by rule
457 if(preg_match("/(.*);q=([0-1]{0,1}.\d{0,4})/i",$val,$matches))
458 $lang[$matches[1]] = (float)$matches[2];
463 #return default language (highest q-value)
465 foreach ($lang as $key => $value) {
466 if ($value > $qval) {
467 $qval = (float)$value;
472 return strtolower($deflang);
476 * overlay array properties..
479 function applyIf($prop, $ar)
481 if (!isset($this->$prop)) {
485 // add only things that where not set!!!.
486 $this->$prop = array_merge($ar,$this->$prop);
489 //foreach($ar as $k=>$v) {
490 // if (!isset($this->$prop->$k)) {
491 // $this->$prop->$k = $v;
498 * - if turned on (dataObjectsCache = true) then
499 * a) ini file points to a parsed version of the structure.
500 * b) links.ini is a merged version of the configured link files.
502 * This only will force a generation if no file exists at all.. - after that it has to be called manually
503 * from the core page.. - which uses the Expires time to determine if regeneration is needed..
508 function _configDataObjectsCache()
510 // cli works under different users... it may cause problems..
512 $this->debug(__METHOD__);
514 if ($this->database === false) {
518 if (function_exists('posix_getpwuid')) {
519 $uinfo = posix_getpwuid( posix_getuid () );
520 $user = $uinfo['name'];
522 $user = getenv('USERNAME'); // windows.
527 $iniCache = ini_get('session.save_path') .'/' .
528 'dbcfg-' . $user . '/'. str_replace('/', '_', $this->project);
531 if ($this->appNameShort) {
532 $iniCache .= '_' . $this->appNameShort;
534 if ($this->version) {
535 $iniCache .= '.' . $this->version;
539 $dburl = parse_url($this->database);
540 if (!empty($dburl['path'])) {
541 $iniCache .= '-'.ltrim($dburl['path'],'/');
545 $this->debug(__METHOD__ . " : ini cache : $iniCache");
547 $dburl = parse_url($this->database);
548 $dbini = 'ini_'. basename($dburl['path']);
549 $this->debug(__METHOD__ . " : ini file : $dbini");
550 //override ini setting... - store original..
551 if (isset($this->DB_DataObject[$dbini])) {
552 $this->dataObjectsOriginalIni = $this->DB_DataObject[$dbini];
553 ///print_r($this->DB_DataObject);exit;
557 $this->DB_DataObject[$dbini] = $iniCache;
558 // we now have the configuration file name..
561 if (!file_exists($iniCache) || empty( $this->dataObjectsCacheExpires)) {
562 $this->debug(__METHOD__ . ':calling generate do cache');
563 $this->generateDataobjectsCache(true);
571 * _generateDataobjectsCache:
573 * create xxx.ini and xxx.links.ini
575 * @arg force (boolean) force generation - default false;
579 function generateDataobjectsCache($force = false)
581 //$this->debug('generateDataobjectsCache: force=' . ($force ? 'yes' : 'no'));
582 if (!$this->dataObjectsCache) { // does not use dataObjects Caching..
583 $this->debug('generateDataobjectsCache: dataObjectsCache - empty');
587 $dburl = parse_url($this->database);
588 $dbini = 'ini_'. basename($dburl['path']);
591 $iniCache = $this->DB_DataObject[$dbini];
592 $this->debug('generateDataobjectsCache:' .dirname($iniCache).'/*.ini');
596 if (file_exists($iniCache)) {
597 $files = glob(dirname($iniCache).'/*.ini');
598 foreach($files as $f) {
599 $replace[$f] = md5(file_get_contents($f)); // hash it..
603 $this->debug('generateDataobjectsCache: DONE ini delete');
605 $iniCacheTmp = $iniCache . '.tmp' .md5(rand()); // random to stop two processes using the same file.
607 $force = ($force ? $force : !file_exists($iniCache)) || !$this->dataObjectsCacheExpires;
608 // $this->debug('generateDataobjectsCache: after check : force=' . ($force ? 'yes' : 'no'));
609 // not force or not expired, do not bother..
611 if ((filemtime($iniCache) + $this->dataObjectsCacheExpires) >time()) {
620 // force quoting of column names..
621 // unless it forced off..
622 if (!isset($this->DB_DataObject['quote_identifiers_tableinfo'] )) {
623 $this->DB_DataObject['quote_identifiers_tableinfo'] = true;
625 if (!file_exists(dirname($iniCache))) {
626 if (!mkdir(dirname($iniCache),0700, true)) {
627 die("Failed to make cache directory : $iniCache\n");
631 $this->DB_DataObject[$dbini] = $iniCacheTmp;
633 $dl = DB_DataObject::DebugLevel();
634 $this->_exposeToPear(); // this will reset the debug level...
635 DB_DataObject::DebugLevel($dl);
637 $this->debug('generateDataobjectsCache: running generator');
638 // DB_DataObject::debugLevel(1);
639 require_once 'HTML/FlexyFramework/Generator.php';
640 $generator = new HTML_FlexyFramework_Generator();
642 $this->debug('generateDataobjectsCache: done generator');
644 HTML_FlexyFramework_Generator::writeCache($iniCacheTmp, $iniCache, $replace);
645 // reset the cache to the correct lcoation.
646 $this->DB_DataObject[$dbini] = $iniCache;
650 $this->_exposeToPear();
651 DB_DataObject::DebugLevel($dl);
653 //$GLOBALS['_DB_DATAOBJECT']['INI'][$this->database] = parse_ini_file($iniCache, true);
654 //$GLOBALS['_DB_DATAOBJECT']['SEQUENCE']
655 // clear any dataobject cache..
662 * DataObject Configuration:
663 * Always in Project/DataObjects
664 * unless enableArray is available...
669 function _parseConfigDataObjects()
671 if ($this->nodatabase && !$this->database) {
674 $dburl = parse_url($this->database);
675 $dbini = 'ini_'. basename($dburl['path']);
677 $dbinis = array(); //array(dirname(__FILE__) . '/Pman/DataObjects/pman.ini');
678 $dbreq = array(); //array( dirname(__FILE__) . '/Pman/DataObjects/');
679 $dbcls = array(); //array('Pman_DataObjects_');
681 $project = explode('/',$this->project)[0];
683 if (!empty($this->enableArray)) {
685 $tops = array_merge( array($project), empty($this->projectExtends) ? array() : $this->projectExtends);
687 foreach($tops as $td) {
689 $bd = $this->rootDir .'/'.$td;
690 foreach($this->enableArray as $m) {
691 // look in Pman/MODULE/DataObjects/*
692 if (file_exists($bd.'/'.$m.'/DataObjects')) {
693 $dbinis[] = $bd.'/'.$m.'/DataObjects/'. strtolower($project).'.ini';
694 $dbcls[] = $td.'_'. $m . '_DataObjects_';
695 $dbreq[] = $bd.'/'.$m.'/DataObjects';
698 // look in MODULE/DataObjects ?? DO WE SUPPORT THIS ANYMORE???
699 if (file_exists($bd.'/../'.$m.'/DataObjects')) {
700 $dbinis[] = $bd.'/../'.$m.'/DataObjects/'. strtolower($project).'.ini';
701 $dbcls[] = $td. '_DataObjects_';
702 $dbreq[] = $bd.'/../'.$m.'/DataObjects';
711 if (isset($this->DB_DataObject['schema_location'])) {
712 $dbinis[] = $this->DB_DataObject['schema_location'] .'/'.basename($dburl['path']).'.ini';
714 $dbinis[] = $this->baseDir.'/DataObjects/'.basename($dburl['path']).'.ini';
718 $dbcls[] = $project .'_DataObjects_';
719 $dbreq[] = $this->baseDir.'/DataObjects';
723 $this->applyIf('DB_DataObject', array(
725 'class_location' => implode(PATH_SEPARATOR,$dbreq),
726 'class_prefix' => implode(PATH_SEPARATOR,$dbcls),
727 'database' => $this->database,
728 ///'require_prefix' =>
729 // 'schema_location' => dirname(__FILE__) . '/Pman/DataObjects/',
730 $dbini=> implode(PATH_SEPARATOR,$dbinis),
734 // print_r($this->DB_DataObject);exit;
740 function _parseConfigTemplate()
744 if (function_exists('posix_getpwuid')) {
745 $uinfo = posix_getpwuid( posix_getuid () );
747 $user = $uinfo['name'];
749 $user = getenv('USERNAME'); // windows.
752 $compileDir = ini_get('session.save_path') .'/' .
753 $user . '_compiled_templates_' . $this->project;
755 if ($this->appNameShort) {
756 $compileDir .= '_' . $this->appNameShort;
758 if ($this->version) {
759 $compileDir .= '.' . $this->version;
762 // templates. -- all this should be cached!!!
766 if ($this->appNameShort && !in_array('Core', explode(',', $this->disable ? $this->disable : ''))) {
767 // in app based version, template directory is in Core
770 $this->baseDir . '/Core/templates'
774 if(!empty($this->projectExtends)){
775 foreach ($this->projectExtends as $e){
776 $add = $this->rootDir . '/' . $e .'/templates';
777 if (!in_array($add,$src) && file_exists($add)) {
783 $src[] = $this->baseDir . '/templates';
787 if (!empty($this->enableArray)) {
790 foreach($this->enableArray as $m) {
791 $add = $this->baseDir . '/' . $m .'/templates';
792 if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
797 if (!empty($this->projectExtends) ) {
798 foreach ($this->projectExtends as $extend){
799 foreach($this->enableArray as $m) {
800 $add = $this->rootDir . '/' . $extend . '/' . $m .'/templates';
801 if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
811 if ($this->appNameShort) {
812 $src[] = $this->baseDir . '/'. $this->appNameShort. '/templates';
815 // images may come from multiple places: - if we have multiple template directories.?
816 // how do we deal with this..?
817 // images/ << should always be mapped to master!
818 // for overridden appdir ones we will have to se rootURL etc.
820 $url_rewrite = 'images/:'. $this->rootURL . '/'. $this->project. '/templates/images/';
822 $this->applyIf('HTML_Template_Flexy', array(
823 'templateDir' => implode(PATH_SEPARATOR, $src),
824 'compileDir' => $compileDir,
825 'multiSource' => true,
827 'url_rewrite' => $url_rewrite,
828 'filters' => 'Php,SimpleTags', /// for non-tokenizer version?
829 'debug' => $this->debug ? 1 : 0,
838 function _parseConfigMail()
840 $this->applyIf('HTML_Template_Flexy', array(
843 'host' => 'localhost',
847 function _exposeToPear()
849 $cls = array_keys(get_class_vars(__CLASS__));
852 // anything that get's set, that's not in our default properties
853 // is assumed to be an option set .
854 foreach(get_object_vars($this) as $k=>$v) {
855 if (in_array($k,$cls)) {
859 $options = &PEAR::getStaticProperty($k,'options');
862 $options = &PEAR::getStaticProperty('HTML_FlexyFramework','options');
868 function _validateEnv()
870 /* have I been initialized */
873 if (version_compare(PHP_VERSION, '7.0.0') < 0 && get_magic_quotes_gpc() && !$this->cli) {
875 "magic quotes is enabled add the line<BR>
876 php_value magic_quotes_gpc 0<BR>
877 to your .htaccess file <BR>
878 (Apache has to be configured to "AllowOverride Options AuthConfig" for the directory)
882 // set up error handling -
883 $this->error = new HTML_FlexyFramework_Error();
885 /// fudge work around bugs in PEAR::setErrorHandling(,)
886 $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_CALLBACK;
887 $GLOBALS['_PEAR_default_error_options'] = array($this->error,'raiseError');
892 require_once 'Benchmark/Timer.php';
893 $this->timer = new BenchMark_Timer(true);
894 register_shutdown_function(function() { echo $this->timer->getOutput(); });
899 function _validateDatabase()
901 //echo "<PRE>"; print_r($this);
903 if ($this->nodatabase) {
906 $options = &PEAR::getStaticProperty('DB_DataObject','options');
907 $dd = empty($options['dont_die']) ? false : true;
908 $options['dont_die'] = true;
910 // database is the only setting - we dont support mult databses?
913 $x = new DB_Dataobject;
914 $x->_database = $this->database;
915 if (PEAR::isError($err = $x->getDatabaseConnection())) {
918 $this->fatalError("Configuration or Database Error: could not connect to Database, <BR>
919 Please check the value given to HTML_FlexyFramework, or run with debug on!<BR>
920 <BR> ".$err->toString());
922 // only applies to mysql...
924 if (preg_match('/^mysql/', $this->database)) {
925 $res = $err->query("SELECT @@global.read_only as ro");
927 $row = is_a($res, 'DB_Error') ? false : $res->fetchRow(DB_FETCHMODE_ASSOC);
928 if (!$row || !empty($row['ro'])) {
929 if (empty($options['skip-read-only-check'])) {
930 $this->fatalError("Database is configured to be read-only - please check database<BR> ".$err->toString());
932 $this->database_is_readonly = true;
936 $options['dont_die'] = $dd ;
940 function _validateTemplate()
942 // check that we have a writeable directory for flexy's compiled templates.
944 if (empty($this->HTML_Template_Flexy['compileDir'])) {
948 if ( !file_exists($this->HTML_Template_Flexy['compileDir'])) {
949 mkdir($this->HTML_Template_Flexy['compileDir'], 0700, true);
952 if ( !file_exists($this->HTML_Template_Flexy['compileDir'])) {
954 $this->fatalError("Configuration Error: you specified a directory that does not exist for<BR>
955 HTML_Template_Flexy => compileDir {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
960 if (!is_writeable($this->HTML_Template_Flexy['compileDir'])) {
961 $this->fatalError("Configuration Error: Please make sure the template cache directory is writeable<BR>
963 chmod 700 {$this->HTML_Template_Flexy['compileDir']}<BR>
964 chgrp apache_user {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
967 //echo "<PRE>";print_R($config);
985 * HTML_FlexyFramework::run('someurl/someother',array('somearg'=>'xxx'));
987 * exit; <- dont cary on!!!!
991 * @param string redirect to url
992 * @param array Args Optional any data you want to send to the next page..
1001 static function run($request,$args=array())
1003 self::$singleton->_run($request,true,$args);
1009 * The main execution loop
1011 * recursivly self called if redirects (eg. return values from page start methods)
1013 * @param string from $_REQUEST or redirect from it'self.
1014 * @param boolean isRedirect = is the request a redirect
1017 * @return false || other false indicates no page was served!
1018 * @access public|private
1019 * @see see also methods.....
1022 function _run($request,$isRedirect = false,$args = array())
1025 // clean the request up.
1028 if ($this->calls > 5) {
1029 // to many redirections...
1030 trigger_error("FlexyFramework:: too many redirects - backtrace me!",E_USER_ERROR);
1034 $newRequest = $this->_getRequest($request,$isRedirect);
1037 // find the class/file to load
1038 list($classname,$subRequest) = $this->requestToClassName($newRequest,FALSE);
1041 $this->debug("requestToClassName return = CLASSNAME: $classname SUB REQUEST: $subRequest");
1043 // assume that this was handled by getclassname ?????
1048 // make page data/object accessable at anypoint in time using this
1049 // not sure if this is used anymore - or even works..?
1050 $classobj = &PEAR::getStaticProperty('HTML_FlexyFramework', 'page');
1052 $classobj = new $classname(); // normally do not have constructors.
1055 $classobj->baseURL = $this->baseURL;
1056 $classobj->rootURL = $this->rootURL;
1057 $classobj->rootDir = $this->rootDir;
1058 $classobj->bootLoader = $this;
1059 $classobj->request = $newRequest;
1060 $classobj->timer = &$this->timer;
1061 $classobj->cli = $this->cli;
1063 $this->page = $classobj;
1064 if ($this->cli && !$isRedirect ) { // redirect always just takes redirect args..
1065 require_once 'HTML/FlexyFramework/Cli.php';
1066 $fcli = new HTML_FlexyFramework_Cli($this);
1067 $nargs = $fcli->cliParse($classname);
1068 $args = $nargs === false ? $args : $nargs; /// replace if found.
1069 $classobj->cli_args = $nargs;
1072 // echo '<PRE>'; print_r($this);exit;
1073 // echo "CHECK GET AUTH?";
1075 if (!method_exists($classobj, 'getAuth')) {
1076 // echo "NO GET AUTH?";
1077 $this->fatalError("class $classname does not have a getAuth Method");
1081 /* check auth on the page */
1082 if (is_string($redirect = $classobj->getAuth())) {
1083 $this->debug("GOT AUTH REDIRECT".$redirect);
1084 return $this->_run($redirect,TRUE);
1086 // used HTML_FlexyFramework::run();
1089 if ($redirect === false) {
1090 $this->debug("GOT AUTH FALSE");
1091 return false; /// Access deined!!! -
1094 // allow the page to implement caching (for the full page..)
1095 // although normally it should implement caching on the outputBody() method.
1097 if (method_exists($classobj,"getCache")) {
1098 if ($result = $classobj->getCache()) {
1103 /* allow redirect from start */
1104 if (method_exists($classobj,"start")) {
1105 if (is_string($redirect = $classobj->start($subRequest,$isRedirect,$args))) {
1106 $this->debug("REDIRECT $redirect <BR>");
1107 return $this->_run($redirect,TRUE);
1109 if ($redirect === false) {
1115 // used HTML_FlexyFramework::run();
1118 * Modules are common page components like navigation headers etc.
1119 * that can have dynamic code.
1120 * Code has been removed now..
1125 $this->timer->setMarker("After $request loadModules Modules");
1128 /* output it - (our base page does not implement output for cli. */
1130 if ( method_exists($classobj,'output')) {
1131 $classobj->output();
1136 $this->timer->setMarker("After $request output");
1137 $this->timer->stop(); //?? really - yes...
1147 exit; /// die here...
1152 * map the request into an object and run the page.
1154 * The core of the work is done here.
1157 * @param request the request string
1158 * @param boolean isRedirect - indicates that it should not attempt to strip the .../index.php from the request.
1163 function _getRequest($request, $isRedirect)
1171 $startRequest = $request;
1172 $ra = explode('?', $request);
1173 $request = array_shift($ra);
1174 $this->debug("INPUT REQUEST $request<BR>");
1176 // check that request forms contains baseurl????
1177 if (!empty($_SERVER['REDIRECT_STATUS']) && !empty($_SERVER['REDIRECT_URL'])) {
1179 $sn = $_SERVER['SCRIPT_NAME'];
1180 $sublen = strlen(substr($sn , 0, strlen($sn) - strlen(basename($sn)) -1 ));
1181 //var_dump(array($sn,$subdir,basename($sn)));exit;
1182 $subreq = $_SERVER['SCRIPT_NAME'];
1183 $request = substr($_SERVER['REDIRECT_URL'],$sublen);
1189 $subreq = substr($request,0, strlen($this->baseURL));
1190 if ($subreq != substr($this->baseURL,0,strlen($subreq))) {
1192 "Configuration error: Got base of $subreq which does not
1193 match configuration of: $this->baseURL} ");
1195 $request = substr($request,strlen($this->baseURL));
1201 // var_Dump(array('req'=>$request,'subreq'=>$subreq));
1204 // echo "REQUEST WAS: $request<BR>";
1205 // $request = preg_replace('/^'.preg_quote($base_url,'/').'/','',trim($request));
1206 // echo "IS NOW: $request<BR>";
1208 // strip valid html stuff
1209 //$request = preg_replace('/\/[.]+/','',$request);
1212 $request = preg_replace('/^[\/]*/','',$request);
1213 $request = preg_replace('/\?.*$/','',$request);
1214 $request = preg_replace('/[\/]*$/','',$request);
1215 $this->baseRequest = $request;
1216 $request = str_replace('&','',$request); // any other invalid characters???
1217 $request = preg_replace('/\.([a-z]+)$/','',$request);
1218 $this->ext = substr($this->baseRequest , strlen($request));
1220 // REDIRECT ROO to index.php! for example..
1222 if (!$request && !$isRedirect) {
1223 if ($this->baseURL && (strlen($startRequest) < strlen($this->baseURL))) {
1224 // needs to handle https + port
1225 $http = ((!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on')) ? 'https' : 'http';
1227 if (!empty($_SERVER['SERVER_PORT'])) {
1228 if ((($http == 'http') && ($_SERVER['SERVER_PORT'] == 80)) || (($http == 'https') && ($_SERVER['SERVER_PORT'] == 443))) {
1231 $sp .= ':'.((int) $_SERVER['SERVER_PORT']);
1234 // not sure why http host would not be set?
1235 $host = !empty($_SERVER["HTTP_X_FORWARDED_HOST"]) ? $_SERVER["HTTP_X_FORWARDED_HOST"] :
1236 (!isset($_SERVER["HTTP_HOST"]) ? 'localhost' : $_SERVER["HTTP_HOST"]);
1238 header('Location: '.$http.'://'.$host .$sp . $this->baseURL);
1244 // var_dump(array($startRequest,$request, $this->baseRequest));
1246 $this->debug("OUTPUT REQUEST $request<BR>");
1248 $this->_handleLanguages($request);
1258 * get the Class name and filename to load
1260 * Parses the request and converts that into a File + Classname
1261 * if the class doesnt exist it will attempt to find a file below it, and
1262 * call that one with the data.
1263 * Used by the module loader to determine the location of the modules
1265 * @param request the request string
1266 * @param boolean showError - if false, allows you to continue if the class doesnt exist.
1269 * @return array classname, filepath
1274 function requestToClassName($request,$showError=TRUE)
1276 // if ($request == "error") {
1277 // return array("HTML_FlexyFramework_Error","");
1280 // special classes ::
1281 if ($this->cli && in_array($request, array('DataObjects'))) {
1282 require_once 'HTML/FlexyFramework/'. $request . '.php';
1283 return array('HTML_FlexyFramework_'. $request,'');
1287 $request_array = explode("/",$request);
1288 $original_request_array = $request_array;
1289 $sub_request_array = array();
1290 $l = count($request_array)-1;
1291 if ($l > 10) { // ?? configurable?
1292 //PEAR::raiseError("Request To Long");
1293 $this->fatalError("Request To Long - " . $request);
1298 // tidy up request array
1300 if ($request_array) {
1301 foreach(array_keys($request_array) as $i) {
1302 $request_array[$i] = preg_replace('/[^a-z0-9]/i','_',urldecode($request_array[$i]));
1305 //echo "<PRE>"; print_r($request_array);
1306 // technically each module should do a check here... similar to this..
1309 for ($i=$l;$i >-1;$i--) {
1310 $location = implode('/',$request_array) . ".php";
1311 if ($location == '.php') {
1312 $this->debug("SKIP first path check, as request str is empty");
1316 $this->debug("baseDIR = {$this->baseDir}");
1318 $floc = "{$this->baseDir}/$location";
1319 $this->debug("CHECK LOCATION = $location");
1323 if (!empty($location) && $location != '.php' && @file_exists($floc )) { // hide? error???
1324 require_once $floc ;
1325 $classname = $this->classPrefix . implode('_',$request_array);
1326 $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1330 // in here check the 'projectExtends' versions..?
1332 if(!empty($this->projectExtends)){
1333 $this->debug("Trying project Extends<BR>");
1334 $has_extend_class = false;
1336 foreach ($this->projectExtends as $e){
1337 $floc = "{$this->rootDir}/{$e}/$location";
1338 $this->debug("Trying file: $floc");
1339 if (!empty($location) && @file_exists($floc)) { // hide? error???
1340 require_once $floc ;
1341 $classname = $e . '_' . implode('_',$request_array);
1342 $has_extend_class = true;
1343 $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1348 if(!empty($has_extend_class)){
1355 $this->debug("$floc - !!FOUND NOT FILE!!");
1357 $sub_request_array[] = $original_request_array[$i];
1358 unset($request_array[$i]);
1359 unset($original_request_array[$i]);
1362 // is this really needed here!
1364 $classname = preg_replace('/[^a-z0-9]/i','_',$classname);
1365 $this->debug("CLASSNAME is '$classname'");
1367 if ($classname && class_exists($classname)) {
1368 $this->debug("using $classname");
1369 //print_r($sub_request_array);
1370 return array($classname,implode('/',array_reverse($sub_request_array)));
1374 $this->fatalError("INVALID REQUEST: \n $request FILE:".$this->baseDir. "/{$location} CLASS:{$classname}");
1379 $this->debug("Try base {$this->baseDir}.php");
1380 // try {project name}.php
1381 // this used to be silenced @ - if this fails we are usually pretty fried..
1383 if (file_exists($this->baseDir.'.php')) {
1386 $classname = str_replace('/', '_', $this->project); // basename($this->baseDir);
1388 $this->debug("FOUND {$this->baseDir} requring and checking class $classname");
1389 require_once $this->baseDir.'.php';
1390 $this->debug("require success");
1392 if (!class_exists($classname)) {
1393 $this->fatalError( "{$this->baseDir}.php did not contain class $classname");
1396 // got projectname.php
1397 if ($classname && class_exists($classname)) {
1398 $this->debug("using $classname");
1399 //print_r($sub_request_array);
1401 return array($classname,implode('/',array_reverse($sub_request_array)));
1405 $this->fatalError( "can not find {$this->baseDir}.php"); // dies..
1411 * ensure Single CLi process
1413 * HTML_FlexyFramework::ensureSingle(__FILE__, $this);
1414 * @param string filename of running class
1415 * @param object class
1418 static function ensureSingle($sig, $class)
1420 //echo "check single: $sig / ". get_class($class) ."\n";
1421 $ff = HTML_FlexyFramework::get();
1422 if (function_exists('posix_getpwuid')) {
1423 $uinfo = posix_getpwuid( posix_getuid () );
1424 $user = $uinfo['name'];
1426 $user = getenv('USERNAME'); // windows.
1428 $fdir = ini_get('session.save_path') .'/' .
1429 $user . '_cli_' . $ff->project ;
1432 if (!file_exists($fdir)) {
1436 $lock = $fdir.'/'. md5($sig) . '.' . get_class($class);
1437 //echo "check single: lock : $lock\n";
1438 if (!file_exists($lock)) {
1439 file_put_contents($lock, getmypid());
1440 //echo "check single: lock : DOES NOT EXIST\n";
1443 $oldpid = file_get_contents($lock);
1444 if (!file_exists('/proc/' . $oldpid)) {
1446 file_put_contents($lock, getmypid());
1447 // echo "check single: lock : PROC NOT EXIST\n";
1450 // file exists, but process might not be the same..
1451 $ea = explode('_', get_class($class));
1452 $name = array_pop($ea);
1453 $cmd = file_get_contents('/proc/' . $oldpid.'/cmdline');
1454 if (!preg_match('/php/i',$cmd) || !preg_match('/'.$name.'/i',$cmd)) {
1455 file_put_contents($lock, getmypid());
1456 //echo "check single: lock : CMDLINE !have PHP \n";
1459 die("process " . $sig . " already running\n");
1463 * removes the lock for the applicaiton - use with care...
1467 static function ensureSingleClear($sig, $class)
1469 $ff = HTML_FlexyFramework::get();
1470 if (function_exists('posix_getpwuid')) {
1471 $uinfo = posix_getpwuid( posix_getuid () );
1472 $user = $uinfo['name'];
1474 $user = getenv('USERNAME'); // windows.
1476 $fdir = ini_get('session.save_path') .'/' .
1477 $user . '_cli_' . $ff->project ;
1480 if (!file_exists($fdir)) {
1483 $lock = $fdir.'/'. md5($sig);
1484 if (!file_exists($lock)) {
1495 * @param string text to output.
1499 function debug($output) {
1501 if (empty($this->debug)) {
1505 "HTML_FlexyFramework::debug - ".$output."\n"
1506 : "<B>HTML_FlexyFramework::debug</B> - ".$output."<BR>\n";
1510 * Raises a fatal error. - normally only used when setting up to help get the config right.
1512 * can redirect to fatal Action page.. - hoepfully not issued before basic vars are set up..
1514 * @param string text to output.
1518 function fatalError($msg,$showConfig = 0)
1522 if ($this->fatalAction) {
1523 HTML_FlexyFramework::run($this->fatalAction,$msg);
1526 header('HTTP/1.1 503 Service Temporarily Unavailable');
1527 header('Status: 503 Service Temporarily Unavailable');
1528 header('Retry-After: 300');
1529 echo $this->cli ? $msg ."\n" : "<H1>$msg</H1>configuration information<PRE>";
1534 $ff = HTML_FlexyFramework::get();