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 'HTML/FlexyFramework2/Page.php';
36 // To be removed ?? or made optional or something..
41 error_reporting(E_ALL & ~E_STRICT );
42 //ini_set('display_errors','off');
43 //ini_set('log_errors','off');
51 * The URL to Object Mapper
54 * Create a index.php and add these lines.
56 * ini_set("include_path", "/path/to/application");
57 * require_once 'HTML/FlexyFramework.php';
58 * HTML_FlexyFramework::factory(array("dir"=>"/where/my/config/dir/is");
61 * the path could include pear's path, if you dont install all the pear
62 * packages into the development directory.
64 * It attempts to load a the config file from the includepath,
65 * looks for ConfigData/default.ini
66 * or ConfigData/{hostname}.ini
67 * if your file is called staging.php rather than index.php
68 * it will try staging.ini
71 #[AllowDynamicProperties]
72 class HTML_FlexyFramework2 {
75 * Confirgurable items..
76 * If we set them to 'true', they must be set, otherwise they are optional.
78 var $project; // base class name
79 var $database; // set to true even if nodatabase=true
83 var $enable = false; // modules
84 var $disable = false; // modules or permissions
86 var $appNameShort = false; // appname (which has templates)
87 var $version = false; // give it a version name. (appended to compile dir)
88 var $nodatabase = false; // set to true to block db config and testing.
89 var $fatalAction = false; // page to redirct to on failure. (eg. databse down etc.)
90 var $charset = false; // default UTF8
91 var $dataObjectsCache = true; // use dataobjects ini cache.. - let's try this as the default behaviour...
92 var $dataObjectsCacheExpires = 72000; // 20 hours..
93 var $languages = false; // language settings -- see _handlelanguage
94 var $projectExtends = false; // if this is an array, it's a fallback of 'Projects' that can be called
95 var $initOnly = false; // use to prevent run() being called...
96 // use $this->run($_SERVER['REQUEST_URI'],false); to manually boot it..
99 var $isDev = false; // is development mode (can debug sql?)
101 var $cli = false; // from cli
102 var $run = false; // from cli
103 var $enableArray = false; // from enable.
104 var $classPrefix = false; // from prject.
105 var $baseDir = false ; // (directory+project)
106 var $rootDir = false ; // (directory that index.php is in!)
108 var $baseURL = false;
109 var $rootURL = false ; // basename($baseURL)
111 var $page = false; // active page..
112 var $timer = false; // the debug timer
113 var $calls = false; // the number of calls made to run!
114 var $start = false; // the start tiem.
116 var $baseRequest = '';
117 var $ext; // the striped extention.
119 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..
170 if ($this->initOnly) {
175 if (!empty($_SERVER['REDIRECT_URL'])) {
177 $this->_run($_SERVER['SCRIPT_NAME'] . $_SERVER['REQUEST_URI'],false);
182 $this->_run($_SERVER['REQUEST_URI'],false);
187 * This is the standard way to get information about the application settings.
188 * $ff = HTML_FlexyFramework::get();
189 * if ($ff->SomeVar[...])....
192 static function get()
194 return self::$singleton;
197 * looks for files in the path and load up the default values for config?
199 function loadModuleConfig($cfg)
203 $proj = $cfg['project'];
204 $rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
206 $cls = $proj.'_Config';
207 if (file_exists($rootDir . '/'.str_replace('_','/', $cls). '.php')) {
208 require_once str_replace('_','/', $cls). '.php';
210 if (method_exists($c,'init')) {
211 $cfg = $c->init($this,$cfg);
215 $mods = empty($cfg['enable']) ? array() : explode(',',$cfg['enable']);
216 array_unshift($mods,'');
218 foreach($mods as $m) {
219 $cls = $proj. (strlen($m) ? '_'. $m : '' ) . '_Config';
221 if (!file_exists($rootDir . '/'.str_replace('_','/', $cls). '.php')) {
224 require_once str_replace('_','/', $cls). '.php';
226 if (method_exists($c,'init')) {
227 $cfg = $c->init($this,$cfg);
235 * parse the configuration set by the constructor.
240 function _parseConfig()
243 // make sure required values are set.. (anything that is not defaulted to false..)
244 foreach(get_class_vars(__CLASS__) as $k =>$v) {
245 if ($v === false && !isset($this->$k)) {
246 die("$k is not set");
250 $this->_handleLanguages();
253 if (!empty($this->enable)) {
254 $this->enableArray = explode(',', $this->enable);
256 if (!in_array('Core',$this->enableArray ) &&
257 !in_array('Core', explode(',', $this->disable ? $this->disable : '')))
259 $this->enable = 'Core,'. $this->enable ;
260 $this->enableArray = explode(',', $this->enable);
263 // are we running cli?
264 $this->cli = php_sapi_name() == 'cli';
266 // will these work ok with cli?
267 $bits = explode(basename($_SERVER["SCRIPT_FILENAME"]), $_SERVER["SCRIPT_NAME"]);
269 $bits[0] = str_replace('%2F','/',urlencode($bits[0]));
270 $this->baseURL = $bits[0] . basename($_SERVER["SCRIPT_FILENAME"]);
272 if (empty($_SERVER['SCRIPT_NAME'])) {
273 $this->baseURL = ''; // ??? this is if we replace top level...
276 // if cli - you have to have set baseURL...
279 $this->rootDir = realpath(dirname($_SERVER["SCRIPT_FILENAME"]));
280 $this->baseDir = $this->rootDir .'/'. $this->project;
281 $this->rootURL = dirname($this->baseURL);
282 $this->rootURL = ($this->rootURL == '/') ? '' : $this->rootURL;
285 //var_dump($this->baseURL);
287 if (!isset($this->database) && isset($this->PDO_DataObject['database'])) {
288 $this->database = $this->PDO_DataObject['database'];
291 $this->classPrefix = str_replace('/', '_', $this->project) . '_';
293 // list the available options..
294 if ($this->cli && empty($_SERVER['argv'][1])) {
295 require_once 'HTML/FlexyFramework2/Cli.php';
296 $fcli = new HTML_FlexyFramework2_Cli($this);
302 // see if it's a framework assignment.
305 require_once 'HTML/FlexyFramework2/Cli.php';
306 $fcli = new HTML_FlexyFramework2_Cli($this);
307 $res = $fcli->parseDefaultOpts();
315 $this->run = $this->cli ? $_SERVER['argv'][1] : false;
318 $this->_parseConfigDataObjects();
319 if ($this->dataObjectsCache && !$this->nodatabase) {
320 $this->_configDataObjectsCache();
323 $this->_parseConfigTemplate();
324 $this->_parseConfigMail();
326 //echo '<PRE>';print_r($this);exit;
328 //$this->_exposeToPear();
331 $this->_validateEnv();
337 $this->_validateDatabase();
339 $this->_validateTemplate();
345 *'languages' => array(
347 'avail' => array('en','zh_HK', 'zh_CN'),
349 'cookie' => 'TalentPricing_lang',
350 'localemap' => array(
351 'en' => 'en_US.utf8',
352 'zh_HK' => 'zh_TW.utf8',
353 'zh_CN' => 'zh_CN.utf8',
358 function _handleLanguages()
361 empty($this->languages) ||
363 !isset($this->languages['cookie']) && !isset($this->languages['default'])
369 $cfg = $this->languages;
371 $default = $cfg['default'];
373 if(!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])){
375 $brower_langs = explode(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
377 foreach ($brower_langs as $bl) {
378 $l = preg_replace('/;(.*)/', '', $bl);
380 $l = str_replace('-', '_', $l);
382 if(!in_array($l, $cfg['avail'])){
391 $lang = isset($_COOKIE[$cfg['cookie']]) ? $_COOKIE[$cfg['cookie']] : $default;
393 //print_r($_COOKIE); print_R($cfg['cookie']);print_R($lang);exit;
395 $lang = preg_replace('/^s:/','', $lang); // for some reason roo's library prefixes values with s:
396 if (isset($_REQUEST[$cfg['param']])) {
397 $lang = $_REQUEST[$cfg['param']];
400 if (!in_array($lang, $cfg['avail'])) {
401 $lang = $cfg['default'];
403 if (isset($cfg['localemap'][$lang])) {
404 setlocale(LC_ALL, $cfg['localemap'][$lang]);
406 setcookie($cfg['cookie'], $lang, 0, '/');
408 $this->locale = $lang;
410 if (!empty($this->HTML_Template_Flexy)) {
411 $this->HTML_Template_Flexy['locale'] = $lang; //set a language for template engine
417 * overlay array properties..
420 function applyIf($prop, $ar) {
421 if (!isset($this->$prop)) {
425 // add only things that where not set!!!.
426 $this->$prop = array_merge($ar,$this->$prop);
429 //foreach($ar as $k=>$v) {
430 // if (!isset($this->$prop->$k)) {
431 // $this->$prop->$k = $v;
438 * - if turned on (dataObjectsCache = true) then
439 * a) ini file points to a parsed version of the structure.
440 * b) links.ini is a merged version of the configured link files.
442 * This only will force a generation if no file exists at all.. - after that it has to be called manually
443 * from the core page.. - which uses the Expires time to determine if regeneration is needed..
448 function _configDataObjectsCache()
450 // cli works under different users... it may cause problems..
451 $this->debug(__METHOD__);
452 if (function_exists('posix_getpwuid')) {
453 $uinfo = posix_getpwuid( posix_getuid () );
454 $user = $uinfo['name'];
456 $user = getenv('USERNAME'); // windows.
461 $iniCache = ini_get('session.save_path') .'/' .
462 'pdocfg-' . $user . '/'. str_replace('/', '_', $this->project) ;
465 if ($this->appNameShort) {
466 $iniCache .= '_' . $this->appNameShort;
468 if ($this->version) {
469 $iniCache .= '.' . $this->version;
471 if ($this->database === false) {
475 $dburl = parse_url($this->database);
476 if (!empty($dburl['path'])) {
477 $iniCache .= '-'.ltrim($dburl['path'],'/');
481 $this->debug(__METHOD__ . " : ini cache : $iniCache");
483 $dburl = parse_url($this->database);
484 //override ini setting... - store original..
486 if (isset($this->PDO_DataObject['schema_location'])) {
487 $this->dataObjectsOriginalIni = $this->PDO_DataObject['schema_location'];
488 ///print_r($this->DB_DataObject);exit;
491 $this->PDO_DataObject['schema_location'] = $iniCache;
492 PDO_DataObject::config($this->PDO_DataObject);
494 // we now have the configuration file name..
496 if (!file_exists($iniCache) || empty( $this->dataObjectsCacheExpires)) {
497 $this->generateDataobjectsCache(true);
505 * generateDataobjectsCache:
507 * if the 'cache file' does not exist, then
508 * create it using HTML_FlexyFramework2_Generator
510 * create xxx.ini and xxx.links.ini
512 * @arg force (boolean) force generation - default false;
516 function generateDataobjectsCache($force = false)
518 //$this->debug('generateDataobjectsCache: force=' . ($force ? 'yes' : 'no'));
519 if (!$this->dataObjectsCache) { // does not use dataObjects Caching..
520 PDO_DataObject::config('schema_location', $this->dataObjectsOriginalIni );
522 $this->debug('generateDataobjectsCache', 'dataObjectsCache - empty');
526 $dburl = parse_url($this->database);
527 $dbnick = basename($dburl['path']);
531 $iniCache = $this->PDO_DataObject['schema_location'];
536 if (file_exists($iniCache)) {
537 $files = glob(dirname($iniCache).'/*.ini');
538 foreach($files as $f) {
539 $replace[$f] = md5(file_get_contents($f)); // hash it..
546 $iniCacheTmp = $iniCache . '.tmp' .md5(rand()); // random to stop two processes using the same file.
548 $force = ($force ? $force : !file_exists($iniCache)) || !$this->dataObjectsCacheExpires;
549 // $this->debug('generateDataobjectsCache: after check : force=' . ($force ? 'yes' : 'no'));
550 // not force or not expired, do not bother..
552 if ((filemtime($iniCache) + $this->dataObjectsCacheExpires) >time()) {
558 $this->debug('generateDataobjectsCache', 'dataObjectsCache generating');
561 // force quoting of column names..
562 // unless it forced off..
563 if (!isset($this->PDO_DataObject['quote_identifiers'] )) {
564 $this->PDO_DataObject['quote_identifiers'] = true;
566 if (!file_exists(dirname($iniCache))) {
567 mkdir(dirname($iniCache),0700, true);
570 $this->PDO_DataObject['schema_location'] = $iniCacheTmp;
572 PDO_DataObject::reset();
574 PDO_DataObject::config($this->PDO_DataObject);
578 // DB_DataObject::debugLevel(1);
579 require_once 'HTML/FlexyFramework2/Generator.php';
581 PDO_DataObject::config('database', $this->database);
582 $generator = new HTML_FlexyFramework2_Generator();
585 $this->debug('generateDataobjectsCache', 'dataObjectsCache writing');
586 HTML_FlexyFramework2_Generator::writeCache($iniCacheTmp, $iniCache, $replace);
587 // reset the cache to the correct lcoation.
588 PDO_DataObject::config('schema_location', $iniCache);
589 $this->PDO_DataObject['schema_location'] = $iniCache;
590 //$this->_exposeToPear();
592 //$GLOBALS['_DB_DATAOBJECT']['INI'][$this->database] = parse_ini_file($iniCache, true);
593 //$GLOBALS['_DB_DATAOBJECT']['SEQUENCE']
594 // clear any dataobject cache..
601 * DataObject Configuration:
602 * Always in Project/DataObjects
603 * unless enableArray is available...
608 function _parseConfigDataObjects()
610 if ($this->nodatabase && !$this->database) {
614 // better done here.. ?? only include if we have database configuration?
615 require_once 'PDO/DataObject.php';
617 $dburl = parse_url($this->database);
618 $dbini = 'ini_'. basename($dburl['path']);
620 $dbinis = array(); //array(dirname(__FILE__) . '/Pman/DataObjects/pman.ini');
621 $dbreq = array(); //array( dirname(__FILE__) . '/Pman/DataObjects/');
622 $dbcls = array(); //array('Pman_DataObjects_');
624 $project = explode('/',$this->project)[0];
626 if (!empty($this->enableArray)) {
628 $tops = array_merge( array($project), empty($this->projectExtends) ? array() : $this->projectExtends);
630 foreach($tops as $td) {
631 $bd = $this->rootDir .'/'.$td;
632 foreach($this->enableArray as $m) {
633 // look in Pman/MODULE/DataObjects/*
634 if (file_exists($bd.'/'.$m.'/DataObjects')) {
635 $dbinis[] = $bd.'/'.$m.'/DataObjects/'. strtolower($td).'.ini';
636 $dbcls[] = $td.'_'. $m . '_DataObjects_';
637 $dbreq[] = $bd.'/'.$m.'/DataObjects';
640 // look in MODULE/DataObjects ?? DO WE SUPPORT THIS ANYMORE???
641 if (file_exists($bd.'/../'.$m.'/DataObjects')) {
642 $dbinis[] = $bd.'/../'.$m.'/DataObjects/'. strtolower($td).'.ini';
643 $dbcls[] = $td. '_DataObjects_';
644 $dbreq[] = $bd.'/../'.$m.'/DataObjects';
653 if (isset($this->PDO_DataObject['schema_location'])) {
654 $dbinis[] = $this->PDO_DataObject['schema_location'] .'/'.basename($dburl['path']).'.ini';
656 $dbinis[] = $this->baseDir.'/DataObjects/'.basename($dburl['path']).'.ini';
660 $dbcls[] = $project .'_DataObjects_';
661 $dbreq[] = $this->baseDir.'/DataObjects';
665 $this->applyIf('PDO_DataObject', array(
667 'class_location' => implode(PATH_SEPARATOR,$dbreq),
668 'class_prefix' => implode(PATH_SEPARATOR,$dbcls),
669 'database' => $this->database,
670 ///'require_prefix' =>
671 // 'schema_location' => dirname(__FILE__) . '/Pman/DataObjects/',
672 'schema_location' => implode(PATH_SEPARATOR,$dbinis),
676 PDO_DataObject::config($this->PDO_DataObject);
683 function _parseConfigTemplate()
687 if (function_exists('posix_getpwuid')) {
688 $uinfo = posix_getpwuid( posix_getuid () );
690 $user = $uinfo['name'];
692 $user = getenv('USERNAME'); // windows.
695 $compileDir = ini_get('session.save_path') .'/' .
696 $user . '_compiled_templates_' . $this->project;
698 if ($this->appNameShort) {
699 $compileDir .= '_' . $this->appNameShort;
701 if ($this->version) {
702 $compileDir .= '.' . $this->version;
705 // templates. -- all this should be cached!!!
709 if ($this->appNameShort && !in_array('Core', explode(',', $this->disable ? $this->disable : ''))) {
710 // in app based version, template directory is in Core
713 $this->baseDir . '/Core/templates'
717 if(!empty($this->projectExtends)){
718 foreach ($this->projectExtends as $e){
719 $add = $this->rootDir . '/' . $e .'/templates';
720 if (!in_array($add,$src) && file_exists($add)) {
726 $src[] = $this->baseDir . '/templates';
730 if (!empty($this->enableArray)) {
733 foreach($this->enableArray as $m) {
734 $add = $this->baseDir . '/' . $m .'/templates';
735 if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
740 if (!empty($this->projectExtends) ) {
741 foreach ($this->projectExtends as $extend){
742 foreach($this->enableArray as $m) {
743 $add = $this->rootDir . '/' . $extend . '/' . $m .'/templates';
744 if (!in_array($add,$src) && file_exists($add) && $this->appNameShort != $m) {
754 if ($this->appNameShort) {
755 $src[] = $this->baseDir . '/'. $this->appNameShort. '/templates';
758 // images may come from multiple places: - if we have multiple template directories.?
759 // how do we deal with this..?
760 // images/ << should always be mapped to master!
761 // for overridden appdir ones we will have to se rootURL etc.
763 $url_rewrite = 'images/:'. $this->rootURL . '/'. $this->project. '/templates/images/';
765 $this->applyIf('HTML_Template_Flexy', array(
766 'templateDir' => implode(PATH_SEPARATOR, $src),
767 'compileDir' => $compileDir,
768 'multiSource' => true,
770 'url_rewrite' => $url_rewrite,
771 'filters' => 'Php,SimpleTags', /// for non-tokenizer version?
772 'debug' => $this->debug ? 1 : 0,
781 function _parseConfigMail()
783 $this->applyIf('HTML_Template_Flexy', array(
786 'host' => 'localhost',
792 * exposes to PEAR::getStaticProperty..
793 * at present, only FlexyFramework uses this..
794 * // we should really stop it..
795 * ctor for Flexy - should read from config...
798 function _exposeToPear()
800 $cls = array_keys(get_class_vars(__CLASS__));
803 // anything that get's set, that's not in our default properties
804 // is assumed to be an option set .
805 foreach(get_object_vars($this) as $k=>$v) {
806 if (in_array($k,$cls)) {
810 $options = &PEAR::getStaticProperty($k,'options');
813 // $options = &PEAR::getStaticProperty('HTML_FlexyFramework2','options');
820 function _validateEnv()
822 /* have I been initialized */
825 if (get_magic_quotes_gpc() && !$this->cli) {
827 "magic quotes is enabled add the line<BR>
828 php_value magic_quotes_gpc 0<BR>
829 to your .htaccess file <BR>
830 (Apache has to be configured to "AllowOverride Options AuthConfig" for the directory)
835 // set up error handling -
836 //$this->error = new HTML_FlexyFramework2_Error();
838 /// fudge work around bugs in PEAR::setErrorHandling(,)
839 //$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_CALLBACK;
840 //$GLOBALS['_PEAR_default_error_options'] = array($this->error,'raiseError');
845 require_once 'Benchmark/Timer.php';
846 $this->timer = new BenchMark_Timer(true);
847 register_shutdown_function(function() { echo $this->timer->getOutput(); });
852 function _validateDatabase()
854 //echo "<PRE>"; print_r($this);
856 if ($this->nodatabase) {
860 // database is the only setting - we dont support mult databses?
863 $x = new PDO_Dataobject();
864 PDO_Dataobject::config('database', $this->database);
867 } catch (Exception $e) {
870 $this->fatalError("Configuration or Database Error: could not connect to Database, <BR>
871 Please check the value given to HTML_FlexyFramework2, or run with debug on!<BR>
872 <BR> ".$e->getMessage());
876 if (preg_match('/^mysql/', $this->database)) {
877 $res = $x->PDO()->query("SELECT @@global.read_only as ro");
879 $row = !is_a($res, 'PDOStatement') ? false : $res->fetch(PDO::FETCH_ASSOC);
882 if (!$row || !empty($row['ro'])) {
883 if (empty($options['skip-read-only-check'])) {
884 $this->fatalError("Database is configured to be read-only - please check database<BR>");
886 $this->database_is_readonly = true;
892 function _validateTemplate()
894 // check that we have a writeable directory for flexy's compiled templates.
896 if (empty($this->HTML_Template_Flexy['compileDir'])) {
900 if ( !file_exists($this->HTML_Template_Flexy['compileDir'])) {
901 mkdir($this->HTML_Template_Flexy['compileDir'], 0700, true);
904 if ( !file_exists($this->HTML_Template_Flexy['compileDir'])) {
906 $this->fatalError("Configuration Error: you specified a directory that does not exist for<BR>
907 HTML_Template_Flexy => compileDir {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
912 if (!is_writeable($this->HTML_Template_Flexy['compileDir'])) {
913 $this->fatalError("Configuration Error: Please make sure the template cache directory is writeable<BR>
915 chmod 700 {$this->HTML_Template_Flexy['compileDir']}<BR>
916 chgrp apache_user {$this->HTML_Template_Flexy['compileDir']}<BR>\n"
919 //echo "<PRE>";print_R($config);
937 * HTML_FlexyFramework::run('someurl/someother',array('somearg'=>'xxx'));
939 * exit; <- dont cary on!!!!
943 * @param string redirect to url
944 * @param array Args Optional any data you want to send to the next page..
953 static function run($request,$args=array())
955 self::$singleton->_run($request,true,$args);
960 * initPage - load the page up, and set the variables, but do not actually run it.
961 * - used where we want features from this framework, buy may actually be running another one..
963 * call with ($_SERVER["SCRIPT_NAME"]) for root page...
966 public function initPage($request, $isRedirect=false, $args=array())
968 $newRequest = $this->_getRequest($request,$isRedirect);
970 // find the class/file to load
971 list($classname,$subRequest) = $this->requestToClassName($newRequest,FALSE);
974 $this->debug("requestToClassName return = CLASSNAME: $classname SUB REQUEST: $subRequest");
976 // assume that this was handled by getclassname ?????
982 // make page data/object accessable at anypoint in time using this
983 // not sure if this is used anymore - or even works..?
985 $classobj = new $classname(); // normally do not have constructors.
987 $classobj->baseURL = $this->baseURL;
988 $classobj->rootURL = $this->rootURL;
989 $classobj->rootDir = $this->rootDir;
990 $classobj->bootLoader = $this;
991 $classobj->request = $newRequest;
992 $classobj->timer = &$this->timer;
993 $classobj->subrequest = $subRequest;
995 $this->page = $classobj;
1001 * The main execution loop
1003 * recursivly self called if redirects (eg. return values from page start methods)
1005 * @param string from $_REQUEST or redirect from it'self.
1006 * @param boolean isRedirect = is the request a redirect TRUE = always handle as 'GET', 1 = handle as POST/GET depending on method, 0 = handle as initial request.
1009 * @return false || other false indicates no page was served!
1010 * @access public|private
1011 * @see see also methods.....
1014 public function _run($request,$isRedirect = false,$args = array())
1017 // clean the request up.
1020 if ($this->calls > 5) {
1021 // to many redirections...
1022 trigger_error("FlexyFramework:: too many redirects - backtrace me!",E_USER_ERROR);
1026 $classobj = $this->initPage($request,$isRedirect,$args);
1029 $classobj->cli = $this->cli;
1031 if ($this->cli && !$isRedirect ) { // redirect always just takes redirect args..
1032 require_once 'HTML/FlexyFramework2/Cli.php';
1033 $fcli = new HTML_FlexyFramework2_Cli($this);
1034 $nargs = $fcli->cliParse(get_class($classobj));
1035 $args = $nargs === false ? $args : $nargs; /// replace if found.
1036 $classobj->cli_args = $nargs;
1039 // echo '<PRE>'; print_r($this);exit;
1040 // echo "CHECK GET AUTH?";
1041 if (!method_exists($classobj, 'getAuth')) {
1042 // echo "NO GET AUTH?";
1043 $this->fatalError("class ". get_class($classobj) . " does not have a getAuth Method");
1047 /* check auth on the page */
1048 if (is_string($redirect = $classobj->getAuth())) {
1049 $this->debug("GOT AUTH REDIRECT".$redirect);
1050 return $this->_run($redirect,TRUE);
1052 // used HTML_FlexyFramework::run();
1055 if ($redirect === false) {
1056 $this->debug("GOT AUTH FALSE");
1057 return false; /// Access deined!!! -
1060 // allow the page to implement caching (for the full page..)
1061 // although normally it should implement caching on the outputBody() method.
1063 if (method_exists($classobj,"getCache")) {
1064 if ($result = $classobj->getCache()) {
1068 /* allow redirect from start */
1069 if (method_exists($classobj,"start")) {
1070 if (is_string($redirect = $classobj->start($classobj->subrequest,$isRedirect,$args))) {
1071 $this->debug("REDIRECT $redirect <BR>");
1072 return $this->_run($redirect,TRUE);
1074 if ($redirect === false) {
1080 // used HTML_FlexyFramework::run();
1083 * Modules are common page components like navigation headers etc.
1084 * that can have dynamic code.
1085 * Code has been removed now..
1090 $this->timer->setMarker("After $request loadModules Modules");
1093 /* output it - (our base page does not implement output for cli. */
1095 if ( method_exists($classobj,'output')) {
1096 $classobj->output();
1101 $this->timer->setMarker("After $request output");
1102 $this->timer->stop(); //?? really - yes...
1112 exit; /// die here...
1117 * map the request into an object and run the page.
1119 * The core of the work is done here.
1122 * @param request the request string
1123 * @param boolean isRedirect - indicates that it should not attempt to strip the .../index.php from the request.
1128 function _getRequest($request, $isRedirect)
1137 $startRequest = $request;
1138 $rq = explode('?', $request);
1139 $request = array_shift($rq);
1140 $this->debug("INPUT REQUEST $request<BR>");
1142 // check that request forms contains baseurl????
1144 $subreq = substr($request,0,strlen($this->baseURL));
1145 if ($subreq != substr($this->baseURL,0,strlen($subreq))) {
1147 "Configuration error: Got base of $subreq which does not
1148 match configuration of: $this->baseURL} ");
1150 $request = substr($request,strlen($this->baseURL));
1154 // echo "REQUEST WAS: $request<BR>";
1155 // $request = preg_replace('/^'.preg_quote($base_url,'/').'/','',trim($request));
1156 // echo "IS NOW: $request<BR>";
1158 // strip valid html stuff
1159 //$request = preg_replace('/\/[.]+/','',$request);
1162 $request = preg_replace('/^[\/]*/','',$request);
1163 $request = preg_replace('/\?.*$/','',$request);
1164 $request = preg_replace('/[\/]*$/','',$request);
1165 $this->baseRequest = $request;
1166 $request = str_replace('&','',$request); // any other invalid characters???
1167 $request = preg_replace('/\.([a-z]+)$/','',$request);
1168 $this->ext = substr($this->baseRequest , strlen($request));
1170 // REDIRECT ROO to index.php! for example..
1172 // this has a slight issue when we are using 'hidden index.php' mod_rewrite..
1175 normal (non-mod_rewrite)
1176 $_SERVER['REQUEST_URI'] start with baseURL..
1178 if (isset($_SERVER['REQUEST_URI']) && substr($_SERVER['REQUEST_URI'], 0, strlen($this->baseURL)) != $this->baseURL) {
1179 // then we are rewriting?
1180 $this->baseURL = $this->rootURL;
1184 //var_dump(array($this->baseURL, $this->rootURL, $request ,$isRedirect, $_SERVER['REQUEST_URI'])); phpinfo();exit;
1185 if (!$request && !$isRedirect) {
1188 if ($this->baseURL && (strlen($startRequest) < strlen($this->baseURL))) {
1190 // needs to handle https + port
1191 $http = ((!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on')) ? 'https' : 'http';
1193 if (!empty($_SERVER['SERVER_PORT'])) {
1194 if ((($http == 'http') && ($_SERVER['SERVER_PORT'] == 80)) || (($http == 'https') && ($_SERVER['SERVER_PORT'] == 443))) {
1197 $sp .= ':'.((int) $_SERVER['SERVER_PORT']);
1200 //var_dump($startRequest); echo '<PRE>'; print_R($this); phpinfo();exit;
1201 $host = !empty($_SERVER["HTTP_X_FORWARDED_HOST"]) ? $_SERVER["HTTP_X_FORWARDED_HOST"] : $_SERVER["HTTP_HOST"];
1202 header('Location: '.$http.'://'.$host .$sp . $this->baseURL);
1208 $this->debug("OUTPUT REQUEST $request<BR>");
1216 * get the Class name and filename to load
1218 * Parses the request and converts that into a File + Classname
1219 * if the class doesnt exist it will attempt to find a file below it, and
1220 * call that one with the data.
1221 * Used by the module loader to determine the location of the modules
1223 * @param request the request string
1224 * @param boolean showError - if false, allows you to continue if the class doesnt exist.
1227 * @return array classname, filepath
1232 function requestToClassName($request,$showError=TRUE)
1234 // if ($request == "error") {
1235 // return array("HTML_FlexyFramework_Error","");
1238 // special classes ::
1239 if ($this->cli && in_array($request, array('DataObjects'))) {
1240 require_once 'HTML/FlexyFramework2/'. $request . '.php';
1241 return array('HTML_FlexyFramework2_'. $request,'');
1245 $request_array=explode("/",$request);
1246 $original_request_array = $request_array;
1247 $sub_request_array = array();
1248 $l = count($request_array)-1;
1249 if ($l > 10) { // ?? configurable?
1250 //PEAR::raiseError("Request To Long");
1251 $this->fatalError("Request To Long - " . $request);
1256 // tidy up request array
1258 if ($request_array) {
1259 foreach(array_keys($request_array) as $i) {
1260 $request_array[$i] = preg_replace('/[^a-z0-9]/i','_',urldecode($request_array[$i]));
1263 //echo "<PRE>"; print_r($request_array);
1264 // technically each module should do a check here... similar to this..
1267 for ($i=$l;$i >-1;$i--) {
1268 $location = implode('/',$request_array) . ".php";
1269 if ($location == '.php') {
1270 $this->debug("SKIP first path check, as request str is empty");
1274 $this->debug("baseDIR = {$this->baseDir}");
1276 $floc = "{$this->baseDir}/$location";
1277 $this->debug("CHECK LOCATION = $floc");
1281 if (!empty($location) && $location != '.php' && @file_exists($floc )) { // hide? error???
1282 require_once $floc ;
1283 $classname = $this->classPrefix . implode('_',$request_array);
1285 if (class_exists($classname) &&
1286 (is_a($classname, 'HTML_FlexyFramework2_Page', true) ||
1287 is_a($classname, 'HTML_FlexyFramework_Page', true))
1290 $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1295 // in here check the 'projectExtends' versions..?
1297 if(!empty($this->projectExtends)){
1298 $this->debug("Trying project Extends <BR>");
1299 $has_extend_class = false;
1301 foreach ($this->projectExtends as $e){
1302 $floc = "{$this->rootDir}/{$e}/$location";
1303 $this->debug("Trying file: $floc");
1304 if (!empty($location) && @file_exists($floc)) { // hide? error???
1305 require_once $floc ;
1306 $classname = $e . '_' . implode('_',$request_array);
1308 if (class_exists($classname) &&
1309 (is_a($classname, 'HTML_FlexyFramework2_Page', true) ||
1310 is_a($classname, 'HTML_FlexyFramework_Page', true)) ) {
1311 $has_extend_class = true;
1312 $this->debug("FOUND FILE - SET CLASS = $classname <BR>");
1318 if(!empty($has_extend_class)){
1325 $this->debug("$floc - !!FOUND NOT FILE!!");
1327 $sub_request_array[] = $original_request_array[$i];
1328 unset($request_array[$i]);
1329 unset($original_request_array[$i]);
1332 // is this really needed here!
1334 $classname = preg_replace('/[^a-z0-9]/i','_',$classname);
1335 $this->debug("CLASSNAME is '$classname'");
1337 if ($classname && class_exists($classname) &&
1338 (is_a($classname, 'HTML_FlexyFramework2_Page', true) ||
1339 is_a($classname, 'HTML_FlexyFramework_Page', true))) {
1340 $this->debug("using $classname");
1341 //print_r($sub_request_array);
1342 return array($classname,implode('/',array_reverse($sub_request_array)));
1344 $this->debug("$classname did not exist - using base");
1347 $this->fatalError("INVALID REQUEST: \n $request FILE:".$this->baseDir. "/{$location} CLASS:{$classname}");
1352 $this->debug("Try base {$this->baseDir}.php");
1353 // try {project name}.php
1354 // this used to be silenced @ - if this fails we are usually pretty fried..
1356 if (file_exists($this->baseDir.'.php')) {
1359 $classname = str_replace('/', '_', $this->project); // basename($this->baseDir);
1361 $this->debug("FOUND {$this->baseDir} requring and checking class $classname");
1362 require_once $this->baseDir.'.php';
1363 $this->debug("require success");
1365 if (!class_exists($classname)) {
1366 $this->fatalError( "{$this->baseDir}.php did not contain class $classname");
1369 // got projectname.php
1370 if ($classname && class_exists($classname) ) {
1371 $this->debug("using $classname");
1372 //print_r($sub_request_array);
1374 return array($classname,implode('/',array_reverse($sub_request_array)));
1378 $this->fatalError( "can not find {$this->baseDir}.php"); // dies..
1384 * ensure Single CLi process
1386 * HTML_FlexyFramework2::ensureSingle(__FILE__, $this);
1387 * @param string filename of running class
1388 * @param object class
1391 static function ensureSingle($sig, $class)
1393 //echo "check single: $sig / ". get_class($class) ."\n";
1394 $ff = HTML_FlexyFramework2::get();
1395 if (function_exists('posix_getpwuid')) {
1396 $uinfo = posix_getpwuid( posix_getuid () );
1397 $user = $uinfo['name'];
1399 $user = getenv('USERNAME'); // windows.
1401 $fdir = ini_get('session.save_path') .'/' .
1402 $user . '_cli_' . $ff->project ;
1405 if (!file_exists($fdir)) {
1409 $lock = $fdir.'/'. md5($sig) . '.' . get_class($class);
1410 //echo "check single: lock : $lock\n";
1411 if (!file_exists($lock)) {
1412 file_put_contents($lock, getmypid());
1413 //echo "check single: lock : DOES NOT EXIST\n";
1416 $oldpid = file_get_contents($lock);
1417 if (!file_exists('/proc/' . $oldpid)) {
1419 file_put_contents($lock, getmypid());
1420 // echo "check single: lock : PROC NOT EXIST\n";
1423 // file exists, but process might not be the same..
1424 $ca = explode('_', get_class($class));
1425 $name = array_pop($ca);
1426 $cmd = file_get_contents('/proc/' . $oldpid.'/cmdline');
1427 if (!preg_match('/php/i',$cmd) || !preg_match('/'.$name.'/i',$cmd)) {
1428 file_put_contents($lock, getmypid());
1429 //echo "check single: lock : CMDLINE !have PHP \n";
1432 die("process " . $sig . " already running\n");
1436 * removes the lock for the applicaiton - use with care...
1440 static function ensureSingleClear($sig, $class)
1442 $ff = HTML_FlexyFramework2::get();
1443 if (function_exists('posix_getpwuid')) {
1444 $uinfo = posix_getpwuid( posix_getuid () );
1445 $user = $uinfo['name'];
1447 $user = getenv('USERNAME'); // windows.
1449 $fdir = ini_get('session.save_path') .'/' .
1450 $user . '_cli_' . $ff->project ;
1453 if (!file_exists($fdir)) {
1456 $lock = $fdir.'/'. md5($sig);
1457 if (!file_exists($lock)) {
1468 * @param string text to output.
1472 function debug($output) {
1474 if (empty($this->debug)) {
1478 "HTML_FlexyFramework2::debug - ".$output."\n"
1479 : "<B>HTML_FlexyFramework2::debug</B> - ".$output."<BR>\n";
1483 * Raises a fatal error. - normally only used when setting up to help get the config right.
1485 * can redirect to fatal Action page.. - hoepfully not issued before basic vars are set up..
1487 * @param string text to output.
1491 function fatalError($msg,$showConfig = 0)
1495 if ($this->fatalAction) {
1496 HTML_FlexyFramework2::run($this->fatalAction,$msg);
1499 header('HTTP/1.1 503 Service Temporarily Unavailable');
1500 header('Status: 503 Service Temporarily Unavailable');
1501 header('Retry-After: 300');
1502 echo $this->cli ? $msg ."\n" : "<H1>$msg</H1>configuration information<PRE>";
1507 $ff = HTML_FlexyFramework2::get();