Issues (29)

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.

tests/JSONTextQueryTest.php (4 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
 * @package silverstripe-jsontext
5
 * @subpackage fields
6
 * @author Russell Michell <[email protected]>
7
 * @todo Add tests where source data is a JSON array, not just a JSON object
8
 *
9
 *
10
 */
11
12
use PhpTek\JSONText\ORM\FieldType\JSONText;
13
use PhpTek\JSONText\Exception\JSONTextException;
14
use SilverStripe\Dev\SapphireTest;
15
use SilverStripe\ORM\FieldType\DBBoolean;
16
use SilverStripe\ORM\FieldType\DBFloat;
17
use SilverStripe\ORM\FieldType\DBVarchar;
18
use SilverStripe\ORM\FieldType\DBInt;
19
20
class JSONTextQueryTest extends SapphireTest
21
{
22
    /**
23
     * @var array
24
     */
25
    protected $fixtures = [
26
        'array'     => 'fixtures/json/array.json',
27
        'object'    => 'fixtures/json/object.json',
28
    ];
29
30
    /**
31
     * @var JSONText
32
     */
33
    protected $sut;
34
35
    /**
36
     * JSONTextTest constructor.
37
     *
38
     * Modify fixtures property to be able to run on PHP <5.6 without use of constant in class property which 5.6+ allows
39
     */
40 View Code Duplication
    public function __construct()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
41
    {
42
        foreach($this->fixtures as $name => $path) {
43
            $this->fixtures[$name] = realpath(__DIR__) . '/' . $path;
44
        }
45
        
46
        parent::__construct();
47
    }
48
49
    /**
50
     * Setup the System Under Test for this test suite.
51
     */
52
    public function setUp()
53
    {
54
        parent::setUp();
55
56
        $this->sut = JSONText::create('MyJSON');
57
    }
58
59
    /**
60
     * Tests query() by means of the integer Postgres Int match operator: '->'
61
     *
62
     * @todo Use same source data instead of repeating..
63
     */
64
    public function testQueryWithMatchOnInt()
65
    {
66
        $field = $this->sut;
67
68
        // Data Source: Array
69
        // Return Type: ARRAY
70
        // Operator: "->" (Int)
71
        $field->setReturnType('array');
72
        $field->setValue($this->getFixture('array'));
73
        $this->assertEquals([2 => 'trabant'], $field->query('->', 2));
74
75
        // Data Source: Array
76
        // Return Type: JSON
77
        // Operator: "->" (Int)
78
        $field->setReturnType('json');
79
        $field->setValue($this->getFixture('array'));
80
        $this->assertEquals('{"2":"trabant"}', $field->query('->', 2));
81
        $this->assertEquals('{"5":101}', $field->query('->', 5));
82
83
        // Data Source: Array
84
        // Return Type: SILVERSTRIPE
85
        // Operator: "->" (Int)
86
        // SS Type: Float
87
        $field->setReturnType('silverstripe');
88
        $field->setValue($this->getFixture('array'));
89
        $this->assertInternalType('array', $field->query('->', 3));
90
        $this->assertInstanceOf(DBFloat::class, $field->query('->', 3)[3]);
91
        $this->assertEquals(44.6, $field->query('->', 3)[3]->getValue());
92
93
        // Data Source: Array
94
        // Return Type: SILVERSTRIPE
95
        // Operator: "->" (Int)
96
        // SS Type: Boolean
97
        $field->setReturnType('silverstripe');
98
        $field->setValue($this->getFixture('array'));
99
        $this->assertInternalType('array', $field->query('->', 1));
100
        $this->assertInstanceOf(DBBoolean::class, $field->query('->', 1)[1]);
101
        $this->assertEquals(1, $field->query('->', 1)[1]->getValue());
102
103
        // Data Source: Array
104
        // Return Type: SILVERSTRIPE
105
        // Operator: "->" (Int)
106
        // SS Type: Int
107
        $field->setReturnType('silverstripe');
108
        $field->setValue($this->getFixture('array'));
109
        $this->assertInternalType('array', $field->query('->', 5));
110
        $this->assertInstanceOf(DBInt::class, $field->query('->', 5)[5]);
111
        $this->assertEquals(101, $field->query('->', 5)[5]->getValue());
112
113
        // Data Source: Array
114
        // Return Type: SILVERSTRIPE
115
        // Operator: "->" (Int)
116
        // SS Type: Varchar
117
        $field->setReturnType('silverstripe');
118
        $field->setValue($this->getFixture('array'));
119
        $this->assertInternalType('array', $field->query('->', 4));
120
        $this->assertInstanceOf(DBVarchar::class, $field->query('->', 4)[4]);
121
        $this->assertEquals('buick', $field->query('->', 4)[4]->getValue());
122
123
        // Test: Empty #1
124
        $field->setReturnType('array');
125
        $field->setValue('');
126
        $this->assertInternalType('array', $field->query('->', 3));
127
        $this->assertCount(0, $field->query('->', 3));
128
129
        // Test: Invalid #1
130
        $field->setReturnType('array');
131
        $field->setValue('["morris"]');
132
        $this->assertEquals([], $field->query('->', 17));
133
    }
134
135
    /**
136
     * Tests query() by means of the integer Postgres String match operator: '->>'
137
     */
138
    public function testQueryWithMatchOnStr()
139
    {
140
        $field = $this->sut;
141
142
        // Data Source: Object
143
        // Return Type: ARRAY
144
        // Operator: "->>" (String)
145
        $field->setReturnType('array');
146
        $field->setValue($this->getFixture('object'));
147
        $this->assertEquals(['Subaru' => 'Impreza'], $field->query('->>', 'Subaru'));
148
        $this->assertEquals(
149
            ['japanese' => ['fast' => ['Subaru' => 'Impreza'], 'slow' => ['Honda' => 'Civic']]],
150
            $field->query('->>', 'japanese')
151
        );
152
153
        // Data Source: Object
154
        // Return Type: JSON
155
        // Operator: "->>" (String)
156
        $field->setReturnType('json');
157
        $field->setValue($this->getFixture('object'));
158
        $this->assertEquals('{"Subaru":"Impreza"}', $field->query('->>', 'Subaru'));
159
        $this->assertEquals(
160
            '{"japanese":{"fast":{"Subaru":"Impreza"},"slow":{"Honda":"Civic"}}}',
161
            $field->query('->>', 'japanese')
162
        );
163
164
        // Data Source: Object
165
        // Return Type: SilverStripe
166
        // Operator: "->>" (String)
167
        // SS Type: Varchar
168
        $field->setReturnType('silverstripe');
169
        $field->setValue($this->getFixture('object'));
170
        $this->assertInternalType('array', $field->query('->>', 'Subaru'));
171
        $this->assertInstanceOf(DBVarchar::class, $field->query('->>', 'Subaru')['Subaru']);
172
        $this->assertEquals('Impreza', $field->query('->>', 'Subaru')['Subaru']->getValue());
173
174
        // Data Source: Object
175
        // Return Type: SilverStripe
176
        // Operator: "->>" (String)
177
        // SS Type: Boolean
178
        $field->setReturnType('silverstripe');
179
        $field->setValue($this->getFixture('object'));
180
        $this->assertInternalType('array', $field->query('->>', 'beer tastes good'));
181
        $this->assertInstanceOf(DBBoolean::class, $field->query('->>', 'beer tastes good')['beer tastes good']);
182
        $this->assertEquals(1, $field->query('->>', 'beer tastes good')['beer tastes good']->getValue());
183
184
        // Data Source: Object
185
        // Return Type: SilverStripe
186
        // Operator: "->>" (String)
187
        // SS Type: Float
188
        $field->setReturnType('silverstripe');
189
        $field->setValue($this->getFixture('object'));
190
        $this->assertInternalType('array', $field->query('->>', 'how sure are you'));
191
        $this->assertInstanceOf(DBFloat::class, $field->query('->>', 'how sure are you')['how sure are you']);
192
        $this->assertEquals(99.99, $field->query('->>', 'how sure are you')['how sure are you']->getValue());
193
194
        // Data Source: Object
195
        // Return Type: SilverStripe
196
        // Operator: "->>" (String)
197
        // SS Type: Int
198
        $field->setReturnType('silverstripe');
199
        $field->setValue($this->getFixture('object'));
200
        $this->assertInternalType('array', $field->query('->>', 'how high'));
201
        $this->assertInstanceOf(DBInt::class, $field->query('->>', 'how high')['how high']);
202
        $this->assertEquals(6, $field->query('->>', 'how high')['how high']->getValue());
203
204
        // Data Source: Object
205
        // Return Type: SilverStripe
206
        // Operator: "->>" (String)
207
        // SS Type: N/A Nested sub-array example, expect an array
208
        $field->setReturnType('silverstripe');
209
        $field->setValue($this->getFixture('object'));
210
        $this->assertInternalType('array', $field->query('->>', 'planes')['planes']);
211
        $this->assertInternalType('array', $field->query('->>', 'planes')['planes']['russian']);
212
        $this->assertCount(2, $field->query('->>', 'planes')['planes']['russian']);
213
        $this->assertInstanceOf(DBVarchar::class, $field->query('->>', 'planes')['planes']['russian'][0]);
214
        $this->assertInstanceOf(DBVarchar::class, $field->query('->>', 'planes')['planes']['russian'][1]);
215
216
        // Test: Empty #1
217
        $field->setReturnType('array');
218
        $field->setValue('');
219
        $this->assertInternalType('array', $field->query('->>', 'planes'));
220
        $this->assertCount(0, $field->query('->', 3));
221
222
        // Test: Empty #2
223
        $field->setReturnType('array');
224
        $field->setValue('["morris"]');
225
        $this->assertEquals([], $field->query('->', 17));
226
227
        // Test: Invalid #1
228
        $field->setReturnType('array');
229
        $field->setValue('["trabant"]');
230
        $this->assertEquals([], $field->query('->', 1));
231
    }
232
233
    /**
234
     * Tests query() by means of the Postgres path-match operator: '#>'
235
     */
236
    public function testQueryWithMatchOnPath()
237
    {
238
        $field = $this->sut;
239
240
        // Data Source: Object
241
        // Return Type: ARRAY
242
        // Operator: "#>" (Path)
243
        // Expect: Array due to duplicate keys in different parts of the source data
244
        $field->setReturnType('array');
245
        $field->setValue($this->getFixture('object'));
246
        $this->assertEquals(
247
            [['Subaru' => 'Impreza'],['Kawasaki' => 'KR1S250']],
248
            $field->query('#>', '{"japanese":"fast"}')
249
        );
250
251
        // Data Source: Object
252
        // Return Type: JSON
253
        // Operator: "#>" (Path)
254
        // Expect: Array due to duplicate keys in different parts of the source data
255
        $field->setReturnType('json');
256
        $field->setValue($this->getFixture('object'));
257
        $this->assertEquals(
258
            '[{"Subaru":"Impreza"},{"Kawasaki":"KR1S250"}]',
259
            $field->query('#>', '{"japanese":"fast"}')
260
        );
261
262
        // Data Source: Object
263
        // Return Type: SILVERSTRIPE
264
        // Operator: "#>" (Path)
265
        // Expect: Array due to duplicate keys in different parts of the source data
266
        $field->setReturnType('silverstripe');
267
        $field->setValue($this->getFixture('object'));
268
        $this->assertInternalType('array', $field->query('#>', '{"japanese":"fast"}'));
269
        $this->assertCount(2, $field->query('#>', '{"japanese":"fast"}'));
270
271
        $one = $field->query('#>', '{"japanese":"fast"}')[0];
272
        $two = $field->query('#>', '{"japanese":"fast"}')[1];
273
274
        $this->assertInternalType('array', $one);
275
        $this->assertInternalType('array', $two);
276
        $this->assertInstanceOf(DBVarchar::class, array_values($one)[0]);
277
        $this->assertInstanceOf(DBVarchar::class, array_values($two)[0]);
278
        $this->assertEquals('Impreza', array_values($one)[0]->getValue());
279
        $this->assertEquals('KR1S250', array_values($two)[0]->getValue());
280
281
        // Data Source: Object
282
        // Return Type: ARRAY
283
        // Operator: "#>" (Path)
284
        // Expect: Direct scalar comparison assertion
285
        $field->setReturnType('array');
286
        $field->setValue($this->getFixture('object'));
287
        $this->assertEquals(['airbus'], $field->query('#>', '{"planes":"french"}'));
288
289
        // Data Source: Object
290
        // Return Type: JSON
291
        // Operator: "#>" (Path)
292
        // Expect: Direct scalar comparison assertion
293
        $field->setReturnType('json');
294
        $field->setValue($this->getFixture('object'));
295
        $this->assertEquals('["airbus"]', $field->query('#>', '{"planes":"french"}'));
296
297
        // Data Source: Object
298
        // Return Type: SILVERSTRIPE
299
        // Operator: "#>" (Path)
300
        // Expect: Direct scalar comparison assertion (Varchar)
301
        $field->setReturnType('silverstripe');
302
        $field->setValue($this->getFixture('object'));
303
        $this->assertInternalType('array', $field->query('#>', '{"planes":"french"}'));
304
        $this->assertInstanceOf(DBVarchar::class, $field->query('#>', '{"planes":"french"}')[0]);
305
        $this->assertEquals('airbus', $field->query('#>', '{"planes":"french"}')[0]->getValue());
306
307
        // Data Source: Object
308
        // Return Type: SILVERSTRIPE
309
        // Operator: "#>" (Path)
310
        // Expect: Direct scalar comparison assertion (Float)
311
        $field->setReturnType('silverstripe');
312
        $field->setValue($this->getFixture('object'));
313
314
        $res = $field->query('#>', '{"floats":"0"}');
315
316
        $this->assertInternalType('array', $res);
317
        $this->assertInternalType('array', $res[0]); // Why? Because value of "floats" key is a JSON array
318
        $this->assertInstanceOf(DBFloat::class, array_values($res[0])[0]);
319
        $this->assertEquals(99.99, array_values($res[0])[0]->getValue());
320
321
        // Data Source: Object
322
        // Return Type: SILVERSTRIPE
323
        // Operator: "#>" (Path)
324
        // Expect: Direct scalar comparison assertion (Int)
325
        $field->setReturnType('silverstripe');
326
        $field->setValue($this->getFixture('object'));
327
328
        $res = $field->query('#>', '{"ints":"0"}');
329
330
        $this->assertInternalType('array', $res);
331
        $this->assertInternalType('array', $res[0]); // Why? Because value of "floats" key is a JSON array
332
        $this->assertInstanceOf(DBInt::class, array_values($res[0])[1]);
333
        $this->assertEquals(6, array_values($res[0])[1]->getValue());
334
335
        // Data Source: Object
336
        // Return Type: SILVERSTRIPE
337
        // Operator: "#>" (Path)
338
        // Expect: Direct scalar comparison assertion (Boolean)
339
        $field->setReturnType('silverstripe');
340
        $field->setValue($this->getFixture('object'));
341
342
        $res = $field->query('#>', '{"booleans":"0"}');
343
344
        $this->assertInternalType('array', $res);
345
        $this->assertInternalType('array', $res[0]); // Why? Because value of "booleans" key is a JSON array
346
        $this->assertInstanceOf(DBBoolean::class, array_values($res[0])[0]);
347
        $this->assertEquals(1, array_values($res[0])[0]->getValue());
348
349
        // #1 Empty source data
350
        $field->setReturnType('array');
351
        $field->setValue('');
352
        $this->assertEquals([], $field->query('#>', '{"japanese":"fast"}'));
353
354
        // #2 JSON path not found
355
        $field->setReturnType('silverstripe');
356
        $field->setValue($this->getFixture('object'));
357
        $this->assertNull($field->query('#>', '{"ints":"1"}')); // The "ints" key only has a single array as a value
358
359
        // #3 Invalid operand on RHS
360
        $this->setExpectedException(JSONTextException::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
361
        $field->setReturnType('array');
362
        $field->setValue($this->getFixture('object'));
363
        $this->assertEquals(['Kawasaki' => 'KR1S250'], $field->query('#>', '{"japanese":"fast"'));
364
    }
365
366
    /**
367
     * Tests query() by means of JSONPath expressions.
368
     * N.b. only a minimum no. tests should be required, given that the 3rd party lib via which this functionality
369
     * is derived, is itself well tested.
370
     */
371
    public function testQueryWithMatchOnExpr()
372
    {
373
        $field = $this->sut;
374
375
        // Data Source: Object
376
        // Return Type: ARRAY
377
        // Expression: "$.." (Everything)
378
        // Expect: Array, obviously due to no. nodes in the source JSON
379
        $field->setReturnType('array');
380
        $field->setValue($this->getFixture('object'));
381
        $this->assertInternalType('array', $field->query('$..'));
382
        $this->assertCount(25, $field->query('$..'));
383
384
        // Data Source: Object
385
        // Return Type: ARRAY
386
        // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese")
387
        // Expect: Array
388
        $field->setReturnType('array');
389
        $field->setValue($this->getFixture('object'));
390
        $this->assertCount(4, $field->query('$..japanese[*]'));
391
        $this->assertEquals([
392
            ['Subaru' => 'Impreza'],
393
            ['Honda' => 'Civic'],
394
            ['Kawasaki' => 'KR1S250'],
395
            ['Honda' => 'FS1']
396
        ], $field->query('$..japanese[*]'));
397
398
        // Data Source: Object
399
        // Return Type: JSON
400
        // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese")
401
        // Expect: JSON Array of JSON objects
402
        $field->setReturnType('json');
403
        $field->setValue($this->getFixture('object'));
404
        $this->assertEquals(
405
            '[{"Subaru":"Impreza"},{"Honda":"Civic"},{"Kawasaki":"KR1S250"},{"Honda":"FS1"}]',
406
            $field->query('$..japanese[*]')
407
        );
408
409
        // Data Source: Object
410
        // Return Type: Array
411
        // Expression: "$.cars.american[*]" (All entries in the american cars node)
412
        // Expect: Array
413
        $field->setReturnType('array');
414
        $field->setValue($this->getFixture('object'));
415
        $this->assertEquals(['buick', 'oldsmobile'], $field->query('$.cars.american[*]'));
416
        $this->assertEquals(['buick'], $field->query('$.cars.american[0]'));
417
418
        // Data Source: Object
419
        // Return Type: Array
420
        // Expression: "$.cars.american[*]" (All entries in the american cars node)
421
        // Expect: Array 0f SilverStripe types
422
        $field->setReturnType('silverstripe');
423
        $field->setValue($this->getFixture('object'));
424
        $this->assertInternalType('array', $field->query('$.cars.american[*]'));
425
        $this->assertCount(2, $field->query('$.cars.american[*]'));
426
        $this->assertInstanceOf(DBVarchar::class, $field->query('$.cars.american[*]')[0]);
427
        $this->assertEquals('buick', $field->query('$.cars.american[*]')[0]->getValue());
428
    }
429
430
    /**
431
     * Tests query() by means of passing bad argument combinations.
432
     */
433
    public function testQueryWithInvalidArgs()
434
    {
435
        $field = $this->sut;
436
437
        $this->setExpectedException(JSONTextException::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
438
        $field->setValue('["trabant"]');
439
        $field->query('$.cars.american[*]', 'foo'); // Cannot pass multiple args when in JSONPath context
440
441
        $this->setExpectedException(null);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
442
        $field->setValue('');
443
        $field->query('$.cars.american[*]', 'foo'); // Still shouldn't, but routine only kicks in _After_ checks made in setValue()
444
    }
445
446
    /**
447
     * Get the contents of a fixture
448
     *
449
     * @param string $fixture
450
     * @return string
451
     */
452
    private function getFixture($fixture)
453
    {
454
        $files = $this->fixtures;
455
        return file_get_contents($files[$fixture]);
456
    }
457
458
}
459