Issues (150)

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/filtered/src/Filtered.php (3 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
3
/**
4
 * File holding the SRFFiltered class.
5
 *
6
 * @author Stephan Gambke
7
 *
8
 */
9
10
namespace SRF\Filtered;
11
12
use Exception;
13
use Html;
14
use SMW\Message;
15
use SMW\Query\PrintRequest;
16
use SMW\Query\QueryLinker;
17
use SMW\Query\ResultPrinters\ResultPrinter;
18
use SMWOutputs;
19
use SMWPropertyValue;
20
use SMWQueryResult;
21
22
/**
23
 * Result printer that displays results in switchable views and offers
24
 * client-side (JavaScript based) filtering.
25
 *
26
 * This result printer is ultimately planned to replace exhibit. Currently only
27
 * a list view is available. It is not yet possible to switch between views.
28
 * There is also only the 'value' filter available yet.
29
 *
30
 * Syntax of the #ask call:
31
 * (This is only a syntax example. For currently available features see the
32
 * documentation of the various classes.)
33
 *
34
 * {{#ask:[[SomeCondition]]
35
 * |? SomePrintout |+filter=value, someFutureFilter |+value filter switches=and or, disable, all, none |+someFutureFilter filter option=someOptionValue
36
 * |? SomeOtherPrintout |+filter=value, someOtherFutureFilter |+someOtherFutureFilter filter option=someOptionValue
37
 *
38
 * |format=filtered
39
 * |views=list, someFutureView, someOtherFutureView
40
 *
41
 * |list view type=list
42
 * |list view template=ListItem
43
 *
44
 * |someFutureView view option=someOptionValue
45
 *
46
 * |someOtherFutureView view option=someOptionValue
47
 *
48
 * }}
49
 *
50
 * All format specific parameters are optional, although leaving the 'views'
51
 * parameter empty probably does not make much sense.
52
 *
53
 */
54
class Filtered extends ResultPrinter {
55
56
	/**
57
	 * The available view types
58
	 *
59
	 * @var array of Strings
60
	 */
61
	private $mViewTypes = [
62
		'list' => 'ListView',
63
		'calendar' => 'CalendarView',
64
		'table' => 'TableView',
65
		'map' => 'MapView',
66
	];
67
68
	/**
69
	 * The available filter types
70
	 *
71
	 * @var array of Strings
72
	 */
73
	private $mFilterTypes = [
74
		'value' => 'ValueFilter',
75
		'distance' => 'DistanceFilter',
76
		'number' => 'NumberFilter',
77
	];
78
79
	private $viewNames;
80
	private $parameters;
81
	private $filtersOnTop;
82
	private $printrequests;
83
84
	private $parser;
85
86
	/**
87
	 * @param string $valueList
88
	 * @param string $delimiter
89
	 *
90
	 * @return string[]
91
	 */
92 1
	public function getArrayFromValueList( $valueList, $delimiter = ',' ) {
93 1
		return array_map( 'trim', explode( $delimiter, $valueList ) );
94
	}
95
96
	/**
97
	 * @return \Parser | \StubObject | null
98
	 */
99 2
	public function getParser() {
100
101 2
		if ( $this->parser === null ) {
102 2
			$this->setParser( $GLOBALS['wgParser'] );
103
		}
104
105 2
		return $this->parser;
106
	}
107
108
	/**
109
	 * @param \Parser | \StubObject $parser
110
	 */
111 2
	public function setParser( $parser ) {
112 2
		$this->parser = $parser;
113 2
	}
114
115
	/**
116
	 * @return mixed
117
	 */
118
	public function getPrintrequests() {
119
		return $this->printrequests;
120
	}
121
122
	public function hasTemplates( $hasTemplates = null ) {
123
		$ret = $this->hasTemplates;
124
		if ( is_bool( $hasTemplates ) ) {
125
			$this->hasTemplates = $hasTemplates;
126
		}
127
		return $ret;
128
	}
129
130
	/**
131
	 * Get a human readable label for this printer.
132
	 *
133
	 * @return string
134
	 */
135
	public function getName() {
136
		return wfMessage( 'srf-printername-filtered' )->text();
137
	}
138
139
	/**
140
	 * Does any additional parameter handling that needs to be done before the
141
	 * actual result is build.
142
	 *
143
	 * @param array $params
144
	 * @param $outputMode
145
	 */
146 2
	protected function handleParameters( array $params, $outputMode ) {
147 2
		parent::handleParameters( $params, $outputMode );
148
149
		// // Set in SMWResultPrinter:
150
		// $this->mIntro = $params['intro'];
151
		// $this->mOutro = $params['outro'];
152
		// $this->mSearchlabel = $params['searchlabel'] === false ? null : $params['searchlabel'];
153
		// $this->mLinkFirst = true | false;
154
		// $this->mLinkOthers = true | false;
155
		// $this->mDefault = str_replace( '_', ' ', $params['default'] );
156
		// $this->mShowHeaders = SMW_HEADERS_HIDE | SMW_HEADERS_PLAIN | SMW_HEADERS_SHOW;
157
158 2
		$this->mSearchlabel = null;
159
160 2
		$this->parameters = $params;
161 2
		$this->viewNames = explode( ',', $params['views'] );
162 2
		$this->filtersOnTop = $params['filter position'] === 'top';
163
164 2
	}
165
166
	/**
167
	 * Return serialised results in specified format.
168
	 *
169
	 * @param SMWQueryResult $res
170
	 * @param $outputmode
171
	 *
172
	 * @return string
173
	 */
174 2
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
175
176
		// collect the query results in an array
177
		/** @var ResultItem[] $resultItems */
178 2
		$resultItems = [];
179 2
		while ( $row = $res->getNext() ) {
180 2
			$resultItems[$this->uniqid()] = new ResultItem( $row, $this );
181 2
			usleep( 1 ); // This is ugly, but for now th opnly way to get all resultItems. See #288.
182
		}
183
184
		$config = [
185 2
			'query' => $res->getQueryString(),
186
			'printrequests' => [],
187
			'views' => [],
188
			'data' => [],
189
		];
190
191 2
		list( $filterHtml, $printrequests ) = $this->getFilterHtml( $res, $resultItems );
192
193 2
		$this->printrequests = $printrequests;
194 2
		$config['printrequests'] = $printrequests;
195
196 2
		list( $viewHtml, $config ) = $this->getViewHtml( $res, $resultItems, $config );
197
198 2
		SMWOutputs::requireResource( 'ext.srf.filtered' );
199
200 2
		$id = $this->uniqid();
201
		// wrap all in a div
202 2
		$html = '<div class="filtered-spinner"><div class="smw-overlay-spinner"></div></div>';
203 2
		$html .= $this->filtersOnTop ? $filterHtml . $viewHtml : $viewHtml . $filterHtml;
204 2
		$html = Html::rawElement( 'div', [ 'class' => 'filtered ' . $id, 'id' => $id ], $html );
205
206 2
		$config['data'] = $this->getResultsForJs( $resultItems );
207
208 2
		$config['filtersOnTop'] = $this->filtersOnTop;
209 2
		$this->addConfigToOutput( $id, $config );
210
211
		try {
212 2
			$this->fullParams['limit']->getOriginalValue();
213
		}
214
		catch ( Exception $exception ) {
215
			$res->getQuery()->setLimit( 0 );
216
		}
217
218 2
		$link = QueryLinker::get( $res->getQuery() );
219 2
		$link->setCaption( Message::get( "srf-filtered-noscript-link-caption" ) );
220 2
		$link->setParameter( 'table', 'format' );
221
222 2
		SMWOutputs::requireResource( 'ext.srf.filtered' );
223 2
		$this->registerResources( [], [ 'ext.srf.filtered' ] );
224
225 2
		return $html;
226
	}
227
228
	/**
229
	 * @see SMWResultPrinter::getParamDefinitions
230
	 * @see DefaultConfig.php of param-processor/param-processor for allowed types
231
	 *
232
	 * @since 1.8
233
	 *
234
	 * @param $definitions array of IParamDefinition
235
	 *
236
	 * @return array of IParamDefinition|array
237
	 */
238 2
	public function getParamDefinitions( array $definitions ) {
239 2
		$params = parent::getParamDefinitions( $definitions );
240
241 2
		$params[] = [
242
			// 'type' => 'string',
243
			'name' => 'views',
244
			'message' => 'srf-paramdesc-filtered-views',
245
			'default' => '',
246
			// 'islist' => false,
247
		];
248
249 2
		$params[] = [
250
			// 'type' => 'string',
251
			'name' => 'filter position',
252
			'message' => 'srf-paramdesc-filtered-filter-position',
253
			'default' => 'top',
254
			// 'islist' => false,
255
		];
256
257 2
		foreach ( $this->mViewTypes as $viewType ) {
258 2
			$params = array_merge( $params, call_user_func( [ 'SRF\Filtered\View\\' . $viewType, 'getParameters' ] ) );
259
		}
260
261 2
		return $params;
262
	}
263
264 2
	public function getLinker( $firstcol = false, $force = false ) {
265 2
		return ( $force ) ? $this->mLinker : parent::getLinker( $firstcol );
266
	}
267
268 2
	private function addConfigToOutput( $id, $config ) {
269
270 2
		if ( $this->getParser()->getOutput() !== null ) {
271 2
			$getter = [ $this->getParser()->getOutput(), 'getExtensionData' ];
272 2
			$setter = [ $this->getParser()->getOutput(), 'setExtensionData' ];
273
		} else {
274
			$getter = [ \RequestContext::getMain()->getOutput(), 'getProperty' ];
275
			$setter = [ \RequestContext::getMain()->getOutput(), 'setProperty' ];
276
		}
277
278 2
		$previousConfig = call_user_func( $getter, 'srf-filtered-config' );
279
280 2
		if ( $previousConfig === null ) {
281 2
			$previousConfig = [];
282
		}
283
284 2
		$previousConfig[$id] = $config;
285
286 2
		call_user_func( $setter, 'srf-filtered-config', $previousConfig );
287
288 2
	}
289
290
	/**
291
	 * @param string | string[] | null $resourceModules
292
	 */
293 1
	protected function registerResourceModules( $resourceModules ) {
294
295 1
		array_map( 'SMWOutputs::requireResource', (array)$resourceModules );
296 1
	}
297
298
	/**
299
	 * @param string|null $id
300
	 *
301
	 * @return string
302
	 */
303 2
	public function uniqid( $id = null ) {
304 2
		$hashedId = ( $id === null ) ? uniqid() : md5( $id );
305 2
		return base_convert( $hashedId, 16, 36 );
306
	}
307
308
	/**
309
	 * @param ResultItem[] $result
310
	 *
311
	 * @return array
312
	 */
313 2
	protected function getResultsForJs( $result ) {
314 2
		$resultAsArray = [];
315 2
		foreach ( $result as $id => $row ) {
316 2
			$resultAsArray[$id] = $row->getArrayRepresentation();
317
		}
318 2
		return $resultAsArray;
319
	}
320
321 1
	public function addError( $errorMessage ) {
322 1
		parent::addError( $errorMessage );
323 1
	}
324
325
	/**
326
	 * @param SMWQueryResult $res
327
	 * @param $result
328
	 *
329
	 * @return array
330
	 */
331 2
	protected function getFilterHtml( SMWQueryResult $res, $result ) {
332
333
		// prepare filter data for inclusion in HTML and  JS
334 2
		$filterHtml = '';
335
336 2
		$printrequests = [];
337
338
		/** @var PrintRequest $printRequest */
339 2
		foreach ( $res->getPrintRequests() as $printRequest ) {
340
341
			$prConfig = [
342 2
				'mode' => $printRequest->getMode(),
343 2
				'label' => $printRequest->getLabel(),
344 2
				'outputformat' => $printRequest->getOutputFormat(),
345 2
				'type' => $printRequest->getTypeID(),
346
			];
347
348 2
			if ( $printRequest->getData() instanceof SMWPropertyValue ) {
0 ignored issues
show
The class SMWPropertyValue does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
349 2
				$prConfig['property'] = $printRequest->getData()->getInceptiveProperty()->getKey();
350
			}
351
352 2
			if ( filter_var( $printRequest->getParameter( 'hide' ), FILTER_VALIDATE_BOOLEAN ) ) {
353
				$prConfig['hide'] = true;
354
			}
355
356 2
			$filtersParam = $printRequest->getParameter( 'filter' );
357
358 2
			if ( $filtersParam ) {
359
360 1
				$filtersForPrintout = $this->getArrayFromValueList( $filtersParam );
361
362 1
				foreach ( $filtersForPrintout as $filterName ) {
363
364 1
					if ( array_key_exists( $filterName, $this->mFilterTypes ) ) {
365
366
						/** @var \SRF\Filtered\Filter\Filter $filter */
367 1
						$filterClassName = '\SRF\Filtered\Filter\\' . $this->mFilterTypes[$filterName];
368 1
						$filter = new  $filterClassName( $result, $printRequest, $this );
369
370 1
						if ( $filter->isValidFilterForPropertyType() ) {
371
372 1
							$this->registerResourceModules( $filter->getResourceModules() );
373
374 1
							$filterid = $this->uniqid();
375 1
							$filterHtml .= Html::rawElement(
376 1
								'div',
377 1
								[ 'id' => $filterid, 'class' => "filtered-filter filtered-$filterName" ],
378 1
								$filter->getResultText()
379
							);
380
381 1
							$filterdata = $filter->getJsConfig();
382 1
							$filterdata['type'] = $filterName;
383 1
							$filterdata['label'] = $printRequest->getLabel();
384
385 1
							$prConfig['filters'][$filterid] = $filterdata;
386
387 1
							foreach ( $result as $row ) {
388 1
								$row->setData( $filterid, $filter->getJsDataForRow( $row ) );
389
							}
390
						} else {
391
							// TODO: I18N
392 1
							$this->addError(
393 1
								"The '$filterName' filter can not be used on the '{$printRequest->getLabel()}' printout."
394
							);
395
						}
396
397
					}
398
				}
399
			}
400
401 2
			$printrequests[$this->uniqid( $printRequest->getHash() )] = $prConfig;
0 ignored issues
show
It seems like $printRequest->getHash() targeting SMW\Query\PrintRequest::getHash() can also be of type boolean; however, SRF\Filtered\Filtered::uniqid() does only seem to accept string|null, 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...
402
		}
403
404 2
		$filterHtml .= '<div class="filtered-filter-spinner" style="display: none;"><div class="smw-overlay-spinner"></div></div>';
405
406
		// wrap filters in a div
407 2
		$filterHtml = Html::rawElement(
408 2
			'div',
409 2
			[ 'class' => 'filtered-filters', 'style' => 'display:none' ],
410 2
			$filterHtml
411
		);
412
413 2
		return [ $filterHtml, $printrequests ];
414
	}
415
416
	/**
417
	 * @param SMWQueryResult $res
418
	 * @param $resultItems
419
	 * @param $config
420
	 *
421
	 * @return array
422
	 */
423 2
	protected function getViewHtml( SMWQueryResult $res, $resultItems, $config ) {
424
425
		// prepare view data for inclusion in HTML and  JS
426 2
		$viewHtml = '';
427 2
		$viewSelectorsHtml = '';
428
429 2
		foreach ( $this->viewNames as $viewName ) {
430
431
			// cut off the selector label (if one was specified) from the actual view name
432 2
			$viewnameComponents = explode( '=', $viewName, 2 );
433
434 2
			$viewName = trim( $viewnameComponents[0] );
435
436 2
			if ( array_key_exists( $viewName, $this->mViewTypes ) ) {
437
438
				// generate unique id
439 2
				$viewid = $this->uniqid();
440
441 2
				if ( count( $viewnameComponents ) > 1 ) {
442
					// a selector label was specified in the wiki text
443
					$viewSelectorLabel = trim( $viewnameComponents[1] );
444
				} else {
445
					// use the default selector label
446 2
					$viewSelectorLabel = Message::get( 'srf-filtered-selectorlabel-' . $viewName );
447
				}
448
449
				/** @var \SRF\Filtered\View\View $view */
450 2
				$viewClassName = '\SRF\Filtered\View\\' . $this->mViewTypes[$viewName];
451 2
				$view = new $viewClassName( $resultItems, $this->parameters, $this, $viewSelectorLabel );
452
453 2
				$initErrorMsg = $view->getInitError();
454
455 2
				if ( $initErrorMsg !== null ) {
456 1
					$res->addErrors( [ $this->msg( $initErrorMsg )->text() ] );
0 ignored issues
show
The method text() does not seem to exist on object<SMW\Message>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
457
				} else {
458
459 1
					$this->registerResourceModules( $view->getResourceModules() );
460
461 1
					$viewHtml .= Html::rawElement(
462 1
						'div',
463 1
						[ 'id' => $viewid, 'class' => "filtered-view filtered-$viewName $viewid" ],
464 1
						$view->getResultText()
465
					);
466 1
					$viewSelectorsHtml .= Html::rawElement(
467 1
						'div',
468 1
						[ 'class' => "filtered-view-selector filtered-$viewName $viewid" ],
469 1
						$viewSelectorLabel
470
					);
471
472 1
					foreach ( $resultItems as $row ) {
473 1
						$row->setData( $viewid, $view->getJsDataForRow( $row ) );
474
					}
475
476 1
					$config['views'][$viewid] = array_merge( [ 'type' => $viewName ], $view->getJsConfig() );
477
				}
478
			}
479
		}
480
481 2
		$viewHtml = Html::rawElement(
482 2
			'div',
483 2
			[ 'class' => 'filtered-views', 'style' => 'display:none' ],
484 2
			Html::rawElement(
485 2
				'div',
486 2
				[ 'class' => 'filtered-views-selectors-container', 'style' => 'display:none' ],
487 2
				$viewSelectorsHtml
488
			) .
489 2
			Html::rawElement( 'div', [ 'class' => 'filtered-views-container' ], $viewHtml )
490
		);
491 2
		return [ $viewHtml, $config ];
492
	}
493
494
}