]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/MVC/SugarApplication.php
Release 6.1.5
[Github/sugarcrm.git] / include / MVC / SugarApplication.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 /*
38  * Created on Mar 21, 2007
39  *
40  * To change the template for this generated file go to
41  * Window - Preferences - PHPeclipse - PHP - Code Templates
42  */
43 require_once('include/MVC/Controller/ControllerFactory.php');
44 require_once('include/MVC/View/ViewFactory.php');
45
46 class SugarApplication
47 {
48         var $controller = null;
49         var $headerDisplayed = false;
50         var $default_module = 'Home';
51         var $default_action = 'index';
52
53         function SugarApplication()
54         {}
55
56         /**
57          * Perform execution of the application. This method is called from index2.php
58          */
59         function execute(){
60                 global $sugar_config;
61                 if(!empty($sugar_config['default_module']))
62                         $this->default_module = $sugar_config['default_module'];
63                 $module = $this->default_module;
64                 if(!empty($_REQUEST['module']))$module = $_REQUEST['module'];
65                 insert_charset_header();
66                 $this->setupPrint();
67                 $this->controller = ControllerFactory::getController($module);
68         // if the entry point is defined to not need auth, then don't authenicate
69                 if( empty($_REQUEST['entryPoint'])
70                 || $this->controller->checkEntryPointRequiresAuth($_REQUEST['entryPoint']) ){
71             $this->loadUser();
72             $this->ACLFilter();
73             $this->preProcess();
74             $this->controller->preProcess();
75             $this->checkHTTPReferer();
76         }
77
78         SugarThemeRegistry::buildRegistry();
79         $this->loadLanguages();
80                 $this->checkDatabaseVersion();
81                 $this->loadDisplaySettings();
82                 $this->loadLicense();
83                 $this->loadGlobals();
84                 $this->setupResourceManagement($module);
85                 $this->controller->execute();
86                 sugar_cleanup();
87         }
88
89         /**
90          * Load the authenticated user. If there is not an authenticated user then redirect to login screen.
91          */
92         function loadUser(){
93                 global $authController, $sugar_config;
94                 // Double check the server's unique key is in the session.  Make sure this is not an attempt to hijack a session
95                 $user_unique_key = (isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : '';
96                 $server_unique_key = (isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : '';
97                 $allowed_actions = (!empty($this->controller->allowed_actions)) ? $this->controller->allowed_actions : $allowed_actions = array('Authenticate', 'Login',);
98
99                 if(($user_unique_key != $server_unique_key) && (!in_array($this->controller->action, $allowed_actions)) &&
100                    (!isset($_SESSION['login_error'])))
101                    {
102                         session_destroy();
103                         $post_login_nav = '';
104
105                         if(!empty($this->controller->module)){
106                                 $post_login_nav .= '&login_module='.$this->controller->module;
107                         }
108                         if(!empty($this->controller->action)){
109                             if(in_array(strtolower($this->controller->action), array('delete')))
110                                 $post_login_nav .= '&login_action=DetailView';
111                             elseif(in_array(strtolower($this->controller->action), array('save')))
112                                 $post_login_nav .= '&login_action=EditView';
113                             elseif(isset($_REQUEST['massupdate'])|| isset($_GET['massupdate']) || isset($_POST['massupdate']))
114                                 $post_login_nav .= '&login_action=index';
115                             else
116                                     $post_login_nav .= '&login_action='.$this->controller->action;
117                         }
118                         if(!empty($this->controller->record)){
119                                 $post_login_nav .= '&login_record='.$this->controller->record;
120                         }
121
122                         header('Location: index.php?action=Login&module=Users'.$post_login_nav);
123                         exit ();
124                 }
125
126                 $authController = new AuthenticationController((!empty($GLOBALS['sugar_config']['authenticationClass'])? $GLOBALS['sugar_config']['authenticationClass'] : 'SugarAuthenticate'));
127                 $GLOBALS['current_user'] = new User();
128                 if(isset($_SESSION['authenticated_user_id'])){
129                         // set in modules/Users/Authenticate.php
130                         if(!$authController->sessionAuthenticate()){
131                                  // if the object we get back is null for some reason, this will break - like user prefs are corrupted
132                                 $GLOBALS['log']->fatal('User retrieval for ID: ('.$_SESSION['authenticated_user_id'].') does not exist in database or retrieval failed catastrophically.  Calling session_destroy() and sending user to Login page.');
133                                 session_destroy();
134                                 SugarApplication::redirect('index.php?action=Login&module=Users');
135                                 die();
136                         }//fi
137                 }elseif(!($this->controller->module == 'Users' && in_array($this->controller->action, $allowed_actions))){
138                         session_destroy();
139                         SugarApplication::redirect('index.php?action=Login&module=Users');
140                         die();
141                 }
142                 $GLOBALS['log']->debug('Current user is: '.$GLOBALS['current_user']->user_name);
143
144                 //set cookies
145                 if(isset($_SESSION['authenticated_user_id'])){
146                         $GLOBALS['log']->debug("setting cookie ck_login_id_20 to ".$_SESSION['authenticated_user_id']);
147                         self::setCookie('ck_login_id_20', $_SESSION['authenticated_user_id'], time() + 86400 * 90);
148                 }
149                 if(isset($_SESSION['authenticated_user_theme'])){
150                         $GLOBALS['log']->debug("setting cookie ck_login_theme_20 to ".$_SESSION['authenticated_user_theme']);
151                         self::setCookie('ck_login_theme_20', $_SESSION['authenticated_user_theme'], time() + 86400 * 90);
152                 }
153                 if(isset($_SESSION['authenticated_user_theme_color'])){
154                         $GLOBALS['log']->debug("setting cookie ck_login_theme_color_20 to ".$_SESSION['authenticated_user_theme_color']);
155                         self::setCookie('ck_login_theme_color_20', $_SESSION['authenticated_user_theme_color'], time() + 86400 * 90);
156                 }
157                 if(isset($_SESSION['authenticated_user_theme_font'])){
158                         $GLOBALS['log']->debug("setting cookie ck_login_theme_font_20 to ".$_SESSION['authenticated_user_theme_font']);
159                         self::setCookie('ck_login_theme_font_20', $_SESSION['authenticated_user_theme_font'], time() + 86400 * 90);
160                 }
161                 if(isset($_SESSION['authenticated_user_language'])){
162                         $GLOBALS['log']->debug("setting cookie ck_login_language_20 to ".$_SESSION['authenticated_user_language']);
163                         self::setCookie('ck_login_language_20', $_SESSION['authenticated_user_language'], time() + 86400 * 90);
164                 }
165                 //check if user can access
166
167         }
168
169         function ACLFilter(){
170                 ACLController :: filterModuleList($GLOBALS['moduleList']);
171                 ACLController :: filterModuleList($GLOBALS['modInvisListActivities']);
172         }
173
174         /**
175          * setupResourceManagement
176          * This function initialize the ResourceManager and calls the setup method
177          * on the ResourceManager instance.
178          *
179          */
180         function setupResourceManagement($module) {
181                 require_once('include/resource/ResourceManager.php');
182                 $resourceManager = ResourceManager::getInstance();
183                 $resourceManager->setup($module);
184         }
185
186         function setupPrint() {
187                 $GLOBALS['request_string'] = '';
188
189                 // merge _GET and _POST, but keep the results local
190                 // this handles the issues where values come in one way or the other
191                 // without affecting the main super globals
192                 $merged = array_merge($_GET, $_POST);
193                 foreach ($merged as $key => $val)
194                 {
195                    if(is_array($val))
196                    {
197                        foreach ($val as $k => $v)
198                        {
199                            $GLOBALS['request_string'] .= urlencode($key).'[]='.urlencode($v).'&';
200                        }
201                    }
202                    else
203                    {
204                        $GLOBALS['request_string'] .= urlencode($key).'='.urlencode($val).'&';
205                    }
206                 }
207                 $GLOBALS['request_string'] .= 'print=true';
208         }
209
210         function preProcess(){
211             $config = new Administration;
212             $config->retrieveSettings();
213                 if(!empty($_SESSION['authenticated_user_id'])){
214                         if(isset($_SESSION['hasExpiredPassword']) && $_SESSION['hasExpiredPassword'] == '1'){
215                                 if( $this->controller->action!= 'Save' && $this->controller->action != 'Logout') {
216                         $this->controller->module = 'Users';
217                         $this->controller->action = 'ChangePassword';
218                         $record = $GLOBALS['current_user']->id;
219                      }else{
220                                         $this->handleOfflineClient();
221                                  }
222                         }else{
223                                 $ut = $GLOBALS['current_user']->getPreference('ut');
224                             if(empty($ut)
225                                     && $this->controller->action != 'AdminWizard'
226                                     && $this->controller->action != 'EmailUIAjax'
227                                     && $this->controller->action != 'Wizard'
228                                     && $this->controller->action != 'SaveAdminWizard'
229                                     && $this->controller->action != 'SaveUserWizard'
230                                     && $this->controller->action != 'SaveTimezone'
231                                     && $this->controller->action != 'Logout') {
232                                         $this->controller->module = 'Users';
233                                         $this->controller->action = 'SetTimezone';
234                                         $record = $GLOBALS['current_user']->id;
235                                 }else{
236                                         if($this->controller->action != 'AdminWizard'
237                                     && $this->controller->action != 'EmailUIAjax'
238                                     && $this->controller->action != 'Wizard'
239                                     && $this->controller->action != 'SaveAdminWizard'
240                                     && $this->controller->action != 'SaveUserWizard'){
241                                                         $this->handleOfflineClient();
242                                     }
243                                 }
244                         }
245                 }
246                 $this->handleAccessControl();
247         }
248
249         function handleOfflineClient(){
250                 if(isset($GLOBALS['sugar_config']['disc_client']) && $GLOBALS['sugar_config']['disc_client']){
251                         if(isset($_REQUEST['action']) && $_REQUEST['action'] != 'SaveTimezone'){
252                                 if (!file_exists('modules/Sync/file_config.php')){
253                                         if($_REQUEST['action'] != 'InitialSync' && $_REQUEST['action'] != 'Logout' &&
254                                            ($_REQUEST['action'] != 'Popup' && $_REQUEST['module'] != 'Sync')){
255                                                 //echo $_REQUEST['action'];
256                                                 //die();
257                                                         $this->controller->module = 'Sync';
258                                                         $this->controller->action = 'InitialSync';
259                                                 }
260                         }else{
261                                 require_once ('modules/Sync/file_config.php');
262                                 if(isset($file_sync_info['is_first_sync']) && $file_sync_info['is_first_sync']){
263                                         if($_REQUEST['action'] != 'InitialSync' && $_REQUEST['action'] != 'Logout' &&
264                                            ( $_REQUEST['action'] != 'Popup' && $_REQUEST['module'] != 'Sync')){
265                                                                 $this->controller->module = 'Sync';
266                                                                 $this->controller->action = 'InitialSync';
267                                                 }
268                                 }
269                         }
270                         }
271                         global $moduleList, $sugar_config, $sync_modules;
272                         require_once('modules/Sync/SyncController.php');
273                         $GLOBALS['current_user']->is_admin = '0'; //No admins for disc client
274                 }
275         }
276
277         /**
278          * Handles everything related to authorization.
279          */
280         function handleAccessControl(){
281                 if(is_admin($GLOBALS['current_user']) || is_admin_for_any_module($GLOBALS['current_user']))
282                         return;
283             if(!empty($_REQUEST['action']) && $_REQUEST['action']=="RetrieveEmail")
284             return;
285                 if(!is_admin($GLOBALS['current_user']) && !empty($GLOBALS['adminOnlyList'][$this->controller->module])
286                 && !empty($GLOBALS['adminOnlyList'][$this->controller->module]['all'])
287                 && (empty($GLOBALS['adminOnlyList'][$this->controller->module][$this->controller->action]) || $GLOBALS['adminOnlyList'][$this->controller->module][$this->controller->action] != 'allow')) {
288                         $this->controller->hasAccess = false;
289                         return;
290                 }
291
292                 if(!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader']))
293                         $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
294
295                 if(in_array($this->controller->module, $GLOBALS['modInvisList']) &&
296                         ((in_array('Activities', $GLOBALS['moduleList'])              &&
297                         in_array('Calendar',$GLOBALS['moduleList']))                 &&
298                         in_array($this->controller->module, $GLOBALS['modInvisListActivities']))
299                         ){
300                                 $this->controller->hasAccess = false;
301                                 return;
302                 }
303         }
304
305         /**
306          * Load only bare minimum of language that can be done before user init and MVC stuff
307          */
308         static function preLoadLanguages()
309         {
310                 if(!empty($_SESSION['authenticated_user_language'])) {
311                         $GLOBALS['current_language'] = $_SESSION['authenticated_user_language'];
312                 }
313                 else {
314                         $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language'];
315                 }
316                 $GLOBALS['log']->debug('current_language is: '.$GLOBALS['current_language']);
317                 //set module and application string arrays based upon selected language
318                 $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']);
319         }
320
321         /**
322          * Load application wide languages as well as module based languages so they are accessible
323          * from the module.
324          */
325         function loadLanguages(){
326                 if(!empty($_SESSION['authenticated_user_language'])) {
327                         $GLOBALS['current_language'] = $_SESSION['authenticated_user_language'];
328                 }
329                 else {
330                         $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language'];
331                 }
332                 $GLOBALS['log']->debug('current_language is: '.$GLOBALS['current_language']);
333                 //set module and application string arrays based upon selected language
334                 $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']);
335                 if(empty($GLOBALS['current_user']->id))$GLOBALS['app_strings']['NTC_WELCOME'] = '';
336                 if(!empty($GLOBALS['system_config']->settings['system_name']))$GLOBALS['app_strings']['LBL_BROWSER_TITLE'] = $GLOBALS['system_config']->settings['system_name'];
337                 $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']);
338                 $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $this->controller->module);
339         }
340         /**
341         * checkDatabaseVersion
342         * Check the db version sugar_version.php and compare to what the version is stored in the config table.
343         * Ensure that both are the same.
344         */
345         function checkDatabaseVersion($dieOnFailure = true)
346         {
347             $row_count = sugar_cache_retrieve('checkDatabaseVersion_row_count');
348             if ( empty($row_count) ) {
349             global $sugar_db_version;
350             $version_query = 'SELECT count(*) as the_count FROM config WHERE category=\'info\' AND name=\'sugar_version\'';
351
352             if($GLOBALS['db']->dbType == 'oci8'){
353             }
354             else if ($GLOBALS['db']->dbType == 'mssql'){
355                 $version_query .= " AND CAST(value AS varchar(8000)) = '$sugar_db_version'";
356             }
357             else {
358                 $version_query .= " AND value = '$sugar_db_version'";
359             }
360
361             $result = $GLOBALS['db']->query($version_query);
362             $row = $GLOBALS['db']->fetchByAssoc($result, -1, true);
363             $row_count = $row['the_count'];
364             sugar_cache_put('checkDatabaseVersion_row_count', $row_count);
365         }
366
367                 if($row_count == 0 && empty($GLOBALS['sugar_config']['disc_client'])){
368                         $sugar_version = $GLOBALS['sugar_version'];
369                         if ( $dieOnFailure )
370                                 sugar_die("Sugar CRM $sugar_version Files May Only Be Used With A Sugar CRM $sugar_db_version Database.");
371                         else
372                             return false;
373                 }
374
375                 return true;
376         }
377
378         /**
379          * Load the themes/images.
380          */
381         function loadDisplaySettings()
382     {
383         global $theme;
384
385         // load the user's default theme
386         $theme = $GLOBALS['current_user']->getPreference('user_theme');
387
388         if (is_null($theme)) {
389             $theme = $GLOBALS['sugar_config']['default_theme'];
390             if(!empty($_SESSION['authenticated_user_theme'])){
391                 $theme = $_SESSION['authenticated_user_theme'];
392             }
393             else if(!empty($_COOKIE['sugar_user_theme'])){
394                 $theme = $_COOKIE['sugar_user_theme'];
395             }
396
397                         if(isset($_SESSION['authenticated_user_theme']) && $_SESSION['authenticated_user_theme'] != '') {
398                                 $_SESSION['theme_changed'] = false;
399                         }
400                 }
401
402         if(!is_null($theme) && !headers_sent())
403         {
404             setcookie('sugar_user_theme', $theme, time() + 31536000); // expires in a year
405         }
406
407         SugarThemeRegistry::set($theme);
408         require_once('include/utils/layout_utils.php');
409         $GLOBALS['image_path'] = SugarThemeRegistry::current()->getImagePath().'/';
410         if ( defined('TEMPLATE_URL') )
411             $GLOBALS['image_path'] = TEMPLATE_URL . '/'. $GLOBALS['image_path'];
412
413         if ( isset($GLOBALS['current_user']) ) {
414             $GLOBALS['gridline'] = (int) ($GLOBALS['current_user']->getPreference('gridline') == 'on');
415             $GLOBALS['current_user']->setPreference('user_theme', $theme, 0, 'global');
416         }
417         }
418
419         function loadLicense(){
420                 loadLicense();
421                 global $user_unique_key, $server_unique_key;
422                 $user_unique_key = (isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : '';
423                 $server_unique_key = (isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : '';
424         }
425
426         function loadGlobals(){
427                 global $currentModule;
428                 $currentModule = $this->controller->module;
429                 if($this->controller->module == $this->default_module){
430                         $_REQUEST['module'] = $this->controller->module;
431                         if(empty($_REQUEST['action']))
432                         $_REQUEST['action'] = $this->default_action;
433                 }
434         }
435
436         /**
437          * Actions that modify data in this controller's instance and thus require referrers
438          * @var array
439          */
440         protected $modifyActions = array();
441         /**
442          * Actions that always modify data and thus require referrers
443          * save* and delete* hardcoded as modified
444          * @var array
445          */
446         private $globalModifyActions = array(
447                 'massupdate', 'configuredashlet', 'import', 'importvcardsave', 'inlinefieldsave',
448             'wlsave', 'quicksave'
449         );
450
451         /**
452          * Modules that modify data and thus require referrers for all actions
453          */
454         private $modifyModules = array(
455                 'Administration' => true,
456                 'UpgradeWizard' => true,
457                 'Configurator' => true,
458                 'Studio' => true,
459                 'ModuleBuilder' => true,
460                 'Emails' => true,
461             'DCETemplates' => true,
462                 'DCEInstances' => true,
463                 'DCEActions' => true,
464                 'Trackers' => array('trackersettings'),
465             'SugarFavorites' => array('tag'),
466             'Import' => array('last', 'undo'),
467         );
468
469         protected function isModifyAction()
470         {
471             $action = strtolower($this->controller->action);
472             if(substr($action, 0, 4) == "save" || substr($action, 0, 6) == "delete") {
473                 return true;
474             }
475             if(isset($this->modifyModules[$this->controller->module])) {
476                 if($this->modifyModules[$this->controller->module] == true) {
477                     return true;
478                 }
479                 if(in_array($this->controller->action, $this->modifyModules[$this->controller->module])) {
480                     return true;
481
482                 }
483             }
484             if(in_array($this->controller->action, $this->globalModifyActions)) {
485             return true;
486         }
487             if(in_array($this->controller->action, $this->modifyActions)) {
488             return true;
489         }
490         return false;
491         }
492
493         /**
494          *
495          * Checks a request to ensure the request is coming from a valid source or it is for one of the white listed actions
496          */
497         function checkHTTPReferer(){
498                 global $sugar_config;
499                 $whiteListActions = (!empty($sugar_config['http_referer']['actions']))?$sugar_config['http_referer']['actions']:array('index', 'ListView', 'DetailView', 'Authenticate', 'Login');
500                 $strong = empty($sugar_config['http_referer']['weak']);
501                 // Bug 39691 - Make sure localhost and 127.0.0.1 are always valid HTTP referers
502                 $whiteListReferers = array('127.0.0.1','localhost');
503                 if(!empty($_SERVER['SERVER_ADDR']))$whiteListReferers[]  = $_SERVER['SERVER_ADDR'];
504                 if ( !empty($sugar_config['http_referer']['list']) ) {
505                         $whiteListReferers = array_merge($whiteListReferers,$sugar_config['http_referer']['list']);
506                 }
507                 if($strong && empty($_SERVER['HTTP_REFERER']) && !in_array($this->controller->action, $whiteListActions) && $this->isModifyAction()){
508                         $whiteListActions[] = $this->controller->action;
509                         $whiteListString = "'" . implode("', '", $whiteListActions) . "'";
510                         header("Cache-Control: no-cache, must-revalidate");
511                         echo <<<EOQ
512                                         <div align='center' style='background:lightgray'>
513                                         <h3 style='color:red'>Possible Cross Site Request Forgery (XSRF) Attack Detected</h3>
514                                         <h4>You've made a request to {$this->controller->action} but your HTTP Referer header is blank.</h4>
515                                         <h4><a href='javascript:void(0);' onclick='document.getElementById("directions").style.display="";'>Click here for directions to allow the HTTP Referer to not be set</a></h4>
516                                         </div>
517                                         <div id='directions' style='display:none'>
518                                                 <h3>Directions to allow HTTP Referer to not be set. This will cause your system to be insecure:</h3>
519                                                 <ol>
520                                                         <li>On your file system go to the root of your SugarCRM instance
521                                                         <li>Open the file config_override.php. If it does not exist, create it. (it should be at the same level as index.php and config.php)
522                                                         <li>Make sure the file starts with <pre>&lt;?php</pre> followed by a new line
523                                                         <li>Add the following line to your config_override.php file<br> <pre>\$sugar_config['http_referer']['weak']= true;</pre>
524                                                         <li>Save the file and it should work
525                                                 </ol>
526                                                 <h3>Attempted action ({$this->controller->action}):</h3>
527                                                 If you feel this is a valid action that should be allowed with or without an HTTP Referer, add the following to your config_override.php file
528                                                 <ul><li><pre>\$sugar_config['http_referer']['actions'] =array( $whiteListString ); </pre></ul>
529                                         </div>
530
531
532 EOQ;
533                         sugar_cleanup(true);
534                 }else if(!empty($_SERVER['HTTP_REFERER']) && !empty($_SERVER['SERVER_NAME'])){
535                         $http_ref = parse_url($_SERVER['HTTP_REFERER']);
536                         if($http_ref['host'] !== $_SERVER['SERVER_NAME']  && !in_array($this->controller->action, $whiteListActions) &&
537                                 (empty($whiteListReferers) || !in_array($http_ref['host'], $whiteListReferers))){
538                                 header("Cache-Control: no-cache, must-revalidate");
539                                 $whiteListActions[] = $this->controller->action;
540                                 $whiteListString = "'" . implode("', '", $whiteListActions) . "'";
541
542                                 echo <<<EOQ
543                                         <div align='center' style='background:lightgray'>
544                                         <h3 style='color:red'>Possible Cross Site Request Forgery (XSRF) Attack Detected</h3>
545                                         <h4>If you think this is a mistake please ask your administrator to add the following site to the acceptable referer list</h4>
546                                         <h3>{$http_ref['host']}</h3>
547                                         <h4><a href='javascript:void(0);' onclick='document.getElementById("directions").style.display="";'>Click here for directions to add this site to the acceptable referer list</a></h4>
548                                         </div>
549                                         <div id='directions' style='display:none'>
550                                                 <h3>Directions:</h3>
551                                                 <ol>
552                                                         <li>On your file system go to the root of your SugarCRM instance
553                                                         <li>Open the file config_override.php. If it does not exist, create it. (it should be at the same level as index.php and config.php)
554                                                         <li>Make sure the file starts with <pre>&lt;?php</pre> followed by a new line
555                                                         <li>Add the following line to your config_override.php file<br> <pre>\$sugar_config['http_referer']['list'][] = '{$http_ref['host']}';</pre>
556                                                         <li>Save the file and it should work
557                                                 </ol>
558                                                 <h3>Attempted action ({$this->controller->action}):</h3>
559                                                 If you feel this is a valid action that should be allowed from any referer, add the following to your config_override.php file
560                                                 <ul><li><pre>\$sugar_config['http_referer']['actions'] =array( $whiteListString ); </pre></ul>
561                                         </div>
562
563
564 EOQ;
565                         sugar_cleanup(true);
566                         }
567                 }
568         }
569         function startSession()
570         {
571             $sessionIdCookie = isset($_COOKIE['PHPSESSID']) ? $_COOKIE['PHPSESSID'] : null;
572             if(isset($_REQUEST['MSID'])) {
573                         session_id($_REQUEST['MSID']);
574                         session_start();
575                         if(isset($_SESSION['user_id']) && isset($_SESSION['seamless_login'])){
576                                 unset ($_SESSION['seamless_login']);
577                         }else{
578                                 if(isset($_COOKIE['PHPSESSID'])){
579                                 self::setCookie('PHPSESSID', '', time()-42000, '/');
580                         }
581                         sugar_cleanup(false);
582                         session_destroy();
583                         exit('Not a valid entry method');
584                         }
585                 }else{
586                         if(can_start_session()){
587                                 session_start();
588                         }
589                 }
590
591                 if ( isset($_REQUEST['login_module']) && isset($_REQUEST['login_action'])
592                         && !($_REQUEST['login_module'] == 'Home' && $_REQUEST['login_action'] == 'index') ) {
593             if ( !is_null($sessionIdCookie) && empty($_SESSION) ) {
594                 self::setCookie('loginErrorMessage', 'LBL_SESSION_EXPIRED', time()+30, '/');
595             }
596         }
597
598         }
599
600         function endSession(){
601                 session_destroy();
602         }
603         /**
604          * Redirect to another URL
605          *
606          * @access      public
607          * @param       string  $url    The URL to redirect to
608          */
609         function redirect(
610             $url
611             )
612         {
613                 /*
614                  * If the headers have been sent, then we cannot send an additional location header
615                  * so we will output a javascript redirect statement.
616                  */
617                 if (headers_sent()) {
618                         echo "<script>document.location.href='$url';</script>\n";
619                 } else {
620                         //@ob_end_clean(); // clear output buffer
621                         session_write_close();
622                         header( 'HTTP/1.1 301 Moved Permanently' );
623                         header( "Location: ". $url );
624                 }
625                 exit();
626         }
627
628         /**
629          * Wrapper for the PHP setcookie() function, to handle cases where headers have
630          * already been sent
631          */
632         public static function setCookie(
633             $name,
634             $value,
635             $expire = 0,
636             $path = '/',
637             $domain = null,
638             $secure = false,
639             $httponly = false
640             )
641         {
642             if ( is_null($domain) )
643                 if ( isset($_SERVER["HTTP_HOST"]) )
644                     $domain = $_SERVER["HTTP_HOST"];
645                 else
646                     $domain = 'localhost';
647
648             if (!headers_sent())
649                 setcookie($name,$value,$expire,$path,$domain,$secure,$httponly);
650
651             $_COOKIE[$name] = $value;
652         }
653 }