Issues (18)

Security Analysis    no request data  

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.

tests/ValueParsers/IsoTimestampParserTest.php (3 issues)

Labels
Severity

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 ValueParsers\Test;
4
5
use DataValues\TimeValue;
6
use ValueParsers\IsoTimestampParser;
7
use ValueParsers\ParseException;
8
use ValueParsers\ParserOptions;
9
10
/**
11
 * @covers ValueParsers\IsoTimestampParser
12
 *
13
 * @group DataValue
14
 * @group DataValueExtensions
15
 *
16
 * @license GPL-2.0+
17
 * @author Addshore
18
 * @author Thiemo Kreuz
19
 */
20
class IsoTimestampParserTest extends ValueParserTestBase {
21
22
	/**
23
	 * @see ValueParserTestBase::getInstance
24
	 *
25
	 * @return IsoTimestampParser
26
	 */
27
	protected function getInstance() {
28
		return new IsoTimestampParser();
29
	}
30
31
	/**
32
	 * @see ValueParserTestBase::validInputProvider
33
	 */
34
	public function validInputProvider() {
35
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
36
		$julian = 'http://www.wikidata.org/entity/Q1985786';
37
38
		$julianOpts = new ParserOptions();
39
		$julianOpts->setOption( IsoTimestampParser::OPT_CALENDAR, $julian );
40
41
		$julianTextOpts = new ParserOptions();
42
		$julianTextOpts->setOption( IsoTimestampParser::OPT_CALENDAR, 'Julian' );
43
44
		$gregorianOpts = new ParserOptions();
45
		$gregorianOpts->setOption( IsoTimestampParser::OPT_CALENDAR, $gregorian );
46
47
		$prec10aOpts = new ParserOptions();
48
		$prec10aOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_YEAR10 );
49
50
		$precDayOpts = new ParserOptions();
51
		$precDayOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_DAY );
52
53
		$precSecondOpts = new ParserOptions();
54
		$precSecondOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_SECOND );
