Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/MVC/Controller/SugarController.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*********************************************************************************
3
 * SugarCRM Community Edition is a customer relationship management program developed by
4
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5
6
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
7
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
8
 *
9
 * This program is free software; you can redistribute it and/or modify it under
10
 * the terms of the GNU Affero General Public License version 3 as published by the
11
 * Free Software Foundation with the addition of the following permission added
12
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
13
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
14
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License along with
22
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
23
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
 * 02110-1301 USA.
25
 *
26
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
27
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
28
 *
29
 * The interactive user interfaces in modified source and object code versions
30
 * of this program must display Appropriate Legal Notices, as required under
31
 * Section 5 of the GNU Affero General Public License version 3.
32
 *
33
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
34
 * these Appropriate Legal Notices must retain the display of the "Powered by
35
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
36
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
37
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
38
 ********************************************************************************/
39
40
require_once('include/MVC/View/SugarView.php');
41
42
/**
43
 * Main SugarCRM controller
44
 * @api
45
 */
46
class SugarController{
47
	/**
48
	 * remap actions in here
49
	 * e.g. make all detail views go to edit views
50
	 * $action_remap = array('detailview'=>'editview');
51
	 */
52
	protected $action_remap = array('index'=>'listview');
53
	/**
54
	 * The name of the current module.
55
	 */
56
	public $module = 'Home';
57
	/**
58
	 * The name of the target module.
59
	 */
60
	public $target_module = null;
61
	/**
62
	 * The name of the current action.
63
	 */
64
	public $action = 'index';
65
	/**
66
	 * The id of the current record.
67
	 */
68
	public $record = '';
69
	/**
70
	 * The name of the return module.
71
	 */
72
	public $return_module = null;
73
	/**
74
	 * The name of the return action.
75
	 */
76
	public $return_action = null;
77
	/**
78
	 * The id of the return record.
79
	 */
80
	public $return_id = null;
81
	/**
82
	 * If the action was remapped it will be set to do_action and then we will just
83
	 * use do_action for the actual action to perform.
84
	 */
85
	protected $do_action = 'index';
86
	/**
87
	 * If a bean is present that set it.
88
	 */
89
	public $bean = null;
90
	/**
91
	 * url to redirect to
92
	 */
93
	public $redirect_url = '';
94
	/**
95
	 * any subcontroller can modify this to change the view
96
	 */
97
	public $view = 'classic';
98
	/**
99
	 * this array will hold the mappings between a key and an object for use within the view.
100
	 */
101
	public $view_object_map = array();
102
103
	/**
104
	 * This array holds the methods that handleAction() will invoke, in sequence.
105
	 */
106
	protected $tasks = array(
107
					   'pre_action',
108
					   'do_action',
109
					   'post_action'
110
					   );
111
	/**
112
	 * List of options to run through within the process() method.
113
	 * This list is meant to easily allow additions for new functionality as well as
114
	 * the ability to add a controller's own handling.
115
	 */
116
	public $process_tasks = array(
117
						'blockFileAccess',
118
						'handleEntryPoint',
119
						'callLegacyCode',
120
						'remapAction',
121
						'handle_action',
122
						'handleActionMaps',
123
					);
124
	/**
125
	 * Whether or not the action has been handled by $process_tasks
126
	 *
127
	 * @var bool
128
	 */
129
	protected $_processed = false;
130
	/**
131
	 * Map an action directly to a file
132
	 */
133
	/**
134
	 * Map an action directly to a file. This will be loaded from action_file_map.php
135
	 */
136
	protected $action_file_map = array();
137
	/**
138
	 * Map an action directly to a view
139
	 */
140
	/**
141
	 * Map an action directly to a view. This will be loaded from action_view_map.php
142
	 */
143
	protected $action_view_map = array();
144
145
	/**
146
	 * This can be set from the application to tell us whether we have authorization to
147
	 * process the action. If this is set we will default to the noaccess view.
148
	 */
149
	public $hasAccess = true;
150
151
	/**
152
	 * Map case sensitive filenames to action.  This is used for linux/unix systems
153
	 * where filenames are case sensitive
154
	 */
155
	public static $action_case_file = array(
156
										'editview'=>'EditView',
157
										'detailview'=>'DetailView',
158
										'listview'=>'ListView'
159
									  );
160
161
	/**
162
	 * Constructor. This ie meant tot load up the module, action, record as well
163
	 * as the mapping arrays.
164
	 */
165 16
	public function __construct(){
166 16
	}
167
168
    /**
169
     * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
170
     */
171
    public function SugarController(){
172
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
173
        if(isset($GLOBALS['log'])) {
174
            $GLOBALS['log']->deprecated($deprecatedMessage);
175
        }
176
        else {
177
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
178
        }
179
        self::__construct();
180
    }
181
182
183
	/**
184
	 * Called from SugarApplication and is meant to perform the setup operations
185
	 * on the controller.
186
	 *
187
	 */
188 2
	public function setup($module = ''){
189 2
		if(empty($module) && !empty($_REQUEST['module']))
190
			$module = $_REQUEST['module'];
191
		//set the module
192 2
		if(!empty($module))
193 2
			$this->setModule($module);
194
195 2
		if(!empty($_REQUEST['target_module']) && $_REQUEST['target_module'] != 'undefined') {
196
			$this->target_module = $_REQUEST['target_module'];
197
		}
198
		//set properties on the controller from the $_REQUEST
199 2
		$this->loadPropertiesFromRequest();
200
		//load the mapping files
201 2
		$this->loadMappings();
202 2
	}
203
	/**
204
	 * Set the module on the Controller
205
	 *
206
	 * @param object $module
207
	 */
208 6
	public function setModule($module){
209 6
		$this->module = $module;
210 6
	}
211
212
	/**
213
	 * Set properties on the Controller from the $_REQUEST
214
	 *
215
	 */
216 2
	private function loadPropertiesFromRequest(){
217 2
		if(!empty($_REQUEST['action']))
218
			$this->action = $_REQUEST['action'];
219 2
		if(!empty($_REQUEST['record']))
220
			$this->record = $_REQUEST['record'];
221 2
		if(!empty($_REQUEST['view']))
222
			$this->view = $_REQUEST['view'];
223 2
		if(!empty($_REQUEST['return_module']))
224
			$this->return_module = $_REQUEST['return_module'];
225 2
		if(!empty($_REQUEST['return_action']))
226
			$this->return_action = $_REQUEST['return_action'];
227 2
		if(!empty($_REQUEST['return_id']))
228
			$this->return_id = $_REQUEST['return_id'];
229 2
	}
230
231
	/**
232
	 * Load map files for use within the Controller
233
	 *
234
	 */
235 2
	private function loadMappings(){
236 2
		$this->loadMapping('action_view_map');
237 2
		$this->loadMapping('action_file_map');
238 2
		$this->loadMapping('action_remap', true);
239 2
	}
240
241
	/**
242
	 * Given a record id load the bean. This bean is accessible from any sub controllers.
243
	 */
244 5
	public function loadBean()
245
	{
246 5
		if(!empty($GLOBALS['beanList'][$this->module])){
247 3
			$class = $GLOBALS['beanList'][$this->module];
248 3
			if(!empty($GLOBALS['beanFiles'][$class])){
249 3
				require_once($GLOBALS['beanFiles'][$class]);
250 3
				$this->bean = new $class();
251 3
				if(!empty($this->record)){
252
					$this->bean->retrieve($this->record);
253
					if($this->bean)
254
						$GLOBALS['FOCUS'] = $this->bean;
255
				}
256
			}
257
		}
258 5
	}
259
260
	/**
261
	 * Generic load method to load mapping arrays.
262
	 */
263 3
	private function loadMapping($var, $merge = false){
264 3
		$$var = sugar_cache_retrieve("CONTROLLER_". $var . "_".$this->module);
265 3
		if(!$$var){
266 2
			if($merge && !empty($this->$var)){
267 1
				$$var = $this->$var;
268
			}else{
269 2
				$$var = array();
270
			}
271 2
			if(file_exists('include/MVC/Controller/'. $var . '.php')){
272 2
				require('include/MVC/Controller/'. $var . '.php');
273
			}
274 2
			if(file_exists('modules/'.$this->module.'/'. $var . '.php')){
275 1
				require('modules/'.$this->module.'/'. $var . '.php');
276
			}
277 2
			if(file_exists('custom/modules/'.$this->module.'/'. $var . '.php')){
278
				require('custom/modules/'.$this->module.'/'. $var . '.php');
279
			}
280 2
			if(file_exists('custom/include/MVC/Controller/'. $var . '.php')){
281
				require('custom/include/MVC/Controller/'. $var . '.php');
282
			}
283
284
            // entry_point_registry -> EntryPointRegistry
285
286 2
			$varname = str_replace(" ","",ucwords(str_replace("_"," ", $var)));
287 2
            if(file_exists("custom/application/Ext/$varname/$var.ext.php")){
288
				require("custom/application/Ext/$varname/$var.ext.php");
289
	        }
290 2
			if(file_exists("custom/modules/{$this->module}/Ext/$varname/$var.ext.php")){
291
				require("custom/modules/{$this->module}/Ext/$varname/$var.ext.php");
292
			}
293
294 2
			sugar_cache_put("CONTROLLER_". $var . "_".$this->module, $$var);
295
		}
296 3
		$this->$var = $$var;
297 3
	}
298
299
	/**
300
	 * This method is called from SugarApplication->execute and it will bootstrap the entire controller process
301
	 */
302 1
	final public function execute()
303
    {
304
305
        try
306
        {
307 1
            $this->process();
308 1
            if(!empty($this->view))
309
            {
310 1
                $this->processView();
311
            }
312
            elseif(!empty($this->redirect_url))
313
            {
314
            			$this->redirect();
315
            }
316
        }
317 1
        catch (Exception $e)
318
        {
319 1
            $this->handleException($e);
320
        }
321
322
323
324 1
	}
325
326
    /**
327
      * Handle exception
328
      * @param Exception $e
329
      */
330 1
    protected function handleException(Exception $e)
331
    {
332 1
        $GLOBALS['log']->fatal('Exception in Controller: ' . $e->getMessage());
333 1
        $logicHook = new LogicHook();
334
335 1
        if (isset($this->bean))
336
        {
337
            $logicHook->setBean($this->bean);
338
            $logicHook->call_custom_logic($this->bean->module_dir, "handle_exception", $e);
339
        }
340
        else
341
        {
342 1
            $logicHook->call_custom_logic('', "handle_exception", $e);
343
        }
344 1
    }
345
346
	/**
347
	 * Display the appropriate view.
348
	 */
349 1
	private function processView(){
350 1
		if(!isset($this->view_object_map['remap_action']) && isset($this->action_view_map[strtolower($this->action)]))
351
		{
352
		  $this->view_object_map['remap_action'] = $this->action_view_map[strtolower($this->action)];
353
		}
354 1
		$view = ViewFactory::loadView($this->view, $this->module, $this->bean, $this->view_object_map, $this->target_module);
355
		$GLOBALS['current_view'] = $view;
356
		if(!empty($this->bean) && !$this->bean->ACLAccess($view->type) && $view->type != 'list'){
357
			ACLController::displayNoAccess(true);
358
			sugar_cleanup(true);
359
		}
360
		if(isset($this->errors)){
361
		  $view->errors = $this->errors;
362
		}
363
		$view->process();
364
	}
365
366
	/**
367
	 * Meant to be overridden by a subclass and allows for specific functionality to be
368
	 * injected prior to the process() method being called.
369
	 */
370
	public function preProcess()
371
	{}
372
373
	/**
374
	 * if we have a function to support the action use it otherwise use the default action
375
	 *
376
	 * 1) check for file
377
	 * 2) check for action
378
	 */
379 2
	public function process(){
380 2
		$GLOBALS['action'] = $this->action;
381 2
		$GLOBALS['module'] = $this->module;
382
383
		//check to ensure we have access to the module.
384 2
		if($this->hasAccess){
385 2
			$this->do_action = $this->action;
386
387 2
			$file = self::getActionFilename($this->do_action);
388
389 2
			$this->loadBean();
390
391 2
			$processed = false;
392 2
            if (!$this->_processed) {
393 2
                foreach ($this->process_tasks as $process) {
394 2
                    $this->$process();
395 2
                    if ($this->_processed) {
396 2
                        break;
397
                    }
398
                }
399
            }
400
401 2
			$this->redirect();
402
		}else{
403
			$this->no_access();
404
		}
405 2
	}
406
407
	/**
408
	 * This method is called from the process method. I could also be called within an action_* method.
409
	 * It allows a developer to override any one of these methods contained within,
410
	 * or if the developer so chooses they can override the entire action_* method.
411
	 *
412
	 * @return true if any one of the pre_, do_, or post_ methods have been defined,
413
	 * false otherwise.  This is important b/c if none of these methods exists, then we will run the
414
	 * action_default() method.
415
	 */
416 2
	protected function handle_action(){
417 2
		$processed = false;
418 2
		foreach($this->tasks as $task){
419 2
			$processed = ($this->$task() || $processed);
420
		}
421 2
		$this->_processed = $processed;
422 2
	}
423
424
	/**
425
	 * Perform an action prior to the specified action.
426
	 * This can be overridde in a sub-class
427
	 */
428 2
	private function pre_action(){
429 2
		$function = 'pre_' . $this->action;
430 2
		if($this->hasFunction($function)){
431
			$GLOBALS['log']->debug('Performing pre_action');
432
			$this->$function();
433
			return true;
434
		}
435 2
		return false;
436
	}
437
438
	/**
439
	 * Perform the specified action.
440
	 * This can be overridde in a sub-class
441
	 */
442 2
	private function do_action(){
443 2
		$function =  'action_'. strtolower($this->do_action);
444 2
		if($this->hasFunction($function)){
445 2
			$GLOBALS['log']->debug('Performing action: '.$function.' MODULE: '.$this->module);
446 2
			$this->$function();
447 2
			return true;
448
		}
449
		return false;
450
	}
451
452
	/**
453
	 * Perform an action after to the specified action has occurred.
454
	 * This can be overridde in a sub-class
455
	 */
456 2
	private function post_action(){
457 2
		$function = 'post_' . $this->action;
458 2
		if($this->hasFunction($function)){
459
			$GLOBALS['log']->debug('Performing post_action');
460
			$this->$function();
461
			return true;
462
		}
463 2
		return false;
464
	}
465
466
	/**
467
	 * If there is no action found then display an error to the user.
468
	 */
469
	protected function no_action(){
470
		sugar_die($GLOBALS['app_strings']['LBL_NO_ACTION']);
471
	}
472
473
	/**
474
	 * The default action handler for instances where we do not have access to process.
475
	 */
476
	protected function no_access(){
477
		$this->view = 'noaccess';
478
	}
479
480
	///////////////////////////////////////////////
481
	/////// HELPER FUNCTIONS
482
	///////////////////////////////////////////////
483
484
	/**
485
	 * Determine if a given function exists on the objects
486
	 * @param function - the function to check
487
	 * @return true if the method exists on the object, false otherwise
488
	 */
489 2
	protected function hasFunction($function){
490 2
		return method_exists($this, $function);
491
	}
492
493
494
	/**
495
	 * Set the url to which we will want to redirect
496
	 *
497
	 * @param string url - the url to which we will want to redirect
498
	 */
499
	protected function set_redirect($url){
500
		$this->redirect_url = $url;
501
	}
502
503
	/**
504
	 * Perform redirection based on the redirect_url
505
	 *
506
	 */
507 2
	protected function redirect(){
508
509 2
		if(!empty($this->redirect_url))
510
			SugarApplication::redirect($this->redirect_url);
511 2
	}
512
513
	////////////////////////////////////////////////////////
514
	////// DEFAULT ACTIONS
515
	///////////////////////////////////////////////////////
516
517
	/*
518
	 * Save a bean
519
	 */
520
521
	/**
522
	 * Do some processing before saving the bean to the database.
523
	 */
524 1
	public function pre_save(){
525 1
		if(!empty($_POST['assigned_user_id']) && $_POST['assigned_user_id'] != $this->bean->assigned_user_id && $_POST['assigned_user_id'] != $GLOBALS['current_user']->id && empty($GLOBALS['sugar_config']['exclude_notifications'][$this->bean->module_dir])){
526
			$this->bean->notify_on_save = true;
527
		}
528 1
		$GLOBALS['log']->debug("SugarController:: performing pre_save.");
529 1
        require_once('include/SugarFields/SugarFieldHandler.php');
530 1
        $sfh = new SugarFieldHandler();
531 1
		foreach($this->bean->field_defs as $field => $properties) {
532 1
			$type = !empty($properties['custom_type']) ? $properties['custom_type'] : $properties['type'];
533 1
		    $sf = $sfh->getSugarField(ucfirst($type), true);
534 1
			if(isset($_POST[$field])) {
535
				if(is_array($_POST[$field]) && !empty($properties['isMultiSelect'])) {
536
					if(empty($_POST[$field][0])) {
537
						unset($_POST[$field][0]);
538
					}
539
					$_POST[$field] = encodeMultienumValue($_POST[$field]);
540
				}
541
				$this->bean->$field = $_POST[$field];
542 1
			} else if(!empty($properties['isMultiSelect']) && !isset($_POST[$field]) && isset($_POST[$field . '_multiselect'])) {
543
				$this->bean->$field = '';
544
			}
545 1
            if($sf != null){
546 1
                $sf->save($this->bean, $_POST, $field, $properties);
547
            }
548
		}
549
550 1
		foreach($this->bean->relationship_fields as $field=>$link){
551
			if(!empty($_POST[$field])){
552
				$this->bean->$field = $_POST[$field];
553
			}
554
		}
555 1
		if(!$this->bean->ACLAccess('save')){
556
			ACLController::displayNoAccess(true);
557
			sugar_cleanup(true);
558
		}
559 1
	}
560
561
	/**
562
	 * Perform the actual save
563
	 */
564 1
	public function action_save(){
565 1
		$this->bean->save(!empty($this->bean->notify_on_save));
566 1
	}
567
568
569 1
    public function action_spot()
570
    {
571 1
            $this->view = 'spot';
572 1
    }
573
574
575
	/**
576
	 * Specify what happens after the save has occurred.
577
	 */
578
	protected function post_save(){
579
		$module = (!empty($this->return_module) ? $this->return_module : $this->module);
580
		$action = (!empty($this->return_action) ? $this->return_action : 'DetailView');
581
		$id = (!empty($this->return_id) ? $this->return_id : $this->bean->id);
582
583
		$url = "index.php?module=".$module."&action=".$action."&record=".$id;
584
		$this->set_redirect($url);
585
	}
586
587
	/*
588
	 * Delete a bean
589
	 */
590
591
	/**
592
	 * Perform the actual deletion.
593
	 */
594
	protected function action_delete(){
595
		//do any pre delete processing
596
		//if there is some custom logic for deletion.
597
		if(!empty($_REQUEST['record'])){
598
			if(!$this->bean->ACLAccess('Delete')){
599
				ACLController::displayNoAccess(true);
600
				sugar_cleanup(true);
601
			}
602
			$this->bean->mark_deleted($_REQUEST['record']);
603
		}else{
604
			sugar_die("A record number must be specified to delete");
605
		}
606
	}
607
608
	/**
609
	 * Specify what happens after the deletion has occurred.
610
	 */
611
	protected function post_delete(){
612
        if (empty($_REQUEST['return_url'])) {
613
            $return_module = isset($_REQUEST['return_module']) ?
614
                $_REQUEST['return_module'] :
615
                $GLOBALS['sugar_config']['default_module'];
616
            $return_action = isset($_REQUEST['return_action']) ?
617
                $_REQUEST['return_action'] :
618
                $GLOBALS['sugar_config']['default_action'];
619
            $return_id = isset($_REQUEST['return_id']) ?
620
                $_REQUEST['return_id'] :
621
                '';
622
            $url = "index.php?module=".$return_module."&action=".$return_action."&record=".$return_id;
623
        } else {
624
            $url = $_REQUEST['return_url'];
625
        }
626
627
		//eggsurplus Bug 23816: maintain VCR after an edit/save. If it is a duplicate then don't worry about it. The offset is now worthless.
628
		if(isset($_REQUEST['offset']) && empty($_REQUEST['duplicateSave'])) {
629
		    $url .= "&offset=".$_REQUEST['offset'];
630
		}
631
632
		$this->set_redirect($url);
633
	}
634
	/**
635
	 * Perform the actual massupdate.
636
	 */
637
	protected function action_massupdate(){
638
		if(!empty($_REQUEST['massupdate']) && $_REQUEST['massupdate'] == 'true' && (!empty($_REQUEST['uid']) || !empty($_REQUEST['entire']))){
639
			if(!empty($_REQUEST['Delete']) && $_REQUEST['Delete']=='true' && !$this->bean->ACLAccess('delete')
640
                || (empty($_REQUEST['Delete']) || $_REQUEST['Delete']!='true') && !$this->bean->ACLAccess('save')){
641
				ACLController::displayNoAccess(true);
642
				sugar_cleanup(true);
643
			}
644
645
            set_time_limit(0);//I'm wondering if we will set it never goes timeout here.
646
            // until we have more efficient way of handling MU, we have to disable the limit
647
            $GLOBALS['db']->setQueryLimit(0);
648
            require_once("include/MassUpdate.php");
649
            require_once('modules/MySettings/StoreQuery.php');
650
            $seed = loadBean($_REQUEST['module']);
0 ignored issues
show
Deprecated Code introduced by
The function loadBean() has been deprecated with message: use SugarModule::loadBean() instead

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
651
            $mass = new MassUpdate();
652
            $mass->setSugarBean($seed);
653
            if(isset($_REQUEST['entire']) && empty($_POST['mass'])) {
654
                $mass->generateSearchWhere($_REQUEST['module'], $_REQUEST['current_query_by_page']);
655
            }
656
            $mass->handleMassUpdate();
657
            $storeQuery = new StoreQuery();//restore the current search. to solve bug 24722 for multi tabs massupdate.
658
            $temp_req = array('current_query_by_page' => $_REQUEST['current_query_by_page'], 'return_module' => $_REQUEST['return_module'], 'return_action' => $_REQUEST['return_action']);
659
            if($_REQUEST['return_module'] == 'Emails') {
660
                if(!empty($_REQUEST['type']) && !empty($_REQUEST['ie_assigned_user_id'])) {
661
                    $this->req_for_email = array('type' => $_REQUEST['type'], 'ie_assigned_user_id' => $_REQUEST['ie_assigned_user_id']); // Specifically for My Achieves
662
                }
663
            }
664
            $_REQUEST = array();
665
            $_REQUEST = sugar_unserialize(base64_decode($temp_req['current_query_by_page']));
666
            unset($_REQUEST[$seed->module_dir.'2_'.strtoupper($seed->object_name).'_offset']);//after massupdate, the page should redirect to no offset page
667
            $storeQuery->saveFromRequest($_REQUEST['module']);
668
            $_REQUEST = array('return_module' => $temp_req['return_module'], 'return_action' => $temp_req['return_action']);//for post_massupdate, to go back to original page.
669
		}else{
670
			sugar_die("You must massupdate at least one record");
671
		}
672
	}
673
	/**
674
	 * Specify what happens after the massupdate has occurred.
675
	 */
676
	protected function post_massupdate(){
677
		$return_module = isset($_REQUEST['return_module']) ?
678
			$_REQUEST['return_module'] :
679
			$GLOBALS['sugar_config']['default_module'];
680
		$return_action = isset($_REQUEST['return_action']) ?
681
			$_REQUEST['return_action'] :
682
			$GLOBALS['sugar_config']['default_action'];
683
		$url = "index.php?module=".$return_module."&action=".$return_action;
684
		if($return_module == 'Emails'){//specificly for My Achieves
685
			if(!empty($this->req_for_email['type']) && !empty($this->req_for_email['ie_assigned_user_id'])) {
686
				$url = $url . "&type=".$this->req_for_email['type']."&assigned_user_id=".$this->req_for_email['ie_assigned_user_id'];
687
			}
688
		}
689
		$this->set_redirect($url);
690
	}
691
	/**
692
	 * Perform the listview action
693
	 */
694 2
	protected function action_listview(){
695 2
		$this->view_object_map['bean'] = $this->bean;
696 2
		$this->view = 'list';
697 2
	}
698
699
/*
700
701
	//THIS IS HANDLED IN ACTION_REMAP WHERE INDEX IS SET TO LISTVIEW
702
	function action_index(){
703
	}
704
*/
705
706
	/**
707
	 * Action to handle when using a file as was done in previous versions of Sugar.
708
	 */
709
	protected function action_default(){
710
		$this->view = 'classic';
711
	}
712
713
	/**
714
	 * this method id used within a Dashlet when performing an ajax call
715
	 */
716
	protected function action_callmethoddashlet(){
717
		if(!empty($_REQUEST['id'])) {
718
		    $id = $_REQUEST['id'];
719
		    $requestedMethod = $_REQUEST['method'];
720
		    $dashletDefs = $GLOBALS['current_user']->getPreference('dashlets', 'Home'); // load user's dashlets config
721
		    if(!empty($dashletDefs[$id])) {
722
		        require_once($dashletDefs[$id]['fileLocation']);
723
724
		        $dashlet = new $dashletDefs[$id]['className']($id, (isset($dashletDefs[$id]['options']) ? $dashletDefs[$id]['options'] : array()));
725
726
		        if(method_exists($dashlet, $requestedMethod) || method_exists($dashlet, '__call')) {
727
		            echo $dashlet->$requestedMethod();
728
		        }
729
		        else {
730
		            echo 'no method';
731
		        }
732
		    }
733
		}
734
	}
735
736
	/**
737
	 * this method is used within a Dashlet when the options configuration is posted
738
	 */
739
	protected function action_configuredashlet(){
740
		global $current_user, $mod_strings;
741
742
		if(!empty($_REQUEST['id'])) {
743
		    $id = $_REQUEST['id'];
744
		    $dashletDefs = $current_user->getPreference('dashlets', $_REQUEST['module']); // load user's dashlets config
745
		    require_once($dashletDefs[$id]['fileLocation']);
746
747
		    $dashlet = new $dashletDefs[$id]['className']($id, (isset($dashletDefs[$id]['options']) ? $dashletDefs[$id]['options'] : array()));
748
		    if(!empty($_REQUEST['configure']) && $_REQUEST['configure']) { // save settings
749
		        $dashletDefs[$id]['options'] = $dashlet->saveOptions($_REQUEST);
750
		        $current_user->setPreference('dashlets', $dashletDefs, 0, $_REQUEST['module']);
751
		    }
752
		    else { // display options
753
		        $json = getJSONobj();
754
		        return 'result = ' . $json->encode((array('header' => $dashlet->title . ' : ' . $mod_strings['LBL_OPTIONS'],
755
		                                                 'body'  => $dashlet->displayOptions())));
756
757
		    }
758
		}
759
		else {
760
		    return '0';
761
		}
762
	}
763
764
    /**
765
     * Global method to delete an attachment
766
     *
767
     * If the bean does not have a deleteAttachment method it will return 'false' as a string
768
     *
769
     * @return void
770
     */
771
    protected function action_deleteattachment()
772
    {
773
        $this->view = 'edit';
774
        $GLOBALS['view'] = $this->view;
775
        ob_clean();
776
        $retval = false;
777
778
        if(method_exists($this->bean, 'deleteAttachment')) {
779
            $duplicate = "false";
780
            if (isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == "true") {
781
                $duplicate = "true";
782
            }
783
            if (isset($_REQUEST['duplicateSave']) && $_REQUEST['duplicateSave'] == "true") {
784
                $duplicate = "true";
785
            }
786
            $retval = $this->bean->deleteAttachment($duplicate);
787
        }
788
        echo json_encode($retval);
789
        sugar_cleanup(true);
790
    }
791
792
	/**
793
	 * getActionFilename
794
	 */
795 4
	public static function getActionFilename($action) {
796 4
	   if(isset(self::$action_case_file[$action])) {
797 1
	   	  return self::$action_case_file[$action];
798
	   }
799 4
	   return $action;
800
	}
801
802
	/********************************************************************/
803
	// 				PROCESS TASKS
804
	/********************************************************************/
805
806
	/**
807
	 * Given the module and action, determine whether the super/admin has prevented access
808
	 * to this url. In addition if any links specified for this module, load the links into
809
	 * GLOBALS
810
	 *
811
	 * @return true if we want to stop processing, false if processing should continue
812
	 */
813 2
	private function blockFileAccess(){
814
		//check if the we have enabled file_access_control and if so then check the mappings on the request;
815 2
		if(!empty($GLOBALS['sugar_config']['admin_access_control']) && $GLOBALS['sugar_config']['admin_access_control']){
816
			$this->loadMapping('file_access_control_map');
817
			//since we have this turned on, check the mapping file
818
			$module = strtolower($this->module);
819
			$action = strtolower($this->do_action);
820
			if(!empty($this->file_access_control_map['modules'][$module]['links'])){
821
				$GLOBALS['admin_access_control_links'] = $this->file_access_control_map['modules'][$module]['links'];
822
			}
823
824
			if(!empty($this->file_access_control_map['modules'][$module]['actions']) && (in_array($action, $this->file_access_control_map['modules'][$module]['actions']) || !empty($this->file_access_control_map['modules'][$module]['actions'][$action]))){
825
				//check params
826
				if(!empty($this->file_access_control_map['modules'][$module]['actions'][$action]['params'])){
827
					$block = true;
828
					$params = $this->file_access_control_map['modules'][$module]['actions'][$action]['params'];
829
					foreach($params as $param => $paramVals){
830
						if(!empty($_REQUEST[$param])){
831
							if(!in_array($_REQUEST[$param], $paramVals)){
832
								$block = false;
833
								break;
834
							}
835
						}
836
					}
837
					if($block){
838
						$this->_processed = true;
839
						$this->no_access();
840
					}
841
				}else{
842
					$this->_processed = true;
843
					$this->no_access();
844
				}
845
			}
846
		}else
847 2
			$this->_processed = false;
848 2
	}
849
850
	/**
851
	 * This code is part of the entry points reworking. We have consolidated all
852
	 * entry points to go through index.php. Now in order to bring up an entry point
853
	 * it will follow the format:
854
	 * 'index.php?entryPoint=download'
855
	 * the download entry point is mapped in the following file: entry_point_registry.php
856
	 *
857
	 */
858 2
	private function handleEntryPoint(){
859 2
		if(!empty($_REQUEST['entryPoint'])){
860
			$this->loadMapping('entry_point_registry');
861
			$entryPoint = $_REQUEST['entryPoint'];
862
863
			if(!empty($this->entry_point_registry[$entryPoint])){
864
				require_once($this->entry_point_registry[$entryPoint]['file']);
865
				$this->_processed = true;
866
				$this->view = '';
867
			}
868
		}
869 2
	}
870
871
    /**
872
     * Checks to see if the requested entry point requires auth
873
     *
874
     * @param  $entrypoint string name of the entrypoint
875
     * @return bool true if auth is required, false if not
876
     */
877 1
    public function checkEntryPointRequiresAuth($entryPoint)
878
    {
879 1
        $this->loadMapping('entry_point_registry');
880
881 1
        if ( isset($this->entry_point_registry[$entryPoint]['auth'])
882 1
                && !$this->entry_point_registry[$entryPoint]['auth'] )
883 1
            return false;
884 1
        return true;
885
    }
886
887
	/**
888
	 * Meant to handle old views e.g. DetailView.php.
889
	 *
890
	 */
891 2
	protected function callLegacyCode()
892
	{
893 2
		$file = self::getActionFilename($this->do_action);
894 2
		if ( isset($this->action_view_map[strtolower($this->do_action)]) ) {
895
	        $action = $this->action_view_map[strtolower($this->do_action)];
896
	    }
897
	    else {
898 2
	        $action = $this->do_action;
899
	    }
900
	    // index actions actually maps to the view.list.php view
901 2
	    if ( $action == 'index' ) {
902 2
	        $action = 'list';
903
	    }
904
905 2
		if ((file_exists('modules/' . $this->module . '/'. $file . '.php')
906 2
                && !file_exists('modules/' . $this->module . '/views/view.'. $action . '.php'))
907 2
            || (file_exists('custom/modules/' . $this->module . '/'. $file . '.php')
908 2
                && !file_exists('custom/modules/' . $this->module . '/views/view.'. $action . '.php'))
909
            ) {
910
			// A 'classic' module, using the old pre-MVC display files
911
			// We should now discard the bean we just obtained for tracking as the pre-MVC module will instantiate its own
912
			unset($GLOBALS['FOCUS']);
913
			$GLOBALS['log']->debug('Module:' . $this->module . ' using file: '. $file);
914
			$this->action_default();
915
			$this->_processed = true;
916
		}
917 2
	}
918
919
	/**
920
	 * If the action has been remapped to a different action as defined in
921
	 * action_file_map.php or action_view_map.php load those maps here.
922
	 *
923
	 */
924
	private function handleActionMaps(){
925
		if(!empty($this->action_file_map[strtolower($this->do_action)])){
926
			$this->view = '';
927
			$GLOBALS['log']->debug('Using Action File Map:' . $this->action_file_map[strtolower($this->do_action)]);
928
			require_once($this->action_file_map[strtolower($this->do_action)]);
929
			$this->_processed = true;
930
		}elseif(!empty($this->action_view_map[strtolower($this->do_action)])){
931
			$GLOBALS['log']->debug('Using Action View Map:' . $this->action_view_map[strtolower($this->do_action)]);
932
			$this->view = $this->action_view_map[strtolower($this->do_action)];
933
			$this->_processed = true;
934
		}else
935
			$this->no_action();
936
	}
937
938
	/**
939
	 * Actually remap the action if required.
940
	 *
941
	 */
942 2
	protected function remapAction(){
943 2
		if(!empty($this->action_remap[$this->do_action])){
944 2
			$this->action = $this->action_remap[$this->do_action];
945 2
			$this->do_action = $this->action;
946
		}
947 2
	}
948
949
}
950
?>
951