![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 /*------------------------------------------------------------------------------- 00003 * Xataface Web Application Framework 00004 * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 *------------------------------------------------------------------------------- 00020 */ 00021 00022 00023 if ( !function_exists('sys_get_temp_dir') ) 00024 { 00025 // Based on http://www.phpit.net/ 00026 // article/creating-zip-tar-archives-dynamically-php/2/ 00027 function sys_get_temp_dir() 00028 { 00029 // Try to get from environment variable 00030 if ( !empty($_ENV['TMP']) ) 00031 { 00032 return realpath( $_ENV['TMP'] ); 00033 } 00034 else if ( !empty($_ENV['TMPDIR']) ) 00035 { 00036 return realpath( $_ENV['TMPDIR'] ); 00037 } 00038 else if ( !empty($_ENV['TEMP']) ) 00039 { 00040 return realpath( $_ENV['TEMP'] ); 00041 } 00042 00043 // Detect by creating a temporary file 00044 else 00045 { 00046 // Try to use system's temporary directory 00047 // as random name shouldn't exist 00048 $temp_file = tempnam( md5(uniqid(rand(), TRUE)), '' ); 00049 if ( $temp_file ) 00050 { 00051 $temp_dir = realpath( dirname($temp_file) ); 00052 unlink( $temp_file ); 00053 return $temp_dir; 00054 } 00055 else 00056 { 00057 return FALSE; 00058 } 00059 } 00060 } 00061 } 00062 00063 require_once dirname(__FILE__)."/../config.inc.php"; 00064 import('Dataface/PermissionsTool.php'); 00065 import('Dataface/LanguageTool.php'); 00066 define('DATAFACE_STRICT_PERMISSIONS', 100); 00067 // the minimum security level that is deemed as strict permissions. 00068 // strict permissions mean that permissions must be explicitly granted to a 00069 // table, record, or action or they will not be accessible 00070 00087 class Dataface_Application { 00088 00089 const EX_FAILED_TO_CREATE_SESSION_DIR = 5500; 00090 00091 00117 public $redirectHandler = null; 00118 00122 var $sessionCookieKey; 00123 00124 00128 var $autoSession = false; 00129 00133 var $_url_filters = array(); 00138 var $_tables = array(); 00139 00144 var $tableIndex = array(); 00145 00150 var $_baseUrl; 00151 00155 var $_currentTable; 00156 00157 00161 var $memcache; 00162 00167 var $_db; 00174 var $_query; 00175 00182 var $rawQuery; 00183 00187 var $queryTool = null; 00188 00192 var $currentRecord = null; 00193 00197 var $_customPages; 00198 00205 var $locations = null; 00206 00214 var $eventListeners = array(); 00215 00219 var $prefs = array( 00220 'show_result_stats'=>1, // The result statistics (e.g. found x of y records in table z) 00221 'show_jump_menu'=>1, // The drop-down menu that allows you to "jump" to any record in the found set. 00222 'show_result_controller'=>1, // Next, previous, page number .. links... 00223 'show_table_tabs'=>1, // Details, List, Find, etc... 00224 'show_actions_menu'=>1, // New record, Show all, delete, etc... 00225 'show_logo'=>1, // Show logo at top right of app 00226 'show_tables_menu'=>1, // The tabs to select a table. 00227 'show_search'=>1, // Show search field in upper right. 00228 'show_record_actions'=>1, // Show actions related to particular record 00229 'show_recent_records_menu'=>1, // Menu to jump to recently visited record (deprecated) 00230 'show_bread_crumbs' => 1, // Bread crumbs at top of page to show where you are 00231 'show_record_tabs' => 1, // View, Edit, Translate, History, etc... 00232 'show_record_tree' => 1, // Tree to navigate the relationships of this record. 00233 'list_view_scroll_horizontal'=>1, // Whether to scroll list horizontal if it exceeds page width 00234 'list_view_scroll_vertical'=>1 // Whether to scroll list vertical if it exceeds page height. 00235 00236 ); 00237 00243 var $tableNamesUsed = array(); 00244 00248 var $main_content_only = false; 00249 // IF true then output only includes main content - not the 00250 // surrounding frame. 00251 00258 var $delegate = -1; 00259 00260 00261 00265 var $errors=array(); 00266 00270 var $messages = array(); 00271 00275 var $debugLog = array(); 00276 00280 var $authenticationTool = null; 00281 00288 var $headContent=array(); 00289 00295 var $mysqlVersion = null; 00296 00297 00298 00299 // @{ 00322 var $_locales = array( 00323 'zh_CN'=>'zh', 00324 'zh_TW'=>'zt', 00325 'zh_HK'=>'zt', 00326 'en_US'=>'en' 00327 ); 00328 00338 var $_languages = array( 00339 'zt'=>'zh' 00340 ); 00341 00368 function getLanguage($langCode){ 00369 if ( isset($this->_languages[$langCode]) ){ 00370 return $this->_languages[$langCode]; 00371 } else { 00372 return $langCode; 00373 } 00374 } 00375 00394 function getLanguageCode($locale){ 00395 if ( isset($this->_locales[$locale]) ) return $this->_locales[$locale]; 00396 else { 00397 list($langCode) = explode('_', $locale); 00398 return $langCode; 00399 } 00400 } 00401 00431 function getAvailableLanguages(){ 00432 $langs = array_keys($this->_conf['languages']); 00433 if ( @$this->_conf['default_language'] ) $langs[] = $this->_conf['default_language']; 00434 else $langs[] = 'en'; 00435 $out = array(); 00436 foreach ($langs as $lang){ 00437 $out[$this->getLanguage($lang)] = true; 00438 } 00439 return array_keys($out); 00440 00441 } 00442 00443 00444 // @} 00445 // END LANGUAGES 00446 00447 00448 // @{ 00459 function db(){ return $this->_db;} 00460 00464 var $_conf; 00465 00469 function Dataface_Application($conf = null){ 00470 $this->sessionCookieKey = md5(DATAFACE_SITE_URL.'#'.__FILE__); 00471 $this->_baseUrl = $_SERVER['PHP_SELF']; 00472 if ( !is_array($conf) ) $conf = array(); 00473 if ( is_readable(DATAFACE_SITE_PATH.'/conf.ini') ){ 00474 $conf = array_merge(parse_ini_file(DATAFACE_SITE_PATH.'/conf.ini', true), $conf); 00475 if ( @$conf['__include__'] ){ 00476 $includes = array_map('trim',explode(',', $conf['__include__'])); 00477 foreach ($includes as $i){ 00478 if ( is_readable($i) ){ 00479 $conf = array_merge($conf, parse_ini_file($i, true)); 00480 } 00481 } 00482 } 00483 } 00484 00485 00486 00487 if ( !isset( $conf['_tables'] ) ){ 00488 throw new Exception('Error loading config file. No tables specified.', E_USER_ERROR); 00489 00490 } 00491 00492 00493 00494 if ( isset( $conf['db'] ) and is_resource($conf['db']) ){ 00495 $this->_db = $conf['db']; 00496 } else { 00497 if ( !isset( $conf['_database'] ) ){ 00498 throw new Exception('Error loading config file. No database specified.', E_USER_ERROR); 00499 00500 } 00501 $dbinfo =& $conf['_database']; 00502 if ( !is_array( $dbinfo ) || !isset($dbinfo['host']) || !isset( $dbinfo['user'] ) || !isset( $dbinfo['password'] ) || !isset( $dbinfo['name'] ) ){ 00503 throw new Exception('Error loading config file. The database information was not entered correctly.<br> 00504 Please enter the database information int its own section of the config file as follows:<br> 00505 <pre> 00506 [_database] 00507 host = localhost 00508 user = foo 00509 password = bar 00510 name = database_name 00511 </pre>', E_USER_ERROR); 00512 00513 } 00514 if ( @$dbinfo['persistent'] ){ 00515 $this->_db = mysql_pconnect( $dbinfo['host'], $dbinfo['user'], $dbinfo['password'] ); 00516 } else { 00517 $this->_db = mysql_connect( $dbinfo['host'], $dbinfo['user'], $dbinfo['password'] ); 00518 } 00519 if ( !$this->_db ){ 00520 throw new Exception('Error connecting to the database: '.mysql_error()); 00521 00522 } 00523 $this->mysqlVersion = mysql_get_server_info($this->_db); 00524 mysql_select_db( $dbinfo['name'] ) or die("Could not select DB: ".mysql_error($this->_db)); 00525 } 00526 if ( !defined( 'DATAFACE_DB_HANDLE') ) define('DATAFACE_DB_HANDLE', $this->_db); 00527 00528 00529 if ( !is_array( $conf['_tables'] ) ){ 00530 throw new Exception("<pre> 00531 Error reading table information from the config file. Please enter the table information in its own section 00532 of the ini file as follows: 00533 [_tables] 00534 table1 = Table 1 Label 00535 table2 = Table 2 Label 00536 </pre>"); 00537 00538 } 00539 00540 $this->_tables = $conf['_tables']; 00541 00542 00543 00544 if ( count($this->_tables) <= 10 ){ 00545 $this->prefs['horizontal_tables_menu'] = 1; 00546 } 00547 00548 // We will register a _cleanup method to run after code execution is complete. 00549 register_shutdown_function(array(&$this, '_cleanup')); 00550 00551 // Set up memcache if it is installed. 00552 if ( DATAFACE_EXTENSION_LOADED_MEMCACHE ){ 00553 if ( isset($conf['_memcache']) ){ 00554 if ( !isset($conf['_memcache']['host']) ){ 00555 $conf['_memcache']['host'] = 'localhost'; 00556 } 00557 if ( !isset($conf['_memcache']['port']) ){ 00558 $conf['_memcache']['port'] = 11211; 00559 } 00560 $this->memcache = new Memcache; 00561 $this->memcache->connect($conf['_memcache']['host'], $conf['_memcache']['port']) or die ("Could not connect to memcache on port 11211"); 00562 00563 } 00564 } 00565 00566 // 00567 // -------- Set up the CONF array ------------------------ 00568 $this->_conf = $conf; 00569 00570 if ( !isset($this->_conf['_disallowed_tables']) ){ 00571 $this->_conf['_disallowed_tables'] = array(); 00572 } 00573 00574 $this->_conf['_disallowed_tables']['history'] = '/__history$/'; 00575 $this->_conf['_disallowed_tables']['cache'] = '__output_cache'; 00576 $this->_conf['_disallowed_tables']['dataface'] = '/^dataface__/'; 00577 if ( !@$this->_conf['_modules'] or !is_array($this->_conf['_modules']) ){ 00578 $this->_conf['_modules'] = array(); 00579 } 00580 00581 // Include XataJax module always. 00582 $mods = array('modules_XataJax'=>'modules/XataJax/XataJax.php'); 00583 foreach ($this->_conf['_modules'] as $k=>$v){ 00584 $mods[$k] = $v; 00585 } 00586 $this->_conf['_modules'] = $mods; 00587 00588 00589 if ( isset($this->_conf['_modules']) and count($this->_conf['_modules'])>0 ){ 00590 import('Dataface/ModuleTool.php'); 00591 } 00592 00593 if ( isset($this->_conf['languages']) ){ 00594 $this->_conf['language_labels'] = $this->_conf['languages']; 00595 foreach ( array_keys($this->_conf['language_labels']) as $lang_code){ 00596 $this->_conf['languages'][$lang_code] = $lang_code; 00597 } 00598 } 00599 00600 if ( @$this->_conf['support_transactions'] ){ 00601 // We will support transactions 00602 @mysql_query('SET AUTOCOMMIT=0', $this->_db); 00603 @mysql_query('START TRANSACTION', $this->_db); 00604 00605 } 00606 if ( !isset($this->_conf['default_ie']) ) $this->_conf['default_ie'] = 'ISO-8859-1'; 00607 if ( !isset($this->_conf['default_oe']) ) $this->_conf['default_oe'] = 'ISO-8859-1'; 00608 if ( isset( $this->_conf['multilingual_content']) || isset($this->_conf['languages']) ){ 00609 $this->_conf['oe'] = 'UTF-8'; 00610 $this->_conf['ie'] = 'UTF-8'; 00611 00612 if (function_exists('mb_substr') ){ 00613 // The mbstring extension is loaded 00614 ini_set('mbstring.internal_encoding', 'UTF-8'); 00615 //ini_set('mbstring.encoding_translation', 'On'); 00616 ini_set('mbstring.func_overload', 7); 00617 00618 } 00619 00620 if ( !isset($this->_conf['default_language']) ){ 00621 if ( count($this->_conf['languages']) > 0 ) 00622 $this->_conf['default_language'] = reset($this->_conf['languages']); 00623 00624 else 00625 $this->_conf['default_language'] = 'en'; 00626 00627 } 00628 00629 } else { 00630 $this->_conf['oe'] = $this->_conf['default_oe']; 00631 $this->_conf['ie'] = $this->_conf['default_ie']; 00632 } 00633 00634 if ( $this->_conf['oe'] == 'UTF-8' ){ 00635 $res = mysql_query('set character_set_results = \'utf8\'', $this->_db); 00636 mysql_query("SET NAMES utf8", $this->_db); 00637 } 00638 if ( $this->_conf['ie'] == 'UTF-8' ){ 00639 $res = mysql_query('set character_set_client = \'utf8\'', $this->_db); 00640 00641 } 00642 00643 00644 if ( isset($this->_conf['use_cache']) and $this->_conf['use_cache'] and !defined('DATAFACE_USE_CACHE') ){ 00645 define('DATAFACE_USE_CACHE', true); 00646 } 00647 00648 if ( isset($this->_conf['debug']) and $this->_conf['debug'] and !defined('DATAFACE_DEBUG') ){ 00649 define('DATAFACE_DEBUG', true); 00650 } else if ( !defined('DATAFACE_DEBUG') ){ 00651 define('DATAFACE_DEBUG',false); 00652 } 00653 00654 if ( !@$this->_conf['config_storage'] ) $this->_conf['config_storage'] = DATAFACE_DEFAULT_CONFIG_STORAGE; 00655 // Set the storage type for config information. It can either be stored in ini files or 00656 // in the database. Database will give better performance, but INI files may be simpler 00657 // to manage for simple applications. 00658 00659 if ( !isset($this->_conf['garbage_collector_threshold']) ){ 00665 $this->_conf['garbage_collector_threshold'] = 10*60; 00666 } 00667 00668 if ( !isset($this->_conf['multilingual_content']) ) $this->_conf['multilingual_content'] = false; 00669 // whether or not the application will use multilingual content. 00670 // multilingual content enables translated versions of content to be stored in 00671 // tables using naming conventions. 00672 // Default to false because this takes a performance hit (sql queries take roughly twice 00673 // as long because they have to be parsed first. 00674 00675 if ( !isset($this->_conf['cookie_prefix']) ) $this->_conf['cookie_prefix'] = 'dataface__'; 00676 00677 if ( !isset($this->_conf['security_level']) ){ 00678 // Default security is strict if security is not specified. This change is effectivce 00679 // for Dataface 0.6 .. 0.5.3 and earlier had a loose permissions model by default that 00680 // could be tightened using delegate classes. 00681 $this->_conf['security_level'] = 0; //DATAFACE_STRICT_PERMISSIONS; 00682 } 00683 00684 00685 if ( !isset($this->_conf['default_action']) ){ 00686 // The default action defines the action that should be set if no 00687 // other action is specified. 00688 $this->_conf['default_action'] = 'list'; 00689 } 00690 00691 if ( !isset($this->_conf['default_browse_action']) ){ 00692 $this->_conf['default_browse_action'] = 'view'; 00693 } 00694 00695 00696 if ( !isset($this->_conf['default_mode'] ) ) $this->_conf['default_mode'] = 'list'; 00697 00698 if ( !isset($this->_conf['default_limit']) ){ 00699 $this->_conf['default_limit'] = 30; 00700 } 00701 00702 if ( !isset($this->_conf['default_table'] ) ){ 00703 // The default table is the table that is used if no other table is specified. 00704 foreach ($this->_tables as $key=>$value){ 00705 $this->_conf['default_table'] = $key; 00706 00707 break; 00708 } 00709 } 00710 00711 if ( !isset($this->_conf['auto_load_results']) ) $this->_conf['auto_load_results'] = false; 00712 00713 if ( !isset( $this->_conf['cache_dir'] ) ){ 00714 if ( ini_get('upload_tmp_dir') ) $this->_conf['cache_dir'] = ini_get('upload_tmp_dir'); 00715 else $this->_conf['cache_dir'] = '/tmp'; 00716 } 00717 00718 if ( !isset( $this->_conf['default_table_role'] ) ){ 00719 00720 if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){ 00721 $this->_conf['default_table_role'] = 'NO ACCESS'; 00722 } else { 00723 $this->_conf['default_table_role'] = 'ADMIN'; 00724 } 00725 00726 } 00727 00728 if ( !isset( $this->_conf['default_field_role'] ) ){ 00729 if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){ 00730 $this->_conf['default_field_role'] = 'NO ACCESS'; 00731 } else { 00732 $this->_conf['default_field_role'] = 'ADMIN'; 00733 00734 } 00735 } 00736 00737 if ( !isset( $this->_conf['default_relationship_role'] ) ){ 00738 if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){ 00739 $this->_conf['default_relationship_role'] = 'READ ONLY'; 00740 } else { 00741 $this->_conf['default_relationship_role'] = 'ADMIN'; 00742 00743 } 00744 } 00745 00746 if ( !isset( $this->_conf['languages'] ) ) $this->_conf['languages'] = array('en'); 00747 else if ( !is_array($this->_conf['languages']) ) $this->_conf['languages'] = array($this->_conf['languages']); 00748 00749 if ( isset($this->_conf['_language_codes']) ){ 00750 $this->_languages = array_merge($this->_languages, $this->_conf['_language_codes']); 00751 } 00752 if ( isset($this->_conf['_locales']) ){ 00753 $this->_locales = array_merge($this->_locales, $this->_conf['_locales']); 00754 } 00755 00756 // Set the language. 00757 // Language is stored in a cookie. It can be changed by passing the -lang GET var with the value 00758 // of a language. e.g. fr, en, cn 00759 if ( !isset( $this->_conf['default_language'] ) ) $this->_conf['default_language'] = 'en'; 00760 $prefix = $this->_conf['cookie_prefix']; 00761 //print_r($_COOKIE); 00762 if ( isset($_REQUEST['--lang']) ){ 00763 $_REQUEST['--lang'] = basename($_REQUEST['--lang']); 00764 $this->_conf['lang'] = $_REQUEST['--lang']; 00765 } else if ( isset( $_REQUEST['-lang'] ) ){ 00766 $_REQUEST['-lang'] = basename($_REQUEST['-lang']); 00767 $this->_conf['lang'] = $_REQUEST['-lang']; 00768 if ( @$_COOKIE[$prefix.'lang'] !== $_REQUEST['-lang'] ){ 00769 setcookie($prefix.'lang', $_REQUEST['-lang'], null, '/'); 00770 } 00771 } else if (isset( $_COOKIE[$prefix.'lang']) ){ 00772 $this->_conf['lang'] = $_COOKIE[$prefix.'lang']; 00773 } else { 00774 import('I18Nv2/I18Nv2.php'); 00775 $negotiator = I18Nv2::createNegotiator($this->_conf['default_language'], 'UTF-8'); 00776 $this->_conf['lang'] = $this->getLanguageCode( 00777 $negotiator->getLocaleMatch( 00778 $this->getAvailableLanguages() 00779 ) 00780 ); 00781 setcookie($prefix.'lang', $this->_conf['lang'], null, '/'); 00782 } 00783 00784 $this->_conf['lang'] = basename($this->_conf['lang']); 00785 00786 00787 // Set the mode (edit or view) 00788 if ( isset($_REQUEST['-usage_mode'] )){ 00789 $this->_conf['usage_mode'] = $_REQUEST['-usage_mode']; 00790 if (@$_COOKIE[$prefix.'usage_mode'] !== $_REQUEST['-usage_mode']){ 00791 setcookie($prefix.'usage_mode', $_REQUEST['-usage_mode'], null, '/'); 00792 } 00793 } else if ( isset( $_COOKIE[$prefix.'usage_mode'] ) ){ 00794 $this->_conf['usage_mode'] = $_COOKIE[$prefix.'usage_mode']; 00795 } else if ( !isset($this->_conf['usage_mode']) ){ 00796 $this->_conf['usage_mode'] = 'view'; 00797 } 00798 00799 define('DATAFACE_USAGE_MODE', $this->_conf['usage_mode']); 00800 00801 if ( @$this->_conf['enable_workflow'] ){ 00802 import('Dataface/WorkflowTool.php'); 00803 } 00804 00805 00806 00807 00808 // ------- Set up the current query --------------------------------- 00809 00810 if ( isset($_REQUEST['__keys__']) and is_array($_REQUEST['__keys__']) ){ 00811 $query = $_REQUEST['__keys__']; 00812 foreach ( array_keys($_REQUEST) as $key ){ 00813 if ( $key{0} == '-' and !in_array($key, array('-search','-cursor','-skip','-limit'))){ 00814 $query[$key] = $_REQUEST[$key]; 00815 } 00816 } 00817 } else { 00818 $query = array_merge($_GET, $_POST); 00819 } 00820 if ( @$query['-action'] ){ 00821 $query['-action'] = trim($query['-action']); 00822 if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-action']) ){ 00823 throw new Exception("Illegal action name."); 00824 } 00825 $query['-action'] = basename($query['-action']); 00826 } 00827 if ( @$query['-table'] ){ 00828 $query['-table'] = trim($query['-table']); 00829 if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-table']) ){ 00830 throw new Exception("Illegal table name."); 00831 } 00832 $query['-table'] = basename($query['-table']); 00833 } 00834 if ( @$query['-lang'] ){ 00835 $query['-lang'] = trim($query['-lang']); 00836 if ( !preg_match('/^[a-zA-Z0-9]{2}$/', $query['-lang']) ){ 00837 throw new Exception("Illegal language code: ".$query['-lang']); 00838 } 00839 $query['-lang'] = basename($query['-lang']); 00840 } 00841 00842 if ( @$query['--lang'] ){ 00843 $query['--lang'] = trim($query['--lang']); 00844 if ( !preg_match('/^[a-zA-Z0-9]{2}$/', $query['--lang']) ){ 00845 throw new Exception("Illegal language code: ".$query['--lang']); 00846 } 00847 $query['--lang'] = basename($query['--lang']); 00848 } 00849 00850 if ( @$query['-theme'] ){ 00851 $query['-theme'] = trim($query['-theme']); 00852 if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-theme']) ){ 00853 throw new Exception("Illegal theme name."); 00854 } 00855 $query['-theme'] = basename($query['-theme']); 00856 } 00857 00858 if ( @$query['-cursor']){ 00859 $query['-cursor'] = intval($query['-cursor']); 00860 } 00861 if ( @$query['-limit'] ){ 00862 $query['-limit'] = intval($query['-limit']); 00863 } 00864 if ( @$query['-skip'] ){ 00865 $query['-skip'] = intval($query['-skip']); 00866 } 00867 if ( @$query['-related-limit'] ){ 00868 $query['-related-limit'] = intval($query['-related-limit']); 00869 } 00870 if ( @$query['-relationship'] ){ 00871 if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-relationship']) ){ 00872 throw new Exception("Illegal relationship name."); 00873 } 00874 } 00875 00876 00877 00878 00879 $this->rawQuery = $query; 00880 00881 if ( !isset( $query['-table'] ) ) $query['-table'] = $this->_conf['default_table']; 00882 $this->_currentTable = $query['-table']; 00883 00884 00885 if ( !@$query['-action'] ) { 00886 $query['-action'] = $this->_conf['default_action']; 00887 $this->_conf['using_default_action'] = true; 00888 } 00889 00890 $query['--original_action'] = $query['-action']; 00891 if ( $query['-action'] == 'browse') { 00892 if ( isset($query['-relationship']) ){ 00893 $query['-action'] = 'related_records_list'; 00894 } else if ( isset($query['-new']) and $query['-new']) { 00895 $query['-action'] = 'new'; 00896 } else { 00897 $query['-action'] = $this->_conf['default_browse_action']; // for backwards compatibility to 0.5.x 00898 } 00899 } else if ( $query['-action'] == 'find_list' ){ 00900 $query['-action'] = 'list'; 00901 } 00902 if ( !isset( $query['-cursor'] ) ) $query['-cursor'] = 0; 00903 if ( !isset( $query['-skip'] ) ) $query['-skip'] = 0; 00904 if ( !isset( $query['-limit'] ) ) $query['-limit'] = $this->_conf['default_limit']; 00905 00906 if ( !isset( $query['-mode'] ) ) $query['-mode'] = $this->_conf['default_mode']; 00907 $this->_query =& $query; 00908 00909 00910 if ( isset( $query['--msg'] ) ) { 00911 $query['--msg'] = preg_replace('#<[^>]*>#','', $query['--msg']); 00912 if ( preg_match('/^@@$/', $query['--msg']) ){ 00913 00914 if ( @$_SESSION['--msg'] ){ 00915 $this->addMessage(@$_SESSION['--msg']); 00916 unset($_SESSION['--msg']); 00917 } 00918 } else { 00919 00920 $this->addMessage($query['--msg']); 00921 } 00922 } 00923 00924 00925 00926 00927 if ( isset($query['--error']) and trim($query['--error']) ){ 00928 $query['--error'] = preg_replace('#<[^>]*>#','', $query['--error']); 00929 $this->addError(PEAR::raiseError($query['--error'])); 00930 } 00931 00932 // Now allow custom setting of theme 00933 if ( isset($query['-theme']) ){ 00934 if ( !isset($this->_conf['_themes']) ) $this->_conf['_themes'] = array(); 00935 $this->_conf['_themes'][basename($query['-theme'])] = 'themes/'.basename($query['-theme']); 00936 } 00937 00938 // Check to see if we should set a custom default preview length 00939 if ( isset($query['--default-preview-length']) ){ 00940 $len = intval($query['--default-preview-length']); 00941 if ( $len > 0 && !defined('XATAFACE_DEFAULT_PREVIEW_LENGTH') ){ 00942 define('XATAFACE_DEFAULT_PREVIEW_LENGTH', $len); 00943 } 00944 } 00945 00946 00947 00948 } 00949 00950 00969 public static function &getInstance($conf=null){ 00970 static $instance = array(); 00971 //static $blobRequestCount = 0; 00972 if ( !isset( $instance[0] ) ){ 00973 $instance[0] = new Dataface_Application($conf); 00974 if ( !defined('DATAFACE_APPLICATION_LOADED') ){ 00975 define('DATAFACE_APPLICATION_LOADED', true); 00976 } 00977 } 00978 00979 return $instance[0]; 00980 } 00981 00982 00983 00995 function &conf(){ 00996 static $loaded = false; 00997 if ( !$loaded ){ 00998 $loaded = true; 00999 $del = $this->getDelegate(); 01000 if ( isset($del) and method_exists($del,'conf') ){ 01001 $conf = $del->conf(); 01002 if ( !is_array($conf) ) throw new Exception("The Application Delegate class defined a method 'conf' that must return an array, but returns something else.", E_USER_ERROR); 01003 foreach ( $conf as $key=>$val){ 01004 if ( isset($this->_conf[$key]) ){ 01005 if ( is_array($this->_conf[$key]) and is_array($val) ){ 01006 $this->_conf[$key] = array_merge($this->_conf[$key], $val); 01007 } else { 01008 $this->_conf[$key] = $val; 01009 } 01010 } else { 01011 $this->_conf[$key] = $val; 01012 } 01013 } 01014 01015 } 01016 01017 } 01018 return $this->_conf; 01019 01020 } 01021 01022 01027 function getMySQLMajorVersion(){ 01028 if ( !isset($this->mysqlVersion) ){ 01029 $this->mysqlVersion = mysql_get_server_info($this->_db); 01030 } 01031 list($mv) = explode('.',$this->mysqlVersion); 01032 return intval($mv); 01033 } 01034 01035 01045 function getSiteTitle(){ 01046 $query =& $this->getQuery(); 01047 if ( isset($this->_conf['title']) ) { 01048 try { 01049 return $this->parseString($this->_conf['title']); 01050 } catch (Exception $ex){ 01051 return $this->_conf['title']; 01052 } 01053 } else if ( ($record = $this->getRecord()) && $query['-mode'] == 'browse' ){ 01054 return $record->getTitle().' - Dataface Application'; 01055 } else { 01056 try { 01057 return $this->parseString('{$tableLabel} - Dataface Application'); 01058 } catch (Exception $ex){ 01059 $tableLabel = Dataface_Table::loadTable($query['-table'])->getLabel(); 01060 return $tableLabel.' - Dataface Application'; 01061 } 01062 } 01063 01064 } 01065 01066 01067 // @} 01068 // END CONFIGURATION 01069 01070 01071 // @{ 01094 function &getQuery(){ 01095 return $this->_query; 01096 } 01097 01121 function &getQueryParam($key){ 01122 if ( isset( $this->_query['-'.$key] ) ){ 01123 return $this->_query['-'.$key]; 01124 } else { 01125 $null = null; 01126 return $null; 01127 } 01128 } 01129 01134 function &getResultSet(){ 01135 if ( $this->queryTool === null ){ 01136 import('Dataface/QueryTool.php'); 01137 $this->queryTool = Dataface_QueryTool::loadResult($this->_query['-table'], $this->db(), $this->_query); 01138 } 01139 return $this->queryTool; 01140 01141 } 01142 01187 function &getRecord(){ 01188 $null = null; 01189 if ( $this->currentRecord === null ){ 01190 $query =& $this->getQuery(); 01191 if ( @$query['--no-query'] ){ 01192 $null = null; 01193 return $null; 01194 } 01195 $q=array(); 01196 if ( isset($_REQUEST['__keys__']) and is_array($_REQUEST['__keys__']) ){ 01197 foreach ($_REQUEST['__keys__'] as $key=>$val) $q[$key] = '='.$val; 01198 $this->currentRecord = df_get_record($query['-table'], $q); 01199 } else if ( isset($_REQUEST['-__keys__']) and is_array($_REQUEST['-__keys__']) ){ 01200 foreach ($_REQUEST['-__keys__'] as $key=>$val) $q[$key] = '='.$val; 01201 $this->currentRecord = df_get_record($query['-table'], $q); 01202 } else if ( isset($_REQUEST['--__keys__']) and is_array($_REQUEST['--__keys__']) ){ 01203 foreach ($_REQUEST['--__keys__'] as $key=>$val) $q[$key] = '='.$val; 01204 $this->currentRecord = df_get_record($query['-table'], $q); 01205 } else if ( isset($_REQUEST['--recordid']) ){ 01206 $this->currentRecord = df_get_record_by_id($_REQUEST['--recordid']); 01207 } else if ( isset($_REQUEST['-recordid']) ){ 01208 $this->currentRecord = df_get_record_by_id($_REQUEST['-recordid']); 01209 } else { 01210 $rs = $this->getResultSet(); 01211 $this->currentRecord = $rs->loadCurrent(); 01212 } 01213 if ( $this->currentRecord === null ) $this->currentRecord = -1; 01214 } 01215 if ( $this->currentRecord === -1 || !$this->currentRecord ) return $null; 01216 return $this->currentRecord; 01217 } 01218 01226 function recordLoaded(){ 01227 return ( $this->currentRecord !== null); 01228 } 01229 01230 01237 function &getAction(){ 01238 import('Dataface/ActionTool.php'); 01239 $actionTool = Dataface_ActionTool::getInstance(); 01240 return $actionTool->getAction(array('name'=>$this->_query['-action'])); 01241 } 01242 01243 // @} 01244 // END Request Context 01245 01246 // @{ 01269 function saveMessage($str){ 01270 $_SESSION['--msg'] = $str; 01271 } 01272 01282 function enableSessions(){ 01283 setcookie($this->sessionCookieKey, 1, 0, DATAFACE_SITE_URL); 01284 } 01285 01295 function disableSessions(){ 01296 setcookie($this->sessionCookieKey, 1, time()-3600*25, DATAFACE_SITE_URL); 01297 } 01298 01307 function sessionEnabled(){ 01308 return @$_COOKIE[$this->sessionCookieKey]; 01309 } 01310 01322 function startSession($conf=null){ 01323 //echo "In startSession()"; 01324 01325 if ( session_id() == "" ){ 01326 $this->enableSessions(); 01327 if ( !isset($conf) ){ 01328 if ( isset($this->_conf['_auth']) ) $conf = $this->_conf['_auth']; 01329 else $conf = array(); 01330 } 01331 01332 $delegate =& $this->getDelegate(); 01333 if ( isset($delegate) and method_exists($delegate, 'startSession') ){ 01334 $delegate->startSession($conf); 01335 } else { 01336 01337 // path for cookies 01338 $cookie_path = "/"; 01339 if ( isset($conf['cookie_path']) ){ 01340 $cookie_path = $conf['cookie_path']; 01341 if ( substr($cookie_path,0,4) == 'php:' ){ 01342 $cookie_path_expr = substr($cookie_path,4); 01343 eval('$cookie_path = '.$cookie_path_expr.';'); 01344 } 01345 } 01346 01347 if ( $cookie_path{strlen($cookie_path)-1} != '/' ) $cookie_path .= '/'; 01348 01349 // timeout value for the cookie 01350 $cookie_timeout = (isset($conf['session_timeout']) ? intval($conf['session_timeout']) : 24*60*60); 01351 01352 01353 // timeout value for the garbage collector 01354 // we add 300 seconds, just in case the user's computer clock 01355 // was synchronized meanwhile; 600 secs (10 minutes) should be 01356 // enough - just to ensure there is session data until the 01357 // cookie expires 01358 $garbage_timeout = $cookie_timeout + 600; // in seconds 01359 01360 // set the PHP session id (PHPSESSID) cookie to a custom value 01361 session_set_cookie_params($cookie_timeout, $cookie_path); 01362 01363 // set the garbage collector - who will clean the session files - 01364 // to our custom timeout 01365 ini_set('session.gc_maxlifetime', $garbage_timeout); 01366 if ( isset($conf['session_timeout']) and ini_get('session.save_handler') == 'files' ){ 01367 // we need a distinct directory for the session files, 01368 // otherwise another garbage collector with a lower gc_maxlifetime 01369 // will clean our files aswell - but in an own directory, we only 01370 // clean sessions with our "own" garbage collector (which has a 01371 // custom timeout/maxlifetime set each time one of our scripts is 01372 // executed) 01373 strstr(strtoupper(substr(@$_SERVER["OS"], 0, 3)), "WIN") ? 01374 $sep = "\\" : $sep = "/"; 01375 $sessdir = session_save_path(); //ini_get('session.save_path'); 01376 $levels = ''; 01377 if (strpos($sessdir, ";") !== FALSE){ 01378 $levels = substr($sessdir, 0, strpos($sessdir, ";")).';'; 01379 $sessdir = substr($sessdir, strpos($sessdir, ";")+1); 01380 } 01381 if ( !$sessdir ) $sessdir = sys_get_temp_dir(); //'/tmp'; 01382 if ( $sessdir and $sessdir{strlen($sessdir)-1} == '/' ) $sessdir = substr($sessdir,0, strlen($sessdir)-1); 01383 01384 if ( @$conf['subdir'] ) $subdir = $conf['subdir']; 01385 else $subdir = md5(DATAFACE_SITE_PATH); 01386 if ( !$subdir ) $subdir = 'dataface'; 01387 $sessdir .= "/".$subdir; 01388 01389 01390 if (!is_dir($sessdir)) { 01391 $res = @mkdir($sessdir, 0777); 01392 if ( !$res ){ 01393 error_log("Failed to create session directory '$sessdir' to store session files in ".__FILE__." on line ".__LINE__); 01394 01395 } 01396 } 01397 if (is_dir($levels.$sessdir) ){ 01398 session_save_path($levels.$sessdir); 01399 } 01400 } else { 01401 // We need to set a unique session name if we're not changing the directory 01402 if ( !@$conf['session_name'] ){ 01403 $conf['session_name'] = md5(DATAFACE_SITE_PATH); 01404 } 01405 } 01406 if ( @$conf['session_name'] ) session_name($conf['session_name']); 01407 session_start(); // start the session 01408 header('P3P: CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"'); 01409 01410 // This updates the session timeout on page load 01411 if ( isset($_COOKIE[session_name()]) ){ 01412 setcookie(session_name(), $_COOKIE[session_name()], time() + $cookie_timeout, $cookie_path); 01413 } 01414 } 01415 } else { 01416 //echo "Session already started"; 01417 } 01418 01419 if ( isset( $_SESSION['--msg'] ) ){ 01420 $this->addMessage($_SESSION['--msg']); 01421 unset($_SESSION['--msg']); 01422 } 01423 01424 01425 } 01426 01430 function writeSessionData(){ 01431 01432 if ( isset($this->locations) ) $_SESSION['locations'] = serialize($this->locations); 01433 } 01434 01438 function encodeLocation($url){ 01439 if ( !isset($this->locations) and isset($_SESSION['locations']) ) $this->locations = unserialize($_SESSION['locations']); 01440 else if ( !isset($this->locations) ) $this->locations = array(); 01441 $key = md5($url); 01442 $this->locations[$key] = $url; 01443 return $key; 01444 } 01445 01449 function decodeLocation($key){ 01450 if ( !isset($this->locations) and isset($_SESSION['locations']) ) $this->locations = unserialize($_SESSION['locations']); 01451 else if ( !isset($this->locations) ) $this->locations = array(); 01452 01453 if ( isset($this->locations[$key]) ){ 01454 $url = $this->locations[$key]; 01455 unset($this->locations[$key]); 01456 return $url; 01457 01458 } else { 01459 return null; 01460 } 01461 01462 } 01463 01464 01471 function &getAuthenticationTool(){ 01472 $null = null; 01473 if ( !isset($this->authenticationTool) ){ 01474 01475 if ( isset($this->_conf['_auth']) ){ 01476 import('Dataface/AuthenticationTool.php'); 01477 $this->authenticationTool = Dataface_AuthenticationTool::getInstance($this->_conf['_auth']); 01478 } else { 01479 return $null; 01480 } 01481 } 01482 01483 return $this->authenticationTool; 01484 } 01485 01486 01487 01488 01489 01490 // @} 01491 // END Session Handling 01492 //===================================================================================================== 01493 01494 // @{ 01524 function addHeadContent($content){ 01525 $this->headContent[] = $content; 01526 } 01527 01528 01549 function getNavItem($key, $label=null){ 01550 $del =& $this->getDelegate(); 01551 $override = array(); 01552 if ( isset($del) and method_exists($del, 'getNavItem') ){ 01553 try { 01554 $override = $del->getNavItem($key, $label?$label:$key); 01555 } catch (Exception $ex){} 01556 } 01557 if ( !isset($override) ){ 01558 return $override; 01559 } 01560 return array_merge(array( 01561 'href'=> DATAFACE_SITE_HREF.'?-table='.urlencode($key), 01562 'label'=> $label ? $label:$key, 01563 'selected' => $this->isNavItemSelected($key) 01564 ), $override); 01565 } 01566 01567 01583 function isNavItemSelected($key){ 01584 $del =& $this->getDelegate(); 01585 if ( isset($del) and method_exists($del, 'isNavItemSelected') ){ 01586 try { 01587 return $del->isNavItemSelected($key); 01588 } catch (Exception $ex){} 01589 } 01590 $query =& $this->getQuery(); 01591 return ($query['-table'] == $key); 01592 } 01593 01594 01595 01606 function addError($err){ 01607 $this->errors[] = $err; 01608 } 01609 01618 function numErrors(){ return count($this->errors); } 01619 01627 function getErrors(){ 01628 return $this->errors; 01629 } 01630 01639 function addMessage($msg){ 01640 $this->messages[] = $msg; 01641 } 01642 01654 function getMessages(){ 01655 if ( trim(@$_SESSION['msg']) ){ 01656 array_push($this->messages, $_SESSION['msg']); 01657 unset($_SESSION['msg']); 01658 } 01659 $msgs = $this->messages; 01660 $response = $this->getResponse(); 01661 if ( @$response['--msg'] ){ 01662 array_push($msgs, $response['--msg']); 01663 } 01664 //print_r($msgs); 01665 return $msgs; 01666 } 01667 01672 function clearMessages(){ 01673 $this->messages = array(); 01674 } 01675 01680 function numMessages(){ 01681 $count = count($this->messages); 01682 $response = $this->getResponse(); 01683 if ( @$response['--msg'] ) $count++; 01684 return $count; 01685 } 01686 01687 01698 public static function &getResponse(){ 01699 static $response = 0; 01700 if ( !$response ){ 01701 $response = array('--msg'=>''); 01702 } 01703 return $response; 01704 } 01705 01706 01707 // @} 01708 // END Template & UI Interaction 01709 //==================================================================================== 01710 01711 // {@ 01729 function fireEvent($name, $params=null){ 01730 $listeners = $this->getEventListeners($name); 01731 foreach ($listeners as $listener){ 01732 $res = call_user_func($listener, $params); 01733 if ( PEAR::isError($res) ) return $res; 01734 } 01735 return true; 01736 } 01737 01748 function registerEventListener($name, $callback){ 01749 if ( !isset($this->eventListeners[$name]) ) $this->eventListeners[$name] = array(); 01750 $this->eventListeners[$name][] = $callback; 01751 } 01752 01753 01760 function unregisterEventListener($name, $callback){ 01761 if ( isset($this->eventListeners[$name]) ){ 01762 $listeners =& $this->eventListeners[$name]; 01763 foreach ( $listeners as $key=>$listener ){ 01764 if ( $listener == $callback ) unset($listeners[$key]); 01765 } 01766 } 01767 } 01768 01774 function getEventListeners($name=null){ 01775 if ( !isset($name) ) return $this->eventListeners; 01776 else if (isset($this->eventListeners[$name])){ 01777 return $this->eventListeners[$name]; 01778 } else { 01779 return array(); 01780 } 01781 } 01782 01783 01784 01785 // @} 01786 // END Event Handling 01787 //===================================================================================== 01788 01789 01790 01791 // @{ 01824 function handleRequest($disableCache=false){ 01825 01826 01827 if ( !$disableCache and (@$_GET['-action'] != 'getBlob') and isset( $this->_conf['_output_cache'] ) and @$this->_conf['_output_cache']['enabled'] and count($_POST) == 0){ 01828 import('Dataface/OutputCache.php'); 01829 $oc = new Dataface_OutputCache($this->_conf['_output_cache']); 01830 $oc->ob_start(); 01831 01832 } 01833 import('Dataface/ActionTool.php'); 01834 import('Dataface/PermissionsTool.php'); 01835 import('Dataface/Table.php'); 01836 01837 if ( isset($this->_conf['_modules']) and count($this->_conf['_modules']) > 0 ){ 01838 $mt = Dataface_ModuleTool::getInstance(); 01839 foreach ($this->_conf['_modules'] as $modname=>$modpath){ 01840 $mt->loadModule($modname); 01841 01842 } 01843 } 01844 01845 $this->fireEvent('beforeHandleRequest'); 01846 $applicationDelegate = $this->getDelegate(); 01847 if ( isset($applicationDelegate) and method_exists($applicationDelegate, 'beforeHandleRequest') ){ 01848 // Do whatever we need to do before the request is handled. 01849 $applicationDelegate->beforeHandleRequest(); 01850 } 01851 01852 // Set up security filters 01853 $query =& $this->getQuery(); 01854 $table = Dataface_Table::loadTable($query['-table']); 01855 01856 //$table->setSecurityFilter(); 01857 /* 01858 * Set up some preferences for the display of the application. 01859 * These can be overridden by the getPreferences() method in the 01860 * application delegate class. 01861 */ 01862 if ( isset($this->_conf['_prefs']) and is_array($this->_conf['_prefs']) ){ 01863 $this->prefs = array_merge($this->prefs,$this->_conf['_prefs']); 01864 } 01865 if ( @$this->_conf['hide_nav_menu'] ){ 01866 $this->prefs['show_tables_menu'] = 0; 01867 } 01868 01869 if ( @$this->_conf['hide_view_tabs'] ){ 01870 $this->prefs['show_table_tabs'] = 0; 01871 } 01872 01873 if ( @$this->_conf['hide_result_controller'] ){ 01874 $this->prefs['show_result_controller'] = 0; 01875 } 01876 01877 if ( @$this->_conf['hide_table_result_stats'] ){ 01878 $this->prefs['show_result_stats'] = 0; 01879 } 01880 01881 if ( @$this->_conf['hide_search'] ){ 01882 $this->prefs['show_search'] = 0; 01883 } 01884 01885 if ( !isset($this->prefs['disable_ajax_record_details']) ){ 01886 $this->prefs['disable_ajax_record_details'] = 1; 01887 } 01888 01889 if ( $query['-action'] == 'login_prompt' ) $this->prefs['no_history'] = 1; 01890 01891 01892 if ( isset($applicationDelegate) and method_exists($applicationDelegate, 'getPreferences') ){ 01893 $this->prefs = array_merge($this->prefs, $applicationDelegate->getPreferences()); 01894 } 01895 $this->prefs = array_map('intval', $this->prefs); 01896 01897 // Check to make sure that this table hasn't been disallowed 01898 $disallowed = false; 01899 if ( isset($this->_conf['_disallowed_tables']) ){ 01900 foreach ( $this->_conf['_disallowed_tables'] as $name=>$pattern ){ 01901 if ( $pattern{0} == '/' and preg_match($pattern, $query['-table']) ){ 01902 $disallowed = true; 01903 break; 01904 } else if ( $pattern == $query['-table'] ){ 01905 $disallowed = true; 01906 break; 01907 } 01908 } 01909 } 01910 01911 if ( $disallowed and isset($this->_conf['_allowed_tables']) ){ 01912 foreach ($this->_conf['_allowed_tables'] as $name=>$pattern ){ 01913 if ( $pattern{0} == '/' and preg_match($pattern, $query['-table']) ){ 01914 $disallowed = false; 01915 break; 01916 } else if ( $pattern == $query['-table'] ){ 01917 $disallowed = false; 01918 break; 01919 } 01920 } 01921 } 01922 01923 01924 if ( $disallowed ){ 01925 return Dataface_Error::permissionDenied( 01926 Dataface_LanguageTool::translate( 01927 /*i18n id*/ 01928 "Permission Denied. This table has been disallowed in the conf.ini file", 01929 /* default error message */ 01930 "Permission denied because this table has been disallowed in the conf.ini file '" 01931 ) 01932 ); 01933 01934 } 01935 01936 01937 $actionTool = Dataface_ActionTool::getInstance(); 01938 01939 //if ( $this->_conf['multilingual_content'] ){ 01940 //import('I18Nv2/I18Nv2.php'); 01941 //I18Nv2::autoConv(); 01942 //} 01943 01944 $params = array( 01945 'table'=>$query['-table'], 01946 'name'=>$query['-action']); 01947 if ( strpos($query['-action'], 'custom_') === 0 ){ 01948 $action = array( 01949 'name' => $query['-action'], 01950 'page' => substr($query['-action'], 7), 01951 'permission' => 'view', 01952 'mode' => 'browse', 01953 'custom' => true 01954 ); 01955 } else { 01956 $action = $actionTool->getAction($params); 01957 if ( is_array($action) and @$action['related'] and @$query['-relationship'] and preg_match('/relationships\.ini/', @$action['allow_override']) ){ 01958 // This action is to be performed on the currently selected relationship. 01959 $raction = $table->getRelationshipsAsActions(array(), $query['-relationship']); 01960 if ( is_array($raction) ){ 01961 $action = array_merge($action,$raction); 01962 } 01963 } 01964 if ( is_array($action) and isset($action['delegate']) ){ 01965 $params['name'] = $query['-action'] = $action['delegate']; 01966 $tmp = $actionTool->getActions($params); 01967 unset($action); 01968 $action =& $tmp; 01969 unset($tmp); 01970 } 01971 if ( is_array($action) and isset($action['auth_type']) ){ 01972 $authTool = $this->getAuthenticationTool(); 01973 $authTool->setAuthType($action['auth_type']); 01974 } 01975 01976 } 01977 01978 01979 if ( (PEAR::isError($action) or !@$action['permission']) and $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){ 01980 // The only reason getAction() will return an error is if the specified action could not be found. 01981 // If the application is set to use strict permissions and no action was defined in the ini file 01982 // then this action cannot be performed. Strict permissions mode requires that permissions be 01983 // strictly set or permission will be denied. 01984 return Dataface_Error::permissionDenied( 01985 Dataface_LanguageTool::translate( 01986 /*i18n id*/ 01987 "Permission Denied. No action found in strict permissions mode", 01988 /* default error message */ 01989 "Permission denied for action '". 01990 $query['-action']. 01991 "'. No entry for this action was found in the actions.ini file. 01992 You are currently using strict permissions mode which requires that you define all actions that you want to use in the actions.ini file with appropriate permissions information.", 01993 /* i18n parameters */ 01994 array('action'=>$query['-action']) 01995 ) 01996 ); 01997 01998 } 01999 02000 else if ( PEAR::isError($action) ){ 02001 $action = array('name'=>$query['-action'], 'label'=>$query['-action']); 02002 } 02003 02004 // Step 1: See if the delegate class has a handler. 02005 02006 $delegate = $table->getDelegate(); 02007 $handled = false; 02008 if ( method_exists($delegate,'handleRequest') ){ 02009 $result = $delegate->handleRequest(); 02010 if ( PEAR::isError($result) and $result->getCode() === DATAFACE_E_REQUEST_NOT_HANDLED ){ 02011 $handled = false; 02012 } else if ( PEAR::isError($result) ){ 02013 return $result; 02014 } else { 02015 $handled = true; 02016 } 02017 } 02018 if ( isset($action['mode']) and $action['mode'] ) $query['-mode'] = $action['mode']; 02019 02020 // Step 2: Look to see if there is a handler defined 02021 if ( isset($action['custom']) ){ 02022 $locations = array( DATAFACE_PATH.'/actions/custom.php'=>'dataface_actions_custom'); 02023 } else { 02024 $locations = array(); 02025 02026 $locations[ Dataface_Table::getBasePath($query['-table']).'/tables/'.basename($query['-table']).'/actions/'.basename($query['-action']).'.php' ] = 'tables_'.$query['-table'].'_actions_'.$query['-action']; 02027 $locations[ DATAFACE_SITE_PATH.'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action']; 02028 02029 if ( isset($this->_conf['_modules']) and count($this->_conf['_modules']) > 0 ){ 02030 $mt = Dataface_ModuleTool::getInstance(); 02031 foreach ($this->_conf['_modules'] as $modname=>$modpath){ 02032 $mt->loadModule($modname); 02033 if ( $modpath{0} == '/' ) 02034 $locations[ dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action']; 02035 else { 02036 $locations[ DATAFACE_SITE_PATH.'/'.dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action']; 02037 $locations[ DATAFACE_PATH.'/'.dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action']; 02038 } 02039 } 02040 } 02041 02042 $locations[ DATAFACE_PATH.'/actions/'.basename($query['-action']).'.php' ] = 'dataface_actions_'.$query['-action']; 02043 $locations[ DATAFACE_PATH.'/actions/default.php' ] = 'dataface_actions_default'; 02044 02045 } 02046 $doParams = array('action'=>&$action); 02047 //parameters to be passed to the do method of the handler 02048 02049 02050 foreach ($locations as $handlerPath=>$handlerClassName){ 02051 if ( is_readable($handlerPath) ){ 02052 import($handlerPath); 02053 $handler = new $handlerClassName; 02054 $params = array(); 02055 if ( is_array($action) and @$action['related'] and @$query['-relationship'] ){ 02056 $params['relationship'] = $query['-relationship']; 02057 } 02058 if ( !PEAR::isError($action) and method_exists($handler, 'getPermissions') ){ 02059 // check the permissions on this action to make sure that we are 'allowed' to perform it 02060 // this method will return an array of Strings that are names of permissions granted to 02061 // the current user. 02062 02063 02064 //echo "Checking permissions:"; 02065 //print_r($params); 02066 $permissions = $handler->getPermissions($params); 02067 //} else if ( $applicationDelegate !== null and method_exists($applicationDelegate, 'getPermissions') ){ 02068 // $permissions =& $applicationDelegate->getPermissions($params); 02069 02070 02071 02072 } else { 02073 //print_r($params); 02074 //print_r($action); 02075 $permissions = $this->getPermissions($params); 02076 } 02077 02078 if ( isset($action['permission']) && !(isset($permissions[$action['permission']]) and $permissions[$action['permission']]) ){ 02079 return Dataface_Error::permissionDenied( 02080 Dataface_LanguageTool::translate( 02081 "Permission Denied for action.", /*i18n id*/ 02082 /* Default error message */ 02083 "Permission to perform action '". 02084 $action['name']. 02085 "' denied. 02086 Requires permission '". 02087 $action['permission']. 02088 "' but only granted '". 02089 Dataface_PermissionsTool::namesAsString($permissions)."'.", 02090 /* i18n parameters */ 02091 array('action'=>$action, 'permissions_granted'=>Dataface_PermissionsTool::namesAsString($permissions)) 02092 ) 02093 ); 02094 02095 } 02096 02097 if ( method_exists($handler, 'handle') ){ 02098 02099 02100 $result = $handler->handle($doParams); 02101 if ( PEAR::isError($result) and $result->getCode() === DATAFACE_E_REQUEST_NOT_HANDLED ){ 02102 continue; 02103 } 02104 return $result; 02105 } 02106 02107 02108 } 02109 02110 } 02111 02112 throw new Exception(df_translate('scripts.Dataface.Application.handleRequest.NO_HANDLER_FOUND',"No handler found for request. This should never happen because, at the very least, the default handler at dataface/actions/default.php should be called. Check the permissions on dataface/actions/default.php to make sure that it is readable by the web server."), E_USER_ERROR); 02113 02114 02115 02116 02117 } 02118 02119 02120 02134 function display($main_content_only=false, $disableCache=false){ 02135 // ---------------- Set the Default Character set for output ----------- 02136 foreach ($this->_tables as $key=>$value){ 02137 $this->_tables[$key] = $this->_conf['_tables'][$key] = df_translate('tables.'.$key.'.label', $value); 02138 } 02139 02140 $this->main_content_only = $main_content_only; 02141 if ( $this->autoSession or $this->sessionEnabled() ){ 02142 $this->startSession(); 02143 } 02144 if ( !@$this->_conf['disable_session_ip_check'] ){ 02145 if ( !@$_SESSION['XATAFACE_REMOTE_ADDR'] ){ 02146 $_SESSION['XATAFACE_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; 02147 } 02148 $ipAddressError = null; 02149 if ( $_SESSION['XATAFACE_REMOTE_ADDR'] != $_SERVER['REMOTE_ADDR'] ){ 02150 $msg = sprintf( 02151 "Session address does not match the remote address. Possible hacking attempt. Session address was '%s', User address was '%s'", 02152 htmlspecialchars($_SESSION['XATAFACE_REMOTE_ADDR']), 02153 htmlspecialchars($_SERVER['REMOTE_ADDR']) 02154 ); 02155 error_log($msg); 02156 //die('Your IP address doesn\'t match the session address. To continue, please clear your cookies or restart your browser and try again.'); 02157 session_destroy(); 02158 $this->startSession(); 02159 if ( !@$_SESSION['XATAFACE_REMOTE_ADDR'] ){ 02160 $_SESSION['XATAFACE_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; 02161 } 02162 02163 } 02164 } 02165 // handle authentication 02166 if ( isset($this->_conf['_auth']) ){ 02167 // The config file _auth section is there so we will be using authentication. 02168 02169 $loginPrompt = false; // flag to indicate if we should show the login prompt 02170 $permissionDenied = false;// flag to indicate if we should show permission denied 02171 $permissionError = ''; //Placeholder for permissions error messages 02172 $loginError = ''; // Placeholder for login error messages. 02173 02174 $authTool = $this->getAuthenticationTool(); 02175 02176 $auth_result = $authTool->authenticate(); 02177 02178 if ( PEAR::isError($auth_result) and $auth_result->getCode() == DATAFACE_E_LOGIN_FAILURE ){ 02179 // There was a login failure, show the login prompt 02180 $loginPrompt = true; 02181 $loginError = $auth_result->getMessage(); 02182 } else if ( $authTool->isLoggedIn() ){ 02183 // The user is logged in ok 02184 // Handle the request 02185 $result = $this->handleRequest(); 02186 if ( Dataface_Error::isPermissionDenied($result) ){ 02187 // Permission was denied on the request. Since the user is already 02188 // logged in, there is no use giving him the login prompt. Just give 02189 // him the permission denied screen. 02190 $permissionDenied = true; 02191 $permissionError = $result->getMessage(); 02192 } 02193 } else if ( isset($this->_conf['_auth']['require_login']) and $this->_conf['_auth']['require_login'] ){ 02194 // The user is not logged in and login is required for this application 02195 // Show the login prompt 02196 $loginPrompt = true; 02197 02198 } else { 02199 // The user is not logged in, but login is not required for this application. 02200 // Allow the user to perform the action. 02201 02202 $result = $this->handleRequest($disableCache); 02203 if ( Dataface_Error::isPermissionDenied($result) ){ 02204 // The user did not have permission to perform the action 02205 // Give the user a login prompt. 02206 02207 $loginPrompt = true; 02208 } 02209 02210 } 02211 if ( $loginPrompt ){ 02212 // The user is supposed to see a login prompt to log in. 02213 // Show the login prompt. 02214 02215 $authTool->showLoginPrompt($loginError); 02216 } else if ($permissionDenied) { 02217 // The user is supposed to see the permissionm denied page. 02218 $query =& $this->getQuery(); 02219 02220 if ( $query['--original_action'] == 'browse' and $query['-action'] != 'view' ){ 02221 $this->redirect($this->url('-action=view')); 02222 } 02223 $this->addError($result); 02224 header("HTTP/1.1 403 Permission Denied"); 02225 df_display(array(), 'Dataface_Permission_Denied.html'); 02226 } else if ( PEAR::isError($result) ){ 02227 // Some other error occurred in handling the request. Just show an 02228 // ugly stack trace. 02229 02230 throw new Exception($result->toString().$result->getDebugInfo(), E_USER_ERROR); 02231 } 02232 } else { 02233 // Authentication is not enabled for this application. 02234 // Just process the request. 02235 02236 $result = $this->handleRequest($disableCache); 02237 if ( Dataface_Error::isPermissionDenied($result) ){ 02238 $query =& $this->getQuery(); 02239 02240 if ( $query['--original_action'] == 'browse' and $query['-action'] != 'view' ){ 02241 $this->redirect($this->url('-action=view')); 02242 } 02243 $this->addError($result); 02244 header("HTTP/1.1 403 Permission Denied"); 02245 df_display(array(), 'Dataface_Permission_Denied.html'); 02246 } else if ( PEAR::isError($result) ){ 02247 02248 throw new Exception($result->toString().$result->getDebugInfo(), E_USER_ERROR); 02249 } 02250 } 02251 02252 } 02253 02263 function _handleGetBlob($request){ 02264 import('Dataface/Application/blob.php'); 02265 return Dataface_Application_blob::_handleGetBlob($request); 02266 } 02267 02268 02269 // @} 02270 // END Request Handling 02271 //====================================================================================== 02272 02273 02274 // @{ 02282 var $_parseStringContext=array(); 02350 function parseString($expression, $context=null){ 02351 // make sure that the expression doesn't try to break the double quotes. 02352 if ( strpos($expression, '"') !== false ){ 02353 throw new Exception( 02354 df_translate( 02355 'scripts.Dataface.Application.parseString.ERROR_PARSING_EXPRESSION_DBL_QUOTE', 02356 "Invalid expression (possible hacking attempt in Dataface_Application::eval(). Expression cannot include double quotes '\"', but recieved '".$expression."'.", 02357 array('expression'=>$expression)) 02358 , E_USER_ERROR); 02359 } 02360 02361 $site_url = DATAFACE_SITE_URL; 02362 $site_href = DATAFACE_SITE_HREF; 02363 $dataface_url = DATAFACE_URL; 02364 $table = $this->_currentTable; 02365 $tableObj = Dataface_Table::loadTable($table); 02366 if ( PEAR::isError($tableObj) ){ 02367 throw new Exception($tableObj->getMessage(), $tableObj->getCode()); 02368 } 02369 $query =& $this->getQuery(); 02370 $app = $this; 02371 $resultSet = $app->getResultSet(); 02372 if ( isset($context['record']) ){ 02373 02374 $record = $context['record']; 02375 } else { 02376 $record = $app->getRecord(); 02377 } 02378 02379 if ( isset($context['relationship']) ){ 02380 //$tableObj = Dataface_Table::loadTable($table); 02381 02382 if ( is_string($context['relationship']) ){ 02383 $relationship = $tableObj->getRelationship($context['relationship']); 02384 if ( !($relationship instanceof Dataface_Relationship) ){ 02385 $relationship = null; 02386 } 02387 } else if ( $context['relationship'] instanceof Dataface_Relationship ){ 02388 $relationship = $context['relationship']; 02389 } 02390 //unset($tableObj); 02391 } 02392 02393 @eval('$parsed = "'.$expression.'";'); 02394 02395 if ( !isset( $parsed ) ){ 02396 throw new Exception(df_translate('scripts.Dataface.Application.parseString.ERROR_PARSING_EXPRESSION',"Error parsing expression '$expression'. ", array('expression'=>$expression)), E_USER_ERROR); 02397 } 02398 return $parsed; 02399 02400 } 02401 02402 02407 function _parsePregMatch($matches){ 02408 extract($this->_parseStringContext); 02409 return @eval('return '.$matches[1].$matches[2].';'); 02410 } 02411 02412 02479 function testCondition($condition, $context=null){ 02480 02481 $site_url = DATAFACE_SITE_URL; 02482 $site_href = DATAFACE_SITE_HREF; 02483 $dataface_url = DATAFACE_URL; 02484 $table = $this->_currentTable; 02485 $tableObj = Dataface_Table::loadTable($table); 02486 if ( PEAR::isError($tableObj) ) throw new Exception($tableObj->getMessage(), $tableObj->getCode()); 02487 $query =& $this->getQuery(); 02488 $app = $this; 02489 $resultSet = $app->getResultSet(); 02490 if ( isset($context['record']) ) $record = $context['record']; 02491 else $record = $app->getRecord(); 02492 02493 if ( isset($context['relationship']) ){ 02494 //$tableObj =& Dataface_Table::loadTable($table); 02495 if ( is_string($context['relationship']) ){ 02496 $relationship = $tableObj->getRelationship($context['relationship']); 02497 if ( !($relationship instanceof Dataface_Relationship) ){ 02498 $relationship = null; 02499 } 02500 } else if ( $context['relationship'] instanceof Dataface_Relationship ){ 02501 $relationship = $context['relationship']; 02502 } 02503 //unset($tableObj); 02504 } 02505 02506 return @eval('return ('.$condition.');'); 02507 } 02508 02509 02510 02537 function url($query, $useContext=true, $forceContext=false){ 02538 import('Dataface/LinkTool.php'); 02539 return Dataface_LinkTool::buildLInk($query, $useContext, $forceContext); 02540 02541 } 02542 02543 02544 02545 02546 02547 02548 02549 02550 02551 02552 02581 function registerUrlFilter( $filter ){ 02582 $this->_url_filters[] = $filter; 02583 } 02584 02585 02595 function filterUrl($url){ 02596 if ( !preg_match( '/[&\?]-table/i', $url ) ){ 02597 if ( preg_match( '/\?/i', $url ) ){ 02598 $url .= '&-table='.$this->_currentTable; 02599 } else { 02600 $url .= '?-table='.$this->_currentTable; 02601 } 02602 } 02603 02604 foreach ($this->_url_filters as $filter){ 02605 $url = call_user_func($filter, $url); 02606 } 02607 return $url; 02608 02609 } 02610 02611 02612 02616 function init(){ 02617 02618 } 02619 02620 02633 function redirect($url){ 02634 if ( isset($this->redirectHandler) and method_exists('redirect', $this->redirectHandler) ){ 02635 $this->redirectHandler->redirect($url); 02636 throw new Dataface_Application_RedirectException($url); 02637 } 02638 header('Location: '.$url); 02639 exit; 02640 02641 } 02642 02643 // @} 02644 // End Utility Functions 02645 //======================================================================================= 02646 02647 02648 02649 // @{ 02666 function &getDelegate(){ 02667 if ( $this->delegate === -1 ){ 02668 $delegate_path = DATAFACE_SITE_PATH.'/conf/ApplicationDelegate.php'; 02669 if ( is_readable($delegate_path) ){ 02670 import($delegate_path); 02671 $this->delegate = new conf_ApplicationDelegate(); 02672 } else { 02673 $this->delegate = null; 02674 } 02675 } 02676 return $this->delegate; 02677 02678 } 02679 02680 02681 02682 02683 // END Delegate Class 02684 // @} 02685 //======================================================================================== 02686 02687 02688 // @{ 02714 function getPermissions($params=array()){ 02715 $query =& $this->getQuery(); 02716 $record = $this->getRecord(); 02717 if ( $record and is_a($record, 'Dataface_Record') ){ 02718 //$params = array(); 02719 return Dataface_PermissionsTool::getPermissions($record, $params); 02720 } else { 02721 $table = Dataface_Table::loadTable($query['-table']); 02722 //$params = array(); 02723 return Dataface_PermissionsTool::getPermissions($table, $params); 02724 } 02725 02726 } 02727 02741 function checkPermission($perm){ 02742 $perms = $this->getPermissions(); 02743 $result = (isset($perms[$perm]) and $perms[$perm]); 02744 return $result; 02745 } 02746 02747 02748 02749 02750 // @} 02751 // END Permissions 02752 //========================================================================================= 02753 02754 02755 02768 function refreshSchemas($tablename){ 02769 if ( @$this->_conf['metadata_enabled'] ){ 02770 $metadataTool = new Dataface_MetadataTool(); 02771 $metadataTool->updateWorkflowTable($tablename); 02772 } 02773 } 02774 02775 02776 02777 02778 02788 function _parseRelatedBlobRequest($request){ 02789 import('Dataface/Application/blob.php'); 02790 return Dataface_Application_blob::_parseRelatedBlobRequest($request); 02791 } 02792 02793 02795 02822 function &getCustomPages(){ 02823 if ( !isset( $this->_customPages ) ){ 02824 $this->_customPages = array(); 02825 $path = DATAFACE_SITE_PATH.'/pages/'; 02826 if ( is_dir($path) ){ 02827 if ( $dh = opendir($path) ){ 02828 while ( ( $file = readdir($dh) ) !== false ){ 02829 if ( preg_match('/\.php$/', $file) ){ 02830 list($name) = explode('.', $file); 02831 //$name = str_replace('_', ' ', $name); 02832 02833 $this->_customPages[$name] = $path.$file; 02834 } 02835 } 02836 } 02837 } 02838 } 02839 return $this->_customPages; 02840 } 02841 02849 function getCustomPagePath($name){ 02850 $pages =& $this->getCustomPages(); 02851 return $pages[$name]; 02852 } 02853 02862 function getCustomPageLabel($name){ 02863 $name = str_replace('_',' ', $name); 02864 return ucwords($name); 02865 } 02866 02867 02868 // @} 02869 // END Custom Pages 02870 //===================================================================================== 02871 02872 02873 02879 function addDebugInfo($info){ 02880 $this->debugLog[] = $info; 02881 } 02882 02888 function displayDebugInfo(){ 02889 echo '<ul class="debug-info"><li> 02890 '; echo implode('</li><li>', $this->debugLog); 02891 echo '</li></ul>'; 02892 } 02893 02897 function _cleanup(){ 02898 if ( session_id() != "" ){ 02899 $this->writeSessionData(); 02900 } 02901 if ( @$this->_conf['support_transactions'] ){ 02902 @mysql_query('COMMIT', $this->_db); 02903 } 02904 } 02905 02906 02907 02908 02909 02910 02911 02912 02913 02914 } 02915 02920 class Dataface_Application_RedirectException extends Exception { 02921 private $url; 02922 public function __construct($url, $code = 0, Exception $previous = null ){ 02923 $this->url = $url; 02924 parent::__construct('Request to redirect to '.$url, $code, $previous); 02925 } 02926 02927 public function getURL(){ 02928 return $this->url; 02929 } 02930 02931 } 02932