Issues (141)

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.

formats/jqplot/SRF_jqPlotSeries.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
3
/**
4
 * A query printer for charts series using the jqPlot JavaScript library.
5
 *
6
 * @since 1.8
7
 * @licence GNU GPL v2 or later
8
 *
9
 * @author mwjames
10
 */
11
class SRFjqPlotSeries extends SMWResultPrinter {
12
13
	/**
14
	 * @see SMWResultPrinter::getName
15
	 */
16
	public function getName() {
17
		return wfMessage( 'srf-printername-jqplotseries' )->text();
18
	}
19
20
	/**
21
	 * Returns an array with the numerical data in the query result.
22
	 *
23
	 *
24
	 * @param SMWQueryResult $result
25
	 * @param $outputMode
26
	 *
27
	 * @return string
28
	 */
29
	protected function getResultText( SMWQueryResult $result, $outputMode ) {
30
31
		// Get data set
32
		$data = $this->getResultData( $result, $outputMode );
33
34
		// Check data availability
35
		if ( $data['series'] === [] ) {
36
			return $result->addErrors(
37
				[
38
					wfMessage( 'srf-warn-empy-chart' )
39
						->inContentLanguage()->text() ]
40
			);
41
		} else {
42
			$options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) );
0 ignored issues
show
Coding Style Comprehensibility introduced by mwjames
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
43
			return $this->getFormatOutput( $this->getFormatSettings( $this->getNumbersTicks( $data ), $options ) );
44
		}
45
	}
46
47
	/**
48
	 * Returns an array with the numerical data
49
	 *
50
	 * @since 1.8
51
	 *
52
	 * @param SMWQueryResult $result
53
	 * @param $outputMode
54
	 *
55
	 * @return array
56
	 */
57
	protected function getResultData( SMWQueryResult $res, $outputMode ) {
58
		$data = [];
59
		$data['series'] = [];
60
61
		while ( $row = $res->getNext() ) {
62
			// Loop over their fields (properties)
63
			$label = '';
64
			$i = 0;
65
66
			foreach ( $row as /* SMWResultArray */
67
					  $field ) {
68
				$i++;
69
				$rowNumbers = [];
70
71
				// Grouping by subject (page object) or property
72
				if ( $this->params['group'] === 'subject' ) {
73
					$groupedBy = $field->getResultSubject()->getTitle()->getText();
74
				} else {
75
					$groupedBy = $field->getPrintRequest()->getLabel();
76
				}
77
78
				// Property label
79
				$property = $field->getPrintRequest()->getLabel();
80
81
				// First column property typeid
82
				$i == 1 ? $data['fcolumntypeid'] = $field->getPrintRequest()->getTypeID() : '';
83
84
				// Loop over all values for the property.
85
				while ( ( /* SMWDataValue */
86
					$object = $field->getNextDataValue() ) !== false ) {
87
88
					if ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_NUMBER ) {
89
						$number = $object->getNumber();
90
91
						// Checking against the row and in case the first column is a numeric
92
						// value it is handled as label with the remaining steps continue to work
93
						// as it were a text label
94
						// The first column container will not be part of the series container
95
						if ( $i == 1 ) {
96
							$label = $number;
97
							continue;
98
						}
99
100
						if ( $label !== '' && $number >= $this->params['min'] ) {
101
102
							// Reference array summarize all items per row
103
							$rowNumbers += [ 'subject' => $label, 'value' => $number, 'property' => $property ];
104
105
							// Store plain numbers for simpler handling
106
							$data['series'][$groupedBy][] = $number;
107
						}
108
					} elseif ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_TIME ) {
109
						$label = $object->getShortWikiText();
110
					} else {
111
						$label = $object->getWikiValue();
112
					}
113
				}
114
				// Only for array's with numbers 
115
				if ( count( $rowNumbers ) > 0 ) {
116
117
					// For cases where mainlabel=- we assume that the subject should not be
118
					// used as identifier and therefore we try to match the groupby
119
					// with the first available text label
120
					if ( $this->params['mainlabel'] == '-' && $this->params['group'] === 'subject' ) {
121
						$data[$this->params['group']][$label][] = $rowNumbers;
122
					} else {
123
						$data[$this->params['group']][$groupedBy][] = $rowNumbers;
124
					}
125
				}
126
			}
127
		}
128
		return $data;
129
	}
130
131
	/**
132
	 * Data set sorting
133
	 *
134
	 * @since 1.8
135
	 *
136
	 * @param array $data label => value
137
	 *
138
	 * @return array
139
	 */
