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.

modules/Home/UnifiedSearchAdvanced.php (6 issues)

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
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
/*********************************************************************************
4
 * SugarCRM Community Edition is a customer relationship management program developed by
5
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
/*********************************************************************************
42
43
 * Description:  TODO: To be written.
44
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
45
 * All Rights Reserved.
46
 * Contributor(s): ______________________________________..
47
 ********************************************************************************/
48
49
50
51
class UnifiedSearchAdvanced {
52
53
    var $query_string = '';
54
    
55
    /* path to search form */
56
    var $searchFormPath = 'include/SearchForm/SearchForm2.php';
57
58
    /*search form class name*/
59
    var $searchFormClass = 'SearchForm';
60
61
    function __construct(){
62
        if(!empty($_REQUEST['query_string'])){
63
            $query_string = trim($_REQUEST['query_string']);
64
            if(!empty($query_string)){
65
                $this->query_string = $query_string;
66
            }
67
        }
68
        $this->cache_search = sugar_cached('modules/unified_search_modules.php');
69
        $this->cache_display = sugar_cached('modules/unified_search_modules_display.php');
70
    }
71
72
	function getDropDownDiv($tpl = 'modules/Home/UnifiedSearchAdvanced.tpl') {
73
		global $app_list_strings, $app_strings;
74
75
		if(!file_exists($this->cache_search))
76
		{
77
			$this->buildCache();
78
		}
79
80
		$unified_search_modules_display = $this->getUnifiedSearchModulesDisplay();
81
82
		global $mod_strings, $modListHeader, $app_list_strings, $current_user, $app_strings, $beanList;
83
		$users_modules = $current_user->getPreference('globalSearch', 'search');
84
85
		// preferences are empty, select all
86
		if(empty($users_modules)) {
87
			$users_modules = array();
88
			foreach($unified_search_modules_display as $module=>$data) {
89
				if (!empty($data['visible']) ) {
90
                    $users_modules[$module] = $beanList[$module];
91
                }
92
			}
93
			$current_user->setPreference('globalSearch', $users_modules, 0, 'search');
94
		}
95
96
		$sugar_smarty = new Sugar_Smarty();
97
98
		$modules_to_search = array();
99
100
		foreach($users_modules as $key=>$module)
101
		{
102
            if(ACLController::checkAccess($key, 'list', true))
103
            {
104
                $modules_to_search[$key]['checked'] = true;
105
            }
106
		}
107
108
		if(!empty($this->query_string))
109
		{
110
			$sugar_smarty->assign('query_string', securexss($this->query_string));
111
		} else {
112
			$sugar_smarty->assign('query_string', '');
113
		}
114
115
		$sugar_smarty->assign('MOD', return_module_language($GLOBALS['current_language'], 'Administration'));
116
		$sugar_smarty->assign('APP', $app_strings);
117
		$sugar_smarty->assign('USE_SEARCH_GIF', 0);
118
		$sugar_smarty->assign('LBL_SEARCH_BUTTON_LABEL', $app_strings['LBL_SEARCH_BUTTON_LABEL']);
119
		$sugar_smarty->assign('LBL_SEARCH_BUTTON_TITLE', $app_strings['LBL_SEARCH_BUTTON_TITLE']);
120
		$sugar_smarty->assign('LBL_SEARCH', $app_strings['LBL_SEARCH']);
121
122
		$json_enabled = array();
123
		$json_disabled = array();
124
125
		//Now add the rest of the modules that are searchable via Global Search settings
126
		foreach($unified_search_modules_display as $module=>$data)
127
		{
128
			if(!isset($modules_to_search[$module]) && $data['visible'] && ACLController::checkAccess($module, 'list', true))
129
			{
130
			   $modules_to_search[$module]['checked'] = false;
131
			} else if (isset($modules_to_search[$module]) && !$data['visible']) {
132
			   unset($modules_to_search[$module]);
133
			}
134
		}
135
136
		//Create the two lists (doing it this way preserves the user's ordering choice for enabled modules)
137
		foreach($modules_to_search as $module=>$data)
138
		{
139
			$label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module;
140
			if(!empty($data['checked']))
141
			{
142
				$json_enabled[] = array("module" => $module, 'label' => $label);
143
			} else {
144
				$json_disabled[] = array("module" => $module, 'label' => $label);
145
			}
146
		}
147
148
		$sugar_smarty->assign('enabled_modules', json_encode($json_enabled));
149
		$sugar_smarty->assign('disabled_modules', json_encode($json_disabled));
150
151
		$showDiv = $current_user->getPreference('showGSDiv', 'search');
152
		if(!isset($showDiv))
153
		{
154
		   $showDiv = 'no';
155
		}
156
157
		$sugar_smarty->assign('SHOWGSDIV', $showDiv);
158
		$sugar_smarty->debugging = true;
159
		return $sugar_smarty->fetch($tpl);
160
	}
161
162
163
    /**
164
     * search
165
     *
166
     * Search function run when user goes to Show All and runs a search again.  This outputs the search results
167
     * calling upon the various listview display functions for each module searched on.
168
     * 
169
     * Todo: Sync this up with SugarSpot.php search method.
170
     *
171
     *
172
     */
173
	function search() {
174
175
        $unified_search_modules = $this->getUnifiedSearchModules();
176
		$unified_search_modules_display = $this->getUnifiedSearchModulesDisplay();
177
178
179
		require_once 'include/ListView/ListViewSmarty.php';
180
181
		global $modListHeader, $beanList, $beanFiles, $current_language, $app_strings, $current_user, $mod_strings;
182
		$home_mod_strings = return_module_language($current_language, 'Home');
183
184
		$this->query_string = $GLOBALS['db']->quote(securexss(from_html(clean_string($this->query_string, 'UNIFIED_SEARCH'))));
0 ignored issues
show
It seems like clean_string($this->quer...ring, 'UNIFIED_SEARCH') targeting clean_string() can also be of type false or null; however, from_html() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
185
186
		if(!empty($_REQUEST['advanced']) && $_REQUEST['advanced'] != 'false') {
187
			$modules_to_search = array();
188
			if(!empty($_REQUEST['search_modules']))
189
			{
190
			    foreach(explode (',', $_REQUEST['search_modules'] ) as $key)
191
	            {
192
                    if (isset($unified_search_modules_display[$key]) && !empty($unified_search_modules_display[$key]['visible']))
193
                    {
194
                        $modules_to_search[$key] = $beanList[$key];
195
                    }
196
	            }
197
			}
198
199
			$current_user->setPreference('showGSDiv', isset($_REQUEST['showGSDiv']) ? $_REQUEST['showGSDiv'] : 'no', 0, 'search');
200
			$current_user->setPreference('globalSearch', $modules_to_search, 0, 'search'); // save selections to user preference
201
		} else {
202
			$users_modules = $current_user->getPreference('globalSearch', 'search');
203
			$modules_to_search = array();
204
205
			if(!empty($users_modules)) {
206
				// use user's previous selections
207
			    foreach ( $users_modules as $key => $value ) {
208
			    	if (isset($unified_search_modules_display[$key]) && !empty($unified_search_modules_display[$key]['visible'])) {
209
		            	$modules_to_search[$key] = $beanList[$key];
210
		        	}
211
			    }
212
			} else {
213
				foreach($unified_search_modules_display as $module=>$data) {
214
				    if (!empty($data['visible']) ) {
215
				        $modules_to_search[$module] = $beanList[$module];
216
				    }
217
				}
218
			}
219
			$current_user->setPreference('globalSearch', $modules_to_search, 'search');
220
		}
221
222
223
		$templateFile = 'modules/Home/UnifiedSearchAdvancedForm.tpl';
224
		if(file_exists('custom/' . $templateFile))
225
		{
226
		   $templateFile = 'custom/'.$templateFile;
227
		}
228
229
		echo $this->getDropDownDiv($templateFile);
230
231
		$module_results = array();
232
		$module_counts = array();
233
		$has_results = false;
234
235
		if(!empty($this->query_string)) {
236
			foreach($modules_to_search as $moduleName => $beanName) {
237
                require_once $beanFiles[$beanName] ;
238
                $seed = new $beanName();
239
240
                $lv = new ListViewSmarty();
241
                $lv->lvd->additionalDetails = false;
242
                $mod_strings = return_module_language($current_language, $seed->module_dir);
243
244
                //retrieve the original list view defs and store for processing in case of custom layout changes
245
                require('modules/'.$seed->module_dir.'/metadata/listviewdefs.php');
246
				$orig_listViewDefs = $listViewDefs;
247
248
                if(file_exists('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php'))
249
                {
250
                    require('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php');
251
                }
252
253
                if ( !isset($listViewDefs) || !isset($listViewDefs[$seed->module_dir]) )
254
                {
255
                    continue;
256
                }
257
258
			    $unifiedSearchFields = array () ;
259
                $innerJoins = array();
260
                foreach ( $unified_search_modules[ $moduleName ]['fields'] as $field=>$def )
261
                {
262
                	$listViewCheckField = strtoupper($field);
263
                	//check to see if the field is in listview defs
264
					if ( empty($listViewDefs[$seed->module_dir][$listViewCheckField]['default']) ) {
265
						//check to see if field is in original list view defs (in case we are using custom layout defs)
266
						if (!empty($orig_listViewDefs[$seed->module_dir][$listViewCheckField]['default']) ) {
267
							//if we are here then the layout has been customized, but the field is still needed for query creation
268
							$listViewDefs[$seed->module_dir][$listViewCheckField] = $orig_listViewDefs[$seed->module_dir][$listViewCheckField];
269
						}
270
271
					}
272
273
                    //bug: 34125 we might want to try to use the LEFT JOIN operator instead of the INNER JOIN in the case we are
274
                    //joining against a field that has not been populated.
275
                    if(!empty($def['innerjoin']) )
276
                    {
277
                        if (empty($def['db_field']) )
278
                        {
279
                            continue;
280
                        }
281
                        $innerJoins[$field] = $def;
282
                        $def['innerjoin'] = str_replace('INNER', 'LEFT', $def['innerjoin']);
283
                    }
284
285
                    if(isset($seed->field_defs[$field]['type']))
286
                    {
287
                        $type = $seed->field_defs[$field]['type'];
288
                        if($type == 'int' && !is_numeric($this->query_string))
289
                        {
290
                            continue;
291
                        }
292
                    }
293
294
                    $unifiedSearchFields[ $moduleName ] [ $field ] = $def ;
295
                    $unifiedSearchFields[ $moduleName ] [ $field ][ 'value' ] = $this->query_string ;
296
                }
297
298
                /*
299
                 * Use searchForm2->generateSearchWhere() to create the search query, as it can generate SQL for the full set of comparisons required
300
                 * generateSearchWhere() expects to find the search conditions for a field in the 'value' parameter of the searchFields entry for that field
301
                 */
302
                require_once $beanFiles[$beanName] ;
303
                $seed = new $beanName();
304
                
305
				require_once $this->searchFormPath;
306
                $searchForm = new $this->searchFormClass ( $seed, $moduleName ) ;
307
308
                $searchForm->setup (array ( $moduleName => array() ) , $unifiedSearchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ;
309
                $where_clauses = $searchForm->generateSearchWhere() ;
310
                //add inner joins back into the where clause
311
                $params = array('custom_select' => "");
312
                foreach($innerJoins as $field=>$def) {
313
                    if (isset ($def['db_field'])) {
314
                      foreach($def['db_field'] as $dbfield)
315
                          $where_clauses[] = $dbfield . " LIKE '" . $this->query_string . "%'";
316
                          $params['custom_select'] .= ", $dbfield";
0 ignored issues
show
The variable $dbfield seems to be defined by a foreach iteration on line 314. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
317
                          $params['distinct'] = true;
318
                          //$filterFields[$dbfield] = $dbfield;
319
                    }
320
                }
321
322
                if (count($where_clauses) > 0)
323
                {
324
                    $where = '(('. implode(' ) OR ( ', $where_clauses) . '))';
325
                }
326
                else
327
                {
328
                    /* Clear $where from prev. module
329
                       if in current module $where_clauses */
330
                    $where = '';
331
                }
332
                $displayColumns = array();
333
                foreach($listViewDefs[$seed->module_dir] as $colName => $param)
334
                {
335
                    if(!empty($param['default']) && $param['default'] == true)
336
                    {
337
                        $param['url_sort'] = true;//bug 27933
338
                        $displayColumns[$colName] = $param;
339
                    }
340
                }
341
342
                if(count($displayColumns) > 0)
343
                {
344
                	$lv->displayColumns = $displayColumns;
345
                } else {
346
                	$lv->displayColumns = $listViewDefs[$seed->module_dir];
347
                }
348
349
                $lv->export = false;
350
                $lv->mergeduplicates = false;
351
                $lv->multiSelect = false;
352
                $lv->delete = false;
353
                $lv->select = false;
354
                $lv->showMassupdateFields = false;
355
                $lv->email = false;
356
357
                $lv->setup($seed, 'include/ListView/ListViewNoMassUpdate.tpl', $where, $params, 0, 10);
358
359
                $module_results[$moduleName] = '<br /><br />' . get_form_header($GLOBALS['app_list_strings']['moduleList'][$seed->module_dir] . ' (' . $lv->data['pageData']['offsets']['total'] . ')', '', false);
360
                $module_counts[$moduleName] = $lv->data['pageData']['offsets']['total'];
361
362
                if($lv->data['pageData']['offsets']['total'] == 0) {
363
                    //$module_results[$moduleName] .= "<li class='noBullet' id='whole_subpanel_{$moduleName}'><div id='div_{$moduleName}'><h2>" . $home_mod_strings['LBL_NO_RESULTS_IN_MODULE'] . '</h2></div></li>';
364
                    $module_results[$moduleName] .= '<h2>' . $home_mod_strings['LBL_NO_RESULTS_IN_MODULE'] . '</h2>';
365
                } else {
366
                    $has_results = true;
367
                    //$module_results[$moduleName] .= "<li class='noBullet' id='whole_subpanel_{$moduleName}'><div id='div_{$moduleName}'>" . $lv->display(false, false) . '</div></li>';
368
                    $module_results[$moduleName] .= $lv->display(false, false);
0 ignored issues
show
The call to ListViewSmarty::display() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
369
                }
370
371
			}
372
		}
373
374
		if($has_results) {
375
			foreach($module_counts as $name=>$value) {
376
				echo $module_results[$name];
377
			}
378
		} else if(empty($_REQUEST['form_only'])) {
379
			echo $home_mod_strings['LBL_NO_RESULTS'];
380
			echo $home_mod_strings['LBL_NO_RESULTS_TIPS'];
381
		}
382
383
	}
384
385
	function buildCache()
386
	{
387
388
		global $beanList, $beanFiles, $dictionary;
389
390
		$supported_modules = array();
391
392
		foreach($beanList as $moduleName=>$beanName)
393
		{
394
			if (!isset($beanFiles[$beanName]))
395
				continue;
396
397
			$beanName = BeanFactory::getObjectName($moduleName);
398
			$manager = new VardefManager ( );
399
			$manager->loadVardef( $moduleName , $beanName ) ;
400
401
			// obtain the field definitions used by generateSearchWhere (duplicate code in view.list.php)
402
			if(file_exists('custom/modules/'.$moduleName.'/metadata/metafiles.php')){
403
                require('custom/modules/'.$moduleName.'/metadata/metafiles.php');
404
            }elseif(file_exists('modules/'.$moduleName.'/metadata/metafiles.php')){
405
                require('modules/'.$moduleName.'/metadata/metafiles.php');
406
            }
407
408
409
			if(!empty($metafiles[$moduleName]['searchfields']))
410
			{
411
				require $metafiles[$moduleName]['searchfields'] ;
412
			} else if(file_exists("modules/{$moduleName}/metadata/SearchFields.php")) {
413
				require "modules/{$moduleName}/metadata/SearchFields.php" ;
414
			}
415
416
			//Load custom SearchFields.php if it exists
417
			if(file_exists("custom/modules/{$moduleName}/metadata/SearchFields.php"))
418
			{
419
				require "custom/modules/{$moduleName}/metadata/SearchFields.php" ;
420
			}				
421
422
            //If there are $searchFields are empty, just continue, there are no search fields defined for the module
423
            if(empty($searchFields[$moduleName]))
424
            {
425
                continue;
426
            }
427
428
			$isCustomModule = preg_match('/^([a-z0-9]{1,5})_([a-z0-9_]+)$/i' , $moduleName);
429
430
			//If the bean supports unified search or if it's a custom module bean and unified search is not defined
431
			if(!empty($dictionary[$beanName]['unified_search']) || $isCustomModule)
432
			{
433
				$fields = array();
434
				foreach ( $dictionary [ $beanName ][ 'fields' ] as $field => $def )
435
				{
436
					// We cannot enable or disable unified_search for email in the vardefs as we don't actually have a vardef entry for 'email'
437
					// the searchFields entry for 'email' doesn't correspond to any vardef entry. Instead it contains SQL to directly perform the search.
438
					// So as a proxy we allow any field in the vardefs that has a name starting with 'email...' to be tagged with the 'unified_search' parameter
439
440
					if (strpos($field,'email') !== false)
441
					{
442
						$field = 'email' ;
443
					}
444
445
					//bug: 38139 - allow phone to be searched through Global Search
446
					if (strpos($field,'phone') !== false)
447
					{
448
						$field = 'phone' ;
449
					}
450
451
					if ( !empty($def['unified_search']) && isset ( $searchFields [ $moduleName ] [ $field ]  ))
452
					{
453
						$fields [ $field ] = $searchFields [ $moduleName ] [ $field ] ;
454
					}
455
				}
456
457
                foreach ($searchFields[$moduleName] as $field => $def)
458
                {
459
                    if (
460
                        isset($def['force_unifiedsearch'])
461
                        and $def['force_unifiedsearch']
462
                    )
463
                    {
464
                        $fields[$field] = $def;
465
                    }
466
                }
467
468
				if(count($fields) > 0) {
469
					$supported_modules [$moduleName] ['fields'] = $fields;
470
					if (isset($dictionary[$beanName]['unified_search_default_enabled']) && $dictionary[$beanName]['unified_search_default_enabled'] === TRUE)
471
					{
472
                        $supported_modules [$moduleName]['default'] = true;
473
                    } else {
474
                        $supported_modules [$moduleName]['default'] = false;
475
                    }
476
				}
477
478
			}
479
480
		}
481
482
		ksort($supported_modules);
483
		write_array_to_file('unified_search_modules', $supported_modules, $this->cache_search);
484
	}
485
486
    /**
487
     * Retrieve the enabled and disabled modules used for global search.
488
     *
489
     * @return array
490
     */
491
    function retrieveEnabledAndDisabledModules()
492
    {
493
        global $app_list_strings;
494
495
        $unified_search_modules_display = $this->getUnifiedSearchModulesDisplay();
496
        //Add the translated attribute for display label
497
        $json_enabled = array();
498
        $json_disabled = array();
499
        foreach($unified_search_modules_display as $module=>$data)
500
        {
501
            $label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module;
502
            if($data['visible'] === true)
503
            {
504
                $json_enabled[] = array("module" => $module, 'label' => $label);
505
            }
506
            else
507
            {
508
                $json_disabled[] = array("module" => $module, 'label' => $label);
509
            }
510
        }
511
512
        //If the file doesn't exist
513
        if(!file_exists($this->cache_search))
514
        {
515
            $this->buildCache();
516
        }
517
518
        include($this->cache_search);
519
520
        //Now add any new modules that may have since been added to unified_search_modules.php
521
        foreach($unified_search_modules as $module=>$data)
0 ignored issues
show
The variable $unified_search_modules does not exist. Did you mean $unified_search_modules_display?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
522
        {
523
            if(!isset($unified_search_modules_display[$module]))
524
            {
525
                $label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module;
526
                if($data['default'])
527
                {
528
                  $json_enabled[] = array("module" => $module, 'label' => $label);
529
                } else {
530
                  $json_disabled[] = array("module" => $module, 'label' => $label);
531
                }
532
            }
533
        }
534
535
        return array('enabled' => $json_enabled, 'disabled' => $json_disabled);
536
    }
537
538
539
	/**
540
	 * saveGlobalSearchSettings
541
	 * This method handles the administrator's request to save the searchable modules selected and stores
542
	 * the results in the unified_search_modules_display.php file
543
	 *
544
	 */
545
	function saveGlobalSearchSettings()
546
	{
547
		if(isset($_REQUEST['enabled_modules']))
548
		{
549
            $unified_search_modules_display = $this->getUnifiedSearchModulesDisplay();
550
551
			$new_unified_search_modules_display = array();
552
553
            foreach(explode (',', $_REQUEST['enabled_modules'] ) as $module)
554
            {
555
                $new_unified_search_modules_display[$module]['visible'] = true;
556
            }
557
558
			foreach($unified_search_modules_display as $module=>$data)
559
			{
560
				if(!isset($new_unified_search_modules_display[$module]))
561
				{
562
				   $new_unified_search_modules_display[$module]['visible'] = false;
563
				}
564
			}
565
566
			$this->writeUnifiedSearchModulesDisplayFile($new_unified_search_modules_display);
567
		}
568
	}
569
570
571
	public static function unlinkUnifiedSearchModulesFile() {
572
		//clear the unified_search_module.php file
573
		$cache_search = sugar_cached('modules/unified_search_modules.php');
574
    	if(file_exists($cache_search))
575
    	{
576
    		$GLOBALS['log']->info("unlink {$cache_search}");
577
    		unlink($cache_search);
578
    	}
579
	}
580
    
581
582
    /**
583
     * getUnifiedSearchModules
584
     *
585
     * Returns the value of the $unified_search_modules variable based on the module's vardefs.php file
586
     * and which fields are marked with the unified_search attribute.
587
     *
588
     * @return $unified_search_modules Array of metadata module definitions along with their fields
0 ignored issues
show
The doc-type $unified_search_modules could not be parsed: Unknown type name "$unified_search_modules" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
589
     */
590
    public function getUnifiedSearchModules()
591
    {
592
		//Make directory if it doesn't exist
593
        $cachedir = sugar_cached('modules');
594
		if(!file_exists($cachedir))
595
		{
596
		   mkdir_recursive($cachedir);
597
		}
598
599
		//Load unified_search_modules.php file
600
        $cachedFile = sugar_cached('modules/unified_search_modules.php');
601
		if(!file_exists($cachedFile))
602
		{
603
			$this->buildCache();
604
		}
605
606
		include $cachedFile;
607
        return $unified_search_modules;
608
    }
609
610
611
    /**
612
     * getUnifiedSearchModulesDisplay
613
     *
614
     * Returns the value of the $unified_search_modules_display variable which is based on the $unified_search_modules
615
     * entries that have been selected to be allowed for searching.
616
     *
617
     * @return $unified_search_modules_display Array value of modules that have enabled for searching
0 ignored issues
show
The doc-type $unified_search_modules_display could not be parsed: Unknown type name "$unified_search_modules_display" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
618
     */
619
    public function getUnifiedSearchModulesDisplay()
620
    {
621
		if(!file_exists('custom/modules/unified_search_modules_display.php'))
622
		{
623
            $unified_search_modules = $this->getUnifiedSearchModules();
624
625
            $unified_search_modules_display = array();
626
627
            if(!empty($unified_search_modules))
628
            {
629
                foreach($unified_search_modules as $module=>$data)
630
                {
631
                    $unified_search_modules_display[$module]['visible'] = (isset($data['default']) && $data['default']) ? true : false;
632
                }
633
            }
634
635
            $this->writeUnifiedSearchModulesDisplayFile($unified_search_modules_display);
636
		}
637
638
		include('custom/modules/unified_search_modules_display.php');
639
        return $unified_search_modules_display;
640
    }
641
642
	/*
643
	 * writeUnifiedSearchModulesDisplayFile
644
	 * Private method to handle writing the unified_search_modules_display value to file
645
	 *
646
	 * @param mixed The array of the unified search modules and their display attributes
647
	 * @return boolean value indication whether or not file was successfully written
648
	 * @throws Exception Thrown if the file write operation fails
649
	 */
650
	private function writeUnifiedSearchModulesDisplayFile($unified_search_modules_display)
651
	{
652
		if(is_null($unified_search_modules_display) || empty($unified_search_modules_display))
653
		{
654
		   return false;
655
		}
656
657
	    if(!write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php'))
658
	    {
659
	    	//Log error message and throw Exception
660
	    	global $app_strings;
661
	    	$msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
662
	    	$GLOBALS['log']->error($msg);
663
	    	throw new Exception($msg);
664
	    }
665
666
	    return true;
667
	}
668
}
669
670
671
function unified_search_modules_cmp($a, $b) {
672
	if(!isset($a['translated']) || !isset($b['translated']))
673
	{
674
	   return 0;
675
	}
676
677
	$name1 = strtolower($a['translated']);
678
	$name2 = strtolower($b['translated']);
679
680
	return $name1 < $name2 ? -1 : 1;
681
}
682