Issues (6)

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/Net/URL2Test.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
 * Net_URL2, a class representing a URL as per RFC 3986.
4
 *
5
 * PHP version 5
6
 *
7
 * @category Networking
8
 * @package  Net_URL2
9
 * @author   Some Pear Developers <[email protected]>
10
 * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
11
 * @link     https://tools.ietf.org/html/rfc3986
12
 */
13
14
/**
15
 * Test class for Net_URL2.
16
 *
17
 * @category Networking
18
 * @package  Net_URL2
19
 * @author   Some Pear Developers <[email protected]>
20
 * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
21
 * @version  Release: @package_version@
22
 * @link     https://pear.php.net/package/Net_URL2
23
 */
24
class Net_URL2Test extends PHPUnit_Framework_TestCase
25
{
26
    /**
27
     * Tests setting a zero-length string and false as authority
28
     * Also: Regression test for Bug #20420
29
     *
30
     * @covers Net_URL2::setAuthority
31
     * @return void
32
     * @link https://pear.php.net/bugs/bug.php?id=20420
33
     */
34
    public function testSetEmptyAuthority()
35
    {
36
        $url = new Net_URL2('http://www.example.com/');
37
        $url->setAuthority('');
38
        $this->assertSame('', $url->getAuthority());
39
        $this->assertSame('', $url->getHost());
40
        $this->assertSame(false, $url->getPort());
41
        $this->assertSame(false, $url->getUserinfo());
42
        $this->assertSame(false, $url->getUser());
43
44
        $url->setAuthority(false);
45
        $this->assertSame(false, $url->getAuthority());
46
    }
47
48
    /**
49
     * Tests setting an empty userinfo part
50
     * Also: Regression test for Bug #20013 and Bug #20399
51
     *
52
     * @covers Net_URL2::setUserinfo
53
     * @covers Net_URL2::getUserinfo
54
     * @covers Net_URL2::getURL
55
     * @return void
56
     * @link https://pear.php.net/bugs/bug.php?id=20013
57
     * @link https://pear.php.net/bugs/bug.php?id=20399
58
     */
59
    public function testSetEmptyUserinfo()
60
    {
61
        $url = new Net_URL2('http://@www.example.com/');
62
        $this->assertSame('http://www.example.com/', $url->getURL());
63
64
        $url = new Net_URL2('http://www.example.com/');
65
        $this->assertSame('http://www.example.com/', $url->getURL());
66
        $url->setUserinfo('');
67
        $this->assertSame('http://www.example.com/', $url->getURL());
68
        $this->assertSame('', $url->getUserinfo());
69
        $url->setUserinfo(false);
70
        $this->assertSame('http://www.example.com/', $url->getURL());
71
        $this->assertFalse($url->getUserinfo());
72
    }
73
74
    /**
75
     * Tests an URL with no userinfo and normalization
76
     *
77
     * Also: Regression test for Bug #20385
78
     *
79
     * @covers Net_URL2::getUserinfo
80
     * @covers Net_URL2::normalize
81
     * @covers Net_URL2::getNormalizedURL
82
     * @return void
83
     * @link https://pear.php.net/bugs/bug.php?id=20385
84
     */
85
    public function testNoUserinfoAndNormalize()
86
    {
87
        $testUrl = 'http://www.example.com/';
88
89
        $url = new Net_URL2($testUrl);
90
        $this->assertFalse($url->getUserinfo());
91
92
        $url->normalize();
93
        $this->assertFalse($url->getUserinfo());
94
95
        $this->assertEquals($testUrl, $url->getURL());
96
        $this->assertEquals($testUrl, $url->getNormalizedURL());
97
    }
98
99
    /**
100
     * Tests setQueryVariable().
101
     *
102
     * @return void
103
     */
104
    public function testSetQueryVariable()
105
    {
106
107
        $url = new Net_URL2('http://www.example.com/');
108
        $url->setQueryVariable('pear', 'fun');
109
        $this->assertEquals($url->getURL(), 'http://www.example.com/?pear=fun');
110
    }
111
112
    /**
113
     * Tests setQueryVariables().
114
     *
115
     * @return void
116
     */
117
    public function testSetQueryVariables()
118
    {
119
120
        $url = new Net_URL2('http://www.example.com/');
121
        $url->setQueryVariables(array('pear' => 'fun'));
122
        $this->assertEquals('http://www.example.com/?pear=fun', $url->getURL());
123
        $url->setQueryVariables(array('pear' => 'fun for sure'));
124
        $this->assertEquals(
125
            'http://www.example.com/?pear=fun%20for%20sure', $url->getURL()
126
        );
127
    }
128
129
    /**
130
     * Tests unsetQueryVariable()
131
     *
132
     * @return void
133
     */
134
    public function testUnsetQueryVariable()
135
    {
136
        $url = new Net_URL2(
137
            'http://www.example.com/?name=david&pear=fun&fish=slippery'
138
        );
139
140
        $removes = array(
141
            'pear' => 'http://www.example.com/?name=david&fish=slippery',
142
            'name' => 'http://www.example.com/?fish=slippery',
143
            'fish' => 'http://www.example.com/',
144
        );
145
146
        foreach ($removes as $name => $expected) {
147
            $url->unsetQueryVariable($name);
148
            $this->assertEquals($expected, $url);
149
        }
150
    }
151
152
    /**
153
     * Tests setQuery().
154
     *
155
     * @return void
156
     */
157
    public function testSetQuery()
158
    {
159
160
        $url = new Net_URL2('http://www.example.com/');
161
        $url->setQuery('flapdoodle&dilly%20all%20day');
162
        $this->assertEquals(
163
            $url->getURL(), 'http://www.example.com/?flapdoodle&dilly%20all%20day'
164
        );
165
    }
166
167
    /**
168
     * Tests getQuery().
169
     *
170
     * @return void
171
     */
172
    public function testGetQuery()
173
    {
174
175
        $url = new Net_URL2('http://www.example.com/?foo');
176
        $this->assertEquals($url->getQuery(), 'foo');
177
        $url = new Net_URL2('http://www.example.com/?pear=fun&fruit=fruity');
178
        $this->assertEquals($url->getQuery(), 'pear=fun&fruit=fruity');
179
    }
180
181
    /**
182
     * Tests setScheme().
183
     *
184
     * @return void
185
     */
186
    public function testSetScheme()
187
    {
188
189
        $url = new Net_URL2('http://www.example.com/');
190
        $url->setScheme('ftp');
191
        $this->assertEquals($url->getURL(), 'ftp://www.example.com/');
192
        $url->setScheme('gopher');
193
        $this->assertEquals($url->getURL(), 'gopher://www.example.com/');
194
    }
195
196
    /**
197
     * Tests setting the fragment.
198
     *
199
     * @return void
200
     */
201
    public function testSetFragment()
202
    {
203
204
        $url = new Net_URL2('http://www.example.com/');
205
        $url->setFragment('pear');
206
        $this->assertEquals('http://www.example.com/#pear', $url->getURL());
207
    }
208
209
    /**
210
     * A dataProvider for paths that are solved to a base URI.
211
     *
212
     * @see testResolveUrls
213
     * @return array
214
     */
215
    public function provideResolveUrls()
216
    {
217
        return array(
218
            array(
219
                // Examples from RFC 3986, section 5.4.
220
                // relative base-URI, (URL => absolute URL), [(options)]
221
                'http://a/b/c/d;p?q',
222
                array(
223
                    'g:h'           => 'g:h',
224
                    'g'             => 'http://a/b/c/g',
225
                    './g'           => 'http://a/b/c/g',
226
                    'g/'            => 'http://a/b/c/g/',
227
                    '/g'            => 'http://a/g',
228
                    '//g'           => 'http://g',
229
                    '?y'            => 'http://a/b/c/d;p?y',
230
                    'g?y'           => 'http://a/b/c/g?y',
231
                    '#s'            => 'http://a/b/c/d;p?q#s',
232
                    'g#s'           => 'http://a/b/c/g#s',
233
                    'g?y#s'         => 'http://a/b/c/g?y#s',
234
                    ';x'            => 'http://a/b/c/;x',
235
                    'g;x'           => 'http://a/b/c/g;x',
236
                    'g;x?y#s'       => 'http://a/b/c/g;x?y#s',
237
                    ''              => 'http://a/b/c/d;p?q',
238
                    '.'             => 'http://a/b/c/',
239
                    './'            => 'http://a/b/c/',
240
                    '..'            => 'http://a/b/',
241
                    '../'           => 'http://a/b/',
242
                    '../g'          => 'http://a/b/g',
243
                    '../..'         => 'http://a/',
244
                    '../../'        => 'http://a/',
245
                    '../../g'       => 'http://a/g',
246
                    '../../../g'    => 'http://a/g',
247
                    '../../../../g' => 'http://a/g',
248
                    '/./g'          => 'http://a/g',
249
                    '/../g'         => 'http://a/g',
250
                    'g.'            => 'http://a/b/c/g.',
251
                    '.g'            => 'http://a/b/c/.g',
252
                    'g..'           => 'http://a/b/c/g..',
253
                    '..g'           => 'http://a/b/c/..g',
254
                    './../g'        => 'http://a/b/g',
255
                    './g/.'         => 'http://a/b/c/g/',
256
                    'g/./h'         => 'http://a/b/c/g/h',
257
                    'g/../h'        => 'http://a/b/c/h',
258
                    'g;x=1/./y'     => 'http://a/b/c/g;x=1/y',
259
                    'g;x=1/../y'    => 'http://a/b/c/y',
260
                    'g?y/./x'       => 'http://a/b/c/g?y/./x',
261
                    'g?y/../x'      => 'http://a/b/c/g?y/../x',
262
                    'g#s/./x'       => 'http://a/b/c/g#s/./x',
263
                    'g#s/../x'      => 'http://a/b/c/g#s/../x',
264
                    'http:g'        => 'http:g',
265
                ),
266
            ),
267
            array(
268
                'http://a/b/c/d;p?q',
269
                array('http:g' => 'http://a/b/c/g'),
270
                array('::OPTION_STRICT' => false)
271
            ),
272
        );
273
    }
274
275
    /**
276
     * Test the resolve() function to resolve URLs to each other.
277
     *
278
     * @param string $baseURL               base-URI
279
     * @param array  $relativeAbsolutePairs url-pairs, relative => resolved
280
     * @param array  $options               Net_URL2 options
281
     *
282
     * @dataProvider provideResolveUrls
283
     * @covers Net_URL2::resolve
284
     * @return void
285
     */
286
    public function testResolveUrls($baseURL, array $relativeAbsolutePairs,
287
        array $options = array()
288
    ) {
289
        $options = $this->_translateOptionData($options);
290
        $base    = new Net_URL2($baseURL, $options);
291
        $count = count($relativeAbsolutePairs);
292
        $this->assertGreaterThan(0, $count, 'relative-absolute-pairs data is empty');
293
        foreach ($relativeAbsolutePairs as $relativeURL => $absoluteURL) {
294
            $this->assertSame($absoluteURL, (string) $base->resolve($relativeURL));
295
        }
296
    }
297
298
    /**
299
     * Helper method to turn options with strings as the constant names
300
     * (to allow to externalize the fixtures) into a concrete options
301
     * array that uses the values from the Net_URL2 class constants.
302
     *
303
     * @param array $options options
304
     *
305
     * @return array
306
     */
307
    private function _translateOptionData(array $options)
308
    {
309
        // translate string option-names to class constant starting with a colon.
310
        foreach ($options as $name => $value) {
311
            if ($name[0] === ':') {
312
                unset($options[$name]);
313
                $options[constant("Net_URL2$name")] = $value;
314
            }
315
        }
316
        return $options;
317
    }
318
319
    /**
320
     * Test the resolve() function throwing an exception with invalid data.
321
     *
322
     * @covers Net_URL2::resolve
323
     * @return void
324
     */
325
    public function testResolveException()
326
    {
327
        // resolving a relative to a relative URL throws an exception
328
        $base = new Net_URL2('news.html?category=arts');
329
        $this->addToAssertionCount(1);
330
        try {
331
            $base->resolve('../arts.html#section-2.4');
332
        } catch (Exception $e) {
333
            $expected = 'Base-URL must be absolute if reference is not fragment-onl';
334
            $this->assertStringStartsWith($expected, $e->getMessage());
335
            return;
336
        }
337
        $this->fail('Expected exception not thrown.');
338
    }
339
340
    /**
341
     * Assert that there is a last error message and it contains needle.
342
     *
343
     * @param string $needle needle
344
     *
345
     * @return void
346
     */
347
    private function _assertLastErrorContains($needle)
348
    {
349
        $error = error_get_last();
350
        $this->assertArrayHasKey('message', $error, 'there was an error previously');
351
        $pos = strpos($error['message'], $needle);
352
353
        $this->assertTrue(
354
            false !== $pos,
355
            sprintf(
356
                'Last error message "%s" contains "%s"', $error['message'], $needle
357
            )
358
        );
359
    }
360
361
    /**
362
     * Test UrlEncoding
363
     *
364
     * @return void
365
     * @link   https://pear.php.net/bugs/bug.php?id=18267
366
     */
367
    public function testUrlEncoding()
368
    {
369
        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
370
        $url     = new Net_URL2('http://localhost/bug.php', $options);
371
        $url->setQueryVariables(
372
            array(
373
                'indexed' => array(
374
                    'first value', 'second value', array('foo', 'bar'),
375
                )
376
            )
377
        );
378
        $this->assertEquals(
379
            'http://localhost/bug.php?indexed[0]=first%20value&indexed[1]' .
380
            '=second%20value&indexed[2][0]=foo&indexed[2][1]=bar',
381
            strval($url)
382
        );
383
    }
384
385
    /**
386
     * A test to verify that keys in QUERY_STRING are encoded by default.
387
     *
388
     * @return void
389
     * @see    Net_URL2::OPTION_ENCODE_KEYS
390
     * @see    Net_URL2::buildQuery()
391
     */
392
    public function testEncodeKeys()
393
    {
394
        $url = new Net_URL2('http://example.org');
395
        $url->setQueryVariables(array('helgi rulez' => 'till too'));
396
        $this->assertEquals(
397
            'http://example.org?helgi%20rulez=till%20too',
398
            strval($url)
399
        );
400
    }
401
402
    /**
403
     * A test to verify that keys in QUERY_STRING are not encoded when we supply
404
     * 'false' via {@link Net_URL2::__construct()}.
405
     *
406
     * @return void
407
     * @see    Net_URL2::OPTION_ENCODE_KEYS
408
     * @see    Net_URL2::buildQuery()
409
     */
410
    public function testDontEncodeKeys()
411
    {
412
        $url = new Net_URL2(
413
            'http://example.org',
414
            array(Net_URL2::OPTION_ENCODE_KEYS => false)
415
        );
416
        $url->setQueryVariables(array('till rulez' => 'helgi too'));
417
        $this->assertEquals(
418
            'http://example.org?till rulez=helgi%20too',
419
            strval($url)
420
        );
421
    }
422
423
    /**
424
     * Brackets for array query variables
425
     *
426
     * Also text to not encode zero based integer sequence into brackets
427
     *
428
     * @return void
429
     *
430
     * @link https://pear.php.net/bugs/bug.php?id=20427
431
     */
432
    public function testUseBrackets()
433
    {
434
        $url = new Net_URL2('http://example.org/');
435
        $url->setQueryVariables(array('foo' => array('bar', 'baz')));
436
        $expected = 'http://example.org/?foo[]=bar&foo[]=baz';
437
        $this->assertEquals($expected, $url->getURL());
438
439
        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
440
        $url     = new Net_URL2('http://example.org/', $options);
441
        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
442
        $expected = 'http://example.org/?foo[0]=bar&foo[1]=foobar';
443
        $this->assertEquals($expected, $url->getURL());
444
    }
445
446
    /**
447
     * Do not use brackets for query variables passed as array
448
     *
449
     * @return void
450
     */
451
    public function testDontUseBrackets()
452
    {
453
        $url = new Net_URL2(
454
            'http://example.org/',
455
            array(Net_URL2::OPTION_USE_BRACKETS => false)
456
        );
457
        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
458
        $this->assertEquals(
459
            'http://example.org/?foo=bar&foo=foobar',
460
            strval($url)
461
        );
462
    }
463
464
    /**
465
     * A dataProvider for example URIs from RFC 3986 Section 1.1.2
466
     *
467
     * @return array
468
     * @link http://tools.ietf.org/html/rfc3986#section-1.1.2
469
     * @see  testExampleUri
470
     */
471
    public function provideExampleUri()
472
    {
473
        return array(
474
            array('ftp://ftp.is.co.za/rfc/rfc1808.txt'),
475
            array('http://www.ietf.org/rfc/rfc2396.txt'),
476
            array('ldap://[2001:db8::7]/c=GB?objectClass?one'),
477
            array('mailto:[email protected]'),
478
            array('news:comp.infosystems.www.servers.unix'),
479
            array('tel:+1-816-555-1212'),
480
            array('telnet://192.0.2.16:80/'),
481
            array('urn:oasis:names:specification:docbook:dtd:xml:4.1.2'),
482
        );
483
    }
484
485
    /**
486
     * test that Net_URL2 works with the example URIs from RFC 3986 Section 1.1.2
487
     *
488
     * @param string $uri example URI
489
     *
490
     * @return       void
491
     * @dataProvider provideExampleUri
492
     * @link         http://tools.ietf.org/html/rfc3986#section-1.1.2
493
     * @see          testComponentRecompositionAndNormalization
494
     */
495
    public function testExampleUri($uri)
496
    {
497
        $url = new Net_URL2($uri);
498
        $this->assertSame($uri, $url->__toString());
499
        $url->normalize();
500
        $this->assertSame($uri, $url->__toString());
501
    }
502
503
    /**
504
     * A dataProvider for pairs of paths with dot segments and
505
     * their form when removed.
506
     *
507
     * @see testRemoveDotSegments
508
     * @return array
509
     */
510
    public function providePath()
511
    {
512
        // The numbers behind are in reference to sections
513
        // in RFC 3986 5.2.4. Remove Dot Segments
514
        return array(
515
            array('../', ''), // 2. A.
516
            array('./', ''), // 2. A.
517
            array('/./', '/'), // 2. B.
518
            array('/.', '/'), // 2. B.
519
            array('/../', '/'), // 2. C.
520
            array('/..', '/'), // 2. C.
521
            array('..', ''), // 2. D.
522
            array('.', ''), // 2. D.
523
            array('a', 'a'), // 2. E.
524
            array('/a', '/a'), // 2. E.
525
            array('/a/b/c/./../../g', '/a/g'), // 3.
526
            array('mid/content=5/../6', 'mid/6'), // 3.
527
            array('../foo/bar.php', 'foo/bar.php'),
528
            array('/foo/../bar/boo.php', '/bar/boo.php'),
529
            array('/boo/..//foo//bar.php', '//foo//bar.php'),
530
            array('/./foo/././bar.php', '/foo/bar.php'),
531
            array('./.', ''),
532
        );
533
    }
534
535
    /**
536
     * Test removal of dot segments
537
     *
538
     * @param string $path      Path
539
     * @param string $assertion Assertion
540
     *
541
     * @dataProvider providePath
542
     * @covers Net_URL2::removeDotSegments
543
     * @return void
544
     */
545
    public function testRemoveDotSegments($path, $assertion)
546
    {
547
        $this->assertEquals($assertion, Net_URL2::removeDotSegments($path));
548
    }
549
550
    /**
551
     * Test removeDotSegments() loop limit warning
552
     *
553
     * @covers Net_URL2::removeDotSegments
554
     * @return void
555
     */
556
    public function testRemoveDotSegmentsLoopLimit()
557
    {
558
        $loopLimit = 256;
559
        $segments  = str_repeat('a/', $loopLimit);
560
561
        @Net_URL2::removeDotSegments($segments . 'b/');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
562
563
        $this->_assertLastErrorContains(sprintf(' loop limit %d ', $loopLimit + 1));
564
        $this->_assertLastErrorContains(" (left: '/b/')");
565
    }
566
567
    /**
568
     * A dataProvider for query strings and their array representation
569
     *
570
     * @see testGetQueryVariables
571
     * @return array
572
     */
573
    public function provideQueryStrings()
574
    {
575
        // If the second (expected) value is set or not null, parse_str() differs.
576
        // Notes on PHP differences with each entry/block
577
        return array(
578
            // Net_URL2::getQueryVariables() non-bracket mode
579
            array('test=1&t%65st=%41&extra=',
580
                array('test' => array('1', 'A'), 'extra' => ''),
581
                array('::OPTION_USE_BRACKETS' => false)),
582
            array(''),
583
            array('='),
584
            array('key'),
585
            array('key='),
586
            array('=value'),
587
            array('k=v'),
588
            // no space as var-name in PHP (array()):
589
            array(' ',   array(' ' => '' )),
590
            array(' =v', array(' ' => 'v')),
591
            array('key=value'),
592
            // PHP replaces ".", " " and "[" in name replaced by "_":
593
            array('key.=value' , array('key.'  => 'value')),
594
            array('key =value' , array('key '  => 'value')),
595
            array('key[=value' , array('key['  => 'value')),
596
            array("key\0=value", array("key\0" => 'value')),
597
            array('key]=value'),
598
            array('key[]=value'),
599
            array('[]=value'),
600
            array(']=value'),
601
            array(']]=value'),
602
            // PHP drops variables that are an open bracket only
603
            array('[=value', array('[' => 'value')),
604
            // PHP drops spaces in brackets:
605
            array('key[ ]=value', array('key'  => array(' ' => 'value'))),
606
            // PHP replaces space " " in name by "_"
607
            array('key []=1'    , array('key ' => array('1'           ))) ,
608
            // PHP does not support "\0" in var-names:
609
            array("key[\0]=value"   , array('key' => array("\0" => 'value'  ))),
610
            array("key[a\0]=value"  , array('key' => array("a\0" => 'value' ))),
611
            array("key[a\0b]=value" , array('key' => array("a\0b" => 'value'))),
612
            array('var[]=1&var[0][]=2'),
613
            array('key[] []=1'),
614
            array('key[] [] []=1'),
615
            array('key[] [] []'),
616
            array('key[] [] []=[] []'),
617
            array('[] [] []=[] []'),
618
        );
619
    }
620
621
    /**
622
     * Test parsing of query variables
623
     *
624
     * @param string $query    string
625
     * @param mixed  $expected null to test against parse_str() behavior
626
     * @param array  $options  Net_URL2 options
627
     *
628
     * @dataProvider provideQueryStrings
629
     * @covers       Net_URL2::getQueryVariables
630
     * @covers       Net_URL2::_queryArrayByKey
631
     * @covers       Net_URL2::_queryArrayByBrackets
632
     * @covers       Net_URL2::_queryKeyBracketOffset
633
     * @return void
634
     */
635
    public function testGetQueryVariables($query, $expected = null,
636
        array $options = array()
637
    ) {
638
        $options = $this->_translateOptionData($options);
639
640
        $url = new Net_URL2('', $options);
641
642
        if ($expected === null) {
643
            // parse_str() is in PHP before copy on write, therefore
644
            // it uses pass-by-reference for $expected to return
645
            // the array
646
            parse_str($query, $expected);
647
        }
648
649
        // Xdebug: If breakpoints are ignored, see Xdebug Issue 0000924
650
        $url->setQuery($query);
651
        $actual = $url->getQueryVariables();
652
653
        // Do two assertions, because the first one shows a more nice diff in case
654
        // it fails and the second one is actually strict which is what has to be
655
        // tested.
656
        $this->assertEquals($expected, $actual);
657
        $this->assertSame($expected, $actual);
658
    }
659
660
    /**
661
     * data provider of host and port
662
     *
663
     * @return array
664
     * @see testHostAndPort
665
     */
666
    public function provideHostAndPort()
667
    {
668
        return array(
669
            array('[::1]', '[::1]', false),
670
            array('[::1]:', '[::1]', false),
671
            array('[::1]:128', '[::1]', '128'),
672
            array('127.0.0.1', '127.0.0.1', false),
673
            array('127.0.0.1:', '127.0.0.1', false),
674
            array('127.0.0.1:128', '127.0.0.1', '128'),
675
            array('localhost', 'localhost', false),
676
            array('localhost:', 'localhost', false),
677
            array('localhost:128', 'localhost', '128'),
678
        );
679
    }
680
681
    /**
682
     * test that an authority containing host and port maps to expected host and port
683
     *
684
     * This is also a regression test to test that using ip-literals works along-
685
     * side ipv4 and reg-name hosts incl. port numbers
686
     *
687
     * It was reported as Bug #20423 on 2014-10-06 18:25 UTC that
688
     * http://[::1]// URI drops the host
689
     *
690
     * @param string      $authority    string
691
     * @param string      $expectedHost string
692
     * @param string|bool $expectedPort string or FALSE
693
     *
694
     * @return void
695
     * @dataProvider provideHostAndPort
696
     * @covers       Net_URL2::setAuthority()
697
     * @link         https://pear.php.net/bugs/bug.php?id=20423
698
     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.2
699
     * @link         http://tools.ietf.org/html/rfc3986#section-3.2
700
     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.3
701
     */
702
    public function testHostAndPort($authority, $expectedHost, $expectedPort)
703
    {
704
        $uri = "http://{$authority}";
705
        $url = new Net_URL2($uri);
706
        $this->assertSame($expectedHost, $url->getHost());
707
        $this->assertSame($expectedPort, $url->getPort());
708
    }
709
710
    /**
711
     * This is a regression test to test that Net_URL2::getQueryVariables() does
712
     * not have a problem with nested array values in form of stacked brackets and
713
     * was reported as Bug #17036 on 2010-01-26 15:48 UTC that there would be
714
     * a problem with parsed query string.
715
     *
716
     * @link   https://pear.php.net/bugs/bug.php?id=17036
717
     * @covers Net_URL2::getQueryVariables
718
     * @return void
719
     */
720
    public function test17036()
721
    {
722
        $queryString = 'start=10&test[0][first][1.1][20]=coucou';
723
        $url         = new Net_URL2('?' . $queryString);
724
        $vars = $url->getQueryVariables();
725
726
        $expected = array();
727
        $expected['start'] = '10';
728
        $expected['test'][0]['first']['1.1'][20] = 'coucou';
729
730
        $this->assertEquals($expected, $vars); // give nice diff in case of failuer
731
        $this->assertSame($expected, $vars);   // strictly assert the premise
732
    }
733
734
    /**
735
     * This is a regression test to test that resolve() does
736
     * merge the path if the base path is empty as the opposite
737
     * was reported as Bug #19176 on 2011-12-31 02:07 UTC
738
     *
739
     * @return void
740
     */
741
    public function test19176()
742
    {
743
        $foo  = new Net_URL2('http://www.example.com');
744
        $test = $foo->resolve('test.html')->getURL();
745
        $this->assertEquals('http://www.example.com/test.html', $test);
746
    }
747
748
    /**
749
     * This is a regression test that removeDotSegments('0') is
750
     * working as it was reported as not-working in Bug #19315
751
     * on 2012-03-04 04:18 UTC.
752
     *
753
     * @return void
754
     */
755
    public function test19315()
756
    {
757
        $actual = Net_URL2::removeDotSegments('0');
758
        $this->assertSame('0', $actual);
759
760
        $nonStringObject = (object)array();
761
        try {
762
            Net_URL2::removeDotSegments($nonStringObject);
763
        } catch (PHPUnit_Framework_Error $error) {
764
            $this->addToAssertionCount(1);
765
        }
766
767
        if (!isset($error)) {
768
            $this->fail('Failed to verify that error was given.');
769
        }
770
        unset($error);
771
    }
772
773
    /**
774
     * This is a regression test to test that recovering from
775
     * a wrongly encoded URL is possible.
776
     *
777
     * It was requested as Request #19684 on 2011-12-31 02:07 UTC
778
     * that redirects containing spaces should work.
779
     *
780
     * @return void
781
     */
782
    public function test19684()
783
    {
784
        // Location: URL obtained Thu, 25 Apr 2013 20:51:31 GMT
785
        $urlWithSpace = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS N'
786
            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
787
            . '48+219853269+219853286';
788
789
        $urlCorrect = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS%20N'
790
            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
791
            . '48+219853269+219853286';
792
793
        $url = new Net_URL2($urlWithSpace);
794
795
        $this->assertTrue($url->isAbsolute());
796
797
        $urlPart = parse_url($urlCorrect, PHP_URL_PATH);
798
        $this->assertSame($urlPart, $url->getPath());
799
800
        $urlPart = parse_url($urlCorrect, PHP_URL_QUERY);
801
        $this->assertSame($urlPart, $url->getQuery());
802
803
        $this->assertSame($urlCorrect, (string)$url);
804
805
        $input    = 'http://example.com/get + + to my nose/';
806
        $expected = 'http://example.com/get%20+%20+%20to%20my%20nose/';
807
        $actual   = new Net_URL2($input);
808
        $this->assertEquals($expected, $actual);
809
        $actual->normalize();
810
    }
811
812
    /**
813
     * data provider of list of equivalent URLs.
814
     *
815
     * @see testNormalize
816
     * @see testConstructSelf
817
     * @return array
818
     */
819
    public function provideEquivalentUrlLists()
820
    {
821
        return array(
822
            // String equivalence:
823
            array('http://example.com/', 'http://example.com/'),
824
825
            // Originally first dataset:
826
            array('http://www.example.com/%9a', 'http://www.example.com/%9A'),
827
828
            // Example from RFC 3986 6.2.2.:
829
            array('example://a/b/c/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d'),
830
831
            // Example from RFC 3986 6.2.2.1.:
832
            array('HTTP://www.EXAMPLE.com/', 'http://www.example.com/'),
833
834
            // Example from RFC 3986 6.2.3.:
835
            array(
836
                'http://example.com', 'http://example.com/',
837
                'http://example.com:/', 'http://example.com:80/'
838
            ),
839
840
            // Bug #20161: URLs with "0" as host fail to normalize with empty path
841
            array('http://0/', 'http://0'),
842
843
            // Bug #20473: Normalize query and fragment broken
844
            array('foo:///?%66%6f%6f#%62%61%72', 'foo:///?foo#bar'),
845
        );
846
    }
847
848
    /**
849
     * This is a coverage test to invoke the normalize()
850
     * method.
851
     *
852
     * @return void
853
     *
854
     * @dataProvider provideEquivalentUrlLists
855
     */
856
    public function testNormalize()
857
    {
858
        $urls = func_get_args();
859
860
        $this->assertGreaterThanOrEqual(2, count($urls));
861
862
        $last = null;
863
864
        foreach ($urls as $index => $url) {
865
            $url = new Net_Url2($url);
866
            $url->normalize();
867
            if ($index) {
868
                $this->assertSame((string)$last, (string)$url);
869
            }
870
            $last = $url;
871
        }
872
    }
873
874
    /**
875
     * This is a coverage test to invoke __get and __set
876
     *
877
     * @covers Net_URL2::__get
878
     * @covers Net_URL2::__set
879
     * @return void
880
     */
881
    public function testMagicSetGet()
882
    {
883
        $url = new Net_URL2('');
884
885
        $property       = 'authority';
886
        $url->$property = $value = 'value';
887
        $this->assertEquals($value, $url->$property);
888
889
        $property       = 'unsetProperty';
890
        $url->$property = $value;
891
        $this->assertEquals(false, $url->$property);
892
    }
893
894
    /**
895
     * data provider of uri and normal URIs
896
     *
897
     * @return array
898
     * @see testComponentRecompositionAndNormalization
899
     */
900
    public function provideComposedAndNormalized()
901
    {
902
        return array(
903
            array(''),
904
            array('http:g'),
905
            array('user@host'),
906
            array('mailto:user@host'),
907
        );
908
    }
909
910
    /**
911
     * Tests Net_URL2 RFC 3986 5.3. Component Recomposition in the light
912
     * of normalization
913
     *
914
     * This is also a regression test to test that a missing authority works well
915
     * with normalization
916
     *
917
     * It was reported as Bug #20418 on 2014-10-02 22:10 UTC that there is an
918
     * Incorrect normalization of URI with missing authority
919
     *
920
     * @param string $uri URI
921
     *
922
     * @return       void
923
     * @covers       Net_URL2::getUrl()
924
     * @covers       Net_URL2::normalize()
925
     * @dataProvider provideComposedAndNormalized
926
     * @link         https://pear.php.net/bugs/bug.php?id=20418
927
     * @see          testExampleUri
928
     */
929
    public function testComponentRecompositionAndNormalization($uri)
930
    {
931
        $url = new Net_URL2($uri);
932
        $this->assertSame($uri, $url->getURL());
933
        $url->normalize();
934
        $this->assertSame($uri, $url->getURL());
935
    }
936
937
    /**
938
     * Tests Net_URL2 ctors URL parameter works with objects implementing
939
     * __toString().
940
     *
941
     * @dataProvider provideEquivalentUrlLists
942
     * @coversNothing
943
     * @return void
944
     */
945
    public function testConstructSelf()
946
    {
947
        $urls = func_get_args();
948
        foreach ($urls as $url) {
949
            $urlA = new Net_URL2($url);
950
            $urlB = new Net_URL2($urlA);
951
            $this->assertSame((string)$urlA, (string)$urlB);
952
        }
953
    }
954
955
    /**
956
     * This is a feature test to see that the userinfo's data is getting
957
     * encoded as outlined in #19684.
958
     *
959
     * @covers Net_URL2::setAuthority
960
     * @covers Net_URL2::setUserinfo
961
     * @return void
962
     */
963
    public function testEncodeDataUserinfoAuthority()
964
    {
965
        $url = new Net_URL2('http://john doe:[email protected]/');
966
        $this->assertSame('http://john%20doe:[email protected]/', (string)$url);
967
968
        $url->setUserinfo('john doe');
969
        $this->assertSame('http://john%[email protected]/', (string)$url);
970
971
        $url->setUserinfo('john doe', 'pa wd');
972
        $this->assertSame('http://john%20doe:pa%[email protected]/', (string)$url);
973
    }
974
975
    /**
976
     * This is a regression test to test that using the
977
     * host-name "0" does work with getAuthority()
978
     *
979
     * It was reported as Bug #20156 on 2013-12-27 22:56 UTC
980
     * that setAuthority() with "0" as host would not work
981
     *
982
     * @covers Net_URL2::setAuthority
983
     * @covers Net_URL2::getAuthority
984
     * @covers Net_URL2::setHost
985
     * @return void
986
     */
987
    public function test20156()
988
    {
989
        $url  = new Net_URL2('http://user:[email protected]:127/');
990
        $host = '0';
991
        $url->setHost($host);
992
        $this->assertSame('user:pass@0:127', $url->getAuthority());
993
994
        $url->setHost(false);
995
        $this->assertSame(false, $url->getAuthority());
996
997
        $url->setAuthority($host);
998
        $this->assertSame($host, $url->getAuthority());
999
    }
1000
1001
    /**
1002
     * This is a regression test to test that setting "0" as path
1003
     * does not break normalize().
1004
     *
1005
     * It was reported as Bug #20157 on 2013-12-27 23:42 UTC that
1006
     * normalize() with "0" as path would not work.
1007
     *
1008
     * @covers Net_URL2::normalize
1009
     * @return void
1010
     */
1011
    public function test20157()
1012
    {
1013
        $subject = 'http://example.com';
1014
        $url     = new Net_URL2($subject);
1015
        $url->setPath('0');
1016
        $url->normalize();
1017
        $this->assertSame("$subject/0", (string)$url);
1018
    }
1019
1020
    /**
1021
     * This is a regression test to ensure that fragment-only references can be
1022
     * resolved to a non-absolute Base-URI.
1023
     *
1024
     * It was reported as Bug #20158 2013-12-28 14:49 UTC that fragment-only
1025
     * references would not be resolved to non-absolute base URI
1026
     *
1027
     * @covers Net_URL2::resolve
1028
     * @covers Net_URL2::_isFragmentOnly
1029
     * @return void
1030
     */
1031
    public function test20158()
1032
    {
1033
        $base     = new Net_URL2('myfile.html');
1034
        $resolved = $base->resolve('#world');
1035
        $this->assertSame('myfile.html#world', (string)$resolved);
1036
    }
1037
1038
    /**
1039
     * This is a regression test to ensure that authority and path are properly
1040
     * combined when the path does not start with a slash which is the separator
1041
     * character between authority and path.
1042
     *
1043
     * It was reported as Bug #20159 2013-12-28 17:18 UTC that authority
1044
     * would not be terminated by slash
1045
     *
1046
     * @covers Net_URL2::getUrl
1047
     * @return void
1048
     */
1049
    public function test20159()
1050
    {
1051
        $url = new Net_URL2('index.html');
1052
        $url->setHost('example.com');
1053
        $this->assertSame('//example.com/index.html', (string)$url);
1054
    }
1055
1056
    /**
1057
     * This is a regression test to test that using the file:// URI scheme with
1058
     * an empty (default) hostname has the empty authority preserved when the
1059
     * full URL is build.
1060
     *
1061
     * It was reported as Bug #20304 on 2014-06-21 00:06 UTC
1062
     * that file:// URI are crippled.
1063
     *
1064
     * Tests with a default authority for the "file" URI scheme
1065
     *
1066
     * @covers Net_URL2::getURL
1067
     * @return void
1068
     * @link https://pear.php.net/bugs/bug.php?id=20304
1069
     */
1070
    public function test20304()
1071
    {
1072
        $file = 'file:///path/to/file';
1073
        $url = new Net_URL2($file);
1074
        $this->assertSame($file, (string) $url);
1075
1076
        $file = 'file://localhost/path/to/file';
1077
        $url = new Net_URL2($file);
1078
        $this->assertSame($file, (string) $url);
1079
1080
        $file = 'file://user@/path/to/file';
1081
        $url = new Net_URL2($file);
1082
        $this->assertSame($file, (string) $url);
1083
1084
        $file = 'FILE:///path/to/file';
1085
        $url = new Net_URL2($file);
1086
        $this->assertSame($file, (string) $url);
1087
    }
1088
}
1089