55
56
		$valid = array(
57
			// Whitespace
58
			"+0000000000002013-07-16T00:00:00Z\n" => array(
59
				'+2013-07-16T00:00:00Z',
60
				TimeValue::PRECISION_DAY,
61
			),
62
			' +0000000000002013-07-00T00:00:00Z ' => array(
63
				'+2013-07-00T00:00:00Z',
64
				TimeValue::PRECISION_MONTH,
65
			),
66
67
			// Empty options tests
68
			'+0000000000002013-00-00T00:00:00Z' => array(
69
				'+2013-00-00T00:00:00Z',
70
				TimeValue::PRECISION_YEAR,
71
			),
72
			'+0000000000000000-00-00T00:00:00Z' => array(
73
				'+0000-00-00T00:00:00Z',
74
				TimeValue::PRECISION_YEAR,
75
				$julian
76
			),
77
			'+0000000000002000-00-00T00:00:00Z' => array(
78
				'+2000-00-00T00:00:00Z',
79
				TimeValue::PRECISION_YEAR,
80
			),
81
			'+0000000000008000-00-00T00:00:00Z' => array(
82
				'+8000-00-00T00:00:00Z',
83
				TimeValue::PRECISION_YEAR1K,
84
			),
85
			'+0000000000020000-00-00T00:00:00Z' => array(
86
				'+20000-00-00T00:00:00Z',
87
				TimeValue::PRECISION_YEAR10K,
88
			),
89
			'+0000000000200000-00-00T00:00:00Z' => array(
90
				'+200000-00-00T00:00:00Z',
91
				TimeValue::PRECISION_YEAR100K,
92
			),
93
			'+0000000002000000-00-00T00:00:00Z' => array(
94
				'+2000000-00-00T00:00:00Z',
95
				TimeValue::PRECISION_YEAR1M,
96
			),
97
			'+0000000020000000-00-00T00:00:00Z' => array(
98
				'+20000000-00-00T00:00:00Z',
99
				TimeValue::PRECISION_YEAR10M,
100
			),
101
			'+0000000200000000-00-00T00:00:00Z' => array(
102
				'+200000000-00-00T00:00:00Z',
103
				TimeValue::PRECISION_YEAR100M,
104
			),
105
			'+0000002000000000-00-00T00:00:00Z' => array(
106
				'+2000000000-00-00T00:00:00Z',
107
				TimeValue::PRECISION_YEAR1G,
108
			),
109
			'+2000000000000000-00-00T00:00:00Z' => array(
110
				'+2000000000000000-00-00T00:00:00Z',
111
				TimeValue::PRECISION_YEAR1G,
112
			),
113
			'-2000000000000000-00-00T00:00:00Z' => array(
114
				'-2000000000000000-00-00T00:00:00Z',
115
				TimeValue::PRECISION_YEAR1G,
116
				$julian
117
			),
118
			'+0000000000002013-07-16T00:00:00Z (Gregorian)' => array(
119
				'+2013-07-16T00:00:00Z',
120
				TimeValue::PRECISION_DAY,
121
			),
122
			'+0000000000000000-01-01T00:00:00Z (Gregorian)' => array(
123
				'+0000-01-01T00:00:00Z',
124
				TimeValue::PRECISION_DAY,
125
126
			),
127
			'+0000000000002001-01-14T00:00:00Z (Julian)' => array(
128
				'+2001-01-14T00:00:00Z',
129
				TimeValue::PRECISION_DAY,
130
				$julian,
131
			),
132
			'+0000000000010000-01-01T00:00:00Z (Gregorian)' => array(
133
				'+10000-01-01T00:00:00Z',
134
				TimeValue::PRECISION_DAY,
135
			),
136
			'-0000000000000001-01-01T00:00:00Z (Gregorian)' => array(
137
				'-0001-01-01T00:00:00Z',
138
				TimeValue::PRECISION_DAY,
139
				$gregorian
140
			),
141
			'-00000000001-01-01T00:00:00Z (Gregorian)' => array(
142
				'-0001-01-01T00:00:00Z',
143
				TimeValue::PRECISION_DAY,
144
				$gregorian,
145
				$julianOpts // overridden by explicit calendar in input string
146
			),
147
			'-00000000001-01-01T00:00:00Z (Julian)' => array(
148
				'-0001-01-01T00:00:00Z',
149
				TimeValue::PRECISION_DAY,
150
				$julian,
151
				$gregorianOpts // overridden by explicit calendar in input string
152
			),
153
			'-000001-01-01T00:00:00Z (Gregorian)' => array(
154
				'-0001-01-01T00:00:00Z',
155
				TimeValue::PRECISION_DAY,
156
				$gregorian
157
			),
158
			'-1-01-01T00:00:00Z (Gregorian)' => array(
159
				'-0001-01-01T00:00:00Z',
160
				TimeValue::PRECISION_DAY,
161
				$gregorian
162
			),
163
164
			// Tests with different options
165
			'-1-01-02T00:00:00Z' => array(
166
				'-0001-01-02T00:00:00Z',
167
				TimeValue::PRECISION_DAY,
168
				$gregorian,
169
				$gregorianOpts,
170
			),
171
			'+2001-01-03T00:00:00Z' => array(
172
				'+2001-01-03T00:00:00Z',
173
				TimeValue::PRECISION_DAY,
174
				$julian,
175
				$julianOpts,
176
			),
177
			'+2001-01-04T00:00:00Z' => array(
178
				'+2001-01-04T00:00:00Z',
179
				TimeValue::PRECISION_DAY,
180
				$julian,
181
				$julianTextOpts,
182
			),
183
			'-1-01-04T00:00:00Z' => array(
184
				'-0001-01-04T00:00:00Z',
185
				TimeValue::PRECISION_YEAR10,
186
				$julian,
187
				$prec10aOpts,
188
			),
189
			'-1-01-05T00:00:00Z' => array(
190
				'-0001-01-05T00:00:00Z',
191
				TimeValue::PRECISION_DAY,
192
				$julian,
193
			),
194
195
			'+1999-00-00T00:00:00Z' => array(
196
				'+1999-00-00T00:00:00Z',
197
				TimeValue::PRECISION_YEAR,
198
			),
199
			'+2000-00-00T00:00:00Z' => array(
200
				'+2000-00-00T00:00:00Z',
201
				TimeValue::PRECISION_YEAR,
202
			),
203
			'+2010-00-00T00:00:00Z' => array(
204
				'+2010-00-00T00:00:00Z',
205
				TimeValue::PRECISION_YEAR,
206
			),
207
208
			// Optional sign character
209
			'2015-01-01T00:00:00Z' => array(
210
				'+2015-01-01T00:00:00Z',
211
				TimeValue::PRECISION_DAY,
212
			),
213
214
			// Optional time zone
215
			'2015-01-01T00:00:00' => array(
216
				'+2015-01-01T00:00:00Z',
217
				TimeValue::PRECISION_DAY,
218
			),
219
220
			// Actual minus character from Unicode; roundtrip with TimeDetailsFormatter
221
			"\xE2\x88\x922015-01-01T00:00:00" => array(
222
				'-2015-01-01T00:00:00Z',
223
				TimeValue::PRECISION_DAY,
224
				$julian
225
			),
226
227
			// Optional colons
228
			'2015-01-01T161718' => array(
229
				'+0000000000002015-01-01T16:17:18Z',
230
				TimeValue::PRECISION_SECOND,
231
			),
232
			'2015-01-01T1617' => array(
233
				'+0000000000002015-01-01T16:17:00Z',
234
				TimeValue::PRECISION_MINUTE,
235
			),
236
237
			// Optional second
238
			'2015-01-01T00:00' => array(
239
				'+2015-01-01T00:00:00Z',
240
				TimeValue::PRECISION_DAY,
241
			),
242
243
			// Optional hour and minute
244
			'2015-01-01' => array(
245
				'+2015-01-01T00:00:00Z',
246
				TimeValue::PRECISION_DAY,
247
			),
248
			'60-01-01' => array(
249
				'+0060-01-01T00:00:00Z',
250
				TimeValue::PRECISION_DAY,
251
				$julian
252
			),
253
			// 32 can not be confused with anything. Can't be day or month. Can't be minute or
254
			// second because a time can not start with minute or second.
255
			'32-01-01' => array(
256
				'+0032-01-01T00:00:00Z',
257
				TimeValue::PRECISION_DAY,
258
				$julian
259
			),
260
261
			// Years <= 31 require either the time part or a year with more than 2 digits
262
			'1-01-01T00:00' => array(
263
				'+0001-01-01T00:00:00Z',
264
				TimeValue::PRECISION_DAY,
265
				$julian
266
			),
267
			'001-01-01' => array(
268
				'+0001-01-01T00:00:00Z',
269
				TimeValue::PRECISION_DAY,
270
				$julian
271
			),
272
			// 00-00-00 to 24-00-00 can be confused with a time, but not if it is signed.
273
			'-01-02-03' => array(
274
				'-0001-02-03T00:00:00Z',
275
				TimeValue::PRECISION_DAY,
276
				$julian
277
			),
278
			'+01-02-03' => array(
279
				'+0001-02-03T00:00:00Z',
280
				TimeValue::PRECISION_DAY,
281
				$julian
282
			),
283
284
			// Day zero
285
			'2015-01-00' => array(
286
				'+2015-01-00T00:00:00Z',
287
				TimeValue::PRECISION_MONTH,
288
			),
289
290
			// Month zero
291
			'2015-00-00' => array(
292
				'+2015-00-00T00:00:00Z',
293
				TimeValue::PRECISION_YEAR,
294
			),
295
296
			// Leap seconds are a valid concept
297
			'+2015-01-01T00:00:61Z' => array(
298
				'+2015-01-01T00:00:61Z',
299
				TimeValue::PRECISION_SECOND,
300
			),
301
302
			// Tests for correct precision when a bad precision is passed through the opts
303
			// @see https://bugzilla.wikimedia.org/show_bug.cgi?id=62730
304
			'+0000000000000012-12-00T00:00:00Z' => array(
305
				'+0012-12-00T00:00:00Z',
306
				TimeValue::PRECISION_MONTH,
307
				$julian,
308
				$precDayOpts,
309
			),
310
			'+2015-01-01T00:00:00Z' => array(
311
				'+2015-01-01T00:00:00Z',
312
				TimeValue::PRECISION_SECOND,
313
				$gregorian,
314
				$precSecondOpts,
315
			),
316
317
			// Test Julian/Gregorian switch in October 1582.
318
			'1583-01-01' => array(
319
				'+1583-01-01T00:00:00Z',
320
				TimeValue::PRECISION_DAY,
321
				$gregorian
322
			),
323
324
			// Test Julian/Gregorian switch in October 1582.
325
			'1582-08-01' => array(
326
				'+1582-08-01T00:00:00Z',
327
				TimeValue::PRECISION_DAY,
328
				$julian
329
			),
330
		);
