Completed
Push — master ( 85e358...cf3219 )
by Rakesh
04:24 queued 10s
created

Zend_Uri_Http   F

Complexity

Total Complexity 99

Size/Duplication

Total Lines 723
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 216
c 1
b 0
f 1
dl 0
loc 723
rs 2
wmc 99

29 Methods

Rating   Name   Duplication   Size   Complexity  
A validateHost() 0 15 3
A setUsername() 0 11 2
C _parseUri() 0 36 12
A getHost() 0 3 2
A validateFragment() 0 20 4
A getUsername() 0 3 2
A __construct() 0 41 4
A validatePort() 0 13 5
A getQuery() 0 3 2
A setFragment() 0 11 2
A addReplaceQueryParameters() 0 4 1
B getUri() 0 21 7
A getQueryAsArray() 0 8 2
A validatePath() 0 20 4
A validateUsername() 0 21 4
A getPassword() 0 3 2
A validateQuery() 0 20 4
A getPort() 0 3 2
A removeQueryParameters() 0 4 1
A getFragment() 0 3 2
A setPassword() 0 11 2
B valid() 0 10 7
A getPath() 0 3 2
A setPort() 0 11 2
A validatePassword() 0 26 6
A setPath() 0 11 2
A setQuery() 0 31 5
A fromString() 0 18 4
A setHost() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like Zend_Uri_Http often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Zend_Uri_Http, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Zend Framework
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://framework.zend.com/license/new-bsd
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category  Zend
16
 * @package   Zend_Uri
17
 * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
18
 * @license   http://framework.zend.com/license/new-bsd     New BSD License
19
 * @version   $Id$
20
 */
21
22
/**
23
 * @see Zend_Uri
24
 */
25
require_once 'Zend/Uri.php';
26
27
/**
28
 * @see Zend_Validate_Hostname
29
 */
30
require_once 'Zend/Validate/Hostname.php';
31
32
/**
33
 * HTTP(S) URI handler
34
 *
35
 * @category  Zend
36
 * @package   Zend_Uri
37
 * @uses      Zend_Uri
38
 * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
39
 * @license   http://framework.zend.com/license/new-bsd     New BSD License
40
 */