140
	private function getFormatSettings( $data, $options ) {
141
142
		// Init
143
		$dataSet = [];
144
		$options['mode'] = 'series';
145
		$options['autoscale'] = false;
146
147
		// Available markers
148
		$marker = [ 'circle', 'diamond', 'square', 'filledCircle', 'filledDiamond', 'filledSquare' ];
149
150
		// Series colour(has to be null otherwise jqplot runs with a type error)
151
		$seriescolors = $this->params['chartcolor'] !== '' ? array_filter(
152
			explode( ",", $this->params['chartcolor'] )
153
		) : null;
154
155
		// Re-grouping
156
		foreach ( $data[$this->params['group']] as $rowKey => $row ) {
157
			$values = [];
158
159
			foreach ( $row as $key => $value ) {
160
				// Switch labels according to the group parameter
161
				$label = $this->params['grouplabel'] === 'property' ? $value['property'] : $value['subject'];
162
				$values[] = [ $label, $value['value'] ];
163
			}
164
			$dataSet[] = $values;
165
		}
166
167
		// Series plotting parameters
168
		foreach ( $data[$this->params['group']] as $key => $row ) {
169
			$series[] = [
170
				'label' => $key,
171
				'xaxis' => 'xaxis', // xaxis could also be xaxis2 or ...
172
				'yaxis' => 'yaxis',
173
				'fill' => $this->params['stackseries'],
174
				'showLine' => $this->params['charttype'] !== 'scatter',
175
				'showMarker' => true,
176
				'trendline' => [
177
					'show' => in_array( $this->params['trendline'], [ 'exp', 'linear' ] ),
178
					'shadow' => $this->params['theme'] !== 'simple',
179
					'type' => $this->params['trendline'],
180
				],
181
				'markerOptions' => [
182
					'style' => $marker[array_rand( $marker )],
183
					'shadow' => $this->params['theme'] !== 'simple'
184
				],
185
				'rendererOptions' => [ 'barDirection' => $this->params['direction'] ]
186
			];
187
		};
188
189
		// Basic parameters
190
		$parameters = [
191
			'numbersaxislabel' => $this->params['numbersaxislabel'],
192
			'labelaxislabel' => $this->params['labelaxislabel'],
193
			'charttitle' => $this->params['charttitle'],
194
			'charttext' => $this->params['charttext'],
195
			'infotext' => $this->params['infotext'],
196
			'theme' => $this->params['theme'] ? $this->params['theme'] : null,
197
			'valueformat' => $this->params['datalabels'] === 'label' ? '' : $this->params['valueformat'],
198
			'ticklabels' => $this->params['ticklabels'],
199
			'highlighter' => $this->params['highlighter'],
200
			'autoscale' => $options['autoscale'],
201
			'gridview' => $this->params['gridview'],
202
			'direction' => $this->params['direction'],
203
			'smoothlines' => $this->params['smoothlines'],
204
			'cursor' => $this->params['cursor'],
205
			'chartlegend' => $this->params['chartlegend'] !== '' ? $this->params['chartlegend'] : 'none',
206
			'colorscheme' => $this->params['colorscheme'] !== '' ? $this->params['colorscheme'] : null,
207
			'pointlabels' => $this->params['datalabels'] === 'none' ? false : $this->params['datalabels'],
208
			'datalabels' => $this->params['datalabels'],
209
			'stackseries' => $this->params['stackseries'],
210
			'grid' => $this->params['theme'] === 'vector' ? [ 'borderColor' => '#a7d7f9' ] : ( $this->params['theme'] === 'simple' ? [ 'borderColor' => '#ddd' ] : null ),
211
			'seriescolors' => $seriescolors
212
		];
213
214
		return [
215
			'data' => $dataSet,
216
			//'rawdata'      => $data , // control array
217
			'series' => $series,
218
			'ticks' => $data['numbersticks'],
219
			'total' => $data['total'],
220
			'fcolumntypeid' => $data['fcolumntypeid'],
221
			'sask' => $options['sask'],
222
			'mode' => $options['mode'],
223
			'renderer' => $this->params['charttype'],
224
			'parameters' => $parameters
225
		];
226
	}
227
228
	/**
229
	 * Fetch numbers ticks
230
	 *
231
	 * @since 1.8
232
	 *
233
	 * @param array $data
234
	 */
235
	protected function getNumbersTicks( array $data ) {
236
237
		// Only look for numeric values that have been stored
238
		$numerics = array_values( $data['series'] );
239
240
		// Find min and max values to determine the graphs axis parameter
241
		$maxValue = count( $numerics ) == 0 ? 0 : max( array_map( "max", $numerics ) );
242
243
		if ( $this->params['min'] === false ) {
244
			$minValue = count( $numerics ) == 0 ? 0 : min( array_map( "min", $numerics ) );
245
		} else {
246
			$minValue = $this->params['min'];
247
		}
248
249
		// Get ticks info
250
		$data['numbersticks'] = SRFjqPlot::getNumbersTicks( $minValue, $maxValue );
251
		$data['total'] = array_sum( array_map( "array_sum", $numerics ) );
252
253
		return $data;
254
	}
255
256
	/**
257
	 * Add resource definitions
258
	 *
259
	 * @since 1.8
260
	 *
261
	 * @param array $data
262
	 *
263
	 * @return string
264
	 */