331
332
		$argLists = array();
333
334
		foreach ( $valid as $key => $value ) {
335
			$timestamp = $value[0];
336
			$precision = isset( $value[1] ) ? $value[1] : TimeValue::PRECISION_DAY;
337
			$calendarModel = isset( $value[2] ) ? $value[2] : $gregorian;
338
			$options = isset( $value[3] ) ? $value[3] : null;
339
340
			$argLists[] = array(
341
				// Because PHP magically turns numeric keys into ints/floats
342
				(string)$key,
343
				new TimeValue( $timestamp, 0, 0, 0, $precision, $calendarModel ),
0 ignored issues
show
It seems like $timestamp defined by $value[0] on line 335 can also be of type object<ValueParsers\ParserOptions>; however, DataValues\TimeValue::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
It seems like $calendarModel defined by isset($value[2]) ? $value[2] : $gregorian on line 337 can also be of type object<ValueParsers\ParserOptions>; however, DataValues\TimeValue::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
344
				new IsoTimestampParser( null, $options )
0 ignored issues
show
It seems like $options defined by isset($value[3]) ? $value[3] : null on line 338 can also be of type string; however, ValueParsers\IsoTimestampParser::__construct() does only seem to accept null|object<ValueParsers\ParserOptions>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
345
			);
346
		}
