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/tagcloud/TagCloud.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
namespace SRF;
4
5
use Html;
6
use SMW\ResultPrinter;
7
use SMWDataValue;
8
use SMWOutputs;
9
use SMWPrintRequest;
10
use SMWQueryResult;
11
use SMWResultArray;
12
use SRFUtils;
13
use Title;
14
15
/**
16
 * Result printer that prints query results as a tag cloud
17
 *
18
 * @since 1.5.3
19
 *
20
 * @ingroup SRF
21
 * @ingroup QueryPrinter
22
 *
23
 * @licence GNU GPL v2 or later
24
 * @author Jeroen De Dauw < [email protected] >
25
 * @author mwjames
26
 */
27
class TagCloud extends ResultPrinter {
28
29
	/**
30
	 * Contains html generated tags
31
	 *
32
	 * @var array
33
	 */
34
	protected $tagsHtml = [];
35
36
	/**
37
	 * Get a human readable label for this printer.
38
	 *
39
	 * @return string
40
	 */
41
	public function getName() {
42
		return $this->msg( 'srf_printername_tagcloud' )->text();
43
	}
44
45
	/**
46
	 * Return serialised results in specified format
47
	 *
48
	 * @param SMWQueryResult $queryResult
49
	 * @param $outputmode
50
	 *
51
	 * @return string
52
	 */
53 2
	public function getResultText( SMWQueryResult $queryResult, $outputmode ) {
54
55 2
		$tags = $this->getTags( $queryResult, $outputmode );
56
57 2
		if ( $tags === [] ) {
58
			$queryResult->addErrors( [ $this->msg( 'smw_result_noresults' )->inContentLanguage()->text() ] );
59
			return '';
60
		}
61
62
		// Check output conditions
63 2
		if ( ( $this->params['widget'] == 'sphere' ) &&
64 2
			( $this->params['link'] !== 'all' ) &&
65 2
			( $this->params['template'] === '' ) ) {
66
			$queryResult->addErrors(
67
				[ $this->msg( 'srf-error-option-link-all', 'sphere' )->inContentLanguage()->text() ]
68
			);
69
			return '';
70
		}
71
72
		// Template support
73 2
		$this->hasTemplates = $this->params['template'] !== '';
74 2
		$this->isHTML = $this->isHTML();
75
76
		// Register RL module
77 2
		if ( in_array( $this->params['widget'], [ 'sphere', 'wordcloud' ] ) ) {
78
			SMWOutputs::requireResource( 'ext.srf.formats.tagcloud' );
79
		}
80
81 2
		return $this->getTagCloud( $this->getTagSizes( $tags ) );
82
	}
83
84 2
	private function isHTML() {
85 2
		$title = $GLOBALS['wgTitle'];
86
87 2
		if ( $title instanceof Title ) {
88
			return $title->isSpecialPage() && !$this->hasTemplates;
89
		}
90
91 2
		return false;
92
	}
93
94
	/**
95
	 * Returns an array with the tags (keys) and the number of times they occur (values).
96
	 *
97
	 * @param SMWQueryResult $queryResult
98
	 * @param $outputMode
99
	 *
100
	 * @return array
101
	 */
102 2
	private function getTags( SMWQueryResult $queryResult, $outputMode ) {
103 2
		$tags = [];
104 2
		$excludetags = explode( ';', $this->params['excludetags'] );
105
106
		/**
107
		 * @var SMWResultArray $row
108
		 * @var SMWDataValue $dataValue
109
		 */
110 2
		while ( $row = $queryResult->getNext() ) { // Objects (pages)
111 2
			for ( $i = 0, $n = count( $row ); $i < $n; $i++ ) { // SMWResultArray for a sinlge property
112
113 2
				while ( ( $dataValue = $row[$i]->getNextDataValue() ) !== false ) { // Data values
114
115 2
					$isSubject = $row[$i]->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS;
116
117
					// If the main object should not be included, skip it.
118 2
					if ( $i == 0 && !$this->params['includesubject'] && $isSubject ) {
119 2
						continue;
120
					}
121
122 2
					$value = null;
123
124
					// Get the HTML for the tag content. Pages are linked, other stuff is just plaintext.
125 2
					if ( $dataValue->getTypeID() === '_wpg' ) {
126
127 1
						$title = $dataValue->getDataItem()->getTitle();
128
129 1
						if ( $title instanceof Title ) {
130 1
							$value = $title->getPrefixedText();
131 1
							$html = $dataValue->getLongText( $outputMode, $this->getLinker( $isSubject ) );
132
						}
133
					}
134
135 2
					if ( $value === null ) {
136 1
						$html = $dataValue->getShortText( $outputMode, $this->getLinker( false ) );
137 1
						$value = $html;
138
					}
139
140
					// Exclude tags from result set
141 2
					if ( in_array( $value, $excludetags ) ) {
142
						continue;
143
					}
144
145
					// Replace content with template inclusion
146 2
					$html = $this->params['template'] !== '' ? $this->addTemplateOutput( $value, $rownum ) : $html;
0 ignored issues
show
The variable $html does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
147
148
					// Store the HTML separately, so sorting can be done easily
149 2
					if ( !array_key_exists( $value, $tags ) ) {
150 2
						$tags[$value] = 0;
151 2
						$this->tagsHtml[$value] = $html;
152
					}
153
154 2
					$tags[$value]++;
155
				}
156
			}
157
		}
158
159 2
		foreach ( $tags as $name => $count ) {
160 2
			if ( $count < $this->params['mincount'] ) {
161
				unset( $tags[$name] );
162
			}
163
		}
164
165 2
		return $tags;
166
	}
167
168
	/**
169
	 * Determines the sizes of tags.
170
	 * This method is based on code from the FolkTagCloud extension by Katharina Wäschle.
171
	 *
172
	 * @param array $tags
173
	 *
174
	 * @return array
175
	 */
176 2
	private function getTagSizes( array $tags ) {
177 2
		if ( count( $tags ) == 0 ) {
178
			return $tags;
179
		}
180
181
		// If the original order needs to be kept, we need a copy of the current order.
182 2
		if ( $this->params['tagorder'] == 'unchanged' ) {
183
			$unchangedTags = array_keys( $tags );
184
		}
185
186 2
		arsort( $tags, SORT_NUMERIC );
187
188 2
		if ( count( $tags ) > $this->params['maxtags'] ) {
189
			$tags = array_slice( $tags, 0, $this->params['maxtags'], true );
190
		}
191
192 2
		$min = end( $tags ) or $min = 0;
193 2
		$max = reset( $tags ) or $max = 1;
194 2
		$maxSizeIncrease = $this->params['maxsize'] - $this->params['minsize'];
195
196
		// Loop over the tags, and replace their count by a size.
197 2
		foreach ( $tags as &$tag ) {
198 2
			switch ( $this->params['increase'] ) {
199 2
				case 'linear':
200
					$divisor = ( $max == $min ) ? 1 : $max - $min;
201
					$tag = $this->params['minsize'] + $maxSizeIncrease * ( $tag - $min ) / $divisor;
202
					break;
203 2
				case 'log' :
204
				default :
205 2
					$divisor = ( $max == $min ) ? 1 : log( $max ) - log( $min );
206 2
					$tag = $this->params['minsize'] + $maxSizeIncrease * ( log( $tag ) - log( $min ) ) / $divisor;
207 2
					break;
208
			}
209
		}
210
211 2
		switch ( $this->params['tagorder'] ) {
212 2
			case 'desc' :
213
				// Tags are already sorted desc
214
				break;
215 2
			case 'asc' :
216
				asort( $tags );
217
				break;
218 2
			case 'alphabetical' :
219 2
				$tagNames = array_keys( $tags );
220 2
				natcasesort( $tagNames );
221 2
				$newTags = [];
222
223 2
				foreach ( $tagNames as $name ) {
224 2
					$newTags[$name] = $tags[$name];
225
				}
226
227 2
				$tags = $newTags;
228 2
				break;
229
			case 'random' :
230
				$tagSizes = $tags;
231
				shuffle( $tagSizes );
232
				$newTags = [];
233
234
				foreach ( $tagSizes as $size ) {
235
					foreach ( $tags as $tagName => $tagSize ) {
236
						if ( $tagSize == $size ) {
237
							$newTags[$tagName] = $tags[$tagName];
238
							break;
239
						}
240
					}
241
				}
242
243
				$tags = $newTags;
244
				break;
245
			case 'unchanged' :
246
			default : // Restore the original order.
247
				$changedTags = $tags;
248
				$tags = [];
249
250
				foreach ( $unchangedTags as $name ) {
251
					// Original tags might have been left out at this point, so only add remaining ones.
252
					if ( array_key_exists( $name, $changedTags ) ) {
253
						$tags[$name] = $changedTags[$name];
254
					}
255
				}
256
				break;
257
		}
258
259 2
		return $tags;
260
	}
261
262
	/**
263
	 * Returns the HTML for the tag cloud.
264
	 *
265
	 * @param array $tags
266
	 *
267
	 * @return string
268
	 */
269 2
	private function getTagCloud( array $tags ) {
270
271
		// Initialize
272 2
		$htmlTags = [];
273 2
		$processing = '';
274
275
		// Count actual output and store div identifier
276 2
		$tagId = 'srf-' . uniqid();
277
278
		// Determine HTML element marker
279 2
		$element = $this->params['widget'] !== '' ? 'li' : 'span';
280
281
		// Add size information
282 2
		foreach ( $tags as $name => $size ) {
283 2
			$htmlTags[] = Html::rawElement(
284 2
				$element,
285
				[
286 2
					'style' => "font-size:$size%" ],
287 2
				$this->tagsHtml[$name]
288
			);
289
		}
290
291
		// Stringify
292 2
		$htmlSTags = implode( ' ', $htmlTags );
293
294
		// Handle sphere/canvas output objects
295 2
		if ( in_array( $this->params['widget'], [ 'sphere', 'wordcloud' ] ) ) {
296
297
			// Wrap LI/UL elements
298
			$htmlCTags = Html::rawElement(
299
				'ul',
300
				[
301
					'style' => 'display:none;'
302
				],
303
				$htmlSTags
304
			);
305
306
			// Wrap tags
307
			$htmlCTags = Html::rawElement(
308
				'div',
309
				[
310
					'id' => $tagId . '-tags',
311
					'class' => 'srf-tags'
312
				],
313
				$htmlCTags
314
			);
315
316
			// Wrap everything in a container object
317
			$htmlSTags = Html::rawElement(
318
				'div',
319
				[
320
					'id' => $tagId . '-container',
321
					'class' => 'srf-container',
322
					'data-width' => $this->params['width'],
323
					'data-height' => $this->params['height'],
324
					'data-font' => $this->params['font']
325
				],
326
				$htmlCTags
327
			);
328
329
			// Processing placeholder
330
			$processing = SRFUtils::htmlProcessingElement();
331
		}
332
333
		// Beautify class selector
334 2
		$class = $this->params['widget'] ? '-' . $this->params['widget'] . ' ' : '';
335 2
		$class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class;
336
337
		// General placeholder
338
		$attribs = [
339 2
			'class' => 'srf-tagcloud' . $class,
340 2
			'data-version' => '0.4.1'
341
		];
342
343 2
		return Html::rawElement( 'div', $attribs, $processing . $htmlSTags );
344
	}
345
346
	/**
347
	 * @param string $value
348
	 * @param int $rowNumber
349
	 *
350
	 * @return string
351
	 */
352 2
	private function addTemplateOutput( $value, &$rowNumber ) {
353 2
		$rowNumber++;
354 2
		$wikitext = $this->params['userparam'] ? "|userparam=" . $this->params['userparam'] : '';
355 2
		$wikitext .= "|" . $value;
356 2
		$wikitext .= "|#=$rowNumber";
357 2
		return '{{' . trim( $this->params['template'] ) . $wikitext . '}}';
358
	}
359
360
	/**
361
	 * @see ResultPrinter::getParamDefinitions
362
	 *
363
	 * @since 1.8
364
	 *
365
	 * @param $definitions array of IParamDefinition
366
	 *
367
	 * @return array of IParamDefinition|array
368
	 */
369 2
	public function getParamDefinitions( array $definitions ) {
370 2
		$params = parent::getParamDefinitions( $definitions );
371
372 2
		$params['template'] = [
373
			'message' => 'srf-paramdesc-template',
374
			'default' => '',
375
		];
376
377 2
		$params['userparam'] = [
378
			'message' => 'srf-paramdesc-userparam',
379
			'default' => '',
380
		];
381
382 2
		$params['excludetags'] = [
383
			'message' => 'srf-paramdesc-excludetags',
384
			'default' => '',
385
		];
386
387 2
		$params['includesubject'] = [
388
			'type' => 'boolean',
389
			'message' => 'srf-paramdesc-includesubject',
390
			'default' => false,
391
		];
392
393 2
		$params['tagorder'] = [
394
			'message' => 'srf_paramdesc_tagorder',
395
			'default' => 'alphabetical',
396
			'values' => [ 'alphabetical', 'asc', 'desc', 'random', 'unchanged' ],
397
		];
398
399 2
		$params['increase'] = [
400
			'message' => 'srf_paramdesc_increase',
401
			'default' => 'log',
402
			'values' => [ 'linear', 'log' ],
403
		];
404
405 2
		$params['widget'] = [
406
			'message' => 'srf-paramdesc-widget',
407
			'default' => '',
408
			'values' => [ 'sphere', 'wordcloud' ],
409
		];
410
411 2
		$params['class'] = [
412
			'message' => 'srf-paramdesc-class',
413
			'default' => '',
414
		];
415
416 2
		$params['font'] = [
417
			'message' => 'srf-paramdesc-font',
418
			'default' => 'impact',
419
		];
420
421 2
		$params['height'] = [
422
			'type' => 'integer',
423
			'message' => 'srf-paramdesc-height',
424
			'default' => 400,
425
			'lowerbound' => 1,
426
		];
427
428 2
		$params['width'] = [
429
			'type' => 'integer',
430
			'message' => 'srf-paramdesc-width',
431
			'default' => 400,
432
			'lowerbound' => 1,
433
		];
434
435 2
		$params['mincount'] = [
436
			'type' => 'integer',
437
			'message' => 'srf_paramdesc_mincount',
438
			'default' => 1,
439
			'manipulatedefault' => false,
440
		];
441
442 2
		$params['minsize'] = [
443
			'type' => 'integer',
444
			'message' => 'srf_paramdesc_minsize',
445
			'default' => 77,
446
			'manipulatedefault' => false,
447
		];
448
449 2
		$params['maxsize'] = [
450
			'type' => 'integer',
451
			'message' => 'srf_paramdesc_maxsize',
452
			'default' => 242,
453
			'manipulatedefault' => false,
454
		];
455
456 2
		$params['maxtags'] = [
457
			'type' => 'integer',
458
			'message' => 'srf_paramdesc_maxtags',
459
			'default' => 1000,
460
			'lowerbound' => 1,
461
		];
462
463 2
		return $params;
464
	}
465
}
466