265
	protected function addResources() {
266
		// RL module
267
		switch ( $this->params['charttype'] ) {
268
			case 'bubble':
269
				SMWOutputs::requireResource( 'ext.srf.jqplot.bubble' );
270
				break;
271
			case 'donut':
272
				SMWOutputs::requireResource( 'ext.srf.jqplot.donut' );
273
				break;
274
			case 'scatter':
275
			case 'line':
276
			case 'bar':
277
				SMWOutputs::requireResource( 'ext.srf.jqplot.bar' );
278
				break;
279
		}
280
281
		// Trendline plugin
282
		if ( in_array( $this->params['trendline'], [ 'exp', 'linear' ] ) ) {
283
			SMWOutputs::requireResource( 'ext.srf.jqplot.trendline' );
284
		}
285
286
		// Cursor plugin
287
		if ( in_array( $this->params['cursor'], [ 'zoom', 'tooltip' ] ) ) {
288
			SMWOutputs::requireResource( 'ext.srf.jqplot.cursor' );
289
		}
290
291
		// Highlighter plugin
292
		if ( $this->params['highlighter'] ) {
293
			SMWOutputs::requireResource( 'ext.srf.jqplot.highlighter' );
294
		}
295
296
		// Enhancedlegend plugin
297
		if ( $this->params['chartlegend'] ) {
298
			SMWOutputs::requireResource( 'ext.srf.jqplot.enhancedlegend' );
299
		}
300
301
		// gridview plugin
302
		if ( in_array( $this->params['gridview'], [ 'tabs' ] ) ) {
303
			SMWOutputs::requireResource( 'ext.srf.util.grid' );
304
		}
305
306
		// Pointlabels plugin
307
		if ( in_array( $this->params['datalabels'], [ 'value', 'label', 'percent' ] ) ) {
308
			SMWOutputs::requireResource( 'ext.srf.jqplot.pointlabels' );
309
		}
310
	}
311
312
	/**
313
	 * Prepare data for the output
314
	 *
315
	 * @since 1.8
316
	 *
317
	 * @param array $data
318
	 *
319
	 * @return string
320
	 */
321
	protected function getFormatOutput( array $data ) {
322
323
		$this->isHTML = true;
324
325
		static $statNr = 0;
326
		$chartID = 'jqplot-series-' . ++$statNr;
327
328
		// Encoding
329
		$requireHeadItem = [ $chartID => FormatJson::encode( $data ) ];
330
		SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
331
332
		// Add RL resources
333
		$this->addResources();
334
335
		// Processing placeholder
336
		$processing = SRFUtils::htmlProcessingElement( $this->isHTML );
337
338
		// Conversion due to a string as value that can contain %
339
		$width = strstr( $this->params['width'], "%" ) ? $this->params['width'] : $this->params['width'] . 'px';
340
341
		// Chart/graph placeholder
342
		$chart = Html::rawElement(
343
			'div',
344
			[
345
				'id' => $chartID,
346
				'class' => 'container',
347
				'style' => "display:none; width: {$width}; height: {$this->params['height']}px;"
348
			],
349
			null
350
		);
351
352
		// Beautify class selector
353
		$class = $this->params['charttype'] ? '-' . $this->params['charttype'] : '';
354
		$class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class . ' jqplot-common';
355
356
		// Chart/graph wrappper
357
		return Html::rawElement(
358
			'div',
359
			[
360
				'class' => 'srf-jqplot' . $class,
361
			],
362
			$processing . $chart
363
		);
364
	}
365
366
	/**
367
	 * @see SMWResultPrinter::getParamDefinitions
368
	 *
369
	 * @since 1.8
370
	 *
371
	 * @param $definitions array of IParamDefinition
372
	 *
373
	 * @return array of IParamDefinition|array
374
	 */
375
	public function getParamDefinitions( array $definitions ) {
376
		$params = array_merge( parent::getParamDefinitions( $definitions ), SRFjqPlot::getCommonParams() );
377
378
		$params['infotext'] = [
379
			'message' => 'srf-paramdesc-infotext',
380
			'default' => '',
381
		];
382
383
		$params['stackseries'] = [
384
			'type' => 'boolean',
385
			'message' => 'srf-paramdesc-stackseries',
386
			'default' => false,
387
		];
388
389
		$params['group'] = [
390
			'message' => 'srf-paramdesc-group',
391
			'default' => 'subject',
392
			'values' => [ 'property', 'subject' ],
393
		];
394
395
		$params['grouplabel'] = [
396
			'message' => 'srf-paramdesc-grouplabel',
397
			'default' => 'subject',
398
			'values' => [ 'property', 'subject' ],
399
		];
400
401
		$params['charttype'] = [
402
			'message' => 'srf-paramdesc-charttype',
403
			'default' => 'bar',
404
			'values' => [ 'bar', 'line', 'donut', 'bubble', 'scatter' ],
405
		];
406
407
		$params['trendline'] = [
408
			'message' => 'srf-paramdesc-trendline',
409
			'default' => 'none',
410
			'values' => [ 'none', 'exp', 'linear' ],
411
		];
412
413
		$params['cursor'] = [
414
			'message' => 'srf-paramdesc-chartcursor',
415
			'default' => 'none',
416
			'values' => [ 'none', 'zoom', 'tooltip' ],
417
		];
418
419
		$params['gridview'] = [
420
			'message' => 'srf-paramdesc-gridview',
421
			'default' => 'none',
422
			'values' => [ 'none', 'tabs' ],
423
		];
424
425
		return $params;
426
	}
427
}