347
348
		return $argLists;
349
	}
350
351
	/**
352
	 * @see ValueParserTestBase::invalidInputProvider
353
	 */
354
	public function invalidInputProvider() {
355
		$argLists = array();
356
357
		$invalid = array(
358
			// Stuff that's not even a string
359
			true,
360
			false,
361
			null,
362
			array(),
363
			'foooooooooo',
364
			'1 June 2014',
365
			// Can be confused with a time (HMS), DMY or MDY
366
			'00-00-00',
367
			'12-01-01',
368
			'24-00-00',
369
			'31-01-01',
370
			// Month and day must be two digits
371
			'2015-12-1',
372
			'2015-1-31',
373
			// Time and seconds are optional, but hour without minutes is not allowed
374
			'+2015-12-31T23',
375
			'+2015-12-31T23Z',
376
			// Elements out of allowed bounds
377
			'+2015-00-01T00:00:00Z',
378
			'+2015-01-00T01:00:00Z',
379
			'+2015-01-00T00:01:00Z',
380
			'+2015-01-00T00:00:01Z',
381
			'+2015-13-01T00:00:00Z',
382
			'+2015-01-32T00:00:00Z',
383
			'+2015-01-01T24:00:00Z',
384
			'+2015-01-01T00:60:00Z',
385
			'+2015-01-01T00:00:62Z',
386
			// This parser should not replace the year parser
387
			'1234567890873',
388
			2134567890
389
		);
390
391
		foreach ( $invalid as $value ) {
392
			$argLists[] = array( $value );
393
		}
394
395
		return $argLists;
396
	}
