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/spreadsheet/SpreadsheetPrinter.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 ImagePage;
6
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
7
use PhpOffice\PhpSpreadsheet\Cell\Cell;
8
use PhpOffice\PhpSpreadsheet\Cell\DataType;
9
use PhpOffice\PhpSpreadsheet\IOFactory;
10
use PhpOffice\PhpSpreadsheet\Spreadsheet;
11
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
12
use PhpOffice\PhpSpreadsheet\Worksheet\Row;
13
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
14
use Sanitizer;
15
use SMW\FileExportPrinter;
16
use SMW\Query\ExportPrinter;
17
use SMWDataValue;
18
use SMWQueryResult;
19
use SMWResultArray;
20
use Title;
21
22
/**
23
 * @author Kim Eik
24
 * @since 1.9
25
 */
26
class SpreadsheetPrinter extends FileExportPrinter {
27
28
	const HEADER_ROW_OFFSET = 1;
29
30
	protected $fileFormats = [
31
		'xlsx' => [
32
			'writer' => 'Xlsx',
33
			'mimetype' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
34
			'extension' => '.xlsx',
35
		],
36
		'xls' => [
37
			'writer' => 'Xls',
38
			'mimetype' => 'aapplication/vnd.ms-excel',
39
			'extension' => '.xls',
40
		],
41
		'ods' => [
42
			'writer' => 'Ods',
43
			'mimetype' => 'application/vnd.oasis.opendocument.spreadsheet',
44
			'extension' => '.ods',
45
		],
46
		'csv' => [
47
			'writer' => 'Csv',
48
			'mimetype' => 'text/csv',
49
			'extension' => '.csv',
50
		],
51
	];
52
53
	protected $styled = false;
54
	protected $fileFormat;
55
56
	/**
57
	 * @see ExportPrinter::getMimeType()
58
	 *
59
	 * @since 1.8
60
	 *
61
	 * @param SMWQueryResult $queryResult
62
	 *
63
	 * @return string
64
	 */
65
	public function getMimeType( SMWQueryResult $queryResult ) {
66
		return $this->fileFormat[ 'mimetype' ];
67
	}
68
69
	/**
70
	 * @see ExportPrinter::getFileName
71
	 *
72
	 * @param SMWQueryResult $queryResult
73
	 *
74
	 * @return string
75
	 */
76
	public function getFileName( SMWQueryResult $queryResult ) {
77
		return ( $this->params[ 'filename' ] ?: base_convert( uniqid(), 16, 36 ) ) . $this->fileFormat[ 'extension' ];
78
	}
79
80
	/**
81
	 * @see ExportPrinter::outputAsFile
82
	 *
83
	 * @param SMWQueryResult $queryResult
84
	 * @param array $params
85
	 */
86
	public function outputAsFile( SMWQueryResult $queryResult, array $params ) {
87
88
		if ( array_key_exists( 'fileformat', $params) && array_key_exists( $params[ 'fileformat' ]->getValue(), $this->fileFormats )) {
89
			$this->fileFormat = $this->fileFormats[ $params[ 'fileformat' ]->getValue() ];
90
		} else {
91
			$this->fileFormat = $this->fileFormats[ 'xlsx' ];
92
		}
93
94
		parent::outputAsFile( $queryResult, $params );
95
	}
96
97
	/**
98
	 * @param $definitions \ParamProcessor\ParamDefinition[]
99
	 *
100
	 * @return array
101
	 */
102
	public function getParamDefinitions( array $definitions ) {
103
		$params = parent::getParamDefinitions( $definitions );
104
105
		$definitions[ 'searchlabel' ]->setDefault( wfMessage( 'srf-spreadsheet-link' )->inContentLanguage()->text() );
106
107
		$params[ 'templatefile' ] = [
108
			'type'    => 'string',
109
			'name'    => 'templatefile',
110
			'default' => '',
111
			'message' => 'srf-paramdesc-spreadsheet-templatefile',
112
		];
113
114
		$params[ 'filename' ] = [
115
			'type'    => 'string',
116
			'name'    => 'filename',
117
			'default' => '',
118
			'message' => 'srf-paramdesc-spreadsheet-filename',
119
		];
120
121
		$params[ 'fileformat' ] = [
122
			'type'    => 'string',
123
			'name'    => 'fileformat',
124
			'default' => 'xlsx',
125
			'tolower' => true,
126
			'message' => 'srf-paramdesc-spreadsheet-fileformat',
127
		];
128
129
		return $params;
130
	}
131
132
	/*
133
	 * Turns the PhpSpreadsheet document object into a string
134
	 */
135
136
	/**
137
	 * Return serialised results in specified format.
138
	 *
139
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
140
	 * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
141
	 */
142 1
	protected function getResultText( SMWQueryResult $queryResult, $outputMode ) {
143
144 1
		if ( $outputMode === SMW_OUTPUT_FILE ) {
145
			return $this->getResultFileContents( $queryResult );
146
		}
147
148 1
		$this->isHTML = ( $outputMode === SMW_OUTPUT_HTML );
149 1
		return $this->getLink( $queryResult, $outputMode )->getText( $outputMode, $this->mLinker );
150
	}
151
152
	/**
153
	 * @param SMWQueryResult $queryResult
154
	 *
155
	 * @return string
156
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
157
	 * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
158
	 */
159
	protected function getResultFileContents( SMWQueryResult $queryResult ) {
160
161
		$spreadsheet = $this->createSpreadsheet();
162
		$worksheet = $spreadsheet->getSheet( 0 );
163
164
		$this->populateWorksheet( $worksheet, $queryResult );
165
166
		//$spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight();
167
168
		for ( $i = 0; $i < count( $queryResult->getPrintRequests() ); $i++ ) {
0 ignored issues
show
Performance Best Practice introduced by Stephan
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
169
			$worksheet->getColumnDimensionByColumn( $i )->setAutoSize( true );
170
		}
171
172
		$result = $this->getStringFromSpreadsheet( $spreadsheet );
173
		return $result;
174
	}
175
176
	/**
177
	 * Creates a new PhpSpreadsheet document and returns it
178
	 *
179
	 * @return Spreadsheet
180
	 * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
181
	 */
182
	protected function createSpreadsheet() {
183
184
		$fileTitle = Title::newFromText( $this->params[ 'templatefile' ], NS_FILE );
185
186
		if ( $fileTitle !== null && $fileTitle->exists() ) {
187
188
			$spreadsheet = $this->createSpreadsheetFromTemplate( $fileTitle );
189
190
			$this->styled = true;
191
192
		} else {
193
194
			$spreadsheet = new Spreadsheet();
195
196
		}
197
198
		// Set document properties
199
		$spreadsheet->getProperties()->setCreator( 'SemanticMediaWiki Spreadsheet Export' );
200
201
		return $spreadsheet;
202
	}
203
204
	/**
205
	 * @param $fileTitle
206
	 *
207
	 * @return Spreadsheet
208
	 * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
209
	 */
210
	private function createSpreadsheetFromTemplate( $fileTitle ) {
211
		$filePage = new ImagePage( $fileTitle, $this );
212
213
		$virtualFile = $filePage->getDisplayedFile();
214
		$virtualFilePath = $virtualFile->getPath();
215
216
		$localFile = $virtualFile->getRepo()->getLocalReference( $virtualFilePath );
217
		$localFilePath = $localFile->getPath();
218
219
		return IOFactory::load( $localFilePath );
220
	}
221
222
	/**
223
	 * @param SMWQueryResult $queryResult
224
	 * @param $worksheet
225
	 *
226
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
227
	 */
228
	protected function populateWorksheet( Worksheet $worksheet, SMWQueryResult $queryResult ) {
229
230
		$rowIterator = $worksheet->getRowIterator( self::HEADER_ROW_OFFSET );
231
232
		//Get headers
233
		if ( $this->mShowHeaders ) {
234
			$this->populateHeaderRow( $rowIterator->current(), $queryResult );
235
			$rowIterator->next();
236
		}
237
238
		while ( $resultRow = $queryResult->getNext() ) {
239
240
			//Get data rows
241
			$this->populateRow( $rowIterator->current(), $resultRow );
242
			$rowIterator->next();
243
		}
244
	}
245
246
	/**
247
	 * Populates the PhpSpreadsheet sheet with the headers from the result query
248
	 *
249
	 * @param Row $row
250
	 * @param SMWQueryResult $queryResult The query result
251
	 *
252
	 * @return Row
253
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
254
	 */
255
	protected function populateHeaderRow( Row $row, SMWQueryResult $queryResult ) {
256
257
		$printRequests = $queryResult->getPrintRequests();
258
		$cellIterator = $row->getCellIterator();
259
260
		foreach ( $printRequests as $printRequest ) {
261
262
			$cell = $cellIterator->current();
263
264
			$cell->setValue( $printRequest->getLabel() );
265
266
			$cell->getStyle()
267
				->getFont()
268
				->setBold( true );
269
270
			$cellIterator->next();
271
272
		}
273
274
		return $row;
275
	}
276
277
	/**
278
	 * Populates the PhpSpreadsheet document with the query data
279
	 *
280
	 * @param Row $row
281
	 * @param $resultRow
282
	 *
283
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
284
	 */
285
	protected function populateRow( Row $row, $resultRow ) {
286
287
		$cellIterator = $row->getCellIterator();
288
289
		foreach ( $resultRow as $resultField ) {
290
291
			$this->populateCell( $cellIterator->current(), $resultField );
292
			$cellIterator->next();
293
		}
294
	}
295
296
	/**
297
	 * @param Cell $cell
298
	 * @param SMWResultArray $field
299
	 *
300
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
301
	 */
302
	protected function populateCell( Cell $cell, SMWResultArray $field ) {
303
304
		$dataItems = $field->getContent();
305
306
		if ( $dataItems === false ) {
307
			return;
308
		}
309
310
		if ( count( $dataItems ) > 1 ) {
311
312
			$values = [];
313
314
			while ( $value = $field->getNextText( SMW_OUTPUT_FILE ) ) {
315
				$values[] = $value;
316
			}
317
318
			$cell->setValueExplicit( join( ', ', $values ), DataType::TYPE_STRING );
319
320
		} else {
321
322
			$nextDataValue = $field->getNextDataValue();
323
324
			if ( $nextDataValue !== false ) {
325
				$this->populateCellAccordingToType( $cell, $nextDataValue );
326
			}
327
328
		}
329
	}
330
331
	/**
332
	 * Checks the type of the value, and set's it in the sheet accordingly
333
	 *
334
	 * @param Cell $cell
335
	 * @param SMWDataValue $value
336
	 *
337
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
338
	 */
339
	protected function populateCellAccordingToType( Cell $cell, SMWDataValue $value ) {
340
341
		//NOTE: must check against subclasses before superclasses
342
		if ( $value instanceof \SMWQuantityValue ) {
343
344
			$this->setQuantityDataValue( $cell, $value );
345
346
		} elseif ( $value instanceof \SMWNumberValue ) {
347
348
			$this->setNumberDataValue( $cell, $value );
349
350
		} elseif ( $value instanceof \SMWTimeValue ) {
351
352
			$this->setTimeDataValue( $cell, $value );
353
354
		} else {
355
356
			$this->setStringDataValue( $cell, $value );
357
358
		}
359
360
	}
361
362
	/**
363
	 * Sets a quantity value at the given col,row location
364
	 *
365
	 * @param Cell $cell
366
	 * @param \SMWQuantityValue $value SMWDataValue  the raw data value object
367
	 *
368
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
369
	 */
370
	protected function setQuantityDataValue( Cell $cell, \SMWQuantityValue $value ) {
371
372
		$type = DataType::TYPE_NUMERIC;
373
		$unit = $value->getUnit();
374
		$number = $value->getNumber();
375
376
		$cell->setValueExplicit( $number, $type );
377
378
		if ( !$this->styled ) {
379
			$cell->getStyle()
380
				->getNumberFormat()
381
				->setFormatCode( '0 "' . $unit . '"' );
382
		}
383
	}
384
385
	/**
386
	 * Sets a numeric value at the given col,row location
387
	 *
388
	 * @param Cell $cell
389
	 * @param \SMWNumberValue $value SMWDataValue the raw data value object
390
	 *
391
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
392
	 */
393
	protected function setNumberDataValue( Cell $cell, \SMWNumberValue $value ) {
394
395
		$type = DataType::TYPE_NUMERIC;
396
		$number = $value->getNumber();
397
398
		$cell->setValueExplicit( $number, $type );
399
	}
400
401
	/**
402
	 * Sets a date/time value at the given col,row location
403
	 *
404
	 * @param Cell $cell
405
	 * @param \SMWTimeValue $value the raw data value object
406
	 *
407
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
408
	 */
409
	protected function setTimeDataValue( Cell $cell, \SMWTimeValue $value ) {
410
411
		$type = DataType::TYPE_NUMERIC;
412
		$number = DateTime::DATEVALUE( str_replace( 'T', ' ', $value->getISO8601Date() ) );
413
414
		$cell->setValueExplicit( $number, $type );
415
416
		if ( !$this->styled ) {
417
			$cell->getStyle()
418
				->getNumberFormat()
419
				->setFormatCode( NumberFormat::FORMAT_DATE_DDMMYYYY );
420
		}
421
	}
422
423
	/**
424
	 * Sets or appends a string value at the given col,row location
425
	 *
426
	 * If there already exists a value at a given col,row location, then
427
	 * convert the cell to a string and append the data value. Creating
428
	 * a list of comma separated entries.
429
	 *
430
	 * @param Cell $cell
431
	 * @param $value SMWDataValue the raw data value object
432
	 *
433
	 * @throws \PhpOffice\PhpSpreadsheet\Exception
434
	 */
435
	protected function setStringDataValue( Cell $cell, SMWDataValue $value ) {
436
437
		$type = DataType::TYPE_STRING;
438
		$text = $value->getWikiValue();
439
		$text = Sanitizer::decodeCharReferences( $text );
440
		$text = DataType::checkString( $text );
441
442
		$cell->setValueExplicit( $text, $type );
443
	}
444
445
	/**
446
	 * @param Spreadsheet $spreadsheet
447
	 *
448
	 * @return string
449
	 * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
450
	 */
451
	protected function getStringFromSpreadsheet( Spreadsheet $spreadsheet ) {
452
453
		$writer = IOFactory::createWriter( $spreadsheet, $this->fileFormat[ 'writer' ] );
454
455
		ob_start();
456
		$writer->save( 'php://output' );
457
		return ob_get_clean();
458
	}
459
460
}
461
462