Source for file URL2.php
Documentation is available at URL2.php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2007-2008, Christian Schmidt, Peytz & Co. A/S |
// | All rights reserved. |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// +-----------------------------------------------------------------------+
// | Author: Christian Schmidt <schmidt at php dot net> |
// +-----------------------------------------------------------------------+
// $Id: URL2.php,v 1.10 2008/04/26 21:57:08 schmidt Exp $
// Net_URL2 Class (PHP5 Only)
// This code is released under the BSD License - http://www.opensource.org/licenses/bsd-license.php
* Do strict parsing in resolve() (see RFC 3986, section 5.2.2). Default
const OPTION_STRICT = 'strict';
* Represent arrays in query using PHP's [] notation. Default is true.
const OPTION_USE_BRACKETS = 'use_brackets';
* URL-encode query variable keys. Default is true.
const OPTION_ENCODE_KEYS = 'encode_keys';
* Query variable separators when parsing the query string. Every character
* is considered a separator. Default is specified by the
* arg_separator.input php.ini setting (this defaults to "&").
const OPTION_SEPARATOR_INPUT = 'input_separator';
* Query variable separator used when generating the query string. Default
* is specified by the arg_separator.output php.ini setting (this defaults
const OPTION_SEPARATOR_OUTPUT = 'output_separator';
* Default options corresponds to how PHP handles $_GET.
private $options = array (
self ::OPTION_STRICT => true ,
self ::OPTION_USE_BRACKETS => true ,
self ::OPTION_ENCODE_KEYS => true ,
self ::OPTION_SEPARATOR_INPUT => 'x&',
self ::OPTION_SEPARATOR_OUTPUT => 'x&',
private $userinfo = false;
private $fragment = false;
* @param string $url an absolute or relative URL
public function __construct ($url, $options = null )
$this->setOption (self ::OPTION_SEPARATOR_INPUT ,
$this->setOption (self ::OPTION_SEPARATOR_OUTPUT ,
foreach ($options as $optionName => $value) {
$this->setOption ($optionName);
if (preg_match('@^([a-z][a-z0-9.+-]*):@i', $url, $reg)) {
$this->setAuthority ($reg[1 ]);
$this->path = substr($url, 0 , $i);
$this->fragment = substr($url, 1 );
* Returns the scheme, e.g. "http" or "urn", or false if there is no
* scheme specified, i.e. if this is a relative URL.
public function getScheme ()
* @param string|bool$scheme
public function setScheme ($scheme)
* Returns the user part of the userinfo part (the part preceding the first
* ":"), or false if there is no userinfo part.
public function getUser ()
return $this->userinfo !== false ? preg_replace('@:.*$@', '', $this->userinfo) : false;
* Returns the password part of the userinfo part (the part after the first
* ":"), or false if there is no userinfo part (i.e. the URL does not
* contain "@" in front of the hostname) or the userinfo part does not
public function getPassword ()
return $this->userinfo !== false ? substr(strstr($this->userinfo, ':'), 1 ) : false;
* Returns the userinfo part, or false if there is none, i.e. if the
* authority part does not contain "@".
public function getUserinfo ()
* Sets the userinfo part. If two arguments are passed, they are combined
* in the userinfo part as username ":" password.
* @param string|bool$userinfo userinfo or username
* @param string|bool$password
public function setUserinfo ($userinfo, $password = false )
$this->userinfo = $userinfo;
if ($password !== false ) {
$this->userinfo .= ':' . $password;
* Returns the host part, or false if there is no authority part, e.g.
public function getHost ()
* @param string|bool$host
public function setHost ($host)
* Returns the port number, or false if there is no port number specified,
* i.e. if the default port is to be used.
public function getPort ()
public function setPort ($port)
* Returns the authority part, i.e. [ userinfo "@" ] host [ ":" port ], or
* false if there is no authority none.
public function getAuthority ()
if ($this->userinfo !== false ) {
$authority .= $this->userinfo . '@';
$authority .= $this->host;
if ($this->port !== false ) {
$authority .= ':' . $this->port;
* @param string|false$authority
public function setAuthority ($authority)
if (preg_match('@^(([^\@]+)\@)?([^:]+)(:(\d*))?$@', $authority, $reg)) {
$this->userinfo = $reg[2 ];
$this->port = intval($reg[5 ]);
* Returns the path part (possibly an empty string).
public function getPath ()
public function setPath ($path)
* Returns the query string (excluding the leading "?"), or false if "?"
* isn't present in the URL.
* @see self::getQueryVariables()
public function getQuery ()
* @param string|bool$query
* @see self::setQueryVariables()
public function setQuery ($query)
* Returns the fragment name, or false if "#" isn't present in the URL.
public function getFragment ()
* @param string|bool$fragment
public function setFragment ($fragment)
$this->fragment = $fragment;
* Returns the query string like an array as the variables would appear in
public function getQueryVariables ()
preg_quote($this->getOption (self ::OPTION_SEPARATOR_INPUT ), '/') .
$parts = preg_split($pattern, $this->query, -1 , PREG_SPLIT_NO_EMPTY );
foreach ($parts as $part) {
if (strpos($part, '=') !== false ) {
list ($key, $value) = explode('=', $part, 2 );
if ($this->getOption (self ::OPTION_ENCODE_KEYS )) {
if ($this->getOption (self ::OPTION_USE_BRACKETS ) &&
preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
if (empty ($return[$key]) || !is_array($return[$key])) {
$return[$key][] = $value;
$return[$key][$idx] = $value;
} elseif (!$this->getOption (self ::OPTION_USE_BRACKETS )
$return[$key] = (array) $return[$key];
$return[$key][] = $value;
* @param array $array (name => value) array
public function setQueryVariables (array $array)
foreach ($array as $name => $value) {
if ($this->getOption (self ::OPTION_ENCODE_KEYS )) {
$name = rawurlencode ($name);
foreach ($value as $k => $v) {
$parts[] = $this->getOption (self ::OPTION_USE_BRACKETS )
? sprintf('%s[%s]=%s', $name, $k, $v)
$parts[] = $name . '=' . $value;
$this->query = implode($this->getOption (self ::OPTION_SEPARATOR_OUTPUT ),
public function setQueryVariable ($name, $value)
$array = $this->getQueryVariables ();
$this->setQueryVariables ($array);
public function unsetQueryVariable ($name)
$array = $this->getQueryVariables ();
$this->setQueryVariables ($array);
* Returns a string representation of this URL.
// See RFC 3986, section 5.3
if ($this->scheme !== false ) {
$url .= $this->scheme . ':';
$authority = $this->getAuthority ();
if ($authority !== false ) {
$url .= '//' . $authority;
if ($this->query !== false ) {
$url .= '?' . $this->query;
if ($this->fragment !== false ) {
$url .= '#' . $this->fragment;
* Returns a normalized string representation of this URL. This is useful
* for comparison of URLs.
public function getNormalizedURL ()
* Returns a normalized Net_URL2 instance.
public function normalize ()
// See RFC 3886, section 6
// Schemes are case-insensitive
// Hostnames are case-insensitive
// Remove default port number for known schemes (RFC 3986, section 6.2.3)
// Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
foreach (array ('userinfo', 'host', 'path') as $part) {
$this->$part = preg_replace('/%[0-9a-f]{2}/ie', 'strtoupper("\0")', $this->$part);
// Path segment normalization (RFC 3986, section 6.2.2.3)
$this->path = self ::removeDotSegments ($this->path );
// Scheme based normalization (RFC 3986, section 6.2.3)
if ($this->host && !$this->path ) {
* Returns whether this instance represents an absolute URL.
public function isAbsolute ()
return (bool) $this->scheme;
* Returns an Net_URL2 instance representing an absolute URL relative to
* @param Net_URL2|string$reference relative URL
public function resolve ($reference)
$reference = new self ($reference);
if (!$this->isAbsolute ()) {
throw new Exception ('Base-URL must be absolute');
// A non-strict parser may ignore a scheme in the reference if it is
// identical to the base URI's scheme.
if (!$this->getOption (self ::OPTION_STRICT ) && $reference->scheme == $this->scheme ) {
$reference->scheme = false;
if ($reference->scheme !== false ) {
$target->scheme = $reference->scheme;
$target->setAuthority ($reference->getAuthority ());
$target->path = self ::removeDotSegments ($reference->path );
$target->query = $reference->query;
$authority = $reference->getAuthority ();
if ($authority !== false ) {
$target->setAuthority ($authority);
$target->path = self ::removeDotSegments ($reference->path );
$target->query = $reference->query;
if ($reference->path == '') {
$target->path = $this->path;
if ($reference->query !== false ) {
$target->query = $reference->query;
$target->query = $this->query;
if (substr($reference->path , 0 , 1 ) == '/') {
$target->path = self ::removeDotSegments ($reference->path );
// Merge paths (RFC 3986, section 5.2.3)
if ($this->host !== false && $this->path == '') {
$target->path = '/' . $this->path;
$target->path = substr($this->path , 0 , $i + 1 );
$target->path .= $reference->path;
$target->path = self ::removeDotSegments ($target->path );
$target->query = $reference->query;
$target->setAuthority ($this->getAuthority ());
$target->scheme = $this->scheme;
$target->fragment = $reference->fragment;
* Removes dots as described in RFC 3986, section 5.2.4, e.g.
* "/foo/../bar/baz" => "/bar/baz"
* @param string $path a path
private static function removeDotSegments ($path)
// Make sure not to be trapped in an infinite loop due to a bug in this
while ($path && $j++ < 100 ) {
if (substr($path, 0 , 2 ) == './') {
} elseif (substr($path, 0 , 3 ) == '../') {
} elseif (substr($path, 0 , 3 ) == '/./' || $path == '/.') {
$path = '/' . substr($path, 3 );
} elseif (substr($path, 0 , 4 ) == '/../' || $path == '/..') {
$path = '/' . substr($path, 4 );
$output = $i === false ? '' : substr($output, 0 , $i);
} elseif ($path == '.' || $path == '..') {
$output .= substr($path, 0 , $i);
* Returns a Net_URL2 instance representing the canonical URL of the
* currently executing PHP script.
public static function getCanonical ()
if (!isset ($_SERVER['REQUEST_METHOD'])) {
// ALERT - no current URL
throw new Exception ('Script was not called through a webserver');
// Begin with a relative URL
$url = new self ($_SERVER['PHP_SELF']);
$url->scheme = isset ($_SERVER['HTTPS']) ? 'https' : 'http';
$url->host = $_SERVER['SERVER_NAME'];
$port = intval($_SERVER['SERVER_PORT']);
if ($url->scheme == 'http' && $port != 80 ||
$url->scheme == 'https' && $port != 443 ) {
* Returns the URL used to retrieve the current request.
public static function getRequestedURL ()
return self ::getRequested ()->getUrl ();
* Returns a Net_URL2 instance representing the URL used to retrieve the
public static function getRequested ()
if (!isset ($_SERVER['REQUEST_METHOD'])) {
// ALERT - no current URL
throw new Exception ('Script was not called through a webserver');
// Begin with a relative URL
$url = new self ($_SERVER['REQUEST_URI']);
$url->scheme = isset ($_SERVER['HTTPS']) ? 'https' : 'http';
// Set host and possibly port
$url->setAuthority ($_SERVER['HTTP_HOST']);
* Sets the specified option.
* @param string $optionName a self::OPTION_ constant
* @param mixed $value option value
* @see self::OPTION_STRICT
* @see self::OPTION_USE_BRACKETS
* @see self::OPTION_ENCODE_KEYS
function setOption ($optionName, $value)
$this->options [$optionName] = $value;
* Returns the value of the specified option.
* @param string $optionName The name of the option to retrieve
function getOption ($optionName)
return isset ($this->options [$optionName])
? $this->options [$optionName] : false;
Documentation generated on Mon, 11 Mar 2019 15:23:07 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|