/packages/zendframework/uri.php
[return to app]1
<?php
2 /**
3 * Zend Framework Uri class isolated from ZF dependencies to work in Vork
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 license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Uri
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Uri.php 22083 2010-05-03 18:49:28Z shahar $
20 */
21
22 /**
23 * Abstract class for all Zend_Uri handlers
24 */
25 abstract class Zend_Uri {
26 /**
27 * Scheme of this URI (http, ftp, etc.)
28 *
29 * @var string
30 */
31 protected $_scheme = '';
32
33 /**
34 * Global configuration array
35 *
36 * @var array
37 */
38 static protected $_config = array(
39 'allow_unwise' => false
40 );
41
42 /**
43 * Return a string representation of this URI.
44 *
45 * @see getUri()
46 * @return string
47 */
48 public function __toString() {
49 return $this->getUri();
50 }
51
52 /**
53 * Convenience function, checks that a $uri string is well-formed
54 * by validating it but not returning an object. Returns TRUE if
55 * $uri is a well-formed URI, or FALSE otherwise.
56 *
57 * @param string $uri The URI to check
58 * @return boolean
59 */
60 public static function check($uri) {
61 try {
62 $uri = self::factory($uri);
63 } catch (Exception $e) {
64 return false;
65 }
66
67 return $uri->valid();
68 }
69
70 /**
71 * Create a new Zend_Uri object for a URI. If building a new URI, then $uri should contain
72 * only the scheme (http, ftp, etc). Otherwise, supply $uri with the complete URI.
73 *
74 * @param string $uri The URI form which a Zend_Uri instance is created
75 * @param string $className The name of the class to use in order to manipulate URI
76 * @throws Zend_Uri_Exception When an empty string was supplied for the scheme
77 * @throws Zend_Uri_Exception When an illegal scheme is supplied
78 * @throws Zend_Uri_Exception When the scheme is not supported
79 * @throws Zend_Uri_Exception When $className doesn't exist or doesn't implements Zend_Uri
80 * @return Zend_Uri
81 * @link http://www.faqs.org/rfcs/rfc2396.html
82 */
83 public static function factory($uri = 'http', $className = null) {
84 // Separate the scheme from the scheme-specific parts
85 $uri = explode(':', $uri, 2);
86 $scheme = strtolower($uri[0]);
87 $schemeSpecific = isset($uri[1]) === true ? $uri[1] : '';
88
89 if (strlen($scheme) === 0) {
90 throw new Exception('An empty string was supplied for the scheme');
91 }
92
93 // Security check: $scheme is used to load a class file, so only alphanumerics are allowed.
94 if (ctype_alnum($scheme) === false) {
95 throw new Exception('Illegal scheme supplied, only alphanumeric characters are permitted');
96 }
97
98 if ($className === null) {
99 /**
100 * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the
101 * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown.
102 */
103 switch ($scheme) {
104 case 'http':
105 // Break intentionally omitted
106 case 'https':
107 $className = 'Zend_Uri_Http';
108 break;
109
110 case 'mailto':
111 // TODO
112 default:
113 throw new Exception("Scheme \"$scheme\" is not supported");
114 break;
115 }
116 }
117 /*
118 if (!class_exists($className)) {
119 require_once 'Zend/Loader.php';
120 try {
121 Zend_Loader::loadClass($className);
122 } catch (Exception $e) {
123 if (!class_exists('Zend_Exception')) require 'exception.php';
124 throw new Zend_Uri_Exception("\"$className\" not found");
125 }
126 }
127 */
128 $schemeHandler = new $className($scheme, $schemeSpecific);
129
130 if (! $schemeHandler instanceof Zend_Uri) {
131 throw new Exception("\"$className\" is not an instance of Zend_Uri");
132 }
133
134 return $schemeHandler;
135 }
136
137 /**
138 * Get the URI's scheme
139 *
140 * @return string|false Scheme or false if no scheme is set.
141 */
142 public function getScheme() {
143 if (empty($this->_scheme) === false) {
144 return $this->_scheme;
145 } else {
146 return false;
147 }
148 }
149
150 /**
151 * Set global configuration options
152 *
153 * @param Zend_Config|array $config
154 */
155 static public function setConfig($config) {
156 if ($config instanceof Zend_Config) {
157 $config = $config->toArray();
158 } elseif (!is_array($config)) {
159 throw new Zend_Uri_Exception("Config must be an array or an instance of Zend_Config.");
160 }
161
162 foreach ($config as $k => $v) {
163 self::$_config[$k] = $v;
164 }
165 }
166
167 /**
168 * Zend_Uri and its subclasses cannot be instantiated directly.
169 * Use Zend_Uri::factory() to return a new Zend_Uri object.
170 *
171 * @param string $scheme The scheme of the URI
172 * @param string $schemeSpecific The scheme-specific part of the URI
173 */
174 abstract protected function __construct($scheme, $schemeSpecific = '');
175
176 /**
177 * Return a string representation of this URI.
178 *
179 * @return string
180 */
181 abstract public function getUri();
182
183 /**
184 * Returns TRUE if this URI is valid, or FALSE otherwise.
185 *
186 * @return boolean
187 */
188 abstract public function valid();
189 }
190
191 /**
192 * Zend Framework
193 *
194 * LICENSE
195 *
196 * This source file is subject to the new BSD license that is bundled
197 * with this package in the file LICENSE.txt.
198 * It is also available through the world-wide-web at this URL:
199 * http://framework.zend.com/license/new-bsd
200 * If you did not receive a copy of the license and are unable to
201 * obtain it through the world-wide-web, please send an email
202 * to license@zend.com so we can send you a copy immediately.
203 *
204 * @category Zend
205 * @package Zend_Uri
206 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
207 * @license http://framework.zend.com/license/new-bsd New BSD License
208 * @version $Id: Http.php 20096 2010-01-06 02:05:09Z bkarwin $
209 */
210 class Zend_Uri_Http extends Zend_Uri {
211 /**
212 * Character classes for validation regular expressions
213 */
214 const CHAR_ALNUM = 'A-Za-z0-9';
215 const CHAR_MARK = '-_.!~*\'()\[\]';
216 const CHAR_RESERVED = ';\/?:@&=+$,';
217 const CHAR_SEGMENT = ':@&=+$,;';
218 const CHAR_UNWISE = '{}|\\\\^`';
219
220 /**
221 * HTTP username
222 *
223 * @var string
224 */
225 protected $_username = '';
226
227 /**
228 * HTTP password
229 *
230 * @var string
231 */
232 protected $_password = '';
233
234 /**
235 * HTTP host
236 *
237 * @var string
238 */
239 protected $_host = '';
240
241 /**
242 * HTTP post
243 *
244 * @var string
245 */
246 protected $_port = '';
247
248 /**
249 * HTTP part
250 *
251 * @var string
252 */
253 protected $_path = '';
254
255 /**
256 * HTTP query
257 *
258 * @var string
259 */
260 protected $_query = '';
261
262 /**
263 * HTTP fragment
264 *
265 * @var string
266 */
267 protected $_fragment = '';
268
269 /**
270 * Regular expression grammar rules for validation; values added by constructor
271 *
272 * @var array
273 */
274 protected $_regex = array();
275
276 /**
277 * Constructor accepts a string $scheme (e.g., http, https) and a scheme-specific part of the URI
278 * (e.g., example.com/path/to/resource?query=param#fragment)
279 *
280 * @param string $scheme The scheme of the URI
281 * @param string $schemeSpecific The scheme-specific part of the URI
282 * @throws Zend_Uri_Exception When the URI is not valid
283 */
284 protected function __construct($scheme, $schemeSpecific = '') {
285 // Set the scheme
286 $this->_scheme = $scheme;
287
288 // Set up grammar rules for validation via regular expressions. These
289 // are to be used with slash-delimited regular expression strings.
290
291 // Escaped special characters (eg. '%25' for '%')
292 $this->_regex['escaped'] = '%[[:xdigit:]]{2}';
293
294 // Unreserved characters
295 $this->_regex['unreserved'] = '[' . self::CHAR_ALNUM . self::CHAR_MARK . ']';
296
297 // Segment can use escaped, unreserved or a set of additional chars
298 $this->_regex['segment'] = '(?:' . $this->_regex['escaped'] . '|[' .
299 self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_SEGMENT . '])*';
300
301 // Path can be a series of segmets char strings seperated by '/'
302 $this->_regex['path'] = '(?:\/(?:' . $this->_regex['segment'] . ')?)+';
303
304 // URI characters can be escaped, alphanumeric, mark or reserved chars
305 $this->_regex['uric'] = '(?:' . $this->_regex['escaped'] . '|[' .
306 self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_RESERVED .
307
308 // If unwise chars are allowed, add them to the URI chars class
309 (self::$_config['allow_unwise'] ? self::CHAR_UNWISE : '') . '])';
310
311 // If no scheme-specific part was supplied, the user intends to create
312 // a new URI with this object. No further parsing is required.
313 if (strlen($schemeSpecific) === 0) {
314 return;
315 }
316
317 // Parse the scheme-specific URI parts into the instance variables.
318 $this->_parseUri($schemeSpecific);
319
320 // Validate the URI
321 if ($this->valid() === false) {
322 if (!class_exists('Zend_Exception')) require 'exception.php';
323 throw new Zend_Uri_Exception('Invalid URI supplied');
324 }
325 }
326
327 /**
328 * Creates a Zend_Uri_Http from the given string
329 *
330 * @param string $uri String to create URI from, must start with
331 * 'http://' or 'https://'
332 * @throws InvalidArgumentException When the given $uri is not a string or
333 * does not start with http:// or https://
334 * @throws Zend_Uri_Exception When the given $uri is invalid
335 * @return Zend_Uri_Http
336 */
337 public static function fromString($uri) {
338 if (is_string($uri) === false) {
339 if (!class_exists('Zend_Exception')) require 'exception.php';
340 throw new Zend_Uri_Exception('$uri is not a string');
341 }
342
343 $uri = explode(':', $uri, 2);
344 $scheme = strtolower($uri[0]);
345 $schemeSpecific = isset($uri[1]) === true ? $uri[1] : '';
346
347 if (in_array($scheme, array('http', 'https')) === false) {
348 if (!class_exists('Zend_Exception')) require 'exception.php';
349 throw new Zend_Uri_Exception("Invalid scheme: '$scheme'");
350 }
351
352 $schemeHandler = new Zend_Uri_Http($scheme, $schemeSpecific);
353 return $schemeHandler;
354 }
355
356 /**
357 * Parse the scheme-specific portion of the URI and place its parts into instance variables.
358 *
359 * @param string $schemeSpecific The scheme-specific portion to parse
360 * @throws Zend_Uri_Exception When scheme-specific decoposition fails
361 * @throws Zend_Uri_Exception When authority decomposition fails
362 * @return void
363 */
364 protected function _parseUri($schemeSpecific) {
365 // High-level decomposition parser
366 $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~';
367 $status = @preg_match($pattern, $schemeSpecific, $matches);
368 if ($status === false) {
369 if (!class_exists('Zend_Exception')) require 'exception.php';
370 throw new Zend_Uri_Exception('Internal error: scheme-specific decomposition failed');
371 }
372
373 // Failed decomposition; no further processing needed
374 if ($status === false) {
375 return;
376 }
377
378 // Save URI components that need no further decomposition
379 $this->_path = isset($matches[4]) === true ? $matches[4] : '';
380 $this->_query = isset($matches[6]) === true ? $matches[6] : '';
381 $this->_fragment = isset($matches[8]) === true ? $matches[8] : '';
382
383 // Additional decomposition to get username, password, host, and port
384 $combo = isset($matches[3]) === true ? $matches[3] : '';
385 $pattern = '~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~';
386 $status = @preg_match($pattern, $combo, $matches);
387 if ($status === false) {
388 if (!class_exists('Zend_Exception')) require 'exception.php';
389 throw new Zend_Uri_Exception('Internal error: authority decomposition failed');
390 }
391
392 // Failed decomposition; no further processing needed
393 if ($status === false) {
394 return;
395 }
396
397 // Save remaining URI components
398 $this->_username = isset($matches[2]) === true ? $matches[2] : '';
399 $this->_password = isset($matches[4]) === true ? $matches[4] : '';
400 $this->_host = isset($matches[5]) === true ? $matches[5] : '';
401 $this->_port = isset($matches[7]) === true ? $matches[7] : '';
402
403 }
404
405 /**
406 * Returns a URI based on current values of the instance variables. If any
407 * part of the URI does not pass validation, then an exception is thrown.
408 *
409 * @throws Zend_Uri_Exception When one or more parts of the URI are invalid
410 * @return string
411 */
412 public function getUri() {
413 if ($this->valid() === false) {
414 if (!class_exists('Zend_Exception')) require 'exception.php';
415 throw new Zend_Uri_Exception('One or more parts of the URI are invalid');
416 }
417
418 $password = strlen($this->_password) > 0 ? ":$this->_password" : '';
419 $auth = strlen($this->_username) > 0 ? "$this->_username$password@" : '';
420 $port = strlen($this->_port) > 0 ? ":$this->_port" : '';
421 $query = strlen($this->_query) > 0 ? "?$this->_query" : '';
422 $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : '';
423
424 return $this->_scheme
425 . '://'
426 . $auth
427 . $this->_host
428 . $port
429 . $this->_path
430 . $query
431 . $fragment;
432 }
433
434 /**
435 * Validate the current URI from the instance variables. Returns true if and only if all
436 * parts pass validation.
437 *
438 * @return boolean
439 */
440 public function valid() {
441 // Return true if and only if all parts of the URI have passed validation
442 return $this->validateUsername()
443 and $this->validatePassword()
444 and $this->validateHost()
445 and $this->validatePort()
446 and $this->validatePath()
447 and $this->validateQuery()
448 and $this->validateFragment();
449 }
450
451 /**
452 * Returns the username portion of the URL, or FALSE if none.
453 *
454 * @return string
455 */
456 public function getUsername() {
457 return strlen($this->_username) > 0 ? $this->_username : false;
458 }
459
460 /**
461 * Returns true if and only if the username passes validation. If no username is passed,
462 * then the username contained in the instance variable is used.
463 *
464 * @param string $username The HTTP username
465 * @throws Zend_Uri_Exception When username validation fails
466 * @return boolean
467 * @link http://www.faqs.org/rfcs/rfc2396.html
468 */
469 public function validateUsername($username = null) {
470 if ($username === null) {
471 $username = $this->_username;
472 }
473
474 // If the username is empty, then it is considered valid
475 if (strlen($username) === 0) {
476 return true;
477 }
478
479 // Check the username against the allowed values
480 $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' .
481 self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $username);
482
483 if ($status === false) {
484 if (!class_exists('Zend_Exception')) require 'exception.php';
485 throw new Zend_Uri_Exception('Internal error: username validation failed');
486 }
487
488 return $status === 1;
489 }
490
491 /**
492 * Sets the username for the current URI, and returns the old username
493 *
494 * @param string $username The HTTP username
495 * @throws Zend_Uri_Exception When $username is not a valid HTTP username
496 * @return string
497 */
498 public function setUsername($username) {
499 if ($this->validateUsername($username) === false) {
500 if (!class_exists('Zend_Exception')) require 'exception.php';
501 throw new Zend_Uri_Exception("Username \"$username\" is not a valid HTTP username");
502 }
503
504 $oldUsername = $this->_username;
505 $this->_username = $username;
506
507 return $oldUsername;
508 }
509
510 /**
511 * Returns the password portion of the URL, or FALSE if none.
512 *
513 * @return string
514 */
515 public function getPassword() {
516 return strlen($this->_password) > 0 ? $this->_password : false;
517 }
518
519 /**
520 * Returns true if and only if the password passes validation. If no password is passed,
521 * then the password contained in the instance variable is used.
522 *
523 * @param string $password The HTTP password
524 * @throws Zend_Uri_Exception When password validation fails
525 * @return boolean
526 * @link http://www.faqs.org/rfcs/rfc2396.html
527 */
528 public function validatePassword($password = null) {
529 if ($password === null) {
530 $password = $this->_password;
531 }
532
533 // If the password is empty, then it is considered valid
534 if (strlen($password) === 0) {
535 return true;
536 }
537
538 // If the password is nonempty, but there is no username, then it is considered invalid
539 if (strlen($password) > 0 and strlen($this->_username) === 0) {
540 return false;
541 }
542
543 // Check the password against the allowed values
544 $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' .
545 self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $password);
546
547 if ($status === false) {
548 if (!class_exists('Zend_Exception')) require 'exception.php';
549 throw new Zend_Uri_Exception('Internal error: password validation failed.');
550 }
551
552 return $status == 1;
553 }
554
555 /**
556 * Sets the password for the current URI, and returns the old password
557 *
558 * @param string $password The HTTP password
559 * @throws Zend_Uri_Exception When $password is not a valid HTTP password
560 * @return string
561 */
562 public function setPassword($password) {
563 if ($this->validatePassword($password) === false) {
564 if (!class_exists('Zend_Exception')) require 'exception.php';
565 throw new Zend_Uri_Exception("Password \"$password\" is not a valid HTTP password.");
566 }
567
568 $oldPassword = $this->_password;
569 $this->_password = $password;
570
571 return $oldPassword;
572 }
573
574 /**
575 * Returns the domain or host IP portion of the URL, or FALSE if none.
576 *
577 * @return string
578 */
579 public function getHost() {
580 return strlen($this->_host) > 0 ? $this->_host : false;
581 }
582
583 /**
584 * Returns true if and only if the host string passes validation. If no host is passed,
585 * then the host contained in the instance variable is used.
586 *
587 * @param string $host The HTTP host
588 * @return boolean
589 * @uses Zend_Filter
590 */
591 public function validateHost($host = null) {
592 return true;
593 if ($host === null) {
594 $host = $this->_host;
595 }
596
597 // If the host is empty, then it is considered invalid
598 if (strlen($host) === 0) {
599 return false;
600 }
601
602 // Check the host against the allowed values; delegated to Zend_Filter.
603 $validate = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL);
604
605 return $validate->isValid($host);
606 }
607
608 /**
609 * Sets the host for the current URI, and returns the old host
610 *
611 * @param string $host The HTTP host
612 * @throws Zend_Uri_Exception When $host is nota valid HTTP host
613 * @return string
614 */
615 public function setHost($host) {
616 if ($this->validateHost($host) === false) {
617 if (!class_exists('Zend_Exception')) require 'exception.php';
618 throw new Zend_Uri_Exception("Host \"$host\" is not a valid HTTP host");
619 }
620
621 $oldHost = $this->_host;
622 $this->_host = $host;
623
624 return $oldHost;
625 }
626
627 /**
628 * Returns the TCP port, or FALSE if none.
629 *
630 * @return string
631 */
632 public function getPort() {
633 return strlen($this->_port) > 0 ? $this->_port : false;
634 }
635
636 /**
637 * Returns true if and only if the TCP port string passes validation. If no port is passed,
638 * then the port contained in the instance variable is used.
639 *
640 * @param string $port The HTTP port
641 * @return boolean
642 */
643 public function validatePort($port = null) {
644 if ($port === null) {
645 $port = $this->_port;
646 }
647
648 // If the port is empty, then it is considered valid
649 if (strlen($port) === 0) {
650 return true;
651 }
652
653 // Check the port against the allowed values
654 return ctype_digit((string) $port) and 1 <= $port and $port <= 65535;
655 }
656
657 /**
658 * Sets the port for the current URI, and returns the old port
659 *
660 * @param string $port The HTTP port
661 * @throws Zend_Uri_Exception When $port is not a valid HTTP port
662 * @return string
663 */
664 public function setPort($port) {
665 if ($this->validatePort($port) === false) {
666 if (!class_exists('Zend_Exception')) require 'exception.php';
667 throw new Zend_Uri_Exception("Port \"$port\" is not a valid HTTP port.");
668 }
669
670 $oldPort = $this->_port;
671 $this->_port = $port;
672
673 return $oldPort;
674 }
675
676 /**
677 * Returns the path and filename portion of the URL, or FALSE if none.
678 *
679 * @return string
680 */
681 public function getPath() {
682 return strlen($this->_path) > 0 ? $this->_path : '/';
683 }
684
685 /**
686 * Returns true if and only if the path string passes validation. If no path is passed,
687 * then the path contained in the instance variable is used.
688 *
689 * @param string $path The HTTP path
690 * @throws Zend_Uri_Exception When path validation fails
691 * @return boolean
692 */
693 public function validatePath($path = null) {
694 if ($path === null) {
695 $path = $this->_path;
696 }
697
698 // If the path is empty, then it is considered valid
699 if (strlen($path) === 0) {
700 return true;
701 }
702
703 // Determine whether the path is well-formed
704 $pattern = '/^' . $this->_regex['path'] . '$/';
705 $status = @preg_match($pattern, $path);
706 if ($status === false) {
707 if (!class_exists('Zend_Exception')) require 'exception.php';
708 throw new Zend_Uri_Exception('Internal error: path validation failed');
709 }
710
711 return (boolean) $status;
712 }
713
714 /**
715 * Sets the path for the current URI, and returns the old path
716 *
717 * @param string $path The HTTP path
718 * @throws Zend_Uri_Exception When $path is not a valid HTTP path
719 * @return string
720 */
721 public function setPath($path) {
722 if ($this->validatePath($path) === false) {
723 if (!class_exists('Zend_Exception')) require 'exception.php';
724 throw new Zend_Uri_Exception("Path \"$path\" is not a valid HTTP path");
725 }
726
727 $oldPath = $this->_path;
728 $this->_path = $path;
729
730 return $oldPath;
731 }
732
733 /**
734 * Returns the query portion of the URL (after ?), or FALSE if none.
735 *
736 * @return string
737 */
738 public function getQuery() {
739 return strlen($this->_query) > 0 ? $this->_query : false;
740 }
741
742 /**
743 * Returns the query portion of the URL (after ?) as a
744 * key-value-array. If the query is empty an empty array
745 * is returned
746 *
747 * @return array
748 */
749 public function getQueryAsArray() {
750 $query = $this->getQuery();
751 $querryArray = array();
752 if ($query !== false) {
753 parse_str($query, $querryArray);
754 }
755 return $querryArray;
756 }
757
758 /**
759 * Returns true if and only if the query string passes validation. If no query is passed,
760 * then the query string contained in the instance variable is used.
761 *
762 * @param string $query The query to validate
763 * @throws Zend_Uri_Exception When query validation fails
764 * @return boolean
765 * @link http://www.faqs.org/rfcs/rfc2396.html
766 */
767 public function validateQuery($query = null) {
768 if ($query === null) {
769 $query = $this->_query;
770 }
771
772 // If query is empty, it is considered to be valid
773 if (strlen($query) === 0) {
774 return true;
775 }
776
777 // Determine whether the query is well-formed
778 $pattern = '/^' . $this->_regex['uric'] . '*$/';
779 $status = @preg_match($pattern, $query);
780 if ($status === false) {
781 if (!class_exists('Zend_Exception')) require 'exception.php';
782 throw new Zend_Uri_Exception('Internal error: query validation failed');
783 }
784
785 return $status == 1;
786 }
787
788 /**
789 * Add or replace params in the query string for the current URI, and
790 * return the old query.
791 *
792 * @param array $queryParams
793 * @return string Old query string
794 */
795 public function addReplaceQueryParameters(array $queryParams) {
796 $queryParams = array_merge($this->getQueryAsArray(), $queryParams);
797 return $this->setQuery($queryParams);
798 }
799
800 /**
801 * Remove params in the query string for the current URI, and
802 * return the old query.
803 *
804 * @param array $queryParamKeys
805 * @return string Old query string
806 */
807 public function removeQueryParameters(array $queryParamKeys) {
808 $queryParams = array_diff_key($this->getQueryAsArray(), array_fill_keys($queryParamKeys, 0));
809 return $this->setQuery($queryParams);
810 }
811
812 /**
813 * Set the query string for the current URI, and return the old query
814 * string This method accepts both strings and arrays.
815 *
816 * @param string|array $query The query string or array
817 * @throws Zend_Uri_Exception When $query is not a valid query string
818 * @return string Old query string
819 */
820 public function setQuery($query) {
821 $oldQuery = $this->_query;
822
823 // If query is empty, set an empty string
824 if (empty($query) === true) {
825 $this->_query = '';
826 return $oldQuery;
827 }
828
829 // If query is an array, make a string out of it
830 if (is_array($query) === true) {
831 $query = http_build_query($query, '', '&');
832 } else {
833 // If it is a string, make sure it is valid. If not parse and encode it
834 $query = (string) $query;
835 if ($this->validateQuery($query) === false) {
836 parse_str($query, $queryArray);
837 $query = http_build_query($queryArray, '', '&');
838 }
839 }
840
841 // Make sure the query is valid, and set it
842 if ($this->validateQuery($query) === false) {
843 if (!class_exists('Zend_Exception')) require 'exception.php';
844 throw new Zend_Uri_Exception("'$query' is not a valid query string");
845 }
846
847 $this->_query = $query;
848
849 return $oldQuery;
850 }
851
852 /**
853 * Returns the fragment portion of the URL (after #), or FALSE if none.
854 *
855 * @return string|false
856 */
857 public function getFragment() {
858 return strlen($this->_fragment) > 0 ? $this->_fragment : false;
859 }
860
861 /**
862 * Returns true if and only if the fragment passes validation. If no fragment is passed,
863 * then the fragment contained in the instance variable is used.
864 *
865 * @param string $fragment Fragment of an URI
866 * @throws Zend_Uri_Exception When fragment validation fails
867 * @return boolean
868 * @link http://www.faqs.org/rfcs/rfc2396.html
869 */
870 public function validateFragment($fragment = null) {
871 if ($fragment === null) {
872 $fragment = $this->_fragment;
873 }
874
875 // If fragment is empty, it is considered to be valid
876 if (strlen($fragment) === 0) {
877 return true;
878 }
879
880 // Determine whether the fragment is well-formed
881 $pattern = '/^' . $this->_regex['uric'] . '*$/';
882 $status = @preg_match($pattern, $fragment);
883 if ($status === false) {
884 if (!class_exists('Zend_Exception')) require 'exception.php';
885 throw new Zend_Uri_Exception('Internal error: fragment validation failed');
886 }
887
888 return (boolean) $status;
889 }
890
891 /**
892 * Sets the fragment for the current URI, and returns the old fragment
893 *
894 * @param string $fragment Fragment of the current URI
895 * @throws Zend_Uri_Exception When $fragment is not a valid HTTP fragment
896 * @return string
897 */
898 public function setFragment($fragment) {
899 if ($this->validateFragment($fragment) === false) {
900 if (!class_exists('Zend_Exception')) require 'exception.php';
901 throw new Zend_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment");
902 }
903
904 $oldFragment = $this->_fragment;
905 $this->_fragment = $fragment;
906
907 return $oldFragment;
908 }
909 }