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/Dashlets/DashletGenericChart.php (1 issue)

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
require_once('include/Dashlets/Dashlet.php');
42
require_once('include/generic/LayoutManager.php');
43
44
abstract class DashletGenericChart extends Dashlet
45
{
46
    /**
47
     * The title of the dashlet
48
     * @var string
49
     */
50
    public $title;
51
52
    public $noDataMessage = "No Results";
53
54
    /**
55
     * @see Dashlet::$isConfigurable
56
     */
57
    public $isConfigurable = true;
58
59
    /**
60
     * @see Dashlet::$isRefreshable
61
     */
62
    public $isRefreshable  = true;
63
64
    /**
65
     * location of smarty template file for configuring
66
     * @var string
67
     */
68
    protected $_configureTpl = 'include/Dashlets/DashletGenericChartConfigure.tpl';
69
70
    /**
71
     * Bean file used in this Dashlet
72
     * @var object
73
     */
74
    private $_seedBean;
75
76
    /**
77
     * Module used in this Dashlet
78
     * @var string
79
     */
80
    protected $_seedName;
81
82
    /**
83
     * Array of fields and thier defintions that we are searching on
84
     * @var array
85
     */
86
    protected $_searchFields;
87
88
    /**
89
     * smarty object for the generic configuration template
90
     * @var object
91
     */
92
    private $_configureSS;
93
94
95
    /**
96
     * Constructor
97
     *
98
     * @param int   $id
99
     * @param array $options
100
     */
101
    public function __construct(
102
        $id,
103
        array $options = null
104
        )
105
    {
106
        parent::__construct($id);
107
108
        if ( isset($options) ) {
109
            foreach ( $options as $key => $value ) {
110
                $this->$key = $value;
111
            }
112
        }
113
114
        // load searchfields
115
        $classname = get_class($this);
116
        if ( is_file("modules/Charts/Dashlets/$classname/$classname.data.php") ) {
117
            require("modules/Charts/Dashlets/$classname/$classname.data.php");
118
            $this->_searchFields = $dashletData[$classname]['searchFields'];
119
        }
120
121
        // load language files
122
        $this->loadLanguage($classname, 'modules/Charts/Dashlets/');
123
124
        if ( empty($options['title']) )
125
            $this->title = $this->dashletStrings['LBL_TITLE'];
126
        if ( isset($options['autoRefresh']) )
127
            $this->autoRefresh = $options['autoRefresh'];
128
129
        $this->layoutManager = new LayoutManager();
130
        $this->layoutManager->setAttribute('context', 'Report');
131
        // fake a reporter object here just to pass along the db type used in many widgets.
132
        // this should be taken out when sugarwidgets change
133
        $temp = (object) array('db' => &$GLOBALS['db'], 'report_def_str' => '');
134
        $this->layoutManager->setAttributePtr('reporter', $temp);
135
    }
136
137
    /**
138
     * @see Dashlet::setRefreshIcon()
139
     */
140
    public function setRefreshIcon()
141
    {
142
    	$additionalTitle = '';
143
        if($this->isRefreshable)
144
145
            $additionalTitle .= '<a href="#" onclick="SUGAR.mySugar.retrieveDashlet(\''
146
                . $this->id
147
                . '\',\'predefined_chart\'); return false;"><!--not_in_theme!-->'
148
                . SugarThemeRegistry::current()->getImage(
149
                    'dashlet-header-refresh',
150
                    'border="0" align="absmiddle" title="'. translate('LBL_DASHLET_REFRESH', 'Home') . '"',
151
                    null,
152
                    null,
153
                    '.gif',
154
                    translate('LBL_DASHLET_REFRESH', 'Home')
155
                )
156
                . '</a>';
157
        return $additionalTitle;
158
    }
159
160
    /**
161
     * Displays the javascript for the dashlet
162
     *
163
     * @return string javascript to use with this dashlet
164
     */
165
    public function displayScript()
166
    {
167
168
		require_once('include/SugarCharts/SugarChartFactory.php');
169
		$sugarChart = SugarChartFactory::getInstance();
170
		return $sugarChart->getDashletScript($this->id);
171
172
    }
173
174
    /**
175
     * Gets the smarty object for the config window. Designed to allow lazy loading the object
176
     * when it's needed.
177
     */
178
    protected function getConfigureSmartyInstance()
179
    {
180
        if ( !($this->_configureSS instanceof Sugar_Smarty) ) {
181
182
            $this->_configureSS = new Sugar_Smarty();
183
        }
184
185
        return $this->_configureSS;
186
    }
187
188
    /**
189
     * Saves the chart config options
190
     * Filter the $_REQUEST and only save only the needed options
191
     *
192
     * @param  array $req
193
     * @return array
194
     */
195
    public function saveOptions(
196
        $req
197
        )
198
    {
199
        global $timedate;
200
201
        $options = array();
202
203
        foreach($req as $name => $value)
204
            if(!is_array($value)) $req[$name] = trim($value);
205
206
        foreach($this->_searchFields as $name => $params) {
207
            $widgetDef = $params;
208
            if ( isset($this->getSeedBean()->field_defs[$name]) )
209
                $widgetDef = $this->getSeedBean()->field_defs[$name];
210
            if ( $widgetDef['type'] == 'date')           // special case date types
211
                $options[$widgetDef['name']] = $timedate->swap_formats($req['type_'.$widgetDef['name']], $timedate->get_date_format(), $timedate->dbDayFormat);
212
            elseif ( $widgetDef['type'] == 'time')       // special case time types
213
                $options[$widgetDef['name']] = $timedate->swap_formats($req['type_'.$widgetDef['name']], $timedate->get_time_format(), $timedate->dbTimeFormat);
214
            elseif ( $widgetDef['type'] == 'datepicker') // special case datepicker types
215
                $options[$widgetDef['name']] = $timedate->swap_formats($req[$widgetDef['name']], $timedate->get_date_format(), $timedate->dbDayFormat);
216
            elseif (!empty($req[$widgetDef['name']]))
217
                $options[$widgetDef['name']] = $req[$widgetDef['name']];
218
        }
219
220
        if (!empty($req['dashletTitle']))
221
            $options['title'] = $req['dashletTitle'];
222
223
        $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh'];
224
225
        return $options;
226
    }
227
228
    /**
229
     * Handles displaying the chart dashlet configuration popup window
230
     *
231
     * @return string HTML to return to the browser
232
     */
233
    public function displayOptions()
234
    {
235
        $currentSearchFields = array();
236
237
        if ( is_array($this->_searchFields) ) {
238
            foreach($this->_searchFields as $name=>$params) {
239
                if(!empty($name)) {
240
                    $name = strtolower($name);
241
                    $currentSearchFields[$name] = array();
242
243
                    $widgetDef = $params;
244
                    if ( isset($this->getSeedBean()->field_defs[$name]) )
245
                        $widgetDef = $this->getSeedBean()->field_defs[$name];
246
247
                    if($widgetDef['type'] == 'enum' || $widgetDef['type'] == 'singleenum') $widgetDef['remove_blank'] = true; // remove the blank option for the dropdown
248
249
                    if ( empty($widgetDef['input_name0']) )
250
                        $widgetDef['input_name0'] = empty($this->$name) ? '' : $this->$name;
251
                    $currentSearchFields[$name]['label'] = translate($widgetDef['vname'], $this->getSeedBean()->module_dir);
252
                    if ( $currentSearchFields[$name]['label'] == $widgetDef['vname'] )
253
                        $currentSearchFields[$name]['label'] = translate($widgetDef['vname'], 'Charts');
254
                    $currentSearchFields[$name]['input'] = $this->layoutManager->widgetDisplayInput($widgetDef, true, (empty($this->$name) ? '' : $this->$name));
255
                }
256
                else { // ability to create spacers in input fields
257
                    $currentSearchFields['blank' + $count]['label'] = '';
258
                    $currentSearchFields['blank' + $count]['input'] = '';
259
                    $count++;
260
                }
261
            }
262
        }
263
        $this->currentSearchFields = $currentSearchFields;
264
        $this->getConfigureSmartyInstance()->assign('title',translate('LBL_TITLE','Charts'));
265
        $this->getConfigureSmartyInstance()->assign('save',$GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL']);
266
        $this->getConfigureSmartyInstance()->assign('clear',$GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL']);
267
        $this->getConfigureSmartyInstance()->assign('id', $this->id);
268
        $this->getConfigureSmartyInstance()->assign('searchFields', $this->currentSearchFields);
269
        $this->getConfigureSmartyInstance()->assign('dashletTitle', $this->title);
270
        $this->getConfigureSmartyInstance()->assign('dashletType', 'predefined_chart');
271
        $this->getConfigureSmartyInstance()->assign('module', $_REQUEST['module']);
272
        $this->getConfigureSmartyInstance()->assign('showClearButton', $this->isConfigPanelClearShown);
273
274
        if($this->isAutoRefreshable()) {
275
       		$this->getConfigureSmartyInstance()->assign('isRefreshable', true);
276
			$this->getConfigureSmartyInstance()->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']);
277
			$this->getConfigureSmartyInstance()->assign('autoRefreshOptions', $this->getAutoRefreshOptions());
278
			$this->getConfigureSmartyInstance()->assign('autoRefreshSelect', $this->autoRefresh);
279
		}
280
281
        return parent::displayOptions() . $this->getConfigureSmartyInstance()->fetch($this->_configureTpl);
282
    }
283
284
    /**
285
     * Returns the DashletGenericChart::_seedBean object. Designed to allow lazy loading the object
286
     * when it's needed.
287
     *
288
     * @return object
289
     */
290
    protected function getSeedBean()
291
    {
292
        if ( !($this->_seedBean instanceof SugarBean) )
293
            $this->_seedBean = SugarModule::get($this->_seedName)->loadBean();
294
295
        return $this->_seedBean;
296
    }
297
298
    /**
299
     * Returns the built query read to feed into SugarChart::getData()
300
     *
301
     * @return string SQL query
302
     */
303
    protected function constructQuery()
304
    {
305
        return '';
306
    }
307
308
    /**
309
     * Returns the array of group by parameters for SugarChart::$group_by
310
     *
311
     * @return string SQL query
312
     */
313
    protected function constructGroupBy()
314
    {
315
        return array();
316
    }
317
318
    /**
319
     * Displays the Dashlet, must call process() prior to calling this
320
     *
321
     * @return string HTML that displays Dashlet
322
     */
323
    public function display()
324
    {
325
        return parent::display() . $this->processAutoRefresh();
326
    }
327
328
    /**
329
     * Processes and displays the auto refresh code for the dashlet
330
     *
331
     * @param int $dashletOffset
332
     * @return string HTML code
333
     */
334
    protected function processAutoRefresh($dashletOffset = 0)
335
    {
336
        global $sugar_config;
337
338
        if ( empty($dashletOffset) ) {
339
            $dashletOffset = 0;
340
            $module = $_REQUEST['module'];
341
            if(isset($_REQUEST[$module.'2_'.strtoupper($this->getSeedBean()->object_name).'_offset'])) {
342
            	$dashletOffset = $_REQUEST[$module.'2_'.strtoupper($this->getSeedBean()->object_name).'_offset'];
343
            }
344
        }
345
346
        if ( !$this->isRefreshable ) {
347
            return '';
348
        }
349
        if ( !empty($sugar_config['dashlet_auto_refresh_min']) && $sugar_config['dashlet_auto_refresh_min'] == -1 ) {
350
            return '';
351
        }
352
        $autoRefreshSS = new Sugar_Smarty();
353
        $autoRefreshSS->assign('dashletOffset', $dashletOffset);
354
        $autoRefreshSS->assign('dashletId', $this->id);
355
        $autoRefreshSS->assign('strippedDashletId', str_replace("-","",$this->id)); //javascript doesn't like "-" in function names
356
        $autoRefreshSS->assign('dashletRefreshInterval', $this->getAutoRefresh());
357
        $autoRefreshSS->assign('url', "predefined_chart");
358
        $tpl = 'include/Dashlets/DashletGenericAutoRefresh.tpl';
359
        if ( $_REQUEST['action'] == "DynamicAction" ) {
360
            $tpl = 'include/Dashlets/DashletGenericAutoRefreshDynamic.tpl';
361
        }
362
363
        return $autoRefreshSS->fetch($tpl);
364
    }
365
366
    //Added as the rgraph charts do not use SugarCharts and this is where this method was previously
367
    function getChartData($query)
368
    {
369
        global $app_list_strings, $db;
370
        $dataSet = array();
371
        $result = $db->query($query);
372
373
        $row = $db->fetchByAssoc($result);
374
375
        while ($row != null){
376
            $dataSet[] = $row;
377
            $row = $db->fetchByAssoc($result);
378
        }
379
        return $dataSet;
380
    }
381
382
    /**
383
      PG copied verbatim from SugarChart as there is no longer the dependency on this from RGraph charts
384
385
    This function is used for localize all the characters in the Chart. And it can also sort all the dom_values by the sequence defined in the dom, but this may produce a lot of extra empty data in the xml file, when the chart is sorted by two key cols.
386
    If the data quantity is large, it maybe a little slow.
387
     * @param         array $data_set           The data get from database
388
    string $keycolname1      We will sort by this key first
389
    bool $translate1            Whether to trabslate the first column
390
    string $keycolname1      We will sort by this key secondly, and  it can be null, then it will only sort by the first column.
391
    bool $translate1            Whether to trabslate the second column
392
    bool $ifsort2                 Whether to sort by the second column or just translate the second column.
393
     * @return        The sorted and translated data.
394
     */
395
    function sortData($data_set, $keycolname1=null, $translate1=false, $keycolname2=null, $translate2=false, $ifsort2=false) {
396
        //You can set whether the columns need to be translated or sorted. It the column needn't to be translated, the sorting must be done in SQL, this function will not do the sorting.
397
        global $app_list_strings;
398
        $sortby1[] = array();
399
        foreach ($data_set as $row) {
400
            $sortby1[]  = $row[$keycolname1];
401
        }
402
        $sortby1 = array_unique($sortby1);
403
        //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
404
        if($translate1) {
405
            $temp_sortby1 = array();
406
            foreach(array_keys($app_list_strings[$keycolname1.'_dom']) as $sortby1_value) {
407
                if(in_array($sortby1_value, $sortby1)) {
408
                    $temp_sortby1[] = $sortby1_value;
409
                }
410
            }
411
            $sortby1 = $temp_sortby1;
412
        }
413
414
        //if(isset($sortby1[0]) && $sortby1[0]=='') unset($sortby1[0]);//the beginning of lead_source_dom is blank.
415
        if(isset($sortby1[0]) && $sortby1[0]==array()) unset($sortby1[0]);//the beginning of month after search is blank.
416
417
        if($ifsort2==false) $sortby2=array(0);
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
418
419
        if($keycolname2!=null) {
420
            $sortby2 = array();
421
            foreach ($data_set as $row) {
422
                $sortby2[]  = $row[$keycolname2];
423
            }
424
            //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
425
            $sortby2 = array_unique($sortby2);
426
            if($translate2) {
427
                $temp_sortby2 = array();
428
                foreach(array_keys($app_list_strings[$keycolname2.'_dom']) as $sortby2_value) {
429
                    if(in_array($sortby2_value, $sortby2)) {
430
                        $temp_sortby2[] = $sortby2_value;
431
                    }
432
                }
433
                $sortby2 = $temp_sortby2;
434
            }
435
        }
436
437
        $data=array();
438
439
        foreach($sortby1 as $sort1) {
440
            foreach($sortby2 as $sort2) {
441
                if($ifsort2) $a=0;
442
                foreach($data_set as $key => $value){
443
                    if($value[$keycolname1] == $sort1 && (!$ifsort2 || $value[$keycolname2]== $sort2)) {
444
                        if($translate1) {
445
                            $value[$keycolname1.'_dom_option'] = $value[$keycolname1];
446
                            $value[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$value[$keycolname1]];
447
                        }
448
                        if($translate2) {
449
                            $value[$keycolname2.'_dom_option'] = $value[$keycolname2];
450
                            $value[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$value[$keycolname2]];
451
                        }
452
                        array_push($data, $value);
453
                        unset($data_set[$key]);
454
                        $a=1;
455
                    }
456
                }
457
                if($ifsort2 && $a==0) {//Add 0 for sorting by the second column, if the first row doesn't have a certain col, it will fill the column with 0.
458
                    $val=array();
459
                    $val['total'] = 0;
460
                    $val['count'] = 0;
461
                    if($translate1) {
462
                        $val[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$sort1];
463
                        $val[$keycolname1.'_dom_option'] = $sort1;
464
                    }
465
                    else {
466
                        $val[$keycolname1] = $sort1;
467
                    }
468
                    if($translate2) {
469
                        $val[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$sort2];
470
                        $val[$keycolname2.'_dom_option'] = $sort2;
471
                    }
472
                    elseif($keycolname2!=null) {
473
                        $val[$keycolname2] = $sort2;
474
                    }
475
                    array_push($data, $val);
476
                }
477
            }
478
        }
479
        return $data;
480
    }
481
}
482