397
398
	/**
399
	 * @dataProvider optionsProvider
400
	 */
401
	public function testOptions(
402
		$value,
403
		array $options,
404
		$timestamp,
405
		$calendarModel,
406
		$precision = TimeValue::PRECISION_DAY
407
	) {
408
		$parser = new IsoTimestampParser( null, new ParserOptions( $options ) );
409
		$this->assertEquals(
410
			new TimeValue( $timestamp, 0, 0, 0, $precision, $calendarModel ),
411
			$parser->parse( $value )
412
		);
413
	}
414
415
	public function optionsProvider() {
416
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
417
		$julian = 'http://www.wikidata.org/entity/Q1985786';
418
419
		return array(
420
			'Auto-detected Gregorian' => array(
421
				'1583-01-31',
422
				array(),
423
				'+1583-01-31T00:00:00Z',
424
				$gregorian
425
			),
426
			'Option overrides auto-detected Gregorian' => array(
427
				'1583-01-31',
428
				array( IsoTimestampParser::OPT_CALENDAR => $julian ),
429
				'+1583-01-31T00:00:00Z',
430
				$julian
431
			),
432
			'Auto-detected Julian' => array(
433
				'1582-01-31',
434
				array(),
435
				'+1582-01-31T00:00:00Z',
436
				$julian
437
			),
438
			'Option overrides auto-detected Julian' => array(
439
				'1582-01-31',
440
				array( IsoTimestampParser::OPT_CALENDAR => $gregorian ),
441
				'+1582-01-31T00:00:00Z',
442
				$gregorian
443
			),
444
			'Option can decrease precision' => array(
445
				'2016-01-31',
446
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_MONTH ),
447
				'+2016-01-31T00:00:00Z',
448
				$gregorian,
449
				TimeValue::PRECISION_MONTH
450
			),
451
			'Option can set minimal precision' => array(
452
				'2016-01-31',
453
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_YEAR1G ),
454
				'+2016-01-31T00:00:00Z',
455
				$gregorian,
456
				TimeValue::PRECISION_YEAR1G
457
			),
458
			'Option can not increase year precision' => array(
459
				'2016-00-00',
460
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_MONTH ),
461
				'+2016-00-00T00:00:00Z',
462
				$gregorian,
463
				TimeValue::PRECISION_YEAR
464
			),
465
			'Option can not increase month precision' => array(
466
				'2016-01-00',
467
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_DAY ),
468
				'+2016-01-00T00:00:00Z',
469
				$gregorian,
470
				TimeValue::PRECISION_MONTH
471
			),
472
			'Option can increase day precision' => array(
473
				'2016-01-31',
474
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_HOUR ),
475
				'+2016-01-31T00:00:00Z',
476
				$gregorian,
477
				TimeValue::PRECISION_HOUR
478
			),
479
			'Precision option accepts strings' => array(
480
				'2016-01-31',
481
				array( IsoTimestampParser::OPT_PRECISION => '10' ),
482
				'+2016-01-31T00:00:00Z',
483
				$gregorian,
484
				TimeValue::PRECISION_MONTH
485
			),
486
		);
487
	}
488
489
	/**
490
	 * @dataProvider invalidOptionsProvider
491
	 */
492
	public function testInvalidOptions( array $options ) {
493
		$parser = new IsoTimestampParser( null, new ParserOptions( $options ) );
494
		$this->setExpectedException( ParseException::class );
495
		$parser->parse( '2016-01-31' );
496
	}
497
498
	public function invalidOptionsProvider() {
499
		return array(
500
			array( array( IsoTimestampParser::OPT_CALENDAR => 'invalid' ) ),
501
			array( array( IsoTimestampParser::OPT_PRECISION => -1 ) ),
502
			array( array( IsoTimestampParser::OPT_PRECISION => 1.5 ) ),
503
			array( array( IsoTimestampParser::OPT_PRECISION => 1000 ) ),
504
			array( array( IsoTimestampParser::OPT_PRECISION => 'invalid' ) ),
505
		);
506
	}
507
508
}
509