Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
Application.php
Go to the documentation of this file.
1 <?php
2 /*-------------------------------------------------------------------------------
3  * Xataface Web Application Framework
4  * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *-------------------------------------------------------------------------------
20  */
21 
22 
23 if ( !function_exists('sys_get_temp_dir') )
24 {
25  // Based on http://www.phpit.net/
26  // article/creating-zip-tar-archives-dynamically-php/2/
27  function sys_get_temp_dir()
28  {
29  // Try to get from environment variable
30  if ( !empty($_ENV['TMP']) )
31  {
32  return realpath( $_ENV['TMP'] );
33  }
34  else if ( !empty($_ENV['TMPDIR']) )
35  {
36  return realpath( $_ENV['TMPDIR'] );
37  }
38  else if ( !empty($_ENV['TEMP']) )
39  {
40  return realpath( $_ENV['TEMP'] );
41  }
42 
43  // Detect by creating a temporary file
44  else
45  {
46  // Try to use system's temporary directory
47  // as random name shouldn't exist
48  $temp_file = tempnam( md5(uniqid(rand(), TRUE)), '' );
49  if ( $temp_file )
50  {
51  $temp_dir = realpath( dirname($temp_file) );
52  unlink( $temp_file );
53  return $temp_dir;
54  }
55  else
56  {
57  return FALSE;
58  }
59  }
60  }
61 }
62 
63 require_once dirname(__FILE__)."/../config.inc.php";
64 import('Dataface/PermissionsTool.php');
65 import('Dataface/LanguageTool.php');
66 define('DATAFACE_STRICT_PERMISSIONS', 100);
67  // the minimum security level that is deemed as strict permissions.
68  // strict permissions mean that permissions must be explicitly granted to a
69  // table, record, or action or they will not be accessible
70 
136 
138 
139 
165  public $redirectHandler = null;
166 
167  private $pageTitle = null;
168 
172  var $sessionCookieKey;
173 
174 
178  var $autoSession = false;
179 
183  var $_url_filters = array();
188  var $_tables = array();
189 
194  var $tableIndex = array();
195 
200  var $_baseUrl;
201 
205  var $_currentTable;
206 
207 
211  var $memcache;
212 
217  var $_db;
224  var $_query;
225 
233 
237  var $queryTool = null;
238 
242  var $currentRecord = null;
243 
247  var $recordContext = null;
248 
252  var $_customPages;
253 
260  var $locations = null;
261 
269  var $eventListeners = array();
270 
274  var $prefs = array(
275  'show_result_stats'=>1, // The result statistics (e.g. found x of y records in table z)
276  'show_jump_menu'=>1, // The drop-down menu that allows you to "jump" to any record in the found set.
277  'show_result_controller'=>1, // Next, previous, page number .. links...
278  'show_table_tabs'=>1, // Details, List, Find, etc...
279  'show_actions_menu'=>1, // New record, Show all, delete, etc...
280  'show_logo'=>1, // Show logo at top right of app
281  'show_tables_menu'=>1, // The tabs to select a table.
282  'show_search'=>1, // Show search field in upper right.
283  'show_record_actions'=>1, // Show actions related to particular record
284  'show_recent_records_menu'=>1, // Menu to jump to recently visited record (deprecated)
285  'show_bread_crumbs' => 1, // Bread crumbs at top of page to show where you are
286  'show_record_tabs' => 1, // View, Edit, Translate, History, etc...
287  'show_record_tree' => 1, // Tree to navigate the relationships of this record.
288  'list_view_scroll_horizontal'=>1, // Whether to scroll list horizontal if it exceeds page width
289  'list_view_scroll_vertical'=>1 // Whether to scroll list vertical if it exceeds page height.
290 
291  );
292 
298  var $tableNamesUsed = array();
299 
303  var $main_content_only = false;
304  // IF true then output only includes main content - not the
305  // surrounding frame.
306 
313  var $delegate = -1;
314 
315 
316 
320  var $errors=array();
321 
325  var $messages = array();
326 
330  var $debugLog = array();
331 
335  var $authenticationTool = null;
336 
343  var $headContent=array();
344 
350  var $mysqlVersion = null;
351 
352 
353 
354  // @{
377  var $_locales = array(
378  'zh_CN'=>'zh',
379  'zh_TW'=>'zt',
380  'zh_HK'=>'zt',
381  'en_US'=>'en'
382  );
383 
393  var $_languages = array(
394  'zt'=>'zh'
395  );
396 
423  function getLanguage($langCode){
424  if ( isset($this->_languages[$langCode]) ){
425  return $this->_languages[$langCode];
426  } else {
427  return $langCode;
428  }
429  }
430 
449  function getLanguageCode($locale){
450  if ( isset($this->_locales[$locale]) ) return $this->_locales[$locale];
451  else {
452  list($langCode) = explode('_', $locale);
453  return $langCode;
454  }
455  }
456 
487  $langs = array_keys($this->_conf['languages']);
488  if ( @$this->_conf['default_language'] ) $langs[] = $this->_conf['default_language'];
489  else $langs[] = 'en';
490  $out = array();
491  foreach ($langs as $lang){
492  $out[$this->getLanguage($lang)] = true;
493  }
494  return array_keys($out);
495 
496  }
497 
498 
499 
500 
501  // @}
502  // END LANGUAGES
503 
504 
505  // @{
516  function db(){ return $this->_db;}
517 
521  var $_conf;
522 
526  function Dataface_Application($conf = null){
527  $this->sessionCookieKey = md5(DATAFACE_SITE_URL.'#'.__FILE__);
528  $this->_baseUrl = $_SERVER['PHP_SELF'];
529  if ( !is_array($conf) ) $conf = array();
530  if ( is_readable(DATAFACE_SITE_PATH.'/conf.ini') ){
531  $conf = array_merge(parse_ini_file(DATAFACE_SITE_PATH.'/conf.ini', true), $conf);
532  if ( @$conf['__include__'] ){
533  $includes = array_map('trim',explode(',', $conf['__include__']));
534  foreach ($includes as $i){
535  if ( is_readable($i) ){
536  $conf = array_merge($conf, parse_ini_file($i, true));
537  }
538  }
539  }
540  }
541 
542 
543 
544  if ( !isset( $conf['_tables'] ) ){
545  throw new Exception('Error loading config file. No tables specified.', E_USER_ERROR);
546 
547  }
548 
549 
550 
551  if ( isset( $conf['db'] ) and is_resource($conf['db']) ){
552  $this->_db = $conf['db'];
553  } else {
554  if ( !isset( $conf['_database'] ) ){
555  throw new Exception('Error loading config file. No database specified.', E_USER_ERROR);
556 
557  }
558  $dbinfo =& $conf['_database'];
559  if ( !is_array( $dbinfo ) || !isset($dbinfo['host']) || !isset( $dbinfo['user'] ) || !isset( $dbinfo['password'] ) || !isset( $dbinfo['name'] ) ){
560  throw new Exception('Error loading config file. The database information was not entered correctly.<br>
561  Please enter the database information int its own section of the config file as follows:<br>
562  <pre>
563  [_database]
564  host = localhost
565  user = foo
566  password = bar
567  name = database_name
568  </pre>', E_USER_ERROR);
569 
570  }
571  if ( @$dbinfo['persistent'] ){
572  $this->_db = mysql_pconnect( $dbinfo['host'], $dbinfo['user'], $dbinfo['password'] );
573  } else {
574  $this->_db = mysql_connect( $dbinfo['host'], $dbinfo['user'], $dbinfo['password'] );
575  }
576  if ( !$this->_db ){
577  throw new Exception('Error connecting to the database: '.mysql_error());
578 
579  }
580  $this->mysqlVersion = mysql_get_server_info($this->_db);
581  mysql_select_db( $dbinfo['name'] ) or die("Could not select DB: ".mysql_error($this->_db));
582  }
583  if ( !defined( 'DATAFACE_DB_HANDLE') ) define('DATAFACE_DB_HANDLE', $this->_db);
584 
585 
586  if ( !is_array( $conf['_tables'] ) ){
587  throw new Exception("<pre>
588  Error reading table information from the config file. Please enter the table information in its own section
589  of the ini file as follows:
590  [_tables]
591  table1 = Table 1 Label
592  table2 = Table 2 Label
593  </pre>");
594 
595  }
596 
597  $this->_tables = $conf['_tables'];
598 
599 
600 
601  if ( count($this->_tables) <= 10 ){
602  $this->prefs['horizontal_tables_menu'] = 1;
603  }
604 
605  // We will register a _cleanup method to run after code execution is complete.
606  register_shutdown_function(array(&$this, '_cleanup'));
607 
608  // Set up memcache if it is installed.
609  if ( DATAFACE_EXTENSION_LOADED_MEMCACHE ){
610  if ( isset($conf['_memcache']) ){
611  if ( !isset($conf['_memcache']['host']) ){
612  $conf['_memcache']['host'] = 'localhost';
613  }
614  if ( !isset($conf['_memcache']['port']) ){
615  $conf['_memcache']['port'] = 11211;
616  }
617  $this->memcache = new Memcache;
618  $this->memcache->connect($conf['_memcache']['host'], $conf['_memcache']['port']) or die ("Could not connect to memcache on port 11211");
619 
620  }
621  }
622 
623  //
624  // -------- Set up the CONF array ------------------------
625  $this->_conf = $conf;
626 
627  if ( !isset($this->_conf['_disallowed_tables']) ){
628  $this->_conf['_disallowed_tables'] = array();
629  }
630 
631  $this->_conf['_disallowed_tables']['history'] = '/__history$/';
632  $this->_conf['_disallowed_tables']['cache'] = '__output_cache';
633  $this->_conf['_disallowed_tables']['dataface'] = '/^dataface__/';
634  if ( !@$this->_conf['_modules'] or !is_array($this->_conf['_modules']) ){
635  $this->_conf['_modules'] = array();
636  }
637 
638  // Include XataJax module always.
639  $mods = array('modules_XataJax'=>'modules/XataJax/XataJax.php');
640  foreach ($this->_conf['_modules'] as $k=>$v){
641  $mods[$k] = $v;
642  }
643  $this->_conf['_modules'] = $mods;
644 
645 
646  if ( isset($this->_conf['_modules']) and count($this->_conf['_modules'])>0 ){
647  import('Dataface/ModuleTool.php');
648  }
649 
650  if ( isset($this->_conf['languages']) ){
651  $this->_conf['language_labels'] = $this->_conf['languages'];
652  foreach ( array_keys($this->_conf['language_labels']) as $lang_code){
653  $this->_conf['languages'][$lang_code] = $lang_code;
654  }
655  }
656 
657  if ( @$this->_conf['support_transactions'] ){
658  // We will support transactions
659  @mysql_query('SET AUTOCOMMIT=0', $this->_db);
660  @mysql_query('START TRANSACTION', $this->_db);
661 
662  }
663  if ( !isset($this->_conf['default_ie']) ) $this->_conf['default_ie'] = 'ISO-8859-1';
664  if ( !isset($this->_conf['default_oe']) ) $this->_conf['default_oe'] = 'ISO-8859-1';
665  if ( isset( $this->_conf['multilingual_content']) || isset($this->_conf['languages']) ){
666  $this->_conf['oe'] = 'UTF-8';
667  $this->_conf['ie'] = 'UTF-8';
668 
669  if (function_exists('mb_substr') ){
670  // The mbstring extension is loaded
671  ini_set('mbstring.internal_encoding', 'UTF-8');
672  //ini_set('mbstring.encoding_translation', 'On');
673  ini_set('mbstring.func_overload', 7);
674 
675  }
676 
677  if ( !isset($this->_conf['languages']) ){
678  $this->_conf['languages'] = array('en'=>'English');
679  }
680  if ( !isset($this->_conf['default_language']) ){
681  if ( count($this->_conf['languages']) > 0 )
682  $this->_conf['default_language'] = reset($this->_conf['languages']);
683 
684  else
685  $this->_conf['default_language'] = 'en';
686 
687  }
688 
689  } else {
690  $this->_conf['oe'] = $this->_conf['default_oe'];
691  $this->_conf['ie'] = $this->_conf['default_ie'];
692  }
693 
694  if ( $this->_conf['oe'] == 'UTF-8' ){
695  $res = mysql_query('set character_set_results = \'utf8\'', $this->_db);
696  mysql_query("SET NAMES utf8", $this->_db);
697  }
698  if ( $this->_conf['ie'] == 'UTF-8' ){
699  $res = mysql_query('set character_set_client = \'utf8\'', $this->_db);
700 
701  }
702 
703 
704  if ( isset($this->_conf['use_cache']) and $this->_conf['use_cache'] and !defined('DATAFACE_USE_CACHE') ){
705  define('DATAFACE_USE_CACHE', true);
706  }
707 
708  if ( isset($this->_conf['debug']) and $this->_conf['debug'] and !defined('DATAFACE_DEBUG') ){
709  define('DATAFACE_DEBUG', true);
710  } else if ( !defined('DATAFACE_DEBUG') ){
711  define('DATAFACE_DEBUG',false);
712  }
713 
714  if ( !@$this->_conf['config_storage'] ) $this->_conf['config_storage'] = DATAFACE_DEFAULT_CONFIG_STORAGE;
715  // Set the storage type for config information. It can either be stored in ini files or
716  // in the database. Database will give better performance, but INI files may be simpler
717  // to manage for simple applications.
718 
719  if ( !isset($this->_conf['garbage_collector_threshold']) ){
725  $this->_conf['garbage_collector_threshold'] = 10*60;
726  }
727 
728  if ( !isset($this->_conf['multilingual_content']) ) $this->_conf['multilingual_content'] = false;
729  // whether or not the application will use multilingual content.
730  // multilingual content enables translated versions of content to be stored in
731  // tables using naming conventions.
732  // Default to false because this takes a performance hit (sql queries take roughly twice
733  // as long because they have to be parsed first.
734 
735  if ( !isset($this->_conf['cookie_prefix']) ) $this->_conf['cookie_prefix'] = 'dataface__';
736 
737  if ( !isset($this->_conf['security_level']) ){
738  // Default security is strict if security is not specified. This change is effectivce
739  // for Dataface 0.6 .. 0.5.3 and earlier had a loose permissions model by default that
740  // could be tightened using delegate classes.
741  $this->_conf['security_level'] = 0; //DATAFACE_STRICT_PERMISSIONS;
742  }
743 
744 
745  if ( !isset($this->_conf['default_action']) ){
746  // The default action defines the action that should be set if no
747  // other action is specified.
748  $this->_conf['default_action'] = 'list';
749  }
750 
751  if ( !isset($this->_conf['default_browse_action']) ){
752  $this->_conf['default_browse_action'] = 'view';
753  }
754 
755 
756  if ( !isset($this->_conf['default_mode'] ) ) $this->_conf['default_mode'] = 'list';
757 
758  if ( !isset($this->_conf['default_limit']) ){
759  $this->_conf['default_limit'] = 30;
760  }
761 
762  if ( !isset($this->_conf['default_table'] ) ){
763  // The default table is the table that is used if no other table is specified.
764  foreach ($this->_tables as $key=>$value){
765  $this->_conf['default_table'] = $key;
766 
767  break;
768  }
769  }
770 
771  if ( !isset($this->_conf['auto_load_results']) ) $this->_conf['auto_load_results'] = false;
772 
773  if ( !isset( $this->_conf['cache_dir'] ) ){
774  if ( ini_get('upload_tmp_dir') ) $this->_conf['cache_dir'] = ini_get('upload_tmp_dir');
775  else $this->_conf['cache_dir'] = '/tmp';
776  }
777 
778  if ( !isset( $this->_conf['default_table_role'] ) ){
779 
780  if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){
781  $this->_conf['default_table_role'] = 'NO ACCESS';
782  } else {
783  $this->_conf['default_table_role'] = 'ADMIN';
784  }
785 
786  }
787 
788  if ( !isset( $this->_conf['default_field_role'] ) ){
789  if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){
790  $this->_conf['default_field_role'] = 'NO ACCESS';
791  } else {
792  $this->_conf['default_field_role'] = 'ADMIN';
793 
794  }
795  }
796 
797  if ( !isset( $this->_conf['default_relationship_role'] ) ){
798  if ( $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){
799  $this->_conf['default_relationship_role'] = 'READ ONLY';
800  } else {
801  $this->_conf['default_relationship_role'] = 'ADMIN';
802 
803  }
804  }
805 
806  if ( !isset( $this->_conf['languages'] ) ) $this->_conf['languages'] = array('en');
807  else if ( !is_array($this->_conf['languages']) ) $this->_conf['languages'] = array($this->_conf['languages']);
808 
809  if ( isset($this->_conf['_language_codes']) ){
810  $this->_languages = array_merge($this->_languages, $this->_conf['_language_codes']);
811  }
812  if ( isset($this->_conf['_locales']) ){
813  $this->_locales = array_merge($this->_locales, $this->_conf['_locales']);
814  }
815 
816  // Set the language.
817  // Language is stored in a cookie. It can be changed by passing the -lang GET var with the value
818  // of a language. e.g. fr, en, cn
819  if ( !isset( $this->_conf['default_language'] ) ) $this->_conf['default_language'] = 'en';
820  $prefix = $this->_conf['cookie_prefix'];
821  //print_r($_COOKIE);
822  if ( isset($_REQUEST['--lang']) ){
823  $_REQUEST['--lang'] = basename($_REQUEST['--lang']);
824  $this->_conf['lang'] = $_REQUEST['--lang'];
825  } else if ( isset( $_REQUEST['-lang'] ) ){
826  $_REQUEST['-lang'] = basename($_REQUEST['-lang']);
827  $this->_conf['lang'] = $_REQUEST['-lang'];
828  if ( @$_COOKIE[$prefix.'lang'] !== $_REQUEST['-lang'] ){
829  setcookie($prefix.'lang', $_REQUEST['-lang'], null, '/');
830  }
831  } else if (isset( $_COOKIE[$prefix.'lang']) ){
832  $this->_conf['lang'] = $_COOKIE[$prefix.'lang'];
833  } else {
834  import('I18Nv2/I18Nv2.php');
835  $negotiator = I18Nv2::createNegotiator($this->_conf['default_language'], 'UTF-8');
836  $this->_conf['lang'] = $this->getLanguageCode(
837  $negotiator->getLocaleMatch(
838  $this->getAvailableLanguages()
839  )
840  );
841  setcookie($prefix.'lang', $this->_conf['lang'], null, '/');
842  }
843 
844  $this->_conf['lang'] = basename($this->_conf['lang']);
845 
846 
847  // Set the mode (edit or view)
848  if ( isset($_REQUEST['-usage_mode'] )){
849  $this->_conf['usage_mode'] = $_REQUEST['-usage_mode'];
850  if (@$_COOKIE[$prefix.'usage_mode'] !== $_REQUEST['-usage_mode']){
851  setcookie($prefix.'usage_mode', $_REQUEST['-usage_mode'], null, '/');
852  }
853  } else if ( isset( $_COOKIE[$prefix.'usage_mode'] ) ){
854  $this->_conf['usage_mode'] = $_COOKIE[$prefix.'usage_mode'];
855  } else if ( !isset($this->_conf['usage_mode']) ){
856  $this->_conf['usage_mode'] = 'view';
857  }
858 
859  define('DATAFACE_USAGE_MODE', $this->_conf['usage_mode']);
860 
861  if ( @$this->_conf['enable_workflow'] ){
862  import('Dataface/WorkflowTool.php');
863  }
864 
865 
866 
867 
868  // ------- Set up the current query ---------------------------------
869 
870  if ( isset($_REQUEST['__keys__']) and is_array($_REQUEST['__keys__']) ){
871  $query = $_REQUEST['__keys__'];
872  foreach ( array_keys($_REQUEST) as $key ){
873  if ( $key{0} == '-' and !in_array($key, array('-search','-cursor','-skip','-limit'))){
874  $query[$key] = $_REQUEST[$key];
875  }
876  }
877  } else {
878  $query = array_merge($_GET, $_POST);
879  }
880  if ( @$query['-action'] ){
881  $query['-action'] = trim($query['-action']);
882  if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-action']) ){
883  throw new Exception("Illegal action name.");
884  }
885  $query['-action'] = basename($query['-action']);
886  }
887  if ( @$query['-table'] ){
888  $query['-table'] = trim($query['-table']);
889  if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-table']) ){
890  throw new Exception("Illegal table name.");
891  }
892  $query['-table'] = basename($query['-table']);
893  }
894  if ( @$query['-lang'] ){
895  $query['-lang'] = trim($query['-lang']);
896  if ( !preg_match('/^[a-zA-Z0-9]{2}$/', $query['-lang']) ){
897  throw new Exception("Illegal language code: ".$query['-lang']);
898  }
899  $query['-lang'] = basename($query['-lang']);
900  }
901 
902  if ( @$query['--lang'] ){
903  $query['--lang'] = trim($query['--lang']);
904  if ( !preg_match('/^[a-zA-Z0-9]{2}$/', $query['--lang']) ){
905  throw new Exception("Illegal language code: ".$query['--lang']);
906  }
907  $query['--lang'] = basename($query['--lang']);
908  }
909 
910  if ( @$query['-theme'] ){
911  $query['-theme'] = trim($query['-theme']);
912  if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-theme']) ){
913  throw new Exception("Illegal theme name.");
914  }
915  $query['-theme'] = basename($query['-theme']);
916  }
917 
918  if ( @$query['-cursor']){
919  $query['-cursor'] = intval($query['-cursor']);
920  }
921  if ( @$query['-limit'] ){
922  $query['-limit'] = intval($query['-limit']);
923  }
924  if ( @$query['-skip'] ){
925  $query['-skip'] = intval($query['-skip']);
926  }
927  if ( @$query['-related-limit'] ){
928  $query['-related-limit'] = intval($query['-related-limit']);
929  }
930  if ( @$query['-relationship'] ){
931  if ( !preg_match('/^[a-zA-Z0-9_]+$/', $query['-relationship']) ){
932  throw new Exception("Illegal relationship name.");
933  }
934  }
935 
936 
937 
938 
939  $this->rawQuery = $query;
940 
941  if ( !isset( $query['-table'] ) ) $query['-table'] = $this->_conf['default_table'];
942  $this->_currentTable = $query['-table'];
943 
944 
945  if ( !@$query['-action'] ) {
946  $query['-action'] = $this->_conf['default_action'];
947  $this->_conf['using_default_action'] = true;
948  }
949 
950  $query['--original_action'] = $query['-action'];
951  if ( $query['-action'] == 'browse') {
952  if ( isset($query['-relationship']) ){
953  $query['-action'] = 'related_records_list';
954  } else if ( isset($query['-new']) and $query['-new']) {
955  $query['-action'] = 'new';
956  } else {
957  $query['-action'] = $this->_conf['default_browse_action']; // for backwards compatibility to 0.5.x
958  }
959  } else if ( $query['-action'] == 'find_list' ){
960  $query['-action'] = 'list';
961  }
962  if ( !isset( $query['-cursor'] ) ) $query['-cursor'] = 0;
963  if ( !isset( $query['-skip'] ) ) $query['-skip'] = 0;
964  if ( !isset( $query['-limit'] ) ) $query['-limit'] = $this->_conf['default_limit'];
965 
966  if ( !isset( $query['-mode'] ) ) $query['-mode'] = $this->_conf['default_mode'];
967  $this->_query =& $query;
968 
969 
970  if ( isset( $query['--msg'] ) ) {
971  $query['--msg'] = preg_replace('#<[^>]*>#','', $query['--msg']);
972  if ( preg_match('/^@@$/', $query['--msg']) ){
973 
974  if ( @$_SESSION['--msg'] ){
975  $this->addMessage(@$_SESSION['--msg']);
976  unset($_SESSION['--msg']);
977  }
978  } else {
979 
980  $this->addMessage($query['--msg']);
981  }
982  }
983 
984 
985 
986 
987  if ( isset($query['--error']) and trim($query['--error']) ){
988  $query['--error'] = preg_replace('#<[^>]*>#','', $query['--error']);
989  $this->addError(PEAR::raiseError($query['--error']));
990  }
991 
992  // Now allow custom setting of theme
993  if ( isset($query['-theme']) ){
994  if ( !isset($this->_conf['_themes']) ) $this->_conf['_themes'] = array();
995  $this->_conf['_themes'][basename($query['-theme'])] = 'themes/'.basename($query['-theme']);
996  }
997 
998  // Check to see if we should set a custom default preview length
999  if ( isset($query['--default-preview-length']) ){
1000  $len = intval($query['--default-preview-length']);
1001  if ( $len > 0 && !defined('XATAFACE_DEFAULT_PREVIEW_LENGTH') ){
1002  define('XATAFACE_DEFAULT_PREVIEW_LENGTH', $len);
1003  }
1004  }
1005 
1006 
1007 
1008  }
1009 
1010 
1029  public static function &getInstance($conf=null){
1030  static $instance = array();
1031  //static $blobRequestCount = 0;
1032  if ( !isset( $instance[0] ) ){
1033  $instance[0] = new Dataface_Application($conf);
1034  if ( !defined('DATAFACE_APPLICATION_LOADED') ){
1035  define('DATAFACE_APPLICATION_LOADED', true);
1036  }
1037  }
1038 
1039  return $instance[0];
1040  }
1041 
1042 
1043 
1055  function &conf(){
1056  static $loaded = false;
1057  if ( !$loaded ){
1058  $loaded = true;
1059  $del = $this->getDelegate();
1060  if ( isset($del) and method_exists($del,'conf') ){
1061  $conf = $del->conf();
1062  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);
1063  foreach ( $conf as $key=>$val){
1064  if ( isset($this->_conf[$key]) ){
1065  if ( is_array($this->_conf[$key]) and is_array($val) ){
1066  $this->_conf[$key] = array_merge($this->_conf[$key], $val);
1067  } else {
1068  $this->_conf[$key] = $val;
1069  }
1070  } else {
1071  $this->_conf[$key] = $val;
1072  }
1073  }
1074 
1075  }
1076 
1077  }
1078  return $this->_conf;
1079 
1080  }
1081 
1082 
1088  if ( !isset($this->mysqlVersion) ){
1089  $this->mysqlVersion = mysql_get_server_info($this->_db);
1090  }
1091  list($mv) = explode('.',$this->mysqlVersion);
1092  return intval($mv);
1093  }
1094 
1095  function getPageTitle(){
1096  if ( isset($this->pageTitle) ){
1097  return $this->pageTitle;
1098  } else {
1099  return $this->getSiteTitle();
1100  }
1101  }
1102 
1103  function setPageTitle($title){
1104  $this->pageTitle = $title;
1105  }
1106 
1107 
1117  function getSiteTitle(){
1118  $query =& $this->getQuery();
1119  $title = 'Dataface Application';
1120 
1121  if ( isset($this->_conf['title']) ) {
1122  try {
1123  $title = $this->parseString($this->_conf['title']);
1124  } catch (Exception $ex){
1125  $title = $this->_conf['title'];
1126  }
1127  }
1128  if ( ($record = $this->getRecord()) && $query['-mode'] == 'browse' ){
1129  return $record->getTitle().' - '.$title;
1130  } else {
1131  $tableLabel = Dataface_Table::loadTable($query['-table'])->getLabel();
1132  return $tableLabel.' - '.$title;
1133 
1134  }
1135 
1136  }
1137 
1138 
1139  // @}
1140  // END CONFIGURATION
1141 
1142 
1143  // @{
1166  function &getQuery(){
1167  return $this->_query;
1168  }
1169 
1193  function &getQueryParam($key){
1194  if ( isset( $this->_query['-'.$key] ) ){
1195  return $this->_query['-'.$key];
1196  } else {
1197  $null = null;
1198  return $null;
1199  }
1200  }
1201 
1206  function &getResultSet(){
1207  if ( $this->queryTool === null ){
1208  import('Dataface/QueryTool.php');
1209  $this->queryTool = Dataface_QueryTool::loadResult($this->_query['-table'], $this->db(), $this->_query);
1210  }
1211  return $this->queryTool;
1212 
1213  }
1214 
1259  function &getRecord(){
1260  $null = null;
1261  if ( $this->currentRecord === null ){
1262  $query =& $this->getQuery();
1263  if ( @$query['--no-query'] ){
1264  $null = null;
1265  return $null;
1266  }
1267  $q=array();
1268  if ( isset($_REQUEST['__keys__']) and is_array($_REQUEST['__keys__']) ){
1269  foreach ($_REQUEST['__keys__'] as $key=>$val) $q[$key] = '='.$val;
1270  $this->currentRecord = df_get_record($query['-table'], $q);
1271  } else if ( isset($_REQUEST['-__keys__']) and is_array($_REQUEST['-__keys__']) ){
1272  foreach ($_REQUEST['-__keys__'] as $key=>$val) $q[$key] = '='.$val;
1273  $this->currentRecord = df_get_record($query['-table'], $q);
1274  } else if ( isset($_REQUEST['--__keys__']) and is_array($_REQUEST['--__keys__']) ){
1275  foreach ($_REQUEST['--__keys__'] as $key=>$val) $q[$key] = '='.$val;
1276  $this->currentRecord = df_get_record($query['-table'], $q);
1277  } else if ( isset($_REQUEST['--recordid']) ){
1278  $this->currentRecord = df_get_record_by_id($_REQUEST['--recordid']);
1279  } else if ( isset($_REQUEST['-recordid']) ){
1280  $this->currentRecord = df_get_record_by_id($_REQUEST['-recordid']);
1281  } else {
1282  $rs = $this->getResultSet();
1283  $this->currentRecord = $rs->loadCurrent();
1284  }
1285  if ( $this->currentRecord === null ) $this->currentRecord = -1;
1286  }
1287  if ( $this->currentRecord === -1 || !$this->currentRecord ) return $null;
1288  return $this->currentRecord;
1289  }
1290 
1302  function getRecordContext($id=null){
1303  if ( !isset($this->recordContext) ){
1304  $this->recordContext = array();
1305  $query = $this->getQuery();
1306  if ( @$query['-portal-context'] ){
1307  $rrec = df_get_record_by_id($query['-portal-context']);
1308  if ( PEAR::isError($rrec) ){
1309  $rrec = null;
1310  }
1311  if ( is_a($rrec, 'Dataface_RelatedRecord') ){
1312  $destRecords = $rrec->toRecords();
1313  foreach ($destRecords as $destRec){
1314  $this->recordContext[$destRec->getId()] = $rrec;
1315  }
1316  }
1317 
1318  }
1319  }
1320  if ( !isset($id) ){
1321  foreach ($this->recordContext as $rrec) return $rrec;
1322  } else {
1323  return @$this->recordContext[$id];
1324  }
1325  }
1326 
1340  $this->getRecordContext();
1341  $destRecords = $rec->toRecords();
1342  foreach ($destRecords as $destRec){
1343  $this->recordContext[$destRec->getId()] = $rec;
1344  }
1346  }
1347 
1348 
1360  $this->recordContext = array();
1361  $contextMasks =& Dataface_PermissionsTool::getInstance()->getContextMasks();
1362  foreach ($contextMasks as $k=>$v){
1363  unset($contextMasks[$k]);
1364  }
1365  }
1366 
1374  function recordLoaded(){
1375  return ( $this->currentRecord !== null);
1376  }
1377 
1378 
1385  function &getAction(){
1386  import('Dataface/ActionTool.php');
1387  $actionTool = Dataface_ActionTool::getInstance();
1388  return $actionTool->getAction(array('name'=>$this->_query['-action']));
1389  }
1390 
1429  function getSearchTarget(array $action=null){
1430  if ( !isset($action) ){
1431  $action = $this->getAction();
1432 
1433  if ( !isset($action) or !is_array($action)){
1434  if ( @$this->_conf['default_search_target'] ) return $this->_conf['default_search_target'];
1435  else return 'list';
1436  } else {
1437  return $this->getSearchTarget($action);
1438  }
1439  } else {
1440 
1441  $table = Dataface_Table::loadTable($this->_query['-table']);
1442  $tableDel = $table->getDelegate();
1443  $method = 'getSearchTarget';
1444  if ( isset($tableDel) and method_exists($tableDel, $method) ){
1445  return $tableDel->$method($action);
1446  }
1447 
1448  $appDel = $this->getDelegate();
1449  if ( isset($appDel) and method_exists($appDel, $method) ){
1450  return $appDel->$method($action);
1451  }
1452 
1453 
1454  if ( @$action['search_target'] ){
1455  return $action['search_target'];
1456  } else {
1457  if ( @$this->_conf['default_search_target'] ) return $this->_conf['default_search_target'];
1458  else return 'list';
1459  }
1460 
1461  }
1462 
1463  }
1464 
1465  // @}
1466  // END Request Context
1467 
1468  // @{
1491  function saveMessage($str){
1492  $_SESSION['--msg'] = $str;
1493  }
1494 
1504  function enableSessions(){
1505  setcookie($this->sessionCookieKey, 1, 0, DATAFACE_SITE_URL);
1506  }
1507 
1517  function disableSessions(){
1518  setcookie($this->sessionCookieKey, 1, time()-3600*25, DATAFACE_SITE_URL);
1519  }
1520 
1529  function sessionEnabled(){
1530  return @$_COOKIE[$this->sessionCookieKey];
1531  }
1532 
1544  function startSession($conf=null){
1545  if ( defined('XATAFACE_NO_SESSION') and XATAFACE_NO_SESSION ) return;
1546  //echo "In startSession()";
1547  if ( !$this->sessionEnabled() ){
1548  $this->enableSessions();
1549  }
1550  if ( session_id() == "" ){
1551  if ( !isset($conf) ){
1552  if ( isset($this->_conf['_auth']) ) $conf = $this->_conf['_auth'];
1553  else $conf = array();
1554  }
1555 
1556  $delegate =& $this->getDelegate();
1557  if ( isset($delegate) and method_exists($delegate, 'startSession') ){
1558  $delegate->startSession($conf);
1559  } else {
1560 
1561  // path for cookies
1562  $parts = parse_url(DATAFACE_SITE_URL);
1563  $cookie_path = $parts['path'];
1564  if ( isset($conf['cookie_path']) ){
1565  $cookie_path = $conf['cookie_path'];
1566  if ( substr($cookie_path,0,4) == 'php:' ){
1567  $cookie_path_expr = substr($cookie_path,4);
1568  eval('$cookie_path = '.$cookie_path_expr.';');
1569  }
1570  }
1571 
1572  if (strlen($cookie_path)==0) $cookie_path = '/';
1573  if ( $cookie_path{strlen($cookie_path)-1} != '/' ) $cookie_path .= '/';
1574 
1575  // timeout value for the cookie
1576  $cookie_timeout = (isset($conf['session_timeout']) ? intval($conf['session_timeout']) : 24*60*60);
1577 
1578 
1579  // timeout value for the garbage collector
1580  // we add 300 seconds, just in case the user's computer clock
1581  // was synchronized meanwhile; 600 secs (10 minutes) should be
1582  // enough - just to ensure there is session data until the
1583  // cookie expires
1584  $garbage_timeout = $cookie_timeout + 600; // in seconds
1585 
1586  // set the PHP session id (PHPSESSID) cookie to a custom value
1587  session_set_cookie_params($cookie_timeout, $cookie_path);
1588 
1589  // set the garbage collector - who will clean the session files -
1590  // to our custom timeout
1591  ini_set('session.gc_maxlifetime', $garbage_timeout);
1592  if ( isset($conf['session_timeout']) and ini_get('session.save_handler') == 'files' ){
1593  // we need a distinct directory for the session files,
1594  // otherwise another garbage collector with a lower gc_maxlifetime
1595  // will clean our files aswell - but in an own directory, we only
1596  // clean sessions with our "own" garbage collector (which has a
1597  // custom timeout/maxlifetime set each time one of our scripts is
1598  // executed)
1599  strstr(strtoupper(substr(@$_SERVER["OS"], 0, 3)), "WIN") ?
1600  $sep = "\\" : $sep = "/";
1601  $sessdir = session_save_path(); //ini_get('session.save_path');
1602  $levels = '';
1603  if (strpos($sessdir, ";") !== FALSE){
1604  $levels = substr($sessdir, 0, strpos($sessdir, ";")).';';
1605  $sessdir = substr($sessdir, strpos($sessdir, ";")+1);
1606  }
1607  if ( !$sessdir ) $sessdir = sys_get_temp_dir(); //'/tmp';
1608  if ( $sessdir and $sessdir{strlen($sessdir)-1} == '/' ) $sessdir = substr($sessdir,0, strlen($sessdir)-1);
1609 
1610  if ( @$conf['subdir'] ) $subdir = $conf['subdir'];
1611  else $subdir = md5(DATAFACE_SITE_PATH);
1612  if ( !$subdir ) $subdir = 'dataface';
1613  $sessdir .= "/".$subdir;
1614 
1615 
1616  if (!is_dir($sessdir)) {
1617  $res = @mkdir($sessdir, 0777);
1618  if ( !$res ){
1619  error_log("Failed to create session directory '$sessdir' to store session files in ".__FILE__." on line ".__LINE__);
1620 
1621  }
1622  }
1623  if (is_dir($sessdir) ){
1624  session_save_path($sessdir);
1625  } else {
1626  }
1627  } else {
1628  // We need to set a unique session name if we're not changing the directory
1629  if ( !@$conf['session_name'] ){
1630  $conf['session_name'] = md5(DATAFACE_SITE_PATH);
1631  }
1632  }
1633  if ( @$conf['session_name'] ) session_name($conf['session_name']);
1634  //echo "Starting session with ".session_name();
1635  session_start(); // start the session
1636  header('P3P: CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"');
1637 
1638  // This updates the session timeout on page load
1639  if ( isset($_COOKIE[session_name()]) ){
1640  setcookie(session_name(), $_COOKIE[session_name()], time() + $cookie_timeout, $cookie_path);
1641  }
1642  }
1643  } else {
1644  //echo "Session already started";
1645  }
1646 
1647  if ( isset( $_SESSION['--msg'] ) ){
1648  $this->addMessage($_SESSION['--msg']);
1649  unset($_SESSION['--msg']);
1650  }
1651 
1652 
1653  }
1654 
1658  function writeSessionData(){
1659 
1660  if ( isset($this->locations) ) $_SESSION['locations'] = serialize($this->locations);
1661  }
1662 
1666  function encodeLocation($url){
1667  if ( !isset($this->locations) and isset($_SESSION['locations']) ) $this->locations = unserialize($_SESSION['locations']);
1668  else if ( !isset($this->locations) ) $this->locations = array();
1669  $key = md5($url);
1670  $this->locations[$key] = $url;
1671  return $key;
1672  }
1673 
1677  function decodeLocation($key){
1678  if ( !isset($this->locations) and isset($_SESSION['locations']) ) $this->locations = unserialize($_SESSION['locations']);
1679  else if ( !isset($this->locations) ) $this->locations = array();
1680 
1681  if ( isset($this->locations[$key]) ){
1682  $url = $this->locations[$key];
1683  unset($this->locations[$key]);
1684  return $url;
1685 
1686  } else {
1687  return null;
1688  }
1689 
1690  }
1691 
1692 
1700  $null = null;
1701  if ( !isset($this->authenticationTool) ){
1702 
1703  if ( isset($this->_conf['_auth']) ){
1704  import('Dataface/AuthenticationTool.php');
1705  $this->authenticationTool = Dataface_AuthenticationTool::getInstance($this->_conf['_auth']);
1706  } else {
1707  return $null;
1708  }
1709  }
1710 
1711  return $this->authenticationTool;
1712  }
1713 
1714 
1715 
1716 
1717 
1718  // @}
1719  // END Session Handling
1720  //=====================================================================================================
1721 
1722  // @{
1752  function addHeadContent($content){
1753  $this->headContent[] = $content;
1754  }
1755 
1756 
1777  function getNavItem($key, $label=null){
1778  $del =& $this->getDelegate();
1779  $override = array();
1780  if ( isset($del) and method_exists($del, 'getNavItem') ){
1781  try {
1782  $override = $del->getNavItem($key, $label?$label:$key);
1783  } catch (Exception $ex){}
1784  }
1785  if ( !isset($override) ){
1786  return $override;
1787  }
1788  return array_merge(array(
1789  'href'=> DATAFACE_SITE_HREF.'?-table='.urlencode($key),
1790  'label'=> $label ? $label:$key,
1791  'selected' => $this->isNavItemSelected($key)
1792  ), $override);
1793  }
1794 
1795 
1811  function isNavItemSelected($key){
1812  $del =& $this->getDelegate();
1813  if ( isset($del) and method_exists($del, 'isNavItemSelected') ){
1814  try {
1815  return $del->isNavItemSelected($key);
1816  } catch (Exception $ex){}
1817  }
1818  $query =& $this->getQuery();
1819  return ($query['-table'] == $key);
1820  }
1821 
1822 
1823 
1834  function addError($err){
1835  $this->errors[] = $err;
1836  }
1837 
1846  function numErrors(){ return count($this->errors); }
1847 
1855  function getErrors(){
1856  return $this->errors;
1857  }
1858 
1867  function addMessage($msg){
1868  $this->messages[] = $msg;
1869  }
1870 
1882  function getMessages(){
1883  if ( trim(@$_SESSION['msg']) ){
1884  array_push($this->messages, $_SESSION['msg']);
1885  unset($_SESSION['msg']);
1886  }
1887  $msgs = $this->messages;
1888  $response = $this->getResponse();
1889  if ( @$response['--msg'] ){
1890  array_push($msgs, $response['--msg']);
1891  }
1892  //print_r($msgs);
1893  return $msgs;
1894  }
1895 
1900  function clearMessages(){
1901  $this->messages = array();
1902  }
1903 
1908  function numMessages(){
1909  $count = count($this->messages);
1910  $response = $this->getResponse();
1911  if ( @$response['--msg'] ) $count++;
1912  return $count;
1913  }
1914 
1915 
1926  public static function &getResponse(){
1927  static $response = 0;
1928  if ( !$response ){
1929  $response = array('--msg'=>'');
1930  }
1931  return $response;
1932  }
1933 
1934 
1935  // @}
1936  // END Template & UI Interaction
1937  //====================================================================================
1938 
1939  // {@
1957  function fireEvent($name, $params=null){
1958  $listeners = $this->getEventListeners($name);
1959  foreach ($listeners as $listener){
1960  $res = call_user_func($listener, $params);
1961  if ( PEAR::isError($res) ) return $res;
1962  }
1963  return true;
1964  }
1965 
1976  function registerEventListener($name, $callback){
1977  if ( !isset($this->eventListeners[$name]) ) $this->eventListeners[$name] = array();
1978  $this->eventListeners[$name][] = $callback;
1979  }
1980 
1981 
1988  function unregisterEventListener($name, $callback){
1989  if ( isset($this->eventListeners[$name]) ){
1990  $listeners =& $this->eventListeners[$name];
1991  foreach ( $listeners as $key=>$listener ){
1992  if ( $listener == $callback ) unset($listeners[$key]);
1993  }
1994  }
1995  }
1996 
2002  function getEventListeners($name=null){
2003  if ( !isset($name) ) return $this->eventListeners;
2004  else if (isset($this->eventListeners[$name])){
2005  return $this->eventListeners[$name];
2006  } else {
2007  return array();
2008  }
2009  }
2010 
2011 
2012 
2013  // @}
2014  // END Event Handling
2015  //=====================================================================================
2016 
2017 
2018 
2019  // @{
2052  function handleRequest($disableCache=false){
2053 
2054 
2055  if ( !$disableCache and (@$_GET['-action'] != 'getBlob') and isset( $this->_conf['_output_cache'] ) and @$this->_conf['_output_cache']['enabled'] and count($_POST) == 0){
2056  import('Dataface/OutputCache.php');
2057  $oc = new Dataface_OutputCache($this->_conf['_output_cache']);
2058  $oc->ob_start();
2059 
2060  }
2061  import('Dataface/ActionTool.php');
2062  import('Dataface/PermissionsTool.php');
2063  import('Dataface/Table.php');
2064 
2065  if ( isset($this->_conf['_modules']) and count($this->_conf['_modules']) > 0 ){
2067  foreach ($this->_conf['_modules'] as $modname=>$modpath){
2068  $mt->loadModule($modname);
2069 
2070  }
2071  }
2072 
2073  $this->fireEvent('beforeHandleRequest');
2074  $applicationDelegate = $this->getDelegate();
2075  if ( isset($applicationDelegate) and method_exists($applicationDelegate, 'beforeHandleRequest') ){
2076  // Do whatever we need to do before the request is handled.
2077  $applicationDelegate->beforeHandleRequest();
2078  }
2079 
2080  // Set up security filters
2081  $query =& $this->getQuery();
2082  $table = Dataface_Table::loadTable($query['-table']);
2083 
2084  //$table->setSecurityFilter();
2085  /*
2086  * Set up some preferences for the display of the application.
2087  * These can be overridden by the getPreferences() method in the
2088  * application delegate class.
2089  */
2090  if ( isset($this->_conf['_prefs']) and is_array($this->_conf['_prefs']) ){
2091  $this->prefs = array_merge($this->prefs,$this->_conf['_prefs']);
2092  }
2093  if ( @$this->_conf['hide_nav_menu'] ){
2094  $this->prefs['show_tables_menu'] = 0;
2095  }
2096 
2097  if ( @$this->_conf['hide_view_tabs'] ){
2098  $this->prefs['show_table_tabs'] = 0;
2099  }
2100 
2101  if ( @$this->_conf['hide_result_controller'] ){
2102  $this->prefs['show_result_controller'] = 0;
2103  }
2104 
2105  if ( @$this->_conf['hide_table_result_stats'] ){
2106  $this->prefs['show_result_stats'] = 0;
2107  }
2108 
2109  if ( @$this->_conf['hide_search'] ){
2110  $this->prefs['show_search'] = 0;
2111  }
2112 
2113  if ( !isset($this->prefs['disable_ajax_record_details']) ){
2114  $this->prefs['disable_ajax_record_details'] = 1;
2115  }
2116 
2117  if ( $query['-action'] == 'login_prompt' ) $this->prefs['no_history'] = 1;
2118 
2119 
2120  if ( isset($applicationDelegate) and method_exists($applicationDelegate, 'getPreferences') ){
2121  $this->prefs = array_merge($this->prefs, $applicationDelegate->getPreferences());
2122  }
2123  $this->prefs = array_map('intval', $this->prefs);
2124 
2125  // Check to make sure that this table hasn't been disallowed
2126  $disallowed = false;
2127  if ( isset($this->_conf['_disallowed_tables']) ){
2128  foreach ( $this->_conf['_disallowed_tables'] as $name=>$pattern ){
2129  if ( $pattern{0} == '/' and preg_match($pattern, $query['-table']) ){
2130  $disallowed = true;
2131  break;
2132  } else if ( $pattern == $query['-table'] ){
2133  $disallowed = true;
2134  break;
2135  }
2136  }
2137  }
2138 
2139  if ( $disallowed and isset($this->_conf['_allowed_tables']) ){
2140  foreach ($this->_conf['_allowed_tables'] as $name=>$pattern ){
2141  if ( $pattern{0} == '/' and preg_match($pattern, $query['-table']) ){
2142  $disallowed = false;
2143  break;
2144  } else if ( $pattern == $query['-table'] ){
2145  $disallowed = false;
2146  break;
2147  }
2148  }
2149  }
2150 
2151 
2152  if ( $disallowed ){
2155  /*i18n id*/
2156  "Permission Denied. This table has been disallowed in the conf.ini file",
2157  /* default error message */
2158  "Permission denied because this table has been disallowed in the conf.ini file '"
2159  )
2160  );
2161 
2162  }
2163 
2164 
2165  $actionTool = Dataface_ActionTool::getInstance();
2166 
2167  //if ( $this->_conf['multilingual_content'] ){
2168  //import('I18Nv2/I18Nv2.php');
2169  //I18Nv2::autoConv();
2170  //}
2171 
2172  $params = array(
2173  'table'=>$query['-table'],
2174  'name'=>$query['-action']);
2175  if ( strpos($query['-action'], 'custom_') === 0 ){
2176  $action = array(
2177  'name' => $query['-action'],
2178  'page' => substr($query['-action'], 7),
2179  'permission' => 'view',
2180  'mode' => 'browse',
2181  'custom' => true
2182  );
2183  } else {
2184  $action = $actionTool->getAction($params);
2185  if ( is_array($action) and @$action['related'] and @$query['-relationship'] and preg_match('/relationships\.ini/', @$action['allow_override']) ){
2186  // This action is to be performed on the currently selected relationship.
2187  $raction = $table->getRelationshipsAsActions(array(), $query['-relationship']);
2188  if ( is_array($raction) ){
2189  $action = array_merge($action,$raction);
2190  }
2191  }
2192  if ( is_array($action) and isset($action['delegate']) ){
2193  $params['name'] = $query['-action'] = $action['delegate'];
2194  $tmp = $actionTool->getActions($params);
2195  unset($action);
2196  $action =& $tmp;
2197  unset($tmp);
2198  }
2199  if ( is_array($action) and isset($action['auth_type']) ){
2200  $authTool = $this->getAuthenticationTool();
2201  $authTool->setAuthType($action['auth_type']);
2202  }
2203 
2204  }
2205 
2206 
2207  if ( (PEAR::isError($action) or !@$action['permission']) and $this->_conf['security_level'] >= DATAFACE_STRICT_PERMISSIONS ){
2208  // The only reason getAction() will return an error is if the specified action could not be found.
2209  // If the application is set to use strict permissions and no action was defined in the ini file
2210  // then this action cannot be performed. Strict permissions mode requires that permissions be
2211  // strictly set or permission will be denied.
2214  /*i18n id*/
2215  "Permission Denied. No action found in strict permissions mode",
2216  /* default error message */
2217  "Permission denied for action '".
2218  $query['-action'].
2219  "'. No entry for this action was found in the actions.ini file.
2220  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.",
2221  /* i18n parameters */
2222  array('action'=>$query['-action'])
2223  )
2224  );
2225 
2226  }
2227 
2228  else if ( PEAR::isError($action) ){
2229  $action = array('name'=>$query['-action'], 'label'=>$query['-action']);
2230  }
2231 
2232  // Step 1: See if the delegate class has a handler.
2233 
2234  $delegate = $table->getDelegate();
2235  $handled = false;
2236  if ( method_exists($delegate,'handleRequest') ){
2237  $result = $delegate->handleRequest();
2238  if ( PEAR::isError($result) and $result->getCode() === DATAFACE_E_REQUEST_NOT_HANDLED ){
2239  $handled = false;
2240  } else if ( PEAR::isError($result) ){
2241  return $result;
2242  } else {
2243  $handled = true;
2244  }
2245  }
2246  if ( isset($action['mode']) and $action['mode'] ) $query['-mode'] = $action['mode'];
2247 
2248  // Step 2: Look to see if there is a handler defined
2249  if ( isset($action['custom']) ){
2250  $locations = array( DATAFACE_PATH.'/actions/custom.php'=>'dataface_actions_custom');
2251  } else {
2252  $locations = array();
2253 
2254  $locations[ Dataface_Table::getBasePath($query['-table']).'/tables/'.basename($query['-table']).'/actions/'.basename($query['-action']).'.php' ] = 'tables_'.$query['-table'].'_actions_'.$query['-action'];
2255  $locations[ DATAFACE_SITE_PATH.'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action'];
2256 
2257  if ( isset($this->_conf['_modules']) and count($this->_conf['_modules']) > 0 ){
2259  foreach ($this->_conf['_modules'] as $modname=>$modpath){
2260  $mt->loadModule($modname);
2261  if ( $modpath{0} == '/' )
2262  $locations[ dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action'];
2263  else {
2264  $locations[ DATAFACE_SITE_PATH.'/'.dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action'];
2265  $locations[ DATAFACE_PATH.'/'.dirname($modpath).'/actions/'.basename($query['-action']).'.php' ] = 'actions_'.$query['-action'];
2266  }
2267  }
2268  }
2269 
2270  $locations[ DATAFACE_PATH.'/actions/'.basename($query['-action']).'.php' ] = 'dataface_actions_'.$query['-action'];
2271  $locations[ DATAFACE_PATH.'/actions/default.php' ] = 'dataface_actions_default';
2272 
2273  }
2274  $doParams = array('action'=>&$action);
2275  //parameters to be passed to the do method of the handler
2276 
2277 
2278  foreach ($locations as $handlerPath=>$handlerClassName){
2279  if ( is_readable($handlerPath) ){
2280  import($handlerPath);
2281  $handler = new $handlerClassName;
2282  $params = array();
2283  if ( is_array($action) and @$action['related'] and @$query['-relationship'] ){
2284  $params['relationship'] = $query['-relationship'];
2285  }
2286  if ( !PEAR::isError($action) and method_exists($handler, 'getPermissions') ){
2287  // check the permissions on this action to make sure that we are 'allowed' to perform it
2288  // this method will return an array of Strings that are names of permissions granted to
2289  // the current user.
2290 
2291 
2292  //echo "Checking permissions:";
2293  //print_r($params);
2294  $permissions = $handler->getPermissions($params);
2295  //} else if ( $applicationDelegate !== null and method_exists($applicationDelegate, 'getPermissions') ){
2296  // $permissions =& $applicationDelegate->getPermissions($params);
2297 
2298 
2299 
2300  } else {
2301  //print_r($params);
2302  //print_r($action);
2303  $permissions = $this->getPermissions($params);
2304  }
2305 
2306  if ( isset($action['permission']) && !(isset($permissions[$action['permission']]) and $permissions[$action['permission']]) ){
2309  "Permission Denied for action.", /*i18n id*/
2310  /* Default error message */
2311  "Permission to perform action '".
2312  $action['name'].
2313  "' denied.
2314  Requires permission '".
2315  $action['permission'].
2316  "' but only granted '".
2317  Dataface_PermissionsTool::namesAsString($permissions)."'.",
2318  /* i18n parameters */
2319  array('action'=>$action, 'permissions_granted'=>Dataface_PermissionsTool::namesAsString($permissions))
2320  )
2321  );
2322 
2323  }
2324 
2325  if ( method_exists($handler, 'handle') ){
2326 
2327 
2328  $result = $handler->handle($doParams);
2329  if ( PEAR::isError($result) and $result->getCode() === DATAFACE_E_REQUEST_NOT_HANDLED ){
2330  continue;
2331  }
2332  return $result;
2333  }
2334 
2335 
2336  }
2337 
2338  }
2339 
2340  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);
2341 
2342 
2343 
2344 
2345  }
2346 
2347 
2348 
2362  function display($main_content_only=false, $disableCache=false){
2363  // ---------------- Set the Default Character set for output -----------
2364  foreach ($this->_tables as $key=>$value){
2365  $this->_tables[$key] = $this->_conf['_tables'][$key] = df_translate('tables.'.$key.'.label', $value);
2366  }
2367 
2368  $this->main_content_only = $main_content_only;
2369  if ( $this->autoSession or $this->sessionEnabled() ){
2370  $this->startSession();
2371  }
2372  if ( isset($this->_conf['disable_session_ip_check']) and !@$this->_conf['disable_session_ip_check'] ){
2373  if ( !@$_SESSION['XATAFACE_REMOTE_ADDR'] ){
2374  $_SESSION['XATAFACE_REMOTE_ADDR'] = df_IPv4To6($_SERVER['REMOTE_ADDR']);
2375  }
2376  $ipAddressError = null;
2377  if ( df_IPv4To6($_SESSION['XATAFACE_REMOTE_ADDR']) != df_IPv4To6($_SERVER['REMOTE_ADDR']) ){
2378  $msg = sprintf(
2379  "Session address does not match the remote address. Possible hacking attempt. Session address was '%s', User address was '%s'",
2380  htmlspecialchars(df_IPv4To6($_SESSION['XATAFACE_REMOTE_ADDR'])),
2381  htmlspecialchars(df_IPv4To6($_SERVER['REMOTE_ADDR']))
2382  );
2383  error_log($msg);
2384  //die('Your IP address doesn\'t match the session address. To continue, please clear your cookies or restart your browser and try again.');
2385  session_destroy();
2386  $this->startSession();
2387  if ( !@$_SESSION['XATAFACE_REMOTE_ADDR'] ){
2388  $_SESSION['XATAFACE_REMOTE_ADDR'] = df_IPv4To6($_SERVER['REMOTE_ADDR']);
2389  }
2390 
2391  }
2392  }
2393  // handle authentication
2394  if ( !(defined('XATAFACE_DISABLE_AUTH') and XATAFACE_DISABLE_AUTH) and isset($this->_conf['_auth']) ){
2395  // The config file _auth section is there so we will be using authentication.
2396 
2397  $loginPrompt = false; // flag to indicate if we should show the login prompt
2398  $permissionDenied = false;// flag to indicate if we should show permission denied
2399  $permissionError = ''; //Placeholder for permissions error messages
2400  $loginError = ''; // Placeholder for login error messages.
2401 
2402  $authTool = $this->getAuthenticationTool();
2403 
2404  $auth_result = $authTool->authenticate();
2405 
2406  if ( PEAR::isError($auth_result) and $auth_result->getCode() == DATAFACE_E_LOGIN_FAILURE ){
2407  // There was a login failure, show the login prompt
2408  $loginPrompt = true;
2409  $loginError = $auth_result->getMessage();
2410  } else if ( $authTool->isLoggedIn() ){
2411  // The user is logged in ok
2412  // Handle the request
2413  $result = $this->handleRequest();
2415  // Permission was denied on the request. Since the user is already
2416  // logged in, there is no use giving him the login prompt. Just give
2417  // him the permission denied screen.
2418  $permissionDenied = true;
2419  $permissionError = $result->getMessage();
2420  }
2421  } else if ( isset($this->_conf['_auth']['require_login']) and $this->_conf['_auth']['require_login'] ){
2422  // The user is not logged in and login is required for this application
2423  // Show the login prompt
2424  $loginPrompt = true;
2425 
2426  } else {
2427  // The user is not logged in, but login is not required for this application.
2428  // Allow the user to perform the action.
2429 
2430  $result = $this->handleRequest($disableCache);
2432  // The user did not have permission to perform the action
2433  // Give the user a login prompt.
2434 
2435  $loginPrompt = true;
2436  }
2437 
2438  }
2439  if ( $loginPrompt ){
2440  // The user is supposed to see a login prompt to log in.
2441  // Show the login prompt.
2442 
2443  $authTool->showLoginPrompt($loginError);
2444  } else if ($permissionDenied) {
2445  // The user is supposed to see the permissionm denied page.
2446  $query =& $this->getQuery();
2447 
2448  if ( $query['--original_action'] == 'browse' and $query['-action'] != 'view' ){
2449  $this->redirect($this->url('-action=view'));
2450  }
2451  $this->addError($result);
2452  header("HTTP/1.1 403 Permission Denied");
2453  df_display(array(), 'Dataface_Permission_Denied.html');
2454  } else if ( PEAR::isError($result) ){
2455  // Some other error occurred in handling the request. Just show an
2456  // ugly stack trace.
2457 
2458  throw new Exception($result->toString().$result->getDebugInfo(), E_USER_ERROR);
2459  }
2460  } else {
2461  // Authentication is not enabled for this application.
2462  // Just process the request.
2463 
2464  $result = $this->handleRequest($disableCache);
2466  $query =& $this->getQuery();
2467 
2468  if ( $query['--original_action'] == 'browse' and $query['-action'] != 'view' ){
2469  $this->redirect($this->url('-action=view'));
2470  }
2471  $this->addError($result);
2472  header("HTTP/1.1 403 Permission Denied");
2473  df_display(array(), 'Dataface_Permission_Denied.html');
2474  } else if ( PEAR::isError($result) ){
2475 
2476  throw new Exception($result->toString().$result->getDebugInfo(), E_USER_ERROR);
2477  }
2478  }
2479 
2480  }
2481 
2491  function _handleGetBlob($request){
2492  import('Dataface/Application/blob.php');
2494  }
2495 
2496 
2497  // @}
2498  // END Request Handling
2499  //======================================================================================
2500 
2501 
2502  // @{
2578  function parseString($expression, $context=null){
2579  // make sure that the expression doesn't try to break the double quotes.
2580  if ( strpos($expression, '"') !== false ){
2581  throw new Exception(
2582  df_translate(
2583  'scripts.Dataface.Application.parseString.ERROR_PARSING_EXPRESSION_DBL_QUOTE',
2584  "Invalid expression (possible hacking attempt in Dataface_Application::eval(). Expression cannot include double quotes '\"', but recieved '".$expression."'.",
2585  array('expression'=>$expression))
2586  , E_USER_ERROR);
2587  }
2588 
2589  $site_url = DATAFACE_SITE_URL;
2590  $site_href = DATAFACE_SITE_HREF;
2591  $dataface_url = DATAFACE_URL;
2592  $table = $this->_currentTable;
2593  $tableObj = Dataface_Table::loadTable($table);
2594  if ( PEAR::isError($tableObj) ){
2595  throw new Exception($tableObj->getMessage(), $tableObj->getCode());
2596  }
2597  $query =& $this->getQuery();
2598  $app = $this;
2599  $resultSet = $app->getResultSet();
2600  if ( isset($context['record']) ){
2601 
2602  $record = $context['record'];
2603  } else {
2604  $record = $app->getRecord();
2605  }
2606 
2607  if ( isset($context['relationship']) ){
2608  //$tableObj = Dataface_Table::loadTable($table);
2609 
2610  if ( is_string($context['relationship']) ){
2611  $relationship = $tableObj->getRelationship($context['relationship']);
2612  if ( !($relationship instanceof Dataface_Relationship) ){
2613  $relationship = null;
2614  }
2615  } else if ( $context['relationship'] instanceof Dataface_Relationship ){
2616  $relationship = $context['relationship'];
2617  }
2618  //unset($tableObj);
2619  }
2620  if ( !@$app->_conf['debug'] ){
2621  @eval('$parsed = "'.$expression.'";');
2622  } else {
2623  eval('$parsed = "'.$expression.'";');
2624  }
2625 
2626  if ( !isset( $parsed ) ){
2627  throw new Exception(df_translate('scripts.Dataface.Application.parseString.ERROR_PARSING_EXPRESSION',"Error parsing expression '$expression'. ", array('expression'=>$expression)), E_USER_ERROR);
2628  }
2629  return $parsed;
2630 
2631  }
2632 
2633 
2638  function _parsePregMatch($matches){
2639  extract($this->_parseStringContext);
2640  if ( !@$this->_conf['debug'] ){
2641  return @eval('return '.$matches[1].$matches[2].';');
2642  } else {
2643  return eval('return '.$matches[1].$matches[2].';');
2644  }
2645  }
2646 
2647 
2714  function testCondition($condition, $context=null){
2715 
2716  $site_url = DATAFACE_SITE_URL;
2717  $site_href = DATAFACE_SITE_HREF;
2718  $dataface_url = DATAFACE_URL;
2719  $table = $this->_currentTable;
2720  $tableObj = Dataface_Table::loadTable($table);
2721  if ( PEAR::isError($tableObj) ) throw new Exception($tableObj->getMessage(), $tableObj->getCode());
2722  $query =& $this->getQuery();
2723  $app = $this;
2724  $resultSet = $app->getResultSet();
2725  if ( isset($context['record']) ) $record = $context['record'];
2726  else $record = $app->getRecord();
2727 
2728  if ( isset($context['relationship']) ){
2729  //$tableObj =& Dataface_Table::loadTable($table);
2730  if ( is_string($context['relationship']) ){
2731  $relationship = $tableObj->getRelationship($context['relationship']);
2732  if ( !($relationship instanceof Dataface_Relationship) ){
2733  $relationship = null;
2734  }
2735  } else if ( $context['relationship'] instanceof Dataface_Relationship ){
2736  $relationship = $context['relationship'];
2737  }
2738  //unset($tableObj);
2739  }
2740  if ( !@$this->_conf['debug'] ){
2741  return @eval('return ('.$condition.');');
2742  } else {
2743  error_log($condition);
2744  return eval('return ('.$condition.');');
2745  }
2746  }
2747 
2748 
2749 
2776  function url($query, $useContext=true, $forceContext=false){
2777  import('Dataface/LinkTool.php');
2778  return Dataface_LinkTool::buildLInk($query, $useContext, $forceContext);
2779 
2780  }
2781 
2782 
2783 
2784 
2785 
2786 
2787 
2788 
2789 
2790 
2791 
2820  function registerUrlFilter( $filter ){
2821  $this->_url_filters[] = $filter;
2822  }
2823 
2824 
2834  function filterUrl($url){
2835  if ( !preg_match( '/[&\?]-table/i', $url ) ){
2836  if ( preg_match( '/\?/i', $url ) ){
2837  $url .= '&-table='.$this->_currentTable;
2838  } else {
2839  $url .= '?-table='.$this->_currentTable;
2840  }
2841  }
2842 
2843  foreach ($this->_url_filters as $filter){
2844  $url = call_user_func($filter, $url);
2845  }
2846  return $url;
2847 
2848  }
2849 
2850 
2851 
2855  function init(){
2856 
2857  }
2858 
2859 
2872  function redirect($url){
2873  if ( isset($this->redirectHandler) and method_exists('redirect', $this->redirectHandler) ){
2874  $this->redirectHandler->redirect($url);
2876  }
2877  header('Location: '.$url);
2878  exit;
2879 
2880  }
2881 
2882  // @}
2883  // End Utility Functions
2884  //=======================================================================================
2885 
2886 
2887 
2888  // @{
2905  function &getDelegate(){
2906  if ( $this->delegate === -1 ){
2907  $delegate_path = DATAFACE_SITE_PATH.'/conf/ApplicationDelegate.php';
2908  if ( is_readable($delegate_path) ){
2909  import($delegate_path);
2910  $this->delegate = new conf_ApplicationDelegate();
2911  } else {
2912  $this->delegate = null;
2913  }
2914  }
2915  return $this->delegate;
2916 
2917  }
2918 
2919 
2920 
2921 
2922  // END Delegate Class
2923  // @}
2924  //========================================================================================
2925 
2926 
2927  // @{
2953  function getPermissions($params=array()){
2954  $query =& $this->getQuery();
2955  $record = $this->getRecord();
2956  if ( @$query['-relationship'] ){
2957  $params['relationship'] = $query['-relationship'];
2958  }
2959  if ( $record and is_a($record, 'Dataface_Record') ){
2960  //$params = array();
2961  return Dataface_PermissionsTool::getPermissions($record, $params);
2962  } else {
2963  $table = Dataface_Table::loadTable($query['-table']);
2964  //$params = array();
2966  }
2967 
2968  }
2969 
2983  function checkPermission($perm){
2984  $perms = $this->getPermissions();
2985  $result = (isset($perms[$perm]) and $perms[$perm]);
2986  return $result;
2987  }
2988 
2989 
2990 
2991 
2992  // @}
2993  // END Permissions
2994  //=========================================================================================
2995 
2996 
2997 
3010  function refreshSchemas($tablename){
3011  if ( @$this->_conf['metadata_enabled'] ){
3012  $metadataTool = new Dataface_MetadataTool();
3013  $metadataTool->updateWorkflowTable($tablename);
3014  }
3015  }
3016 
3017 
3018 
3019 
3020 
3030  function _parseRelatedBlobRequest($request){
3031  import('Dataface/Application/blob.php');
3033  }
3034 
3035 
3037 
3064  function &getCustomPages(){
3065  if ( !isset( $this->_customPages ) ){
3066  $this->_customPages = array();
3067  $path = DATAFACE_SITE_PATH.'/pages/';
3068  if ( is_dir($path) ){
3069  if ( $dh = opendir($path) ){
3070  while ( ( $file = readdir($dh) ) !== false ){
3071  if ( preg_match('/\.php$/', $file) ){
3072  list($name) = explode('.', $file);
3073  //$name = str_replace('_', ' ', $name);
3074 
3075  $this->_customPages[$name] = $path.$file;
3076  }
3077  }
3078  }
3079  }
3080  }
3081  return $this->_customPages;
3082  }
3083 
3091  function getCustomPagePath($name){
3092  $pages =& $this->getCustomPages();
3093  return $pages[$name];
3094  }
3095 
3104  function getCustomPageLabel($name){
3105  $name = str_replace('_',' ', $name);
3106  return ucwords($name);
3107  }
3108 
3109 
3110  // @}
3111  // END Custom Pages
3112  //=====================================================================================
3113 
3114 
3115 
3121  function addDebugInfo($info){
3122  $this->debugLog[] = $info;
3123  }
3124 
3130  function displayDebugInfo(){
3131  echo '<ul class="debug-info"><li>
3132  '; echo implode('</li><li>', $this->debugLog);
3133  echo '</li></ul>';
3134  }
3135 
3139  function _cleanup(){
3140  if ( session_id() != "" ){
3141  $this->writeSessionData();
3142  }
3143  if ( @$this->_conf['support_transactions'] ){
3144  @mysql_query('COMMIT', $this->_db);
3145  }
3146  }
3147 
3148 
3149 
3150 
3151 
3152 
3153 
3154 
3155 
3156 }
3157 
3163  private $url;
3164  public function __construct($url, $code = 0, Exception $previous = null ){
3165  $this->url = $url;
3166  parent::__construct('Request to redirect to '.$url, $code, $previous);
3167  }
3168 
3169  public function getURL(){
3170  return $this->url;
3171  }
3172 
3173 }
3174