41
class Zend_Uri_Http extends Zend_Uri
42
{
43
    /**
44
     * Character classes for validation regular expressions
45
     */
46
    const CHAR_ALNUM    = 'A-Za-z0-9';
47
    const CHAR_MARK     = '-_.!~*\'()\[\]';
48
    const CHAR_RESERVED = ';\/?:@&=+$,';
49
    const CHAR_SEGMENT  = ':@&=+$,;';
50
    const CHAR_UNWISE   = '{}|\\\\^`';
51
52
    /**
53
     * HTTP username
54
     *
55
     * @var string
56
     */
57
    protected $_username = '';
58
59
    /**
60
     * HTTP password
61
     *
62
     * @var string
63
     */
64
    protected $_password = '';
65
66
    /**
67
     * HTTP host
68
     *
69
     * @var string
70
     */
71
    protected $_host = '';
72
73
    /**
74
     * HTTP post
75
     *
76
     * @var string
77
     */
78
    protected $_port = '';
79
80
    /**
81
     * HTTP part
82
     *
83
     * @var string
84
     */
85
    protected $_path = '';
86
87
    /**
88
     * HTTP query
89
     *
90
     * @var string
91
     */
92
    protected $_query = '';
93
94
    /**
95
     * HTTP fragment
96
     *
97
     * @var string
98
     */
99
    protected $_fragment = '';
100
101
    /**
102
     * Regular expression grammar rules for validation; values added by constructor
103
     *
104
     * @var array
105
     */
106
    protected $_regex = array();
107
108
    /**
109
     * Constructor accepts a string $scheme (e.g., http, https) and a scheme-specific part of the URI
110
     * (e.g., example.com/path/to/resource?query=param#fragment)
111
     *
112
     * @param  string $scheme         The scheme of the URI
113
     * @param  string $schemeSpecific The scheme-specific part of the URI
114
     * @throws Zend_Uri_Exception When the URI is not valid
115
     */
116
    protected function __construct($scheme, $schemeSpecific = '')
117
    {
118
        // Set the scheme
119
        $this->_scheme = $scheme;
120
121
        // Set up grammar rules for validation via regular expressions. These
122
        // are to be used with slash-delimited regular expression strings.
123
124
        // Escaped special characters (eg. '%25' for '%')
125
        $this->_regex['escaped']    = '%[[:xdigit:]]{2}';
126
127
        // Unreserved characters
128
        $this->_regex['unreserved'] = '[' . self::CHAR_ALNUM . self::CHAR_MARK . ']';
129
130
        // Segment can use escaped, unreserved or a set of additional chars
131
        $this->_regex['segment']    = '(?:' . $this->_regex['escaped'] . '|[' .
132
            self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_SEGMENT . '])*';
133
134
        // Path can be a series of segmets char strings seperated by '/'
135
        $this->_regex['path']       = '(?:\/(?:' . $this->_regex['segment'] . ')?)+';
136
137
        // URI characters can be escaped, alphanumeric, mark or reserved chars
138
        $this->_regex['uric']       = '(?:' . $this->_regex['escaped'] . '|[' .
139
            self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_RESERVED .
140
141
        // If unwise chars are allowed, add them to the URI chars class
142
            (self::$_config['allow_unwise'] ? self::CHAR_UNWISE : '') . '])';
143
144
        // If no scheme-specific part was supplied, the user intends to create
145
        // a new URI with this object.  No further parsing is required.
146
        if (strlen($schemeSpecific) === 0) {
147
            return;
148
        }
149
150
        // Parse the scheme-specific URI parts into the instance variables.
151
        $this->_parseUri($schemeSpecific);
152
153
        // Validate the URI
154
        if ($this->valid() === false) {
155
            require_once 'Zend/Uri/Exception.php';
156
            throw new Zend_Uri_Exception('Invalid URI supplied');
157
        }
158
    }
159
160
    /**
161
     * Creates a Zend_Uri_Http from the given string
162
     *
163
     * @param  string $uri String to create URI from, must start with
164
     *                     'http://' or 'https://'
165
     * @throws InvalidArgumentException  When the given $uri is not a string or
166
     *                                   does not start with http:// or https://
167
     * @throws Zend_Uri_Exception        When the given $uri is invalid
168
     * @return Zend_Uri_Http
169
     */
170
    public static function fromString($uri)
171
    {
172
        if (is_string($uri) === false) {
0 ignored issues
show
introduced by
The condition is_string($uri) === false is always false.
Loading history...
173
            require_once 'Zend/Uri/Exception.php';
174
            throw new Zend_Uri_Exception('$uri is not a string');
175
        }
176
177
        $uri            = explode(':', $uri, 2);
178
        $scheme         = strtolower($uri[0]);
179
        $schemeSpecific = isset($uri[1]) === true ? $uri[1] : '';
180
181
        if (in_array($scheme, array('http', 'https')) === false) {
182
            require_once 'Zend/Uri/Exception.php';
183
            throw new Zend_Uri_Exception("Invalid scheme: '$scheme'");
184
        }
185
186
        $schemeHandler = new Zend_Uri_Http($scheme, $schemeSpecific);
187
        return $schemeHandler;
188
    }
189
190
    /**
191
     * Parse the scheme-specific portion of the URI and place its parts into instance variables.
192
     *
193
     * @param  string $schemeSpecific The scheme-specific portion to parse
194
     * @throws Zend_Uri_Exception When scheme-specific decoposition fails
195
     * @throws Zend_Uri_Exception When authority decomposition fails
196
     * @return void
197
     */
198
    protected function _parseUri($schemeSpecific)
199
    {
200
        // High-level decomposition parser
201
        $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~';
202
        $status  = @preg_match($pattern, $schemeSpecific, $matches);
203
        if ($status === false) {
204
            require_once 'Zend/Uri/Exception.php';
205
            throw new Zend_Uri_Exception('Internal error: scheme-specific decomposition failed');
206
        }
207
208
        // Failed decomposition; no further processing needed
209
        if ($status === false) {
210
            return;
211
        }
212
213
        // Save URI components that need no further decomposition
214
        $this->_path     = isset($matches[4]) === true ? $matches[4] : '';
215
        $this->_query    = isset($matches[6]) === true ? $matches[6] : '';
216
        $this->_fragment = isset($matches[8]) === true ? $matches[8] : '';
217
218
        // Additional decomposition to get username, password, host, and port
219
        $combo   = isset($matches[3]) === true ? $matches[3] : '';
220
        $pattern = '~^(([^:@]*)(:([^@]*))?@)?((?(?=[[])[[][^]]+[]]|[^:]+))(:(.*))?$~';        
221
        $status  = @preg_match($pattern, $combo, $matches);
222
        if ($status === false) {
223
            require_once 'Zend/Uri/Exception.php';
224
            throw new Zend_Uri_Exception('Internal error: authority decomposition failed');
225
        }
226
        
227
        // Save remaining URI components
228
        $this->_username = isset($matches[2]) === true ? $matches[2] : '';
229
        $this->_password = isset($matches[4]) === true ? $matches[4] : '';
230
        $this->_host     = isset($matches[5]) === true 
231
                         ? preg_replace('~^\[([^]]+)\]$~', '\1', $matches[5])  // Strip wrapper [] from IPv6 literal
232
                         : '';
233
        $this->_port     = isset($matches[7]) === true ? $matches[7] : '';
234
    }
235
236
    /**
237
     * Returns a URI based on current values of the instance variables. If any
238
     * part of the URI does not pass validation, then an exception is thrown.
239
     *
240
     * @throws Zend_Uri_Exception When one or more parts of the URI are invalid
241
     * @return string
242
     */
243
    public function getUri()
244
    {
245
        if ($this->valid() === false) {
246
            require_once 'Zend/Uri/Exception.php';
247
            throw new Zend_Uri_Exception('One or more parts of the URI are invalid');
248
        }
249
250
        $password = strlen($this->_password) > 0 ? ":$this->_password" : '';
251
        $auth     = strlen($this->_username) > 0 ? "$this->_username$password@" : '';
252
        $port     = strlen($this->_port) > 0 ? ":$this->_port" : '';
253
        $query    = strlen($this->_query) > 0 ? "?$this->_query" : '';
254
        $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : '';
255
256
        return $this->_scheme
257
             . '://'
258
             . $auth
259
             . $this->_host
260
             . $port
261
             . $this->_path
262
             . $query
263
             . $fragment;
264
    }
265
266
    /**
267
     * Validate the current URI from the instance variables. Returns true if and only if all
268
     * parts pass validation.
269
     *
270
     * @return boolean
271
     */
272
    public function valid()
273
    {
274
        // Return true if and only if all parts of the URI have passed validation
275
        return $this->validateUsername()
276
           and $this->validatePassword()
277
           and $this->validateHost()
278
           and $this->validatePort()
279
           and $this->validatePath()
280
           and $this->validateQuery()
281
           and $this->validateFragment();
282
    }
283
284
    /**
285
     * Returns the username portion of the URL, or FALSE if none.
286
     *
287
     * @return string
288
     */
289
    public function getUsername()
290
    {
291
        return strlen($this->_username) > 0 ? $this->_username : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return strlen($this->_us...this->_username : false could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
292
    }
293
294
    /**
295
     * Returns true if and only if the username passes validation. If no username is passed,
296
     * then the username contained in the instance variable is used.
297
     *
298
     * @param  string $username The HTTP username
299
     * @throws Zend_Uri_Exception When username validation fails
300
     * @return boolean
301
     * @link   http://www.faqs.org/rfcs/rfc2396.html
302
     */
303
    public function validateUsername($username = null)
304
    {
305
        if ($username === null) {
306
            $username = $this->_username;
307
        }
308
309
        // If the username is empty, then it is considered valid
310
        if (strlen($username) === 0) {
311
            return true;
312
        }
313
314
        // Check the username against the allowed values
315
        $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' .
316
            self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $username);
317
318
        if ($status === false) {
319
            require_once 'Zend/Uri/Exception.php';
320
            throw new Zend_Uri_Exception('Internal error: username validation failed');
321
        }
322
323
        return $status === 1;
324
    }
325
326
    /**
327
     * Sets the username for the current URI, and returns the old username
328
     *
329
     * @param  string $username The HTTP username
330
     * @throws Zend_Uri_Exception When $username is not a valid HTTP username
331
     * @return string
332
     */
333
    public function setUsername($username)
334
    {
335
        if ($this->validateUsername($username) === false) {
336
            require_once 'Zend/Uri/Exception.php';
337
            throw new Zend_Uri_Exception("Username \"$username\" is not a valid HTTP username");
338
        }
339
340
        $oldUsername     = $this->_username;
341
        $this->_username = $username;
342
343
        return $oldUsername;
344
    }
345
346
    /**
347
     * Returns the password portion of the URL, or FALSE if none.
348
     *
349
     * @return string
350
     */
351
    public function getPassword()
352
    {
353
        return strlen($this->_password) > 0 ? $this->_password : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return strlen($this->_pa...this->_password : false could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
354
    }
355
356
    /**
357
     * Returns true if and only if the password passes validation. If no password is passed,
358
     * then the password contained in the instance variable is used.
359
     *
360
     * @param  string $password The HTTP password
361
     * @throws Zend_Uri_Exception When password validation fails
362
     * @return boolean
363
     * @link   http://www.faqs.org/rfcs/rfc2396.html
364
     */
365
    public function validatePassword($password = null)
366
    {
367
        if ($password === null) {
368
            $password = $this->_password;
369
        }
370
371
        // If the password is empty, then it is considered valid
372
        if (strlen($password) === 0) {
373
            return true;
374
        }
375
376
        // If the password is nonempty, but there is no username, then it is considered invalid
377
        if (strlen($password) > 0 and strlen($this->_username) === 0) {
378
            return false;
379
        }
380
381
        // Check the password against the allowed values
382
        $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' .
383
            self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $password);
384
385
        if ($status === false) {
386
            require_once 'Zend/Uri/Exception.php';
387
            throw new Zend_Uri_Exception('Internal error: password validation failed.');
388
        }
389
390
        return $status == 1;
391
    }
392
393
    /**
394
     * Sets the password for the current URI, and returns the old password
395
     *
396
     * @param  string $password The HTTP password
397
     * @throws Zend_Uri_Exception When $password is not a valid HTTP password
398
     * @return string
399
     */
400
    public function setPassword($password)
401
    {
402
        if ($this->validatePassword($password) === false) {
403
            require_once 'Zend/Uri/Exception.php';
404
            throw new Zend_Uri_Exception("Password \"$password\" is not a valid HTTP password.");
405
        }
406
407
        $oldPassword     = $this->_password;
408
        $this->_password = $password;
409
410
        return $oldPassword;
411
    }
412
413
    /**
414
     * Returns the domain or host IP portion of the URL, or FALSE if none.
415
     *
416
     * @return string
417
     */
418
    public function getHost()
419
    {
420
        return strlen($this->_host) > 0 ? $this->_host : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return strlen($this->_ho... ? $this->_host : false could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
421
    }
422
423
    /**
424
     * Returns true if and only if the host string passes validation. If no host is passed,
425
     * then the host contained in the instance variable is used.
426
     *
427
     * @param  string $host The HTTP host
428
     * @return boolean
429
     * @uses   Zend_Filter
430
     */
431
    public function validateHost($host = null)
432
    {
433
        if ($host === null) {
434
            $host = $this->_host;
435
        }
436
437
        // If the host is empty, then it is considered invalid
438
        if (strlen($host) === 0) {
439
            return false;
440
        }
441
442
        // Check the host against the allowed values; delegated to Zend_Filter.
443
        $validate = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL);
444
445
        return $validate->isValid($host);
446
    }
447
448
    /**
449
     * Sets the host for the current URI, and returns the old host
450
     *
451
     * @param  string $host The HTTP host
452
     * @throws Zend_Uri_Exception When $host is nota valid HTTP host
453
     * @return string
454
     */
455
    public function setHost($host)
456
    {
457
        if ($this->validateHost($host) === false) {
458
            require_once 'Zend/Uri/Exception.php';
459
            throw new Zend_Uri_Exception("Host \"$host\" is not a valid HTTP host");
460
        }
461
462
        $oldHost     = $this->_host;
463
        $this->_host = $host;
464
465
        return $oldHost;
466
    }
467
468
    /**
469
     * Returns the TCP port, or FALSE if none.
470
     *
471
     * @return string
472
     */
473
    public function getPort()
474
    {
475
        return strlen($this->_port) > 0 ? $this->_port : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return strlen($this->_po... ? $this->_port : false could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
476
    }
477
478
    /**
479
     * Returns true if and only if the TCP port string passes validation. If no port is passed,
480
     * then the port contained in the instance variable is used.
481
     *
482
     * @param  string $port The HTTP port
483
     * @return boolean
484
     */
485
    public function validatePort($port = null)
486
    {
487
        if ($port === null) {
488
            $port = $this->_port;
489
        }
490
491
        // If the port is empty, then it is considered valid
492
        if (strlen($port) === 0) {
493
            return true;
494
        }
495
496
        // Check the port against the allowed values
497
        return ctype_digit((string) $port) and 1 <= $port and $port <= 65535;
498
    }
499
500
    /**
501
     * Sets the port for the current URI, and returns the old port
502
     *
503
     * @param  string $port The HTTP port
504
     * @throws Zend_Uri_Exception When $port is not a valid HTTP port
505
     * @return string
506
     */
507
    public function setPort($port)
508
    {
509
        if ($this->validatePort($port) === false) {
510
            require_once 'Zend/Uri/Exception.php';
511
            throw new Zend_Uri_Exception("Port \"$port\" is not a valid HTTP port.");
512
        }
513
514
        $oldPort     = $this->_port;
515
        $this->_port = $port;
516
517
        return $oldPort;
518
    }
519
520
    /**
521
     * Returns the path and filename portion of the URL.
522
     *
523
     * @return string
524
     */
525
    public function getPath()
526
    {
527
        return strlen($this->_path) > 0 ? $this->_path : '/';
528
    }
529
530
    /**
531
     * Returns true if and only if the path string passes validation. If no path is passed,
532
     * then the path contained in the instance variable is used.
533
     *
534
     * @param  string $path The HTTP path
535
     * @throws Zend_Uri_Exception When path validation fails
536
     * @return boolean
537
     */
538
    public function validatePath($path = null)
539
    {
540
        if ($path === null) {
541
            $path = $this->_path;
542
        }
543
544
        // If the path is empty, then it is considered valid
545
        if (strlen($path) === 0) {
546
            return true;
547
        }
548
549
        // Determine whether the path is well-formed
550
        $pattern = '/^' . $this->_regex['path'] . '$/';
551
        $status  = @preg_match($pattern, $path);
552
        if ($status === false) {
553
            require_once 'Zend/Uri/Exception.php';
554
            throw new Zend_Uri_Exception('Internal error: path validation failed');
555
        }
556
557
        return (boolean) $status;
558
    }
559
560
    /**
561
     * Sets the path for the current URI, and returns the old path
562
     *
563
     * @param  string $path The HTTP path
564
     * @throws Zend_Uri_Exception When $path is not a valid HTTP path
565
     * @return string
566
     */
567
    public function setPath($path)
568
    {
569
        if ($this->validatePath($path) === false) {
570
            require_once 'Zend/Uri/Exception.php';
571
            throw new Zend_Uri_Exception("Path \"$path\" is not a valid HTTP path");
572
        }
573
574
        $oldPath     = $this->_path;
575
        $this->_path = $path;
576
577
        return $oldPath;
578
    }
579
580
    /**
581
     * Returns the query portion of the URL (after ?), or FALSE if none.
582
     *
583
     * @return string
584
     */
585
    public function getQuery()
586
    {
587
        return strlen($this->_query) > 0 ? $this->_query : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return strlen($this->_qu...? $this->_query : false could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
588
    }
589
590
    /**
591
     * Returns the query portion of the URL (after ?) as a
592
     * key-value-array. If the query is empty an empty array
593
     * is returned
594
     *
595
     * @return array
596
     */
597
    public function getQueryAsArray()
598
    {
599
        $query = $this->getQuery();
600
        $querryArray = array();
601
        if ($query !== false) {
0 ignored issues
show
introduced by
The condition $query !== false is always true.
Loading history...
602
            parse_str($query, $querryArray);
603
        }
604
        return $querryArray;
605
    }
606
607
    /**
608
     * Returns true if and only if the query string passes validation. If no query is passed,
609
     * then the query string contained in the instance variable is used.
610
     *
611
     * @param  string $query The query to validate
612
     * @throws Zend_Uri_Exception When query validation fails
613
     * @return boolean
614
     * @link   http://www.faqs.org/rfcs/rfc2396.html
615
     */
616
    public function validateQuery($query = null)
617
    {
618
        if ($query === null) {
619
            $query = $this->_query;
620
        }
621
622
        // If query is empty, it is considered to be valid
623
        if (strlen($query) === 0) {
624
            return true;
625
        }
626
627
        // Determine whether the query is well-formed
628
        $pattern = '/^' . $this->_regex['uric'] . '*$/';
629
        $status  = @preg_match($pattern, $query);
630
        if ($status === false) {
631
            require_once 'Zend/Uri/Exception.php';
632
            throw new Zend_Uri_Exception('Internal error: query validation failed');
633
        }
634
635
        return $status == 1;
636
    }
637
638
    /**
639
     * Add or replace params in the query string for the current URI, and
640
     * return the old query.
641
     *
642
     * @param  array $queryParams
643
     * @return string Old query string
644
     */
645
    public function addReplaceQueryParameters(array $queryParams)
646
    {
647
        $queryParams = array_merge($this->getQueryAsArray(), $queryParams);
648
        return $this->setQuery($queryParams);
649
    }
650
651
    /**
652
     * Remove params in the query string for the current URI, and
653
     * return the old query.
654
     *
655
     * @param  array $queryParamKeys
656
     * @return string Old query string
657
     */
658
    public function removeQueryParameters(array $queryParamKeys)
659
    {
660
        $queryParams = array_diff_key($this->getQueryAsArray(), array_fill_keys($queryParamKeys, 0));
661
        return $this->setQuery($queryParams);
662
    }
663
664
    /**
665
     * Set the query string for the current URI, and return the old query
666
     * string This method accepts both strings and arrays.
667
     *
668
     * @param  string|array $query The query string or array
669
     * @throws Zend_Uri_Exception When $query is not a valid query string
670
     * @return string              Old query string
671
     */
672
    public function setQuery($query)
673
    {
674
        $oldQuery = $this->_query;
675
676
        // If query is empty, set an empty string
677
        if (empty($query) === true) {
678
            $this->_query = '';
679
            return $oldQuery;
680
        }
681
682
        // If query is an array, make a string out of it
683
        if (is_array($query) === true) {
684
            $query = http_build_query($query, '', '&');
685
        } else {
686
            // If it is a string, make sure it is valid. If not parse and encode it
687
            $query = (string) $query;
688
            if ($this->validateQuery($query) === false) {
689
                parse_str($query, $queryArray);
690
                $query = http_build_query($queryArray, '', '&');
691
            }
692
        }
693
694
        // Make sure the query is valid, and set it
695
        if ($this->validateQuery($query) === false) {
696
            require_once 'Zend/Uri/Exception.php';
697
            throw new Zend_Uri_Exception("'$query' is not a valid query string");
698
        }
699
700
        $this->_query = $query;
701
702
        return $oldQuery;
703
    }
704
705
    /**
706
     * Returns the fragment portion of the URL (after #), or FALSE if none.
707
     *
708
     * @return string|false
709
     */
710
    public function getFragment()
711
    {
712
        return strlen($this->_fragment) > 0 ? $this->_fragment : false;
713
    }
714
715
    /**
716
     * Returns true if and only if the fragment passes validation. If no fragment is passed,
717
     * then the fragment contained in the instance variable is used.
718
     *
719
     * @param  string $fragment Fragment of an URI
720
     * @throws Zend_Uri_Exception When fragment validation fails
721
     * @return boolean
722
     * @link   http://www.faqs.org/rfcs/rfc2396.html
723
     */
724
    public function validateFragment($fragment = null)
725
    {
726
        if ($fragment === null) {
727
            $fragment = $this->_fragment;
728
        }
729
730
        // If fragment is empty, it is considered to be valid
731
        if (strlen($fragment) === 0) {
732
            return true;
733
        }
734
735
        // Determine whether the fragment is well-formed
736
        $pattern = '/^' . $this->_regex['uric'] . '*$/';
737
        $status  = @preg_match($pattern, $fragment);
738
        if ($status === false) {
739
            require_once 'Zend/Uri/Exception.php';
740
            throw new Zend_Uri_Exception('Internal error: fragment validation failed');
741
        }
742
743
        return (boolean) $status;
744
    }
745
746
    /**
747
     * Sets the fragment for the current URI, and returns the old fragment
748
     *
749
     * @param  string $fragment Fragment of the current URI
750
     * @throws Zend_Uri_Exception When $fragment is not a valid HTTP fragment
751
     * @return string
752
     */
753
    public function setFragment($fragment)
754
    {
755
        if ($this->validateFragment($fragment) === false) {
756
            require_once 'Zend/Uri/Exception.php';
757
            throw new Zend_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment");
758
        }
759
760
        $oldFragment     = $this->_fragment;
761
        $this->_fragment = $fragment;
762
763
        return $oldFragment;
764
    }
765
}
766