diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/Net/URL2.php 2.2.3-1/Net_URL2-2.2.1/Net/URL2.php
--- 2.2.1-0.2/Net_URL2-2.2.1/Net/URL2.php	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/Net/URL2.php	1970-01-01 00:00:00.000000000 +0000
@@ -1,1219 +0,0 @@
-<?php
-/**
- * Net_URL2, a class representing a URL as per RFC 3986.
- *
- * PHP version 5
- *
- * LICENSE:
- *
- * Copyright (c) 2007-2009, 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
- * are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * 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.
- *   * Neither the name of the Net_URL2 nor the names of its contributors may
- *     be used to endorse or promote products derived from this software
- *     without specific prior written permission.
- *
- * 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.
- *
- * @category  Networking
- * @package   Net_URL2
- * @author    Christian Schmidt <schmidt@php.net>
- * @copyright 2007-2009 Peytz & Co. A/S
- * @license   https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @version   CVS: $Id$
- * @link      https://tools.ietf.org/html/rfc3986
- */
-
-/**
- * Represents a URL as per RFC 3986.
- *
- * @category  Networking
- * @package   Net_URL2
- * @author    Christian Schmidt <schmidt@php.net>
- * @copyright 2007-2009 Peytz & Co. A/S
- * @license   https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @version   Release: 2.2.1
- * @link      https://pear.php.net/package/Net_URL2
- */
-class Net_URL2
-{
-    /**
-     * Do strict parsing in resolve() (see RFC 3986, section 5.2.2). Default
-     * is true.
-     */
-    const OPTION_STRICT = 'strict';
-
-    /**
-     * Represent arrays in query using PHP's [] notation. Default is true.
-     */
-    const OPTION_USE_BRACKETS = 'use_brackets';
-
-    /**
-     * Drop zero-based integer sequences in query using PHP's [] notation. Default
-     * is true.
-     */
-    const OPTION_DROP_SEQUENCE = 'drop_sequence';
-
-    /**
-     * 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 "&".
-     */
-    const OPTION_SEPARATOR_INPUT = 'input_separator';
-
-    /**
-     * Query variable separator used when generating the query string. Default
-     * is "&".
-     */
-    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_DROP_SEQUENCE    => true,
-        self::OPTION_ENCODE_KEYS      => true,
-        self::OPTION_SEPARATOR_INPUT  => '&',
-        self::OPTION_SEPARATOR_OUTPUT => '&',
-        );
-
-    /**
-     * @var  string|bool
-     */
-    private $_scheme = false;
-
-    /**
-     * @var  string|bool
-     */
-    private $_userinfo = false;
-
-    /**
-     * @var  string|bool
-     */
-    private $_host = false;
-
-    /**
-     * @var  string|bool
-     */
-    private $_port = false;
-
-    /**
-     * @var  string
-     */
-    private $_path = '';
-
-    /**
-     * @var  string|bool
-     */
-    private $_query = false;
-
-    /**
-     * @var  string|bool
-     */
-    private $_fragment = false;
-
-    /**
-     * Constructor.
-     *
-     * @param string $url     an absolute or relative URL
-     * @param array  $options an array of OPTION_xxx constants
-     *
-     * @uses   self::parseUrl()
-     */
-    public function __construct($url, array $options = array())
-    {
-        foreach ($options as $optionName => $value) {
-            if (array_key_exists($optionName, $this->_options)) {
-                $this->_options[$optionName] = $value;
-            }
-        }
-
-        $this->parseUrl($url);
-    }
-
-    /**
-     * Magic Setter.
-     *
-     * This method will magically set the value of a private variable ($var)
-     * with the value passed as the args
-     *
-     * @param string $var The private variable to set.
-     * @param mixed  $arg An argument of any type.
-     *
-     * @return void
-     */
-    public function __set($var, $arg)
-    {
-        $method = 'set' . $var;
-        if (method_exists($this, $method)) {
-            $this->$method($arg);
-        }
-    }
-
-    /**
-     * Magic Getter.
-     *
-     * This is the magic get method to retrieve the private variable
-     * that was set by either __set() or it's setter...
-     *
-     * @param string $var The property name to retrieve.
-     *
-     * @return mixed  $this->$var Either a boolean false if the
-     *                            property is not set or the value
-     *                            of the private property.
-     */
-    public function __get($var)
-    {
-        $method = 'get' . $var;
-        if (method_exists($this, $method)) {
-            return $this->$method();
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the scheme, e.g. "http" or "urn", or false if there is no
-     * scheme specified, i.e. if this is a relative URL.
-     *
-     * @return string|bool
-     */
-    public function getScheme()
-    {
-        return $this->_scheme;
-    }
-
-    /**
-     * Sets the scheme, e.g. "http" or "urn". Specify false if there is no
-     * scheme specified, i.e. if this is a relative URL.
-     *
-     * @param string|bool $scheme e.g. "http" or "urn", or false if there is no
-     *                            scheme specified, i.e. if this is a relative
-     *                            URL
-     *
-     * @return $this
-     * @see    getScheme
-     */
-    public function setScheme($scheme)
-    {
-        $this->_scheme = $scheme;
-        return $this;
-    }
-
-    /**
-     * Returns the user part of the userinfo part (the part preceding the first
-     *  ":"), or false if there is no userinfo part.
-     *
-     * @return string|bool
-     */
-    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
-     * contain ":".
-     *
-     * @return string|bool
-     */
-    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 "@".
-     *
-     * @return string|bool
-     */
-    public function getUserinfo()
-    {
-        return $this->_userinfo;
-    }
-
-    /**
-     * 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 optional password, or false
-     *
-     * @return $this
-     */
-    public function setUserinfo($userinfo, $password = false)
-    {
-        if ($password !== false) {
-            $userinfo .= ':' . $password;
-        }
-
-        if ($userinfo !== false) {
-            $userinfo = $this->_encodeData($userinfo);
-        }
-
-        $this->_userinfo = $userinfo;
-        return $this;
-    }
-
-    /**
-     * Returns the host part, or false if there is no authority part, e.g.
-     * relative URLs.
-     *
-     * @return string|bool a hostname, an IP address, or false
-     */
-    public function getHost()
-    {
-        return $this->_host;
-    }
-
-    /**
-     * Sets the host part. Specify false if there is no authority part, e.g.
-     * relative URLs.
-     *
-     * @param string|bool $host a hostname, an IP address, or false
-     *
-     * @return $this
-     */
-    public function setHost($host)
-    {
-        $this->_host = $host;
-        return $this;
-    }
-
-    /**
-     * Returns the port number, or false if there is no port number specified,
-     * i.e. if the default port is to be used.
-     *
-     * @return string|bool
-     */
-    public function getPort()
-    {
-        return $this->_port;
-    }
-
-    /**
-     * Sets the port number. Specify false if there is no port number specified,
-     * i.e. if the default port is to be used.
-     *
-     * @param string|bool $port a port number, or false
-     *
-     * @return $this
-     */
-    public function setPort($port)
-    {
-        $this->_port = $port;
-        return $this;
-    }
-
-    /**
-     * Returns the authority part, i.e. [ userinfo "@" ] host [ ":" port ], or
-     * false if there is no authority.
-     *
-     * @return string|bool
-     */
-    public function getAuthority()
-    {
-        if (false === $this->_host) {
-            return false;
-        }
-
-        $authority = '';
-
-        if (strlen($this->_userinfo)) {
-            $authority .= $this->_userinfo . '@';
-        }
-
-        $authority .= $this->_host;
-
-        if ($this->_port !== false) {
-            $authority .= ':' . $this->_port;
-        }
-
-        return $authority;
-    }
-
-    /**
-     * Sets the authority part, i.e. [ userinfo "@" ] host [ ":" port ]. Specify
-     * false if there is no authority.
-     *
-     * @param string|bool $authority a hostname or an IP address, possibly
-     *                                with userinfo prefixed and port number
-     *                                appended, e.g. "foo:bar@example.org:81".
-     *
-     * @return $this
-     */
-    public function setAuthority($authority)
-    {
-        $this->_userinfo = false;
-        $this->_host     = false;
-        $this->_port     = false;
-
-        if ('' === $authority) {
-            $this->_host = $authority;
-            return $this;
-        }
-
-        if (!preg_match('(^(([^@]*)@)?(.+?)(:(\d*))?$)', $authority, $matches)) {
-            return $this;
-        }
-
-        if ($matches[1]) {
-            $this->_userinfo = $this->_encodeData($matches[2]);
-        }
-
-        $this->_host = $matches[3];
-
-        if (isset($matches[5]) && strlen($matches[5])) {
-            $this->_port = $matches[5];
-        }
-        return $this;
-    }
-
-    /**
-     * Returns the path part (possibly an empty string).
-     *
-     * @return string
-     */
-    public function getPath()
-    {
-        return $this->_path;
-    }
-
-    /**
-     * Sets the path part (possibly an empty string).
-     *
-     * @param string $path a path
-     *
-     * @return $this
-     */
-    public function setPath($path)
-    {
-        $this->_path = $path;
-        return $this;
-    }
-
-    /**
-     * Returns the query string (excluding the leading "?"), or false if "?"
-     * is not present in the URL.
-     *
-     * @return  string|bool
-     * @see     getQueryVariables
-     */
-    public function getQuery()
-    {
-        return $this->_query;
-    }
-
-    /**
-     * Sets the query string (excluding the leading "?"). Specify false if "?"
-     * is not present in the URL.
-     *
-     * @param string|bool $query a query string, e.g. "foo=1&bar=2"
-     *
-     * @return $this
-     * @see    setQueryVariables
-     */
-    public function setQuery($query)
-    {
-        $this->_query = $query;
-        return $this;
-    }
-
-    /**
-     * Returns the fragment name, or false if "#" is not present in the URL.
-     *
-     * @return string|bool
-     */
-    public function getFragment()
-    {
-        return $this->_fragment;
-    }
-
-    /**
-     * Sets the fragment name. Specify false if "#" is not present in the URL.
-     *
-     * @param string|bool $fragment a fragment excluding the leading "#", or
-     *                              false
-     *
-     * @return $this
-     */
-    public function setFragment($fragment)
-    {
-        $this->_fragment = $fragment;
-        return $this;
-    }
-
-    /**
-     * Returns the query string like an array as the variables would appear in
-     * $_GET in a PHP script. If the URL does not contain a "?", an empty array
-     * is returned.
-     *
-     * @return array
-     */
-    public function getQueryVariables()
-    {
-        $separator   = $this->getOption(self::OPTION_SEPARATOR_INPUT);
-        $encodeKeys  = $this->getOption(self::OPTION_ENCODE_KEYS);
-        $useBrackets = $this->getOption(self::OPTION_USE_BRACKETS);
-
-        $return  = array();
-
-        for ($part = strtok($this->_query, $separator);
-            strlen($part);
-            $part = strtok($separator)
-        ) {
-            list($key, $value) = explode('=', $part, 2) + array(1 => '');
-
-            if ($encodeKeys) {
-                $key = rawurldecode($key);
-            }
-            $value = rawurldecode($value);
-
-            if ($useBrackets) {
-                $return = $this->_queryArrayByKey($key, $value, $return);
-            } else {
-                if (isset($return[$key])) {
-                    $return[$key]  = (array) $return[$key];
-                    $return[$key][] = $value;
-                } else {
-                    $return[$key] = $value;
-                }
-            }
-        }
-
-        return $return;
-    }
-
-    /**
-     * Parse a single query key=value pair into an existing php array
-     *
-     * @param string $key   query-key
-     * @param string $value query-value
-     * @param array  $array of existing query variables (if any)
-     *
-     * @return mixed
-     */
-    private function _queryArrayByKey($key, $value, array $array = array())
-    {
-        if (!strlen($key)) {
-            return $array;
-        }
-
-        $offset = $this->_queryKeyBracketOffset($key);
-        if ($offset === false) {
-            $name = $key;
-        } else {
-            $name = substr($key, 0, $offset);
-        }
-
-        if (!strlen($name)) {
-            return $array;
-        }
-
-        if (!$offset) {
-            // named value
-            $array[$name] = $value;
-        } else {
-            // array
-            $brackets = substr($key, $offset);
-            if (!isset($array[$name])) {
-                $array[$name] = null;
-            }
-            $array[$name] = $this->_queryArrayByBrackets(
-                $brackets, $value, $array[$name]
-            );
-        }
-
-        return $array;
-    }
-
-    /**
-     * Parse a key-buffer to place value in array
-     *
-     * @param string $buffer to consume all keys from
-     * @param string $value  to be set/add
-     * @param array  $array  to traverse and set/add value in
-     *
-     * @throws Exception
-     * @return array
-     */
-    private function _queryArrayByBrackets($buffer, $value, array $array = null)
-    {
-        $entry = &$array;
-
-        for ($iteration = 0; strlen($buffer); $iteration++) {
-            $open = $this->_queryKeyBracketOffset($buffer);
-            if ($open !== 0) {
-                // Opening bracket [ must exist at offset 0, if not, there is
-                // no bracket to parse and the value dropped.
-                // if this happens in the first iteration, this is flawed, see
-                // as well the second exception below.
-                if ($iteration) {
-                    break;
-                }
-                // @codeCoverageIgnoreStart
-                throw new Exception(
-                    'Net_URL2 Internal Error: '. __METHOD__ .'(): ' .
-                    'Opening bracket [ must exist at offset 0'
-                );
-                // @codeCoverageIgnoreEnd
-            }
-
-            $close = strpos($buffer, ']', 1);
-            if (!$close) {
-                // this error condition should never be reached as this is a
-                // private method and bracket pairs are checked beforehand.
-                // See as well the first exception for the opening bracket.
-                // @codeCoverageIgnoreStart
-                throw new Exception(
-                    'Net_URL2 Internal Error: '. __METHOD__ .'(): ' .
-                    'Closing bracket ] must exist, not found'
-                );
-                // @codeCoverageIgnoreEnd
-            }
-
-            $index = substr($buffer, 1, $close - 1);
-            if (strlen($index)) {
-                $entry = &$entry[$index];
-            } else {
-                if (!is_array($entry)) {
-                    $entry = array();
-                }
-                $entry[] = &$new;
-                $entry = &$new;
-                unset($new);
-            }
-            $buffer = substr($buffer, $close + 1);
-        }
-
-        $entry = $value;
-
-        return $array;
-    }
-
-    /**
-     * Query-key has brackets ("...[]")
-     *
-     * @param string $key query-key
-     *
-     * @return bool|int offset of opening bracket, false if no brackets
-     */
-    private function _queryKeyBracketOffset($key)
-    {
-        if (false !== $open = strpos($key, '[')
-            and false === strpos($key, ']', $open + 1)
-        ) {
-            $open = false;
-        }
-
-        return $open;
-    }
-
-    /**
-     * Sets the query string to the specified variable in the query string.
-     *
-     * @param array $array (name => value) array
-     *
-     * @return $this
-     */
-    public function setQueryVariables(array $array)
-    {
-        if (!$array) {
-            $this->_query = false;
-        } else {
-            $this->_query = $this->buildQuery(
-                $array,
-                $this->getOption(self::OPTION_SEPARATOR_OUTPUT)
-            );
-        }
-        return $this;
-    }
-
-    /**
-     * Sets the specified variable in the query string.
-     *
-     * @param string $name  variable name
-     * @param mixed  $value variable value
-     *
-     * @return $this
-     */
-    public function setQueryVariable($name, $value)
-    {
-        $array = $this->getQueryVariables();
-        $array[$name] = $value;
-        $this->setQueryVariables($array);
-        return $this;
-    }
-
-    /**
-     * Removes the specified variable from the query string.
-     *
-     * @param string $name a query string variable, e.g. "foo" in "?foo=1"
-     *
-     * @return void
-     */
-    public function unsetQueryVariable($name)
-    {
-        $array = $this->getQueryVariables();
-        unset($array[$name]);
-        $this->setQueryVariables($array);
-    }
-
-    /**
-     * Returns a string representation of this URL.
-     *
-     * @return string
-     */
-    public function getURL()
-    {
-        // See RFC 3986, section 5.3
-        $url = '';
-
-        if ($this->_scheme !== false) {
-            $url .= $this->_scheme . ':';
-        }
-
-        $authority = $this->getAuthority();
-        if ($authority === false && strtolower($this->_scheme) === 'file') {
-            $authority = '';
-        }
-
-        $url .= $this->_buildAuthorityAndPath($authority, $this->_path);
-
-        if ($this->_query !== false) {
-            $url .= '?' . $this->_query;
-        }
-
-        if ($this->_fragment !== false) {
-            $url .= '#' . $this->_fragment;
-        }
-
-        return $url;
-    }
-
-    /**
-     * Put authority and path together, wrapping authority
-     * into proper separators/terminators.
-     *
-     * @param string|bool $authority authority
-     * @param string      $path      path
-     *
-     * @return string
-     */
-    private function _buildAuthorityAndPath($authority, $path)
-    {
-        if ($authority === false) {
-            return $path;
-        }
-
-        $terminator = ($path !== '' && $path[0] !== '/') ? '/' : '';
-
-        return '//' . $authority . $terminator . $path;
-    }
-
-    /**
-     * Returns a string representation of this URL.
-     *
-     * @return string
-     * @link https://php.net/language.oop5.magic#object.tostring
-     */
-    public function __toString()
-    {
-        return $this->getURL();
-    }
-
-    /**
-     * Returns a normalized string representation of this URL. This is useful
-     * for comparison of URLs.
-     *
-     * @return string
-     */
-    public function getNormalizedURL()
-    {
-        $url = clone $this;
-        $url->normalize();
-        return $url->getURL();
-    }
-
-    /**
-     * Normalizes the URL
-     *
-     * See RFC 3986, Section 6.  Normalization and Comparison
-     *
-     * @link https://tools.ietf.org/html/rfc3986#section-6
-     *
-     * @return void
-     */
-    public function normalize()
-    {
-        // See RFC 3986, section 6
-
-        // Scheme is case-insensitive
-        if ($this->_scheme) {
-            $this->_scheme = strtolower($this->_scheme);
-        }
-
-        // Hostname is case-insensitive
-        if ($this->_host) {
-            $this->_host = strtolower($this->_host);
-        }
-
-        // Remove default port number for known schemes (RFC 3986, section 6.2.3)
-        if ('' === $this->_port
-            || $this->_port
-            && $this->_scheme
-            && $this->_port == getservbyname($this->_scheme, 'tcp')
-        ) {
-            $this->_port = false;
-        }
-
-        // Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
-        // Normalize percentage-encoded unreserved characters (section 6.2.2.2)
-        $fields = array(&$this->_userinfo, &$this->_host, &$this->_path,
-                        &$this->_query, &$this->_fragment);
-        foreach ($fields as &$field) {
-            if ($field !== false) {
-                $field = $this->_normalize("$field");
-            }
-        }
-        unset($field);
-
-        // 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 (false !== $this->_host && '' === $this->_path) {
-            $this->_path = '/';
-        }
-
-        // path should start with '/' if there is authority (section 3.3.)
-        if (strlen($this->getAuthority())
-            && strlen($this->_path)
-            && $this->_path[0] !== '/'
-        ) {
-            $this->_path = '/' . $this->_path;
-        }
-    }
-
-    /**
-     * Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
-     * Normalize percentage-encoded unreserved characters (section 6.2.2.2)
-     *
-     * @param string|array $mixed string or array of strings to normalize
-     *
-     * @return string|array
-     * @see normalize
-     * @see _normalizeCallback()
-     */
-    private function _normalize($mixed)
-    {
-        return preg_replace_callback(
-            '((?:%[0-9a-fA-Z]{2})+)', array($this, '_normalizeCallback'),
-            $mixed
-        );
-    }
-
-    /**
-     * Callback for _normalize() of %XX percentage-encodings
-     *
-     * @param array $matches as by preg_replace_callback
-     *
-     * @return string
-     * @see normalize
-     * @see _normalize
-     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
-     */
-    private function _normalizeCallback($matches)
-    {
-        return self::urlencode(urldecode($matches[0]));
-    }
-
-    /**
-     * Returns whether this instance represents an absolute URL.
-     *
-     * @return bool
-     */
-    public function isAbsolute()
-    {
-        return (bool) $this->_scheme;
-    }
-
-    /**
-     * Returns an Net_URL2 instance representing an absolute URL relative to
-     * this URL.
-     *
-     * @param Net_URL2|string $reference relative URL
-     *
-     * @throws Exception
-     * @return $this
-     */
-    public function resolve($reference)
-    {
-        if (!$reference instanceof Net_URL2) {
-            $reference = new self($reference);
-        }
-        if (!$reference->_isFragmentOnly() && !$this->isAbsolute()) {
-            throw new Exception(
-                'Base-URL must be absolute if reference is not fragment-only'
-            );
-        }
-
-        // 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;
-        }
-
-        $target = new self('');
-        if ($reference->_scheme !== false) {
-            $target->_scheme = $reference->_scheme;
-            $target->setAuthority($reference->getAuthority());
-            $target->_path  = self::removeDotSegments($reference->_path);
-            $target->_query = $reference->_query;
-        } else {
-            $authority = $reference->getAuthority();
-            if ($authority !== false) {
-                $target->setAuthority($authority);
-                $target->_path  = self::removeDotSegments($reference->_path);
-                $target->_query = $reference->_query;
-            } else {
-                if ($reference->_path == '') {
-                    $target->_path = $this->_path;
-                    if ($reference->_query !== false) {
-                        $target->_query = $reference->_query;
-                    } else {
-                        $target->_query = $this->_query;
-                    }
-                } else {
-                    if (substr($reference->_path, 0, 1) == '/') {
-                        $target->_path = self::removeDotSegments($reference->_path);
-                    } else {
-                        // Merge paths (RFC 3986, section 5.2.3)
-                        if ($this->_host !== false && $this->_path == '') {
-                            $target->_path = '/' . $reference->_path;
-                        } else {
-                            $i = strrpos($this->_path, '/');
-                            if ($i !== false) {
-                                $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;
-
-        return $target;
-    }
-
-    /**
-     * URL is fragment-only
-     *
-     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
-     * @return bool
-     */
-    private function _isFragmentOnly()
-    {
-        return (
-            $this->_fragment !== false
-            && $this->_query === false
-            && $this->_path === ''
-            && $this->_port === false
-            && $this->_host === false
-            && $this->_userinfo === false
-            && $this->_scheme === false
-        );
-    }
-
-    /**
-     * Removes dots as described in RFC 3986, section 5.2.4, e.g.
-     * "/foo/../bar/baz" => "/bar/baz"
-     *
-     * @param string $path a path
-     *
-     * @return string a path
-     */
-    public static function removeDotSegments($path)
-    {
-        $path = (string) $path;
-        $output = '';
-
-        // Make sure not to be trapped in an infinite loop due to a bug in this
-        // method
-        $loopLimit = 256;
-        $j = 0;
-        while ('' !== $path && $j++ < $loopLimit) {
-            if (substr($path, 0, 2) === './') {
-                // Step 2.A
-                $path = substr($path, 2);
-            } elseif (substr($path, 0, 3) === '../') {
-                // Step 2.A
-                $path = substr($path, 3);
-            } elseif (substr($path, 0, 3) === '/./' || $path === '/.') {
-                // Step 2.B
-                $path = '/' . substr($path, 3);
-            } elseif (substr($path, 0, 4) === '/../' || $path === '/..') {
-                // Step 2.C
-                $path   = '/' . substr($path, 4);
-                $i      = strrpos($output, '/');
-                $output = $i === false ? '' : substr($output, 0, $i);
-            } elseif ($path === '.' || $path === '..') {
-                // Step 2.D
-                $path = '';
-            } else {
-                // Step 2.E
-                $i = strpos($path, '/', $path[0] === '/');
-                if ($i === false) {
-                    $output .= $path;
-                    $path = '';
-                    break;
-                }
-                $output .= substr($path, 0, $i);
-                $path = substr($path, $i);
-            }
-        }
-
-        if ($path !== '') {
-            $message = sprintf(
-                'Unable to remove dot segments; hit loop limit %d (left: %s)',
-                $j, var_export($path, true)
-            );
-            trigger_error($message, E_USER_WARNING);
-        }
-
-        return $output;
-    }
-
-    /**
-     * Percent-encodes all non-alphanumeric characters except these: _ . - ~
-     * Similar to PHP's rawurlencode(), except that it also encodes ~ in PHP
-     * 5.2.x and earlier.
-     *
-     * @param string $string string to encode
-     *
-     * @return string
-     */
-    public static function urlencode($string)
-    {
-        $encoded = rawurlencode($string);
-
-        // This is only necessary in PHP < 5.3.
-        $encoded = str_replace('%7E', '~', $encoded);
-        return $encoded;
-    }
-
-    /**
-     * Returns a Net_URL2 instance representing the canonical URL of the
-     * currently executing PHP script.
-     *
-     * @throws Exception
-     * @return string
-     */
-    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 = $_SERVER['SERVER_PORT'];
-        if ($url->_scheme == 'http' && $port != 80
-            || $url->_scheme == 'https' && $port != 443
-        ) {
-            $url->_port = $port;
-        }
-        return $url;
-    }
-
-    /**
-     * Returns the URL used to retrieve the current request.
-     *
-     * @return  string
-     */
-    public static function getRequestedURL()
-    {
-        return self::getRequested()->getUrl();
-    }
-
-    /**
-     * Returns a Net_URL2 instance representing the URL used to retrieve the
-     * current request.
-     *
-     * @throws Exception
-     * @return $this
-     */
-    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']);
-        return $url;
-    }
-
-    /**
-     * Returns the value of the specified option.
-     *
-     * @param string $optionName The name of the option to retrieve
-     *
-     * @return mixed
-     */
-    public function getOption($optionName)
-    {
-        return isset($this->_options[$optionName])
-            ? $this->_options[$optionName] : false;
-    }
-
-    /**
-     * A simple version of http_build_query in userland. The encoded string is
-     * percentage encoded according to RFC 3986.
-     *
-     * @param array  $data      An array, which has to be converted into
-     *                          QUERY_STRING. Anything is possible.
-     * @param string $separator Separator {@link self::OPTION_SEPARATOR_OUTPUT}
-     * @param string $key       For stacked values (arrays in an array).
-     *
-     * @return string
-     */
-    protected function buildQuery(array $data, $separator, $key = null)
-    {
-        $query = array();
-        $drop_names = (
-            $this->_options[self::OPTION_DROP_SEQUENCE] === true
-            && array_keys($data) === array_keys(array_values($data))
-        );
-        foreach ($data as $name => $value) {
-            if ($this->getOption(self::OPTION_ENCODE_KEYS) === true) {
-                $name = rawurlencode($name);
-            }
-            if ($key !== null) {
-                if ($this->getOption(self::OPTION_USE_BRACKETS) === true) {
-                    $drop_names && $name = '';
-                    $name = $key . '[' . $name . ']';
-                } else {
-                    $name = $key;
-                }
-            }
-            if (is_array($value)) {
-                $query[] = $this->buildQuery($value, $separator, $name);
-            } else {
-                $query[] = $name . '=' . rawurlencode($value);
-            }
-        }
-        return implode($separator, $query);
-    }
-
-    /**
-     * This method uses a regex to parse the url into the designated parts.
-     *
-     * @param string $url URL
-     *
-     * @return void
-     * @uses   self::$_scheme, self::setAuthority(), self::$_path, self::$_query,
-     *         self::$_fragment
-     * @see    __construct
-     */
-    protected function parseUrl($url)
-    {
-        // The regular expression is copied verbatim from RFC 3986, appendix B.
-        // The expression does not validate the URL but matches any string.
-        preg_match(
-            '(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)',
-            $url, $matches
-        );
-
-        // "path" is always present (possibly as an empty string); the rest
-        // are optional.
-        $this->_scheme   = !empty($matches[1]) ? $matches[2] : false;
-        $this->setAuthority(!empty($matches[3]) ? $matches[4] : false);
-        $this->_path     = $this->_encodeData($matches[5]);
-        $this->_query    = !empty($matches[6])
-                           ? $this->_encodeData($matches[7])
-                           : false
-            ;
-        $this->_fragment = !empty($matches[8]) ? $matches[9] : false;
-    }
-
-    /**
-     * Encode characters that might have been forgotten to encode when passing
-     * in an URL. Applied onto Userinfo, Path and Query.
-     *
-     * @param string $url URL
-     *
-     * @return string
-     * @see parseUrl
-     * @see setAuthority
-     * @link https://pear.php.net/bugs/bug.php?id=20425
-     */
-    private function _encodeData($url)
-    {
-        return preg_replace_callback(
-            '([\x-\x20\x22\x3C\x3E\x7F-\xFF]+)',
-            array($this, '_encodeCallback'), $url
-        );
-    }
-
-    /**
-     * callback for encoding character data
-     *
-     * @param array $matches Matches
-     *
-     * @return string
-     * @see _encodeData
-     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
-     */
-    private function _encodeCallback(array $matches)
-    {
-        return rawurlencode($matches[0]);
-    }
-}
diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/docs/6470.php 2.2.3-1/Net_URL2-2.2.1/docs/6470.php
--- 2.2.1-0.2/Net_URL2-2.2.1/docs/6470.php	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/docs/6470.php	1970-01-01 00:00:00.000000000 +0000
@@ -1,56 +0,0 @@
-<?php
-/**
- * Net_URL2, a class representing a URL as per RFC 3986.
- *
- * PHP version 5
- *
- * This file contains code Copyright (c) 2002-2003, Richard Heyes,
- * See BSD-3-CLAUSE-Heyes,
- * Author: Richard Heyes <richard at php net>
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @link     https://tools.ietf.org/html/rfc3986
- */
-
-/**
-* This example will decode the url given and display its
-* constituent parts.
-*/
-    error_reporting(E_ALL | E_STRICT);
-
-    require_once 'Net/URL2.php';
-
-    $url = new Net_URL2('https://www.example.com/foo/bar/index.php?foo=bar');
-
-?>
-<html>
-<body>
-
-<pre>
-Protocol...: <?php echo $url->protocol; ?>
-
-Username...: <?php echo $url->user; ?>
-
-Password...: <?php echo $url->pass; ?>
-
-Server.....: <?php echo $url->host; ?>
-
-Port.......: <?php $url->port; ?>
-
-File/path..: <?php $url->path; ?>
-
-Querystring: <?php print_r($url->querystring); ?>
-
-Anchor.....: <?php echo $url->anchor;?>
-
-Full URL...: <?php echo $url->getUrl(); ?>
-
-Resolve path (/.././/foo/bar/joe/./././../jabba): <b><?php
-        echo $url->resolve('/.././/foo/bar/joe/./././../jabba'); ?></b>
-</pre>
-
-</body>
-</html>
diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/docs/BSD-3-CLAUSE-Heyes 2.2.3-1/Net_URL2-2.2.1/docs/BSD-3-CLAUSE-Heyes
--- 2.2.1-0.2/Net_URL2-2.2.1/docs/BSD-3-CLAUSE-Heyes	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/docs/BSD-3-CLAUSE-Heyes	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-Copyright (c) 2002-2003, Richard Heyes
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1) Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2) 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.
-3) Neither the name of the Richard Heyes nor the names of his
-   contributors may be used to endorse or promote products derived
-   from this software without specific prior written permission.
-
-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
-HOLDER 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.
diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/docs/example.php 2.2.3-1/Net_URL2-2.2.1/docs/example.php
--- 2.2.1-0.2/Net_URL2-2.2.1/docs/example.php	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/docs/example.php	1970-01-01 00:00:00.000000000 +0000
@@ -1,62 +0,0 @@
-<?php
-/**
- * Net_URL2, a class representing a URL as per RFC 3986.
- *
- * PHP version 5
- *
- * This file contains code Copyright (c) 2002-2003, Richard Heyes,
- * See BSD-3-CLAUSE-Heyes,
- * Author: Richard Heyes <richard at php net>
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @link     https://tools.ietf.org/html/rfc3986
- */
-
-/**
-* This example will decode the url given and display its
-* constituent parts.
-*/
-
-error_reporting(E_ALL | E_STRICT);
-
-require 'Net/URL2.php';
-
-$url = new Net_URL2(
-    'https://example.com/pls/portal30/PORTAL30.wwpob_page.changetabs?'
-    .'p_back_url=http%3A%2F%2Fexample.com%2Fservlet%2Fpage%3F_pageid%3D360'
-    .'%2C366%2C368%2C382%26_dad%3Dportal30%26_schema%3DPORTAL30&foo=bar'
-);
-
-?>
-<html>
-<body>
-
-<pre>
-Protocol...: <?php echo $url->protocol; ?>
-
-Username...: <?php echo $url->user; ?>
-
-Password...: <?php echo $url->pass; ?>
-
-Server.....: <?php echo $url->host; ?>
-
-Port.......: <?php $url->port; ?>
-
-File/path..: <?php $url->path; ?>
-
-Querystring: <?php print_r($url->querystring); ?>
-
-Anchor.....: <?php echo $url->anchor;?>
-
-Full URL...: <?php echo $url->getUrl(); ?>
-
-
-Resolve path (.././/foo/bar/joe/./././../jabba): <b><?php
-        echo $url->resolve('.././/foo/bar/joe/./././../jabba'); ?></b>
-</pre>
-
-</body>
-</html>
diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/tests/AllTests.php 2.2.3-1/Net_URL2-2.2.1/tests/AllTests.php
--- 2.2.1-0.2/Net_URL2-2.2.1/tests/AllTests.php	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/tests/AllTests.php	1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-<?php
-/**
- * Net_URL2, a class representing a URL as per RFC 3986.
- *
- * PHP version 5
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @link     https://tools.ietf.org/html/rfc3986
- */
-
-require_once 'PHPUnit/Autoload.php';
-
-chdir(dirname(__FILE__) .  '/../');
-
-require_once 'Net/URL2Test.php';
-require_once 'Net/URL2.php';
-
-/**
- * Test class for Net_URL2.
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @version  Release: @package_version@
- * @link     https://pear.php.net/package/Net_URL2
- */
-class Net_URL2_AllTests
-{
-    /**
-     * main()
-     *
-     * @return void
-     */
-    public static function main()
-    {
-
-        PHPUnit_TextUI_TestRunner::run(self::suite());
-    }
-
-    /**
-     * suite()
-     *
-     * @return PHPUnit_Framework_TestSuite
-     */
-    public static function suite()
-    {
-        $suite = new PHPUnit_Framework_TestSuite('Net_URL2 tests');
-        /** Add testsuites, if there is. */
-        $suite->addTestSuite('Net_URL2Test');
-
-        return $suite;
-    }
-}
-
-Net_URL2_AllTests::main();
diff -pruN 2.2.1-0.2/Net_URL2-2.2.1/tests/Net/URL2Test.php 2.2.3-1/Net_URL2-2.2.1/tests/Net/URL2Test.php
--- 2.2.1-0.2/Net_URL2-2.2.1/tests/Net/URL2Test.php	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.1/tests/Net/URL2Test.php	1970-01-01 00:00:00.000000000 +0000
@@ -1,1088 +0,0 @@
-<?php
-/**
- * Net_URL2, a class representing a URL as per RFC 3986.
- *
- * PHP version 5
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @link     https://tools.ietf.org/html/rfc3986
- */
-
-/**
- * Test class for Net_URL2.
- *
- * @category Networking
- * @package  Net_URL2
- * @author   Some Pear Developers <pear@php.net>
- * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
- * @version  Release: 2.2.1
- * @link     https://pear.php.net/package/Net_URL2
- */
-class Net_URL2Test extends PHPUnit_Framework_TestCase
-{
-    /**
-     * Tests setting a zero-length string and false as authority
-     * Also: Regression test for Bug #20420
-     *
-     * @covers Net_URL2::setAuthority
-     * @return void
-     * @link https://pear.php.net/bugs/bug.php?id=20420
-     */
-    public function testSetEmptyAuthority()
-    {
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setAuthority('');
-        $this->assertSame('', $url->getAuthority());
-        $this->assertSame('', $url->getHost());
-        $this->assertSame(false, $url->getPort());
-        $this->assertSame(false, $url->getUserinfo());
-        $this->assertSame(false, $url->getUser());
-
-        $url->setAuthority(false);
-        $this->assertSame(false, $url->getAuthority());
-    }
-
-    /**
-     * Tests setting an empty userinfo part
-     * Also: Regression test for Bug #20013 and Bug #20399
-     *
-     * @covers Net_URL2::setUserinfo
-     * @covers Net_URL2::getUserinfo
-     * @covers Net_URL2::getURL
-     * @return void
-     * @link https://pear.php.net/bugs/bug.php?id=20013
-     * @link https://pear.php.net/bugs/bug.php?id=20399
-     */
-    public function testSetEmptyUserinfo()
-    {
-        $url = new Net_URL2('http://@www.example.com/');
-        $this->assertSame('http://www.example.com/', $url->getURL());
-
-        $url = new Net_URL2('http://www.example.com/');
-        $this->assertSame('http://www.example.com/', $url->getURL());
-        $url->setUserinfo('');
-        $this->assertSame('http://www.example.com/', $url->getURL());
-        $this->assertSame('', $url->getUserinfo());
-        $url->setUserinfo(false);
-        $this->assertSame('http://www.example.com/', $url->getURL());
-        $this->assertFalse($url->getUserinfo());
-    }
-
-    /**
-     * Tests an URL with no userinfo and normalization
-     *
-     * Also: Regression test for Bug #20385
-     *
-     * @covers Net_URL2::getUserinfo
-     * @covers Net_URL2::normalize
-     * @covers Net_URL2::getNormalizedURL
-     * @return void
-     * @link https://pear.php.net/bugs/bug.php?id=20385
-     */
-    public function testNoUserinfoAndNormalize()
-    {
-        $testUrl = 'http://www.example.com/';
-
-        $url = new Net_URL2($testUrl);
-        $this->assertFalse($url->getUserinfo());
-
-        $url->normalize();
-        $this->assertFalse($url->getUserinfo());
-
-        $this->assertEquals($testUrl, $url->getURL());
-        $this->assertEquals($testUrl, $url->getNormalizedURL());
-    }
-
-    /**
-     * Tests setQueryVariable().
-     *
-     * @return void
-     */
-    public function testSetQueryVariable()
-    {
-
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setQueryVariable('pear', 'fun');
-        $this->assertEquals($url->getURL(), 'http://www.example.com/?pear=fun');
-    }
-
-    /**
-     * Tests setQueryVariables().
-     *
-     * @return void
-     */
-    public function testSetQueryVariables()
-    {
-
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setQueryVariables(array('pear' => 'fun'));
-        $this->assertEquals('http://www.example.com/?pear=fun', $url->getURL());
-        $url->setQueryVariables(array('pear' => 'fun for sure'));
-        $this->assertEquals(
-            'http://www.example.com/?pear=fun%20for%20sure', $url->getURL()
-        );
-    }
-
-    /**
-     * Tests unsetQueryVariable()
-     *
-     * @return void
-     */
-    public function testUnsetQueryVariable()
-    {
-        $url = new Net_URL2(
-            'http://www.example.com/?name=david&pear=fun&fish=slippery'
-        );
-
-        $removes = array(
-            'pear' => 'http://www.example.com/?name=david&fish=slippery',
-            'name' => 'http://www.example.com/?fish=slippery',
-            'fish' => 'http://www.example.com/',
-        );
-
-        foreach ($removes as $name => $expected) {
-            $url->unsetQueryVariable($name);
-            $this->assertEquals($expected, $url);
-        }
-    }
-
-    /**
-     * Tests setQuery().
-     *
-     * @return void
-     */
-    public function testSetQuery()
-    {
-
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setQuery('flapdoodle&dilly%20all%20day');
-        $this->assertEquals(
-            $url->getURL(), 'http://www.example.com/?flapdoodle&dilly%20all%20day'
-        );
-    }
-
-    /**
-     * Tests getQuery().
-     *
-     * @return void
-     */
-    public function testGetQuery()
-    {
-
-        $url = new Net_URL2('http://www.example.com/?foo');
-        $this->assertEquals($url->getQuery(), 'foo');
-        $url = new Net_URL2('http://www.example.com/?pear=fun&fruit=fruity');
-        $this->assertEquals($url->getQuery(), 'pear=fun&fruit=fruity');
-    }
-
-    /**
-     * Tests setScheme().
-     *
-     * @return void
-     */
-    public function testSetScheme()
-    {
-
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setScheme('ftp');
-        $this->assertEquals($url->getURL(), 'ftp://www.example.com/');
-        $url->setScheme('gopher');
-        $this->assertEquals($url->getURL(), 'gopher://www.example.com/');
-    }
-
-    /**
-     * Tests setting the fragment.
-     *
-     * @return void
-     */
-    public function testSetFragment()
-    {
-
-        $url = new Net_URL2('http://www.example.com/');
-        $url->setFragment('pear');
-        $this->assertEquals('http://www.example.com/#pear', $url->getURL());
-    }
-
-    /**
-     * A dataProvider for paths that are solved to a base URI.
-     *
-     * @see testResolveUrls
-     * @return array
-     */
-    public function provideResolveUrls()
-    {
-        return array(
-            array(
-                // Examples from RFC 3986, section 5.4.
-                // relative base-URI, (URL => absolute URL), [(options)]
-                'http://a/b/c/d;p?q',
-                array(
-                    'g:h'           => 'g:h',
-                    'g'             => 'http://a/b/c/g',
-                    './g'           => 'http://a/b/c/g',
-                    'g/'            => 'http://a/b/c/g/',
-                    '/g'            => 'http://a/g',
-                    '//g'           => 'http://g',
-                    '?y'            => 'http://a/b/c/d;p?y',
-                    'g?y'           => 'http://a/b/c/g?y',
-                    '#s'            => 'http://a/b/c/d;p?q#s',
-                    'g#s'           => 'http://a/b/c/g#s',
-                    'g?y#s'         => 'http://a/b/c/g?y#s',
-                    ';x'            => 'http://a/b/c/;x',
-                    'g;x'           => 'http://a/b/c/g;x',
-                    'g;x?y#s'       => 'http://a/b/c/g;x?y#s',
-                    ''              => 'http://a/b/c/d;p?q',
-                    '.'             => 'http://a/b/c/',
-                    './'            => 'http://a/b/c/',
-                    '..'            => 'http://a/b/',
-                    '../'           => 'http://a/b/',
-                    '../g'          => 'http://a/b/g',
-                    '../..'         => 'http://a/',
-                    '../../'        => 'http://a/',
-                    '../../g'       => 'http://a/g',
-                    '../../../g'    => 'http://a/g',
-                    '../../../../g' => 'http://a/g',
-                    '/./g'          => 'http://a/g',
-                    '/../g'         => 'http://a/g',
-                    'g.'            => 'http://a/b/c/g.',
-                    '.g'            => 'http://a/b/c/.g',
-                    'g..'           => 'http://a/b/c/g..',
-                    '..g'           => 'http://a/b/c/..g',
-                    './../g'        => 'http://a/b/g',
-                    './g/.'         => 'http://a/b/c/g/',
-                    'g/./h'         => 'http://a/b/c/g/h',
-                    'g/../h'        => 'http://a/b/c/h',
-                    'g;x=1/./y'     => 'http://a/b/c/g;x=1/y',
-                    'g;x=1/../y'    => 'http://a/b/c/y',
-                    'g?y/./x'       => 'http://a/b/c/g?y/./x',
-                    'g?y/../x'      => 'http://a/b/c/g?y/../x',
-                    'g#s/./x'       => 'http://a/b/c/g#s/./x',
-                    'g#s/../x'      => 'http://a/b/c/g#s/../x',
-                    'http:g'        => 'http:g',
-                ),
-            ),
-            array(
-                'http://a/b/c/d;p?q',
-                array('http:g' => 'http://a/b/c/g'),
-                array('::OPTION_STRICT' => false)
-            ),
-        );
-    }
-
-    /**
-     * Test the resolve() function to resolve URLs to each other.
-     *
-     * @param string $baseURL               base-URI
-     * @param array  $relativeAbsolutePairs url-pairs, relative => resolved
-     * @param array  $options               Net_URL2 options
-     *
-     * @dataProvider provideResolveUrls
-     * @covers Net_URL2::resolve
-     * @return void
-     */
-    public function testResolveUrls($baseURL, array $relativeAbsolutePairs,
-        array $options = array()
-    ) {
-        $options = $this->_translateOptionData($options);
-        $base    = new Net_URL2($baseURL, $options);
-        $count = count($relativeAbsolutePairs);
-        $this->assertGreaterThan(0, $count, 'relative-absolute-pairs data is empty');
-        foreach ($relativeAbsolutePairs as $relativeURL => $absoluteURL) {
-            $this->assertSame($absoluteURL, (string) $base->resolve($relativeURL));
-        }
-    }
-
-    /**
-     * Helper method to turn options with strings as the constant names
-     * (to allow to externalize the fixtures) into a concrete options
-     * array that uses the values from the Net_URL2 class constants.
-     *
-     * @param array $options options
-     *
-     * @return array
-     */
-    private function _translateOptionData(array $options)
-    {
-        // translate string option-names to class constant starting with a colon.
-        foreach ($options as $name => $value) {
-            if ($name[0] === ':') {
-                unset($options[$name]);
-                $options[constant("Net_URL2$name")] = $value;
-            }
-        }
-        return $options;
-    }
-
-    /**
-     * Test the resolve() function throwing an exception with invalid data.
-     *
-     * @covers Net_URL2::resolve
-     * @return void
-     */
-    public function testResolveException()
-    {
-        // resolving a relative to a relative URL throws an exception
-        $base = new Net_URL2('news.html?category=arts');
-        $this->addToAssertionCount(1);
-        try {
-            $base->resolve('../arts.html#section-2.4');
-        } catch (Exception $e) {
-            $expected = 'Base-URL must be absolute if reference is not fragment-onl';
-            $this->assertStringStartsWith($expected, $e->getMessage());
-            return;
-        }
-        $this->fail('Expected exception not thrown.');
-    }
-
-    /**
-     * Assert that there is a last error message and it contains needle.
-     *
-     * @param string $needle needle
-     *
-     * @return void
-     */
-    private function _assertLastErrorContains($needle)
-    {
-        $error = error_get_last();
-        $this->assertArrayHasKey('message', $error, 'there was an error previously');
-        $pos = strpos($error['message'], $needle);
-
-        $this->assertTrue(
-            false !== $pos,
-            sprintf(
-                'Last error message "%s" contains "%s"', $error['message'], $needle
-            )
-        );
-    }
-
-    /**
-     * Test UrlEncoding
-     *
-     * @return void
-     * @link   https://pear.php.net/bugs/bug.php?id=18267
-     */
-    public function testUrlEncoding()
-    {
-        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
-        $url     = new Net_URL2('http://localhost/bug.php', $options);
-        $url->setQueryVariables(
-            array(
-                'indexed' => array(
-                    'first value', 'second value', array('foo', 'bar'),
-                )
-            )
-        );
-        $this->assertEquals(
-            'http://localhost/bug.php?indexed[0]=first%20value&indexed[1]' .
-            '=second%20value&indexed[2][0]=foo&indexed[2][1]=bar',
-            strval($url)
-        );
-    }
-
-    /**
-     * A test to verify that keys in QUERY_STRING are encoded by default.
-     *
-     * @return void
-     * @see    Net_URL2::OPTION_ENCODE_KEYS
-     * @see    Net_URL2::buildQuery()
-     */
-    public function testEncodeKeys()
-    {
-        $url = new Net_URL2('http://example.org');
-        $url->setQueryVariables(array('helgi rulez' => 'till too'));
-        $this->assertEquals(
-            'http://example.org?helgi%20rulez=till%20too',
-            strval($url)
-        );
-    }
-
-    /**
-     * A test to verify that keys in QUERY_STRING are not encoded when we supply
-     * 'false' via {@link Net_URL2::__construct()}.
-     *
-     * @return void
-     * @see    Net_URL2::OPTION_ENCODE_KEYS
-     * @see    Net_URL2::buildQuery()
-     */
-    public function testDontEncodeKeys()
-    {
-        $url = new Net_URL2(
-            'http://example.org',
-            array(Net_URL2::OPTION_ENCODE_KEYS => false)
-        );
-        $url->setQueryVariables(array('till rulez' => 'helgi too'));
-        $this->assertEquals(
-            'http://example.org?till rulez=helgi%20too',
-            strval($url)
-        );
-    }
-
-    /**
-     * Brackets for array query variables
-     *
-     * Also text to not encode zero based integer sequence into brackets
-     *
-     * @return void
-     *
-     * @link https://pear.php.net/bugs/bug.php?id=20427
-     */
-    public function testUseBrackets()
-    {
-        $url = new Net_URL2('http://example.org/');
-        $url->setQueryVariables(array('foo' => array('bar', 'baz')));
-        $expected = 'http://example.org/?foo[]=bar&foo[]=baz';
-        $this->assertEquals($expected, $url->getURL());
-
-        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
-        $url     = new Net_URL2('http://example.org/', $options);
-        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
-        $expected = 'http://example.org/?foo[0]=bar&foo[1]=foobar';
-        $this->assertEquals($expected, $url->getURL());
-    }
-
-    /**
-     * Do not use brackets for query variables passed as array
-     *
-     * @return void
-     */
-    public function testDontUseBrackets()
-    {
-        $url = new Net_URL2(
-            'http://example.org/',
-            array(Net_URL2::OPTION_USE_BRACKETS => false)
-        );
-        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
-        $this->assertEquals(
-            'http://example.org/?foo=bar&foo=foobar',
-            strval($url)
-        );
-    }
-
-    /**
-     * A dataProvider for example URIs from RFC 3986 Section 1.1.2
-     *
-     * @return array
-     * @link http://tools.ietf.org/html/rfc3986#section-1.1.2
-     * @see  testExampleUri
-     */
-    public function provideExampleUri()
-    {
-        return array(
-            array('ftp://ftp.is.co.za/rfc/rfc1808.txt'),
-            array('http://www.ietf.org/rfc/rfc2396.txt'),
-            array('ldap://[2001:db8::7]/c=GB?objectClass?one'),
-            array('mailto:John.Doe@example.com'),
-            array('news:comp.infosystems.www.servers.unix'),
-            array('tel:+1-816-555-1212'),
-            array('telnet://192.0.2.16:80/'),
-            array('urn:oasis:names:specification:docbook:dtd:xml:4.1.2'),
-        );
-    }
-
-    /**
-     * test that Net_URL2 works with the example URIs from RFC 3986 Section 1.1.2
-     *
-     * @param string $uri example URI
-     *
-     * @return       void
-     * @dataProvider provideExampleUri
-     * @link         http://tools.ietf.org/html/rfc3986#section-1.1.2
-     * @see          testComponentRecompositionAndNormalization
-     */
-    public function testExampleUri($uri)
-    {
-        $url = new Net_URL2($uri);
-        $this->assertSame($uri, $url->__toString());
-        $url->normalize();
-        $this->assertSame($uri, $url->__toString());
-    }
-
-    /**
-     * A dataProvider for pairs of paths with dot segments and
-     * their form when removed.
-     *
-     * @see testRemoveDotSegments
-     * @return array
-     */
-    public function providePath()
-    {
-        // The numbers behind are in reference to sections
-        // in RFC 3986 5.2.4. Remove Dot Segments
-        return array(
-            array('../', ''), // 2. A.
-            array('./', ''), // 2. A.
-            array('/./', '/'), // 2. B.
-            array('/.', '/'), // 2. B.
-            array('/../', '/'), // 2. C.
-            array('/..', '/'), // 2. C.
-            array('..', ''), // 2. D.
-            array('.', ''), // 2. D.
-            array('a', 'a'), // 2. E.
-            array('/a', '/a'), // 2. E.
-            array('/a/b/c/./../../g', '/a/g'), // 3.
-            array('mid/content=5/../6', 'mid/6'), // 3.
-            array('../foo/bar.php', 'foo/bar.php'),
-            array('/foo/../bar/boo.php', '/bar/boo.php'),
-            array('/boo/..//foo//bar.php', '//foo//bar.php'),
-            array('/./foo/././bar.php', '/foo/bar.php'),
-            array('./.', ''),
-        );
-    }
-
-    /**
-     * Test removal of dot segments
-     *
-     * @param string $path      Path
-     * @param string $assertion Assertion
-     *
-     * @dataProvider providePath
-     * @covers Net_URL2::removeDotSegments
-     * @return void
-     */
-    public function testRemoveDotSegments($path, $assertion)
-    {
-        $this->assertEquals($assertion, Net_URL2::removeDotSegments($path));
-    }
-
-    /**
-     * Test removeDotSegments() loop limit warning
-     *
-     * @covers Net_URL2::removeDotSegments
-     * @return void
-     */
-    public function testRemoveDotSegmentsLoopLimit()
-    {
-        $loopLimit = 256;
-        $segments  = str_repeat('a/', $loopLimit);
-
-        @Net_URL2::removeDotSegments($segments . 'b/');
-
-        $this->_assertLastErrorContains(sprintf(' loop limit %d ', $loopLimit + 1));
-        $this->_assertLastErrorContains(" (left: '/b/')");
-    }
-
-    /**
-     * A dataProvider for query strings and their array representation
-     *
-     * @see testGetQueryVariables
-     * @return array
-     */
-    public function provideQueryStrings()
-    {
-        // If the second (expected) value is set or not null, parse_str() differs.
-        // Notes on PHP differences with each entry/block
-        return array(
-            // Net_URL2::getQueryVariables() non-bracket mode
-            array('test=1&t%65st=%41&extra=',
-                array('test' => array('1', 'A'), 'extra' => ''),
-                array('::OPTION_USE_BRACKETS' => false)),
-            array(''),
-            array('='),
-            array('key'),
-            array('key='),
-            array('=value'),
-            array('k=v'),
-            // no space as var-name in PHP (array()):
-            array(' ',   array(' ' => '' )),
-            array(' =v', array(' ' => 'v')),
-            array('key=value'),
-            // PHP replaces ".", " " and "[" in name replaced by "_":
-            array('key.=value' , array('key.'  => 'value')),
-            array('key =value' , array('key '  => 'value')),
-            array('key[=value' , array('key['  => 'value')),
-            array("key\0=value", array("key\0" => 'value')),
-            array('key]=value'),
-            array('key[]=value'),
-            array('[]=value'),
-            array(']=value'),
-            array(']]=value'),
-            // PHP drops variables that are an open bracket only
-            array('[=value', array('[' => 'value')),
-            // PHP drops spaces in brackets:
-            array('key[ ]=value', array('key'  => array(' ' => 'value'))),
-            // PHP replaces space " " in name by "_"
-            array('key []=1'    , array('key ' => array('1'           ))) ,
-            // PHP does not support "\0" in var-names:
-            array("key[\0]=value"   , array('key' => array("\0" => 'value'  ))),
-            array("key[a\0]=value"  , array('key' => array("a\0" => 'value' ))),
-            array("key[a\0b]=value" , array('key' => array("a\0b" => 'value'))),
-            array('var[]=1&var[0][]=2'),
-            array('key[] []=1'),
-            array('key[] [] []=1'),
-            array('key[] [] []'),
-            array('key[] [] []=[] []'),
-            array('[] [] []=[] []'),
-        );
-    }
-
-    /**
-     * Test parsing of query variables
-     *
-     * @param string $query    string
-     * @param mixed  $expected null to test against parse_str() behavior
-     * @param array  $options  Net_URL2 options
-     *
-     * @dataProvider provideQueryStrings
-     * @covers       Net_URL2::getQueryVariables
-     * @covers       Net_URL2::_queryArrayByKey
-     * @covers       Net_URL2::_queryArrayByBrackets
-     * @covers       Net_URL2::_queryKeyBracketOffset
-     * @return void
-     */
-    public function testGetQueryVariables($query, $expected = null,
-        array $options = array()
-    ) {
-        $options = $this->_translateOptionData($options);
-
-        $url = new Net_URL2('', $options);
-
-        if ($expected === null) {
-            // parse_str() is in PHP before copy on write, therefore
-            // it uses pass-by-reference for $expected to return
-            // the array
-            parse_str($query, $expected);
-        }
-
-        // Xdebug: If breakpoints are ignored, see Xdebug Issue 0000924
-        $url->setQuery($query);
-        $actual = $url->getQueryVariables();
-
-        // Do two assertions, because the first one shows a more nice diff in case
-        // it fails and the second one is actually strict which is what has to be
-        // tested.
-        $this->assertEquals($expected, $actual);
-        $this->assertSame($expected, $actual);
-    }
-
-    /**
-     * data provider of host and port
-     *
-     * @return array
-     * @see testHostAndPort
-     */
-    public function provideHostAndPort()
-    {
-        return array(
-            array('[::1]', '[::1]', false),
-            array('[::1]:', '[::1]', false),
-            array('[::1]:128', '[::1]', '128'),
-            array('127.0.0.1', '127.0.0.1', false),
-            array('127.0.0.1:', '127.0.0.1', false),
-            array('127.0.0.1:128', '127.0.0.1', '128'),
-            array('localhost', 'localhost', false),
-            array('localhost:', 'localhost', false),
-            array('localhost:128', 'localhost', '128'),
-        );
-    }
-
-    /**
-     * test that an authority containing host and port maps to expected host and port
-     *
-     * This is also a regression test to test that using ip-literals works along-
-     * side ipv4 and reg-name hosts incl. port numbers
-     *
-     * It was reported as Bug #20423 on 2014-10-06 18:25 UTC that
-     * http://[::1]// URI drops the host
-     *
-     * @param string      $authority    string
-     * @param string      $expectedHost string
-     * @param string|bool $expectedPort string or FALSE
-     *
-     * @return void
-     * @dataProvider provideHostAndPort
-     * @covers       Net_URL2::setAuthority()
-     * @link         https://pear.php.net/bugs/bug.php?id=20423
-     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.2
-     * @link         http://tools.ietf.org/html/rfc3986#section-3.2
-     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.3
-     */
-    public function testHostAndPort($authority, $expectedHost, $expectedPort)
-    {
-        $uri = "http://{$authority}";
-        $url = new Net_URL2($uri);
-        $this->assertSame($expectedHost, $url->getHost());
-        $this->assertSame($expectedPort, $url->getPort());
-    }
-
-    /**
-     * This is a regression test to test that Net_URL2::getQueryVariables() does
-     * not have a problem with nested array values in form of stacked brackets and
-     * was reported as Bug #17036 on 2010-01-26 15:48 UTC that there would be
-     * a problem with parsed query string.
-     *
-     * @link   https://pear.php.net/bugs/bug.php?id=17036
-     * @covers Net_URL2::getQueryVariables
-     * @return void
-     */
-    public function test17036()
-    {
-        $queryString = 'start=10&test[0][first][1.1][20]=coucou';
-        $url         = new Net_URL2('?' . $queryString);
-        $vars = $url->getQueryVariables();
-
-        $expected = array();
-        $expected['start'] = '10';
-        $expected['test'][0]['first']['1.1'][20] = 'coucou';
-
-        $this->assertEquals($expected, $vars); // give nice diff in case of failuer
-        $this->assertSame($expected, $vars);   // strictly assert the premise
-    }
-
-    /**
-     * This is a regression test to test that resolve() does
-     * merge the path if the base path is empty as the opposite
-     * was reported as Bug #19176 on 2011-12-31 02:07 UTC
-     *
-     * @return void
-     */
-    public function test19176()
-    {
-        $foo  = new Net_URL2('http://www.example.com');
-        $test = $foo->resolve('test.html')->getURL();
-        $this->assertEquals('http://www.example.com/test.html', $test);
-    }
-
-    /**
-     * This is a regression test that removeDotSegments('0') is
-     * working as it was reported as not-working in Bug #19315
-     * on 2012-03-04 04:18 UTC.
-     *
-     * @return void
-     */
-    public function test19315()
-    {
-        $actual = Net_URL2::removeDotSegments('0');
-        $this->assertSame('0', $actual);
-
-        $nonStringObject = (object)array();
-        try {
-            Net_URL2::removeDotSegments($nonStringObject);
-        } catch (PHPUnit_Framework_Error $error) {
-            $this->addToAssertionCount(1);
-        }
-
-        if (!isset($error)) {
-            $this->fail('Failed to verify that error was given.');
-        }
-        unset($error);
-    }
-
-    /**
-     * This is a regression test to test that recovering from
-     * a wrongly encoded URL is possible.
-     *
-     * It was requested as Request #19684 on 2011-12-31 02:07 UTC
-     * that redirects containing spaces should work.
-     *
-     * @return void
-     */
-    public function test19684()
-    {
-        // Location: URL obtained Thu, 25 Apr 2013 20:51:31 GMT
-        $urlWithSpace = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS N'
-            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
-            . '48+219853269+219853286';
-
-        $urlCorrect = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS%20N'
-            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
-            . '48+219853269+219853286';
-
-        $url = new Net_URL2($urlWithSpace);
-
-        $this->assertTrue($url->isAbsolute());
-
-        $urlPart = parse_url($urlCorrect, PHP_URL_PATH);
-        $this->assertSame($urlPart, $url->getPath());
-
-        $urlPart = parse_url($urlCorrect, PHP_URL_QUERY);
-        $this->assertSame($urlPart, $url->getQuery());
-
-        $this->assertSame($urlCorrect, (string)$url);
-
-        $input    = 'http://example.com/get + + to my nose/';
-        $expected = 'http://example.com/get%20+%20+%20to%20my%20nose/';
-        $actual   = new Net_URL2($input);
-        $this->assertEquals($expected, $actual);
-        $actual->normalize();
-    }
-
-    /**
-     * data provider of list of equivalent URLs.
-     *
-     * @see testNormalize
-     * @see testConstructSelf
-     * @return array
-     */
-    public function provideEquivalentUrlLists()
-    {
-        return array(
-            // String equivalence:
-            array('http://example.com/', 'http://example.com/'),
-
-            // Originally first dataset:
-            array('http://www.example.com/%9a', 'http://www.example.com/%9A'),
-
-            // Example from RFC 3986 6.2.2.:
-            array('example://a/b/c/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d'),
-
-            // Example from RFC 3986 6.2.2.1.:
-            array('HTTP://www.EXAMPLE.com/', 'http://www.example.com/'),
-
-            // Example from RFC 3986 6.2.3.:
-            array(
-                'http://example.com', 'http://example.com/',
-                'http://example.com:/', 'http://example.com:80/'
-            ),
-
-            // Bug #20161: URLs with "0" as host fail to normalize with empty path
-            array('http://0/', 'http://0'),
-
-            // Bug #20473: Normalize query and fragment broken
-            array('foo:///?%66%6f%6f#%62%61%72', 'foo:///?foo#bar'),
-        );
-    }
-
-    /**
-     * This is a coverage test to invoke the normalize()
-     * method.
-     *
-     * @return void
-     *
-     * @dataProvider provideEquivalentUrlLists
-     */
-    public function testNormalize()
-    {
-        $urls = func_get_args();
-
-        $this->assertGreaterThanOrEqual(2, count($urls));
-
-        $last = null;
-
-        foreach ($urls as $index => $url) {
-            $url = new Net_Url2($url);
-            $url->normalize();
-            if ($index) {
-                $this->assertSame((string)$last, (string)$url);
-            }
-            $last = $url;
-        }
-    }
-
-    /**
-     * This is a coverage test to invoke __get and __set
-     *
-     * @covers Net_URL2::__get
-     * @covers Net_URL2::__set
-     * @return void
-     */
-    public function testMagicSetGet()
-    {
-        $url = new Net_URL2('');
-
-        $property       = 'authority';
-        $url->$property = $value = 'value';
-        $this->assertEquals($value, $url->$property);
-
-        $property       = 'unsetProperty';
-        $url->$property = $value;
-        $this->assertEquals(false, $url->$property);
-    }
-
-    /**
-     * data provider of uri and normal URIs
-     *
-     * @return array
-     * @see testComponentRecompositionAndNormalization
-     */
-    public function provideComposedAndNormalized()
-    {
-        return array(
-            array(''),
-            array('http:g'),
-            array('user@host'),
-            array('mailto:user@host'),
-        );
-    }
-
-    /**
-     * Tests Net_URL2 RFC 3986 5.3. Component Recomposition in the light
-     * of normalization
-     *
-     * This is also a regression test to test that a missing authority works well
-     * with normalization
-     *
-     * It was reported as Bug #20418 on 2014-10-02 22:10 UTC that there is an
-     * Incorrect normalization of URI with missing authority
-     *
-     * @param string $uri URI
-     *
-     * @return       void
-     * @covers       Net_URL2::getUrl()
-     * @covers       Net_URL2::normalize()
-     * @dataProvider provideComposedAndNormalized
-     * @link         https://pear.php.net/bugs/bug.php?id=20418
-     * @see          testExampleUri
-     */
-    public function testComponentRecompositionAndNormalization($uri)
-    {
-        $url = new Net_URL2($uri);
-        $this->assertSame($uri, $url->getURL());
-        $url->normalize();
-        $this->assertSame($uri, $url->getURL());
-    }
-
-    /**
-     * Tests Net_URL2 ctors URL parameter works with objects implementing
-     * __toString().
-     *
-     * @dataProvider provideEquivalentUrlLists
-     * @coversNothing
-     * @return void
-     */
-    public function testConstructSelf()
-    {
-        $urls = func_get_args();
-        foreach ($urls as $url) {
-            $urlA = new Net_URL2($url);
-            $urlB = new Net_URL2($urlA);
-            $this->assertSame((string)$urlA, (string)$urlB);
-        }
-    }
-
-    /**
-     * This is a feature test to see that the userinfo's data is getting
-     * encoded as outlined in #19684.
-     *
-     * @covers Net_URL2::setAuthority
-     * @covers Net_URL2::setUserinfo
-     * @return void
-     */
-    public function testEncodeDataUserinfoAuthority()
-    {
-        $url = new Net_URL2('http://john doe:secret@example.com/');
-        $this->assertSame('http://john%20doe:secret@example.com/', (string)$url);
-
-        $url->setUserinfo('john doe');
-        $this->assertSame('http://john%20doe@example.com/', (string)$url);
-
-        $url->setUserinfo('john doe', 'pa wd');
-        $this->assertSame('http://john%20doe:pa%20wd@example.com/', (string)$url);
-    }
-
-    /**
-     * This is a regression test to test that using the
-     * host-name "0" does work with getAuthority()
-     *
-     * It was reported as Bug #20156 on 2013-12-27 22:56 UTC
-     * that setAuthority() with "0" as host would not work
-     *
-     * @covers Net_URL2::setAuthority
-     * @covers Net_URL2::getAuthority
-     * @covers Net_URL2::setHost
-     * @return void
-     */
-    public function test20156()
-    {
-        $url  = new Net_URL2('http://user:pass@example.com:127/');
-        $host = '0';
-        $url->setHost($host);
-        $this->assertSame('user:pass@0:127', $url->getAuthority());
-
-        $url->setHost(false);
-        $this->assertSame(false, $url->getAuthority());
-
-        $url->setAuthority($host);
-        $this->assertSame($host, $url->getAuthority());
-    }
-
-    /**
-     * This is a regression test to test that setting "0" as path
-     * does not break normalize().
-     *
-     * It was reported as Bug #20157 on 2013-12-27 23:42 UTC that
-     * normalize() with "0" as path would not work.
-     *
-     * @covers Net_URL2::normalize
-     * @return void
-     */
-    public function test20157()
-    {
-        $subject = 'http://example.com';
-        $url     = new Net_URL2($subject);
-        $url->setPath('0');
-        $url->normalize();
-        $this->assertSame("$subject/0", (string)$url);
-    }
-
-    /**
-     * This is a regression test to ensure that fragment-only references can be
-     * resolved to a non-absolute Base-URI.
-     *
-     * It was reported as Bug #20158 2013-12-28 14:49 UTC that fragment-only
-     * references would not be resolved to non-absolute base URI
-     *
-     * @covers Net_URL2::resolve
-     * @covers Net_URL2::_isFragmentOnly
-     * @return void
-     */
-    public function test20158()
-    {
-        $base     = new Net_URL2('myfile.html');
-        $resolved = $base->resolve('#world');
-        $this->assertSame('myfile.html#world', (string)$resolved);
-    }
-
-    /**
-     * This is a regression test to ensure that authority and path are properly
-     * combined when the path does not start with a slash which is the separator
-     * character between authority and path.
-     *
-     * It was reported as Bug #20159 2013-12-28 17:18 UTC that authority
-     * would not be terminated by slash
-     *
-     * @covers Net_URL2::getUrl
-     * @return void
-     */
-    public function test20159()
-    {
-        $url = new Net_URL2('index.html');
-        $url->setHost('example.com');
-        $this->assertSame('//example.com/index.html', (string)$url);
-    }
-
-    /**
-     * This is a regression test to test that using the file:// URI scheme with
-     * an empty (default) hostname has the empty authority preserved when the
-     * full URL is build.
-     *
-     * It was reported as Bug #20304 on 2014-06-21 00:06 UTC
-     * that file:// URI are crippled.
-     *
-     * Tests with a default authority for the "file" URI scheme
-     *
-     * @covers Net_URL2::getURL
-     * @return void
-     * @link https://pear.php.net/bugs/bug.php?id=20304
-     */
-    public function test20304()
-    {
-        $file = 'file:///path/to/file';
-        $url = new Net_URL2($file);
-        $this->assertSame($file, (string) $url);
-
-        $file = 'file://localhost/path/to/file';
-        $url = new Net_URL2($file);
-        $this->assertSame($file, (string) $url);
-
-        $file = 'file://user@/path/to/file';
-        $url = new Net_URL2($file);
-        $this->assertSame($file, (string) $url);
-
-        $file = 'FILE:///path/to/file';
-        $url = new Net_URL2($file);
-        $this->assertSame($file, (string) $url);
-    }
-}
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/Net/URL2.php 2.2.3-1/Net_URL2-2.2.3/Net/URL2.php
--- 2.2.1-0.2/Net_URL2-2.2.3/Net/URL2.php	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/Net/URL2.php	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,1241 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2007-2009, 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
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * 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.
+ *   * Neither the name of the Net_URL2 nor the names of its contributors may
+ *     be used to endorse or promote products derived from this software
+ *     without specific prior written permission.
+ *
+ * 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.
+ *
+ * @category  Networking
+ * @package   Net_URL2
+ * @author    Christian Schmidt <schmidt@php.net>
+ * @copyright 2007-2009 Peytz & Co. A/S
+ * @license   https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @version   CVS: $Id$
+ * @link      https://tools.ietf.org/html/rfc3986
+ */
+
+/**
+ * Represents a URL as per RFC 3986.
+ *
+ * @category  Networking
+ * @package   Net_URL2
+ * @author    Christian Schmidt <schmidt@php.net>
+ * @copyright 2007-2009 Peytz & Co. A/S
+ * @license   https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @version   Release: 2.2.3
+ * @link      https://pear.php.net/package/Net_URL2
+ */
+class Net_URL2
+{
+    /**
+     * Do strict parsing in resolve() (see RFC 3986, section 5.2.2). Default
+     * is true.
+     */
+    const OPTION_STRICT = 'strict';
+
+    /**
+     * Represent arrays in query using PHP's [] notation. Default is true.
+     */
+    const OPTION_USE_BRACKETS = 'use_brackets';
+
+    /**
+     * Drop zero-based integer sequences in query using PHP's [] notation. Default
+     * is true.
+     */
+    const OPTION_DROP_SEQUENCE = 'drop_sequence';
+
+    /**
+     * 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 "&".
+     */
+    const OPTION_SEPARATOR_INPUT = 'input_separator';
+
+    /**
+     * Query variable separator used when generating the query string. Default
+     * is "&".
+     */
+    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_DROP_SEQUENCE    => true,
+        self::OPTION_ENCODE_KEYS      => true,
+        self::OPTION_SEPARATOR_INPUT  => '&',
+        self::OPTION_SEPARATOR_OUTPUT => '&',
+        );
+
+    /**
+     * The scheme, false for none
+     *
+     * @var string|bool
+     */
+    private $_scheme = false;
+
+    /**
+     * The user, false for no userinfo
+     *
+     * @var string|bool
+     */
+    private $_userinfo = false;
+
+    /**
+     * The host, false for no authority
+     *
+     * @var string|bool
+     */
+    private $_host = false;
+
+    /**
+     * The port number, false for no port number
+     *
+     * @var string|bool
+     */
+    private $_port = false;
+
+    /**
+     * The path
+     *
+     * @var string
+     */
+    private $_path = '';
+
+    /**
+     * The query string without the leading "?" (search), false for no query
+     *
+     * @var string|bool
+     */
+    private $_query = false;
+
+    /**
+     * The fragment name without the leading "#" (anchor), false for no "#" fragment
+     *
+     * @var string|bool
+     */
+    private $_fragment = false;
+
+    /**
+     * Constructor.
+     *
+     * @param string $url     an absolute or relative URL
+     * @param array  $options an array of OPTION_xxx constants
+     *
+     * @uses self::parseUrl()
+     */
+    public function __construct($url, array $options = array())
+    {
+        foreach ($options as $optionName => $value) {
+            if (array_key_exists($optionName, $this->_options)) {
+                $this->_options[$optionName] = $value;
+            }
+        }
+
+        $this->parseUrl($url);
+    }
+
+    /**
+     * Magic Setter.
+     *
+     * This method will magically set the value of a private variable ($var)
+     * with the value passed as the args
+     *
+     * @param string $var The private variable to set.
+     * @param mixed  $arg An argument of any type.
+     *
+     * @return void
+     */
+    public function __set($var, $arg)
+    {
+        $method = 'set' . $var;
+        if (method_exists($this, $method)) {
+            $this->$method($arg);
+        }
+    }
+
+    /**
+     * Magic Getter.
+     *
+     * This is the magic get method to retrieve the private variable
+     * that was set by either __set() or it's setter...
+     *
+     * @param string $var The property name to retrieve.
+     *
+     * @return mixed  $this->$var Either a boolean false if the
+     *                            property is not set or the value
+     *                            of the private property.
+     */
+    public function __get($var)
+    {
+        $method = 'get' . $var;
+        if (method_exists($this, $method)) {
+            return $this->$method();
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the scheme, e.g. "http" or "urn", or false if there is no
+     * scheme specified, i.e. if this is a relative URL.
+     *
+     * @return string|bool
+     */
+    public function getScheme()
+    {
+        return $this->_scheme;
+    }
+
+    /**
+     * Sets the scheme, e.g. "http" or "urn". Specify false if there is no
+     * scheme specified, i.e. if this is a relative URL.
+     *
+     * @param string|bool $scheme e.g. "http" or "urn", or false if there is no
+     *                            scheme specified, i.e. if this is a relative
+     *                            URL
+     *
+     * @return $this
+     * @see    getScheme
+     */
+    public function setScheme($scheme)
+    {
+        $this->_scheme = $scheme;
+        return $this;
+    }
+
+    /**
+     * Returns the user part of the userinfo part (the part preceding the first
+     *  ":"), or false if there is no userinfo part.
+     *
+     * @return string|bool
+     */
+    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
+     * contain ":".
+     *
+     * @return string|bool
+     */
+    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 "@".
+     *
+     * @return string|bool
+     */
+    public function getUserinfo()
+    {
+        return $this->_userinfo;
+    }
+
+    /**
+     * 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 optional password, or false
+     *
+     * @return $this
+     */
+    public function setUserinfo($userinfo, $password = false)
+    {
+        if ($password !== false) {
+            $userinfo .= ':' . $password;
+        }
+
+        if ($userinfo !== false) {
+            $userinfo = $this->_encodeData($userinfo);
+        }
+
+        $this->_userinfo = $userinfo;
+        return $this;
+    }
+
+    /**
+     * Returns the host part, or false if there is no authority part, e.g.
+     * relative URLs.
+     *
+     * @return string|bool a hostname, an IP address, or false
+     */
+    public function getHost()
+    {
+        return $this->_host;
+    }
+
+    /**
+     * Sets the host part. Specify false if there is no authority part, e.g.
+     * relative URLs.
+     *
+     * @param string|bool $host a hostname, an IP address, or false
+     *
+     * @return $this
+     */
+    public function setHost($host)
+    {
+        $this->_host = $host;
+        return $this;
+    }
+
+    /**
+     * Returns the port number, or false if there is no port number specified,
+     * i.e. if the default port is to be used.
+     *
+     * @return string|bool
+     */
+    public function getPort()
+    {
+        return $this->_port;
+    }
+
+    /**
+     * Sets the port number. Specify false if there is no port number specified,
+     * i.e. if the default port is to be used.
+     *
+     * @param string|bool $port a port number, or false
+     *
+     * @return $this
+     */
+    public function setPort($port)
+    {
+        $this->_port = $port;
+        return $this;
+    }
+
+    /**
+     * Returns the authority part, i.e. [ userinfo "@" ] host [ ":" port ], or
+     * false if there is no authority.
+     *
+     * @return string|bool
+     */
+    public function getAuthority()
+    {
+        if (false === $this->_host) {
+            return false;
+        }
+
+        $authority = '';
+
+        if (strlen($this->_userinfo)) {
+            $authority .= $this->_userinfo . '@';
+        }
+
+        $authority .= $this->_host;
+
+        if ($this->_port !== false) {
+            $authority .= ':' . $this->_port;
+        }
+
+        return $authority;
+    }
+
+    /**
+     * Sets the authority part, i.e. [ userinfo "@" ] host [ ":" port ]. Specify
+     * false if there is no authority.
+     *
+     * @param string|bool $authority a hostname or an IP address, possibly
+     *                               with userinfo prefixed and port number
+     *                               appended, e.g. "foo:bar@example.org:81".
+     *
+     * @return $this
+     */
+    public function setAuthority($authority)
+    {
+        $this->_userinfo = false;
+        $this->_host     = false;
+        $this->_port     = false;
+
+        if ('' === $authority) {
+            $this->_host = $authority;
+            return $this;
+        }
+
+        if (!preg_match('(^(([^@]*)@)?(.+?)(:(\d*))?$)', $authority, $matches)) {
+            return $this;
+        }
+
+        if ($matches[1]) {
+            $this->_userinfo = $this->_encodeData($matches[2]);
+        }
+
+        $this->_host = $matches[3];
+
+        if (isset($matches[5]) && strlen($matches[5])) {
+            $this->_port = $matches[5];
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the path part (possibly an empty string).
+     *
+     * @return string
+     */
+    public function getPath()
+    {
+        return $this->_path;
+    }
+
+    /**
+     * Sets the path part (possibly an empty string).
+     *
+     * @param string $path a path
+     *
+     * @return $this
+     */
+    public function setPath($path)
+    {
+        $this->_path = $path;
+        return $this;
+    }
+
+    /**
+     * Returns the query string (excluding the leading "?"), or false if "?"
+     * is not present in the URL.
+     *
+     * @return string|bool
+     * @see    getQueryVariables
+     */
+    public function getQuery()
+    {
+        return $this->_query;
+    }
+
+    /**
+     * Sets the query string (excluding the leading "?"). Specify false if "?"
+     * is not present in the URL.
+     *
+     * @param string|bool $query a query string, e.g. "foo=1&bar=2"
+     *
+     * @return $this
+     * @see    setQueryVariables
+     */
+    public function setQuery($query)
+    {
+        $this->_query = $query;
+        return $this;
+    }
+
+    /**
+     * Returns the fragment name, or false if "#" is not present in the URL.
+     *
+     * @return string|bool
+     */
+    public function getFragment()
+    {
+        return $this->_fragment;
+    }
+
+    /**
+     * Sets the fragment name. Specify false if "#" is not present in the URL.
+     *
+     * @param string|bool $fragment a fragment excluding the leading "#", or
+     *                              false
+     *
+     * @return $this
+     */
+    public function setFragment($fragment)
+    {
+        $this->_fragment = $fragment;
+        return $this;
+    }
+
+    /**
+     * Returns the query string like an array as the variables would appear in
+     * $_GET in a PHP script. If the URL does not contain a "?", an empty array
+     * is returned.
+     *
+     * @throws Exception
+     * @return array
+     */
+    public function getQueryVariables()
+    {
+        $separator   = $this->getOption(self::OPTION_SEPARATOR_INPUT);
+        $encodeKeys  = $this->getOption(self::OPTION_ENCODE_KEYS);
+        $useBrackets = $this->getOption(self::OPTION_USE_BRACKETS);
+
+        $return  = array();
+
+        for ($part = strtok($this->_query, $separator);
+            strlen($part);
+            $part = strtok($separator)
+        ) {
+            list($key, $value) = explode('=', $part, 2) + array(1 => '');
+
+            if ($encodeKeys) {
+                $key = rawurldecode($key);
+            }
+            $value = rawurldecode($value);
+
+            if ($useBrackets) {
+                $return = $this->_queryArrayByKey($key, $value, $return);
+            } else {
+                if (isset($return[$key])) {
+                    $return[$key]  = (array) $return[$key];
+                    $return[$key][] = $value;
+                } else {
+                    $return[$key] = $value;
+                }
+            }
+        }
+
+        return $return;
+    }
+
+    /**
+     * Parse a single query key=value pair into an existing php array
+     *
+     * @param string $key   query-key
+     * @param string $value query-value
+     * @param array  $array of existing query variables (if any)
+     *
+     * @throws Exception
+     * @return mixed
+     */
+    private function _queryArrayByKey($key, $value, array $array = array())
+    {
+        if (!strlen($key)) {
+            return $array;
+        }
+
+        $offset = $this->_queryKeyBracketOffset($key);
+        if ($offset === false) {
+            $name = $key;
+        } else {
+            $name = substr($key, 0, $offset);
+        }
+
+        if (!strlen($name)) {
+            return $array;
+        }
+
+        if (!$offset) {
+            // named value
+            $array[$name] = $value;
+        } else {
+            // array
+            $brackets = substr($key, $offset);
+            if (!isset($array[$name])) {
+                $array[$name] = array();
+            }
+            $array[$name] = $this->_queryArrayByBrackets(
+                $brackets, $value, $array[$name]
+            );
+        }
+
+        return $array;
+    }
+
+    /**
+     * Parse a key-buffer to place value in array
+     *
+     * @param string $buffer to consume all keys from
+     * @param string $value  to be set/add
+     * @param array  $array  to traverse and set/add value in
+     *
+     * @throws Exception
+     * @return array
+     */
+    private function _queryArrayByBrackets($buffer, $value, array $array)
+    {
+        $entry = &$array;
+
+        for ($iteration = 0; strlen($buffer); $iteration++) {
+            $open = $this->_queryKeyBracketOffset($buffer);
+            if ($open !== 0) {
+                // Opening bracket [ must exist at offset 0, if not, there is
+                // no bracket to parse and the value dropped.
+                // if this happens in the first iteration, this is flawed, see
+                // as well the second exception below.
+                if ($iteration) {
+                    break;
+                }
+                // @codeCoverageIgnoreStart
+                throw new Exception(
+                    'Net_URL2 Internal Error: '. __METHOD__ .'(): ' .
+                    'Opening bracket [ must exist at offset 0'
+                );
+                // @codeCoverageIgnoreEnd
+            }
+
+            $close = strpos($buffer, ']', 1);
+            if (!$close) {
+                // this error condition should never be reached as this is a
+                // private method and bracket pairs are checked beforehand.
+                // See as well the first exception for the opening bracket.
+                // @codeCoverageIgnoreStart
+                throw new Exception(
+                    'Net_URL2 Internal Error: '. __METHOD__ .'(): ' .
+                    'Closing bracket ] must exist, not found'
+                );
+                // @codeCoverageIgnoreEnd
+            }
+
+            $index = substr($buffer, 1, $close - 1);
+            if (strlen($index)) {
+                $entry = &$entry[$index];
+            } else {
+                if (!is_array($entry)) {
+                    $entry = array();
+                }
+                $entry[] = &$new;
+                $entry = &$new;
+                unset($new);
+            }
+            $buffer = substr($buffer, $close + 1);
+        }
+
+        $entry = $value;
+
+        return $array;
+    }
+
+    /**
+     * Query-key has brackets ("...[]")
+     *
+     * @param string $key query-key
+     *
+     * @return bool|int offset of opening bracket, false if no brackets
+     */
+    private function _queryKeyBracketOffset($key)
+    {
+        if (false !== $open = strpos($key, '[')
+            and false === strpos($key, ']', $open + 1)
+        ) {
+            $open = false;
+        }
+
+        return $open;
+    }
+
+    /**
+     * Sets the query string to the specified variable in the query string.
+     *
+     * @param array $array (name => value) array
+     *
+     * @return $this
+     */
+    public function setQueryVariables(array $array)
+    {
+        if (!$array) {
+            $this->_query = false;
+        } else {
+            $this->_query = $this->buildQuery(
+                $array,
+                $this->getOption(self::OPTION_SEPARATOR_OUTPUT)
+            );
+        }
+        return $this;
+    }
+
+    /**
+     * Sets the specified variable in the query string.
+     *
+     * @param string $name  variable name
+     * @param mixed  $value variable value
+     *
+     * @throws Exception
+     * @return $this
+     */
+    public function setQueryVariable($name, $value)
+    {
+        $array = $this->getQueryVariables();
+        $array[$name] = $value;
+        $this->setQueryVariables($array);
+        return $this;
+    }
+
+    /**
+     * Removes the specified variable from the query string.
+     *
+     * @param string $name a query string variable, e.g. "foo" in "?foo=1"
+     *
+     * @throws Exception
+     * @return void
+     */
+    public function unsetQueryVariable($name)
+    {
+        $array = $this->getQueryVariables();
+        unset($array[$name]);
+        $this->setQueryVariables($array);
+    }
+
+    /**
+     * Returns a string representation of this URL.
+     *
+     * @return string
+     */
+    public function getURL()
+    {
+        // See RFC 3986, section 5.3
+        $url = '';
+
+        if ($this->_scheme !== false) {
+            $url .= $this->_scheme . ':';
+        }
+
+        $authority = $this->getAuthority();
+        if ($authority === false && strtolower($this->_scheme) === 'file') {
+            $authority = '';
+        }
+
+        $url .= $this->_buildAuthorityAndPath($authority, $this->_path);
+
+        if ($this->_query !== false) {
+            $url .= '?' . $this->_query;
+        }
+
+        if ($this->_fragment !== false) {
+            $url .= '#' . $this->_fragment;
+        }
+
+        return $url;
+    }
+
+    /**
+     * Put authority and path together, wrapping authority
+     * into proper separators/terminators.
+     *
+     * @param string|bool $authority authority
+     * @param string      $path      path
+     *
+     * @return string
+     */
+    private function _buildAuthorityAndPath($authority, $path)
+    {
+        if ($authority === false) {
+            return $path;
+        }
+
+        $terminator = ($path !== '' && $path[0] !== '/') ? '/' : '';
+
+        return '//' . $authority . $terminator . $path;
+    }
+
+    /**
+     * Returns a string representation of this URL.
+     *
+     * @return string
+     * @link   https://php.net/language.oop5.magic#object.tostring
+     */
+    public function __toString()
+    {
+        return $this->getURL();
+    }
+
+    /**
+     * Returns a normalized string representation of this URL. This is useful
+     * for comparison of URLs.
+     *
+     * @return string
+     */
+    public function getNormalizedURL()
+    {
+        $url = clone $this;
+        $url->normalize();
+        return $url->getURL();
+    }
+
+    /**
+     * Normalizes the URL
+     *
+     * See RFC 3986, Section 6.  Normalization and Comparison
+     *
+     * @link https://tools.ietf.org/html/rfc3986#section-6
+     *
+     * @return void
+     */
+    public function normalize()
+    {
+        // See RFC 3986, section 6
+
+        // Scheme is case-insensitive
+        if ($this->_scheme) {
+            $this->_scheme = strtolower($this->_scheme);
+        }
+
+        // Hostname is case-insensitive
+        if ($this->_host) {
+            $this->_host = strtolower($this->_host);
+        }
+
+        // Remove default port number for known schemes (RFC 3986, section 6.2.3)
+        if ('' === $this->_port
+            || $this->_port
+            && $this->_scheme
+            && $this->_port == getservbyname($this->_scheme, 'tcp')
+        ) {
+            $this->_port = false;
+        }
+
+        // Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
+        // Normalize percentage-encoded unreserved characters (section 6.2.2.2)
+        $fields = array(&$this->_userinfo, &$this->_host, &$this->_path,
+                        &$this->_query, &$this->_fragment);
+        foreach ($fields as &$field) {
+            if ($field !== false) {
+                $field = $this->_normalize("$field");
+            }
+        }
+        unset($field);
+
+        // 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 (false !== $this->_host && '' === $this->_path) {
+            $this->_path = '/';
+        }
+
+        // path should start with '/' if there is authority (section 3.3.)
+        if (strlen($this->getAuthority())
+            && strlen($this->_path)
+            && $this->_path[0] !== '/'
+        ) {
+            $this->_path = '/' . $this->_path;
+        }
+    }
+
+    /**
+     * Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
+     * Normalize percentage-encoded unreserved characters (section 6.2.2.2)
+     *
+     * @param string|array $mixed string or array of strings to normalize
+     *
+     * @return string|array
+     * @see    normalize
+     * @see    _normalizeCallback()
+     */
+    private function _normalize($mixed)
+    {
+        return preg_replace_callback(
+            '((?:%[0-9a-fA-Z]{2})+)', array($this, '_normalizeCallback'),
+            $mixed
+        );
+    }
+
+    /**
+     * Callback for _normalize() of %XX percentage-encodings
+     *
+     * @param array $matches as by preg_replace_callback
+     *
+     * @return string
+     * @see    normalize
+     * @see    _normalize
+     *
+     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+     */
+    private function _normalizeCallback($matches)
+    {
+        return self::urlencode(urldecode($matches[0]));
+    }
+
+    /**
+     * Returns whether this instance represents an absolute URL.
+     *
+     * @return bool
+     */
+    public function isAbsolute()
+    {
+        return (bool) $this->_scheme;
+    }
+
+    /**
+     * Returns an Net_URL2 instance representing an absolute URL relative to
+     * this URL.
+     *
+     * @param Net_URL2|string $reference relative URL
+     *
+     * @throws Exception
+     * @return $this
+     */
+    public function resolve($reference)
+    {
+        if (!$reference instanceof Net_URL2) {
+            $reference = new self($reference);
+        }
+        if (!$reference->_isFragmentOnly() && !$this->isAbsolute()) {
+            throw new Exception(
+                'Base-URL must be absolute if reference is not fragment-only'
+            );
+        }
+
+        // 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;
+        }
+
+        $target = new self('');
+        if ($reference->_scheme !== false) {
+            $target->_scheme = $reference->_scheme;
+            $target->setAuthority($reference->getAuthority());
+            $target->_path  = self::removeDotSegments($reference->_path);
+            $target->_query = $reference->_query;
+        } else {
+            $authority = $reference->getAuthority();
+            if ($authority !== false) {
+                $target->setAuthority($authority);
+                $target->_path  = self::removeDotSegments($reference->_path);
+                $target->_query = $reference->_query;
+            } else {
+                if ($reference->_path == '') {
+                    $target->_path = $this->_path;
+                    if ($reference->_query !== false) {
+                        $target->_query = $reference->_query;
+                    } else {
+                        $target->_query = $this->_query;
+                    }
+                } else {
+                    if (substr($reference->_path, 0, 1) == '/') {
+                        $target->_path = self::removeDotSegments($reference->_path);
+                    } else {
+                        // Merge paths (RFC 3986, section 5.2.3)
+                        if ($this->_host !== false && $this->_path == '') {
+                            $target->_path = '/' . $reference->_path;
+                        } else {
+                            $i = strrpos($this->_path, '/');
+                            if ($i !== false) {
+                                $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;
+
+        return $target;
+    }
+
+    /**
+     * URL is fragment-only
+     *
+     * @return bool
+     *
+     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+     */
+    private function _isFragmentOnly()
+    {
+        return (
+            $this->_fragment !== false
+            && $this->_query === false
+            && $this->_path === ''
+            && $this->_port === false
+            && $this->_host === false
+            && $this->_userinfo === false
+            && $this->_scheme === false
+        );
+    }
+
+    /**
+     * Removes dots as described in RFC 3986, section 5.2.4, e.g.
+     * "/foo/../bar/baz" => "/bar/baz"
+     *
+     * @param string $path a path
+     *
+     * @return string a path
+     */
+    public static function removeDotSegments($path)
+    {
+        $path = (string) $path;
+        $output = '';
+
+        // Make sure not to be trapped in an infinite loop due to a bug in this
+        // method
+        $loopLimit = 256;
+        $j = 0;
+        while ('' !== $path && $j++ < $loopLimit) {
+            if (substr($path, 0, 2) === './') {
+                // Step 2.A
+                $path = substr($path, 2);
+            } elseif (substr($path, 0, 3) === '../') {
+                // Step 2.A
+                $path = substr($path, 3);
+            } elseif (substr($path, 0, 3) === '/./' || $path === '/.') {
+                // Step 2.B
+                $path = '/' . substr($path, 3);
+            } elseif (substr($path, 0, 4) === '/../' || $path === '/..') {
+                // Step 2.C
+                $path   = '/' . substr($path, 4);
+                $i      = strrpos($output, '/');
+                $output = $i === false ? '' : substr($output, 0, $i);
+            } elseif ($path === '.' || $path === '..') {
+                // Step 2.D
+                $path = '';
+            } else {
+                // Step 2.E
+                $i = strpos($path, '/', $path[0] === '/');
+                if ($i === false) {
+                    $output .= $path;
+                    $path = '';
+                    break;
+                }
+                $output .= substr($path, 0, $i);
+                $path = substr($path, $i);
+            }
+        }
+
+        if ($path !== '') {
+            $message = sprintf(
+                'Unable to remove dot segments; hit loop limit %d (left: %s)',
+                $j, var_export($path, true)
+            );
+            trigger_error($message, E_USER_WARNING);
+        }
+
+        return $output;
+    }
+
+    /**
+     * Percent-encodes all non-alphanumeric characters except these: _ . - ~
+     * Similar to PHP's rawurlencode(), except that it also encodes ~ in PHP
+     * 5.2.x and earlier.
+     *
+     * @param string $string string to encode
+     *
+     * @return string
+     */
+    public static function urlencode($string)
+    {
+        $encoded = rawurlencode($string);
+
+        // This is only necessary in PHP < 5.3.
+        $encoded = str_replace('%7E', '~', $encoded);
+        return $encoded;
+    }
+
+    /**
+     * Returns a Net_URL2 instance representing the canonical URL of the
+     * currently executing PHP script.
+     *
+     * @throws Exception
+     * @return string
+     */
+    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 = $_SERVER['SERVER_PORT'];
+        if ($url->_scheme == 'http' && $port != 80
+            || $url->_scheme == 'https' && $port != 443
+        ) {
+            $url->_port = $port;
+        }
+        return $url;
+    }
+
+    /**
+     * Returns the URL used to retrieve the current request.
+     *
+     * @throws Exception
+     * @return string
+     */
+    public static function getRequestedURL()
+    {
+        return self::getRequested()->getUrl();
+    }
+
+    /**
+     * Returns a Net_URL2 instance representing the URL used to retrieve the
+     * current request.
+     *
+     * @throws Exception
+     * @return $this
+     */
+    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']);
+        return $url;
+    }
+
+    /**
+     * Returns the value of the specified option.
+     *
+     * @param string $optionName The name of the option to retrieve
+     *
+     * @return mixed
+     */
+    public function getOption($optionName)
+    {
+        return isset($this->_options[$optionName])
+            ? $this->_options[$optionName] : false;
+    }
+
+    /**
+     * A simple version of http_build_query in userland. The encoded string is
+     * percentage encoded according to RFC 3986.
+     *
+     * @param array  $data      An array, which has to be converted into
+     *                          QUERY_STRING. Anything is possible.
+     * @param string $separator Separator {@link self::OPTION_SEPARATOR_OUTPUT}
+     * @param string $key       For stacked values (arrays in an array).
+     *
+     * @return string
+     */
+    protected function buildQuery(array $data, $separator, $key = null)
+    {
+        $query = array();
+        $drop_names = (
+            $this->_options[self::OPTION_DROP_SEQUENCE] === true
+            && array_keys($data) === array_keys(array_values($data))
+        );
+        foreach ($data as $name => $value) {
+            if ($this->getOption(self::OPTION_ENCODE_KEYS) === true) {
+                $name = rawurlencode($name);
+            }
+            if ($key !== null) {
+                if ($this->getOption(self::OPTION_USE_BRACKETS) === true) {
+                    $drop_names && $name = '';
+                    $name = $key . '[' . $name . ']';
+                } else {
+                    $name = $key;
+                }
+            }
+            if (is_array($value)) {
+                $query[] = $this->buildQuery($value, $separator, $name);
+            } else {
+                $query[] = $name . '=' . rawurlencode($value);
+            }
+        }
+        return implode($separator, $query);
+    }
+
+    /**
+     * This method uses a regex to parse the url into the designated parts.
+     *
+     * @param string $url URL
+     *
+     * @return void
+     * @uses   self::$_scheme, self::setAuthority(), self::$_path, self::$_query,
+     *         self::$_fragment
+     * @see    __construct
+     */
+    protected function parseUrl($url)
+    {
+        // The regular expression is copied verbatim from RFC 3986, appendix B.
+        // The expression does not validate the URL but matches any string.
+        preg_match(
+            '(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)',
+            $url, $matches
+        );
+
+        // "path" is always present (possibly as an empty string); the rest
+        // are optional.
+        $this->_scheme   = !empty($matches[1]) ? $matches[2] : false;
+        $this->setAuthority(!empty($matches[3]) ? $matches[4] : false);
+        $this->_path     = $this->_encodeData($matches[5]);
+        $this->_query    = !empty($matches[6])
+                           ? $this->_encodeData($matches[7])
+                           : false
+            ;
+        $this->_fragment = !empty($matches[8]) ? $matches[9] : false;
+    }
+
+    /**
+     * Encode characters that might have been forgotten to encode when passing
+     * in an URL. Applied onto Userinfo, Path and Query.
+     *
+     * @param string $url URL
+     *
+     * @return string
+     * @see    parseUrl
+     * @see    setAuthority
+     * @link   https://pear.php.net/bugs/bug.php?id=20425
+     */
+    private function _encodeData($url)
+    {
+        return preg_replace_callback(
+            '([\x00-\x20\x22\x3C\x3E\x7F-\xFF]+)',
+            array($this, '_encodeCallback'), $url
+        );
+    }
+
+    /**
+     * Callback for encoding character data
+     *
+     * @param array $matches Matches
+     *
+     * @return string
+     * @see    _encodeData
+     *
+     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+     */
+    private function _encodeCallback(array $matches)
+    {
+        return rawurlencode($matches[0]);
+    }
+}
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/docs/6470.php 2.2.3-1/Net_URL2-2.2.3/docs/6470.php
--- 2.2.1-0.2/Net_URL2-2.2.3/docs/6470.php	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/docs/6470.php	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * This file contains code Copyright (c) 2002-2003, Richard Heyes,
+ * See BSD-3-CLAUSE-Heyes,
+ * Author: Richard Heyes <richard at php net>
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @link     https://tools.ietf.org/html/rfc3986
+ */
+
+/**
+* This example will decode the url given and display its
+* constituent parts.
+*/
+    error_reporting(E_ALL | E_STRICT);
+
+    require_once 'Net/URL2.php';
+
+    $url = new Net_URL2('https://www.example.com/foo/bar/index.php?foo=bar');
+
+?>
+<html>
+<body>
+
+<pre>
+Protocol...: <?php echo $url->protocol; ?>
+
+Username...: <?php echo $url->user; ?>
+
+Password...: <?php echo $url->pass; ?>
+
+Server.....: <?php echo $url->host; ?>
+
+Port.......: <?php $url->port; ?>
+
+File/path..: <?php $url->path; ?>
+
+Querystring: <?php print_r($url->querystring); ?>
+
+Anchor.....: <?php echo $url->anchor;?>
+
+Full URL...: <?php echo $url->getUrl(); ?>
+
+Resolve path (/.././/foo/bar/joe/./././../jabba): <b><?php
+        echo $url->resolve('/.././/foo/bar/joe/./././../jabba'); ?></b>
+</pre>
+
+</body>
+</html>
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/docs/BSD-3-CLAUSE-Heyes 2.2.3-1/Net_URL2-2.2.3/docs/BSD-3-CLAUSE-Heyes
--- 2.2.1-0.2/Net_URL2-2.2.3/docs/BSD-3-CLAUSE-Heyes	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/docs/BSD-3-CLAUSE-Heyes	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,27 @@
+Copyright (c) 2002-2003, Richard Heyes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1) Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2) 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.
+3) Neither the name of the Richard Heyes nor the names of his
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+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
+HOLDER 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.
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/docs/example.php 2.2.3-1/Net_URL2-2.2.3/docs/example.php
--- 2.2.1-0.2/Net_URL2-2.2.3/docs/example.php	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/docs/example.php	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * This file contains code Copyright (c) 2002-2003, Richard Heyes,
+ * See BSD-3-CLAUSE-Heyes,
+ * Author: Richard Heyes <richard at php net>
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @link     https://tools.ietf.org/html/rfc3986
+ */
+
+/**
+* This example will decode the url given and display its
+* constituent parts.
+*/
+
+error_reporting(E_ALL | E_STRICT);
+
+require 'Net/URL2.php';
+
+$url = new Net_URL2(
+    'https://example.com/pls/portal30/PORTAL30.wwpob_page.changetabs?'
+    .'p_back_url=http%3A%2F%2Fexample.com%2Fservlet%2Fpage%3F_pageid%3D360'
+    .'%2C366%2C368%2C382%26_dad%3Dportal30%26_schema%3DPORTAL30&foo=bar'
+);
+
+?>
+<html>
+<body>
+
+<pre>
+Protocol...: <?php echo $url->protocol; ?>
+
+Username...: <?php echo $url->user; ?>
+
+Password...: <?php echo $url->pass; ?>
+
+Server.....: <?php echo $url->host; ?>
+
+Port.......: <?php $url->port; ?>
+
+File/path..: <?php $url->path; ?>
+
+Querystring: <?php print_r($url->querystring); ?>
+
+Anchor.....: <?php echo $url->anchor;?>
+
+Full URL...: <?php echo $url->getUrl(); ?>
+
+
+Resolve path (.././/foo/bar/joe/./././../jabba): <b><?php
+        echo $url->resolve('.././/foo/bar/joe/./././../jabba'); ?></b>
+</pre>
+
+</body>
+</html>
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/tests/AllTests.php 2.2.3-1/Net_URL2-2.2.3/tests/AllTests.php
--- 2.2.1-0.2/Net_URL2-2.2.3/tests/AllTests.php	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/tests/AllTests.php	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @link     https://tools.ietf.org/html/rfc3986
+ */
+
+require_once 'PHPUnit/Autoload.php';
+
+chdir(dirname(__FILE__) .  '/../');
+
+require_once 'Net/URL2Test.php';
+require_once 'Net/URL2.php';
+
+/**
+ * Test class for Net_URL2.
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @version  Release: @package_version@
+ * @link     https://pear.php.net/package/Net_URL2
+ */
+class Net_URL2_AllTests
+{
+    /**
+     * main()
+     *
+     * @return void
+     */
+    public static function main()
+    {
+
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    /**
+     * suite()
+     *
+     * @return PHPUnit_Framework_TestSuite
+     */
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Net_URL2 tests');
+        /** Add testsuites, if there is. */
+        $suite->addTestSuite('Net_URL2Test');
+
+        return $suite;
+    }
+}
+
+Net_URL2_AllTests::main();
diff -pruN 2.2.1-0.2/Net_URL2-2.2.3/tests/Net/URL2Test.php 2.2.3-1/Net_URL2-2.2.3/tests/Net/URL2Test.php
--- 2.2.1-0.2/Net_URL2-2.2.3/tests/Net/URL2Test.php	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/Net_URL2-2.2.3/tests/Net/URL2Test.php	2025-03-24 08:21:14.000000000 +0000
@@ -0,0 +1,1098 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @link     https://tools.ietf.org/html/rfc3986
+ */
+
+/**
+ * Test class for Net_URL2.
+ *
+ * @category Networking
+ * @package  Net_URL2
+ * @author   Some Pear Developers <pear@php.net>
+ * @license  https://spdx.org/licenses/BSD-3-Clause BSD-3-Clause
+ * @version  Release: 2.2.3
+ * @link     https://pear.php.net/package/Net_URL2
+ */
+class Net_URL2Test extends PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests setting a zero-length string and false as authority
+     * Also: Regression test for Bug #20420
+     *
+     * @covers Net_URL2::setAuthority
+     * @return void
+     * @link https://pear.php.net/bugs/bug.php?id=20420
+     */
+    public function testSetEmptyAuthority()
+    {
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setAuthority('');
+        $this->assertSame('', $url->getAuthority());
+        $this->assertSame('', $url->getHost());
+        $this->assertSame(false, $url->getPort());
+        $this->assertSame(false, $url->getUserinfo());
+        $this->assertSame(false, $url->getUser());
+
+        $url->setAuthority(false);
+        $this->assertSame(false, $url->getAuthority());
+    }
+
+    /**
+     * Tests setting an empty userinfo part
+     * Also: Regression test for Bug #20013 and Bug #20399
+     *
+     * @covers Net_URL2::setUserinfo
+     * @covers Net_URL2::getUserinfo
+     * @covers Net_URL2::getURL
+     * @return void
+     * @link https://pear.php.net/bugs/bug.php?id=20013
+     * @link https://pear.php.net/bugs/bug.php?id=20399
+     */
+    public function testSetEmptyUserinfo()
+    {
+        $url = new Net_URL2('http://@www.example.com/');
+        $this->assertSame('http://www.example.com/', $url->getURL());
+
+        $url = new Net_URL2('http://www.example.com/');
+        $this->assertSame('http://www.example.com/', $url->getURL());
+        $url->setUserinfo('');
+        $this->assertSame('http://www.example.com/', $url->getURL());
+        $this->assertSame('', $url->getUserinfo());
+        $url->setUserinfo(false);
+        $this->assertSame('http://www.example.com/', $url->getURL());
+        $this->assertFalse($url->getUserinfo());
+    }
+
+    /**
+     * Tests an URL with no userinfo and normalization
+     *
+     * Also: Regression test for Bug #20385
+     *
+     * @covers Net_URL2::getUserinfo
+     * @covers Net_URL2::normalize
+     * @covers Net_URL2::getNormalizedURL
+     * @return void
+     * @link https://pear.php.net/bugs/bug.php?id=20385
+     */
+    public function testNoUserinfoAndNormalize()
+    {
+        $testUrl = 'http://www.example.com/';
+
+        $url = new Net_URL2($testUrl);
+        $this->assertFalse($url->getUserinfo());
+
+        $url->normalize();
+        $this->assertFalse($url->getUserinfo());
+
+        $this->assertEquals($testUrl, $url->getURL());
+        $this->assertEquals($testUrl, $url->getNormalizedURL());
+    }
+
+    /**
+     * Tests setQueryVariable().
+     *
+     * @return void
+     */
+    public function testSetQueryVariable()
+    {
+
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setQueryVariable('pear', 'fun');
+        $this->assertEquals($url->getURL(), 'http://www.example.com/?pear=fun');
+    }
+
+    /**
+     * Tests setQueryVariables().
+     *
+     * @return void
+     */
+    public function testSetQueryVariables()
+    {
+
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setQueryVariables(array('pear' => 'fun'));
+        $this->assertEquals('http://www.example.com/?pear=fun', $url->getURL());
+        $url->setQueryVariables(array('pear' => 'fun for sure'));
+        $this->assertEquals(
+            'http://www.example.com/?pear=fun%20for%20sure', $url->getURL()
+        );
+    }
+
+    /**
+     * Tests unsetQueryVariable()
+     *
+     * @return void
+     */
+    public function testUnsetQueryVariable()
+    {
+        $url = new Net_URL2(
+            'http://www.example.com/?name=david&pear=fun&fish=slippery'
+        );
+
+        $removes = array(
+            'pear' => 'http://www.example.com/?name=david&fish=slippery',
+            'name' => 'http://www.example.com/?fish=slippery',
+            'fish' => 'http://www.example.com/',
+        );
+
+        foreach ($removes as $name => $expected) {
+            $url->unsetQueryVariable($name);
+            $this->assertEquals($expected, $url);
+        }
+    }
+
+    /**
+     * Tests setQuery().
+     *
+     * @return void
+     */
+    public function testSetQuery()
+    {
+
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setQuery('flapdoodle&dilly%20all%20day');
+        $this->assertEquals(
+            $url->getURL(), 'http://www.example.com/?flapdoodle&dilly%20all%20day'
+        );
+    }
+
+    /**
+     * Tests getQuery().
+     *
+     * @return void
+     */
+    public function testGetQuery()
+    {
+
+        $url = new Net_URL2('http://www.example.com/?foo');
+        $this->assertEquals($url->getQuery(), 'foo');
+        $url = new Net_URL2('http://www.example.com/?pear=fun&fruit=fruity');
+        $this->assertEquals($url->getQuery(), 'pear=fun&fruit=fruity');
+    }
+
+    /**
+     * Tests setScheme().
+     *
+     * @return void
+     */
+    public function testSetScheme()
+    {
+
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setScheme('ftp');
+        $this->assertEquals($url->getURL(), 'ftp://www.example.com/');
+        $url->setScheme('gopher');
+        $this->assertEquals($url->getURL(), 'gopher://www.example.com/');
+    }
+
+    /**
+     * Tests setting the fragment.
+     *
+     * @return void
+     */
+    public function testSetFragment()
+    {
+
+        $url = new Net_URL2('http://www.example.com/');
+        $url->setFragment('pear');
+        $this->assertEquals('http://www.example.com/#pear', $url->getURL());
+    }
+
+    /**
+     * A dataProvider for paths that are solved to a base URI.
+     *
+     * @see testResolveUrls
+     * @return array
+     */
+    public static function provideResolveUrls()
+    {
+        return array(
+            array(
+                // Examples from RFC 3986, section 5.4.
+                // relative base-URI, (URL => absolute URL), [(options)]
+                'http://a/b/c/d;p?q',
+                array(
+                    'g:h'           => 'g:h',
+                    'g'             => 'http://a/b/c/g',
+                    './g'           => 'http://a/b/c/g',
+                    'g/'            => 'http://a/b/c/g/',
+                    '/g'            => 'http://a/g',
+                    '//g'           => 'http://g',
+                    '?y'            => 'http://a/b/c/d;p?y',
+                    'g?y'           => 'http://a/b/c/g?y',
+                    '#s'            => 'http://a/b/c/d;p?q#s',
+                    'g#s'           => 'http://a/b/c/g#s',
+                    'g?y#s'         => 'http://a/b/c/g?y#s',
+                    ';x'            => 'http://a/b/c/;x',
+                    'g;x'           => 'http://a/b/c/g;x',
+                    'g;x?y#s'       => 'http://a/b/c/g;x?y#s',
+                    ''              => 'http://a/b/c/d;p?q',
+                    '.'             => 'http://a/b/c/',
+                    './'            => 'http://a/b/c/',
+                    '..'            => 'http://a/b/',
+                    '../'           => 'http://a/b/',
+                    '../g'          => 'http://a/b/g',
+                    '../..'         => 'http://a/',
+                    '../../'        => 'http://a/',
+                    '../../g'       => 'http://a/g',
+                    '../../../g'    => 'http://a/g',
+                    '../../../../g' => 'http://a/g',
+                    '/./g'          => 'http://a/g',
+                    '/../g'         => 'http://a/g',
+                    'g.'            => 'http://a/b/c/g.',
+                    '.g'            => 'http://a/b/c/.g',
+                    'g..'           => 'http://a/b/c/g..',
+                    '..g'           => 'http://a/b/c/..g',
+                    './../g'        => 'http://a/b/g',
+                    './g/.'         => 'http://a/b/c/g/',
+                    'g/./h'         => 'http://a/b/c/g/h',
+                    'g/../h'        => 'http://a/b/c/h',
+                    'g;x=1/./y'     => 'http://a/b/c/g;x=1/y',
+                    'g;x=1/../y'    => 'http://a/b/c/y',
+                    'g?y/./x'       => 'http://a/b/c/g?y/./x',
+                    'g?y/../x'      => 'http://a/b/c/g?y/../x',
+                    'g#s/./x'       => 'http://a/b/c/g#s/./x',
+                    'g#s/../x'      => 'http://a/b/c/g#s/../x',
+                    'http:g'        => 'http:g',
+                ),
+            ),
+            array(
+                'http://a/b/c/d;p?q',
+                array('http:g' => 'http://a/b/c/g'),
+                array('::OPTION_STRICT' => false)
+            ),
+        );
+    }
+
+    /**
+     * Test the resolve() function to resolve URLs to each other.
+     *
+     * @param string $baseURL               base-URI
+     * @param array  $relativeAbsolutePairs url-pairs, relative => resolved
+     * @param array  $options               Net_URL2 options
+     *
+     * @dataProvider provideResolveUrls
+     * @covers Net_URL2::resolve
+     * @return void
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideResolveUrls')]
+    public function testResolveUrls($baseURL, array $relativeAbsolutePairs,
+        array $options = array()
+    ) {
+        $options = $this->_translateOptionData($options);
+        $base    = new Net_URL2($baseURL, $options);
+        $count = count($relativeAbsolutePairs);
+        $this->assertGreaterThan(0, $count, 'relative-absolute-pairs data is empty');
+        foreach ($relativeAbsolutePairs as $relativeURL => $absoluteURL) {
+            $this->assertSame($absoluteURL, (string) $base->resolve($relativeURL));
+        }
+    }
+
+    /**
+     * Helper method to turn options with strings as the constant names
+     * (to allow to externalize the fixtures) into a concrete options
+     * array that uses the values from the Net_URL2 class constants.
+     *
+     * @param array $options options
+     *
+     * @return array
+     */
+    private function _translateOptionData(array $options)
+    {
+        // translate string option-names to class constant starting with a colon.
+        foreach ($options as $name => $value) {
+            if ($name[0] === ':') {
+                unset($options[$name]);
+                $options[constant("Net_URL2$name")] = $value;
+            }
+        }
+        return $options;
+    }
+
+    /**
+     * Test the resolve() function throwing an exception with invalid data.
+     *
+     * @covers Net_URL2::resolve
+     * @return void
+     */
+    public function testResolveException()
+    {
+        // resolving a relative to a relative URL throws an exception
+        $base = new Net_URL2('news.html?category=arts');
+        $this->addToAssertionCount(1);
+        try {
+            $base->resolve('../arts.html#section-2.4');
+        } catch (Exception $e) {
+            $expected = 'Base-URL must be absolute if reference is not fragment-onl';
+            $this->assertStringStartsWith($expected, $e->getMessage());
+            return;
+        }
+        $this->fail('Expected exception not thrown.');
+    }
+
+    /**
+     * Assert that there is a last error message and it contains needle.
+     *
+     * @param string $needle needle
+     *
+     * @return void
+     */
+    private function _assertLastErrorContains($needle)
+    {
+        $error = error_get_last();
+        $this->assertArrayHasKey('message', $error, 'there was an error previously');
+        $pos = strpos($error['message'], $needle);
+
+        $this->assertTrue(
+            false !== $pos,
+            sprintf(
+                'Last error message "%s" contains "%s"', $error['message'], $needle
+            )
+        );
+    }
+
+    /**
+     * Test UrlEncoding
+     *
+     * @return void
+     * @link   https://pear.php.net/bugs/bug.php?id=18267
+     */
+    public function testUrlEncoding()
+    {
+        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
+        $url     = new Net_URL2('http://localhost/bug.php', $options);
+        $url->setQueryVariables(
+            array(
+                'indexed' => array(
+                    'first value', 'second value', array('foo', 'bar'),
+                )
+            )
+        );
+        $this->assertEquals(
+            'http://localhost/bug.php?indexed[0]=first%20value&indexed[1]' .
+            '=second%20value&indexed[2][0]=foo&indexed[2][1]=bar',
+            strval($url)
+        );
+    }
+
+    /**
+     * A test to verify that keys in QUERY_STRING are encoded by default.
+     *
+     * @return void
+     * @see    Net_URL2::OPTION_ENCODE_KEYS
+     * @see    Net_URL2::buildQuery()
+     */
+    public function testEncodeKeys()
+    {
+        $url = new Net_URL2('http://example.org');
+        $url->setQueryVariables(array('helgi rulez' => 'till too'));
+        $this->assertEquals(
+            'http://example.org?helgi%20rulez=till%20too',
+            strval($url)
+        );
+    }
+
+    /**
+     * A test to verify that keys in QUERY_STRING are not encoded when we supply
+     * 'false' via {@link Net_URL2::__construct()}.
+     *
+     * @return void
+     * @see    Net_URL2::OPTION_ENCODE_KEYS
+     * @see    Net_URL2::buildQuery()
+     */
+    public function testDontEncodeKeys()
+    {
+        $url = new Net_URL2(
+            'http://example.org',
+            array(Net_URL2::OPTION_ENCODE_KEYS => false)
+        );
+        $url->setQueryVariables(array('till rulez' => 'helgi too'));
+        $this->assertEquals(
+            'http://example.org?till rulez=helgi%20too',
+            strval($url)
+        );
+    }
+
+    /**
+     * Brackets for array query variables
+     *
+     * Also text to not encode zero based integer sequence into brackets
+     *
+     * @return void
+     *
+     * @link https://pear.php.net/bugs/bug.php?id=20427
+     */
+    public function testUseBrackets()
+    {
+        $url = new Net_URL2('http://example.org/');
+        $url->setQueryVariables(array('foo' => array('bar', 'baz')));
+        $expected = 'http://example.org/?foo[]=bar&foo[]=baz';
+        $this->assertEquals($expected, $url->getURL());
+
+        $options = array(Net_URL2::OPTION_DROP_SEQUENCE => false);
+        $url     = new Net_URL2('http://example.org/', $options);
+        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
+        $expected = 'http://example.org/?foo[0]=bar&foo[1]=foobar';
+        $this->assertEquals($expected, $url->getURL());
+    }
+
+    /**
+     * Do not use brackets for query variables passed as array
+     *
+     * @return void
+     */
+    public function testDontUseBrackets()
+    {
+        $url = new Net_URL2(
+            'http://example.org/',
+            array(Net_URL2::OPTION_USE_BRACKETS => false)
+        );
+        $url->setQueryVariables(array('foo' => array('bar', 'foobar')));
+        $this->assertEquals(
+            'http://example.org/?foo=bar&foo=foobar',
+            strval($url)
+        );
+    }
+
+    /**
+     * A dataProvider for example URIs from RFC 3986 Section 1.1.2
+     *
+     * @return array
+     * @link http://tools.ietf.org/html/rfc3986#section-1.1.2
+     * @see  testExampleUri
+     */
+    public static function provideExampleUri()
+    {
+        return array(
+            array('ftp://ftp.is.co.za/rfc/rfc1808.txt'),
+            array('http://www.ietf.org/rfc/rfc2396.txt'),
+            array('ldap://[2001:db8::7]/c=GB?objectClass?one'),
+            array('mailto:John.Doe@example.com'),
+            array('news:comp.infosystems.www.servers.unix'),
+            array('tel:+1-816-555-1212'),
+            array('telnet://192.0.2.16:80/'),
+            array('urn:oasis:names:specification:docbook:dtd:xml:4.1.2'),
+        );
+    }
+
+    /**
+     * test that Net_URL2 works with the example URIs from RFC 3986 Section 1.1.2
+     *
+     * @param string $uri example URI
+     *
+     * @return       void
+     * @dataProvider provideExampleUri
+     * @link         http://tools.ietf.org/html/rfc3986#section-1.1.2
+     * @see          testComponentRecompositionAndNormalization
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideExampleUri')]
+    public function testExampleUri($uri)
+    {
+        $url = new Net_URL2($uri);
+        $this->assertSame($uri, $url->__toString());
+        $url->normalize();
+        $this->assertSame($uri, $url->__toString());
+    }
+
+    /**
+     * A dataProvider for pairs of paths with dot segments and
+     * their form when removed.
+     *
+     * @see testRemoveDotSegments
+     * @return array
+     */
+    public static function providePath()
+    {
+        // The numbers behind are in reference to sections
+        // in RFC 3986 5.2.4. Remove Dot Segments
+        return array(
+            array('../', ''), // 2. A.
+            array('./', ''), // 2. A.
+            array('/./', '/'), // 2. B.
+            array('/.', '/'), // 2. B.
+            array('/../', '/'), // 2. C.
+            array('/..', '/'), // 2. C.
+            array('..', ''), // 2. D.
+            array('.', ''), // 2. D.
+            array('a', 'a'), // 2. E.
+            array('/a', '/a'), // 2. E.
+            array('/a/b/c/./../../g', '/a/g'), // 3.
+            array('mid/content=5/../6', 'mid/6'), // 3.
+            array('../foo/bar.php', 'foo/bar.php'),
+            array('/foo/../bar/boo.php', '/bar/boo.php'),
+            array('/boo/..//foo//bar.php', '//foo//bar.php'),
+            array('/./foo/././bar.php', '/foo/bar.php'),
+            array('./.', ''),
+        );
+    }
+
+    /**
+     * Test removal of dot segments
+     *
+     * @param string $path      Path
+     * @param string $assertion Assertion
+     *
+     * @dataProvider providePath
+     * @covers Net_URL2::removeDotSegments
+     * @return void
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('providePath')]
+    public function testRemoveDotSegments($path, $assertion)
+    {
+        $this->assertEquals($assertion, Net_URL2::removeDotSegments($path));
+    }
+
+    /**
+     * Test removeDotSegments() loop limit warning
+     *
+     * @covers Net_URL2::removeDotSegments
+     * @return void
+     */
+    public function testRemoveDotSegmentsLoopLimit()
+    {
+        $loopLimit = 256;
+        $segments  = str_repeat('a/', $loopLimit);
+
+        @Net_URL2::removeDotSegments($segments . 'b/');
+
+        $this->_assertLastErrorContains(sprintf(' loop limit %d ', $loopLimit + 1));
+        $this->_assertLastErrorContains(" (left: '/b/')");
+    }
+
+    /**
+     * A dataProvider for query strings and their array representation
+     *
+     * @see testGetQueryVariables
+     * @return array
+     */
+    public static function provideQueryStrings()
+    {
+        // If the second (expected) value is set or not null, parse_str() differs.
+        // Notes on PHP differences with each entry/block
+        return array(
+            // Net_URL2::getQueryVariables() non-bracket mode
+            array('test=1&t%65st=%41&extra=',
+                array('test' => array('1', 'A'), 'extra' => ''),
+                array('::OPTION_USE_BRACKETS' => false)),
+            array(''),
+            array('='),
+            array('key'),
+            array('key='),
+            array('=value'),
+            array('k=v'),
+            // no space as var-name in PHP (array()):
+            array(' ',   array(' ' => '' )),
+            array(' =v', array(' ' => 'v')),
+            array('key=value'),
+            // PHP replaces ".", " " and "[" in name replaced by "_":
+            array('key.=value' , array('key.'  => 'value')),
+            array('key =value' , array('key '  => 'value')),
+            array('key[=value' , array('key['  => 'value')),
+            array("key\0=value", array("key\0" => 'value')),
+            array('key]=value'),
+            array('key[]=value'),
+            array('[]=value'),
+            array(']=value'),
+            array(']]=value'),
+            // PHP drops variables that are an open bracket only
+            array('[=value', array('[' => 'value')),
+            // PHP drops spaces in brackets:
+            array('key[ ]=value', array('key'  => array(' ' => 'value'))),
+            // PHP replaces space " " in name by "_"
+            array('key []=1'    , array('key ' => array('1'           ))) ,
+            // PHP does not support "\0" in var-names:
+            array("key[\0]=value"   , array('key' => array("\0" => 'value'  ))),
+            array("key[a\0]=value"  , array('key' => array("a\0" => 'value' ))),
+            array("key[a\0b]=value" , array('key' => array("a\0b" => 'value'))),
+            array('var[]=1&var[0][]=2'),
+            array('key[] []=1'),
+            array('key[] [] []=1'),
+            array('key[] [] []'),
+            array('key[] [] []=[] []'),
+            array('[] [] []=[] []'),
+        );
+    }
+
+    /**
+     * Test parsing of query variables
+     *
+     * @param string $query    string
+     * @param mixed  $expected null to test against parse_str() behavior
+     * @param array  $options  Net_URL2 options
+     *
+     * @dataProvider provideQueryStrings
+     * @covers       Net_URL2::getQueryVariables
+     * @covers       Net_URL2::_queryArrayByKey
+     * @covers       Net_URL2::_queryArrayByBrackets
+     * @covers       Net_URL2::_queryKeyBracketOffset
+     * @return void
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideQueryStrings')]
+    public function testGetQueryVariables($query, $expected = null,
+        array $options = array()
+    ) {
+        $options = $this->_translateOptionData($options);
+
+        $url = new Net_URL2('', $options);
+
+        if ($expected === null) {
+            // parse_str() is in PHP before copy on write, therefore
+            // it uses pass-by-reference for $expected to return
+            // the array
+            parse_str($query, $expected);
+        }
+
+        // Xdebug: If breakpoints are ignored, see Xdebug Issue 0000924
+        $url->setQuery($query);
+        $actual = $url->getQueryVariables();
+
+        // Do two assertions, because the first one shows a more nice diff in case
+        // it fails and the second one is actually strict which is what has to be
+        // tested.
+        $this->assertEquals($expected, $actual);
+        $this->assertSame($expected, $actual);
+    }
+
+    /**
+     * data provider of host and port
+     *
+     * @return array
+     * @see testHostAndPort
+     */
+    public static function provideHostAndPort()
+    {
+        return array(
+            array('[::1]', '[::1]', false),
+            array('[::1]:', '[::1]', false),
+            array('[::1]:128', '[::1]', '128'),
+            array('127.0.0.1', '127.0.0.1', false),
+            array('127.0.0.1:', '127.0.0.1', false),
+            array('127.0.0.1:128', '127.0.0.1', '128'),
+            array('localhost', 'localhost', false),
+            array('localhost:', 'localhost', false),
+            array('localhost:128', 'localhost', '128'),
+        );
+    }
+
+    /**
+     * test that an authority containing host and port maps to expected host and port
+     *
+     * This is also a regression test to test that using ip-literals works along-
+     * side ipv4 and reg-name hosts incl. port numbers
+     *
+     * It was reported as Bug #20423 on 2014-10-06 18:25 UTC that
+     * http://[::1]// URI drops the host
+     *
+     * @param string      $authority    string
+     * @param string      $expectedHost string
+     * @param string|bool $expectedPort string or FALSE
+     *
+     * @return void
+     * @dataProvider provideHostAndPort
+     * @covers       Net_URL2::setAuthority()
+     * @link         https://pear.php.net/bugs/bug.php?id=20423
+     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.2
+     * @link         http://tools.ietf.org/html/rfc3986#section-3.2
+     * @link         http://tools.ietf.org/html/rfc3986#section-3.2.3
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideHostAndPort')]
+    public function testHostAndPort($authority, $expectedHost, $expectedPort)
+    {
+        $uri = "http://{$authority}";
+        $url = new Net_URL2($uri);
+        $this->assertSame($expectedHost, $url->getHost());
+        $this->assertSame($expectedPort, $url->getPort());
+    }
+
+    /**
+     * This is a regression test to test that Net_URL2::getQueryVariables() does
+     * not have a problem with nested array values in form of stacked brackets and
+     * was reported as Bug #17036 on 2010-01-26 15:48 UTC that there would be
+     * a problem with parsed query string.
+     *
+     * @link   https://pear.php.net/bugs/bug.php?id=17036
+     * @covers Net_URL2::getQueryVariables
+     * @return void
+     */
+    public function test17036()
+    {
+        $queryString = 'start=10&test[0][first][1.1][20]=coucou';
+        $url         = new Net_URL2('?' . $queryString);
+        $vars = $url->getQueryVariables();
+
+        $expected = array();
+        $expected['start'] = '10';
+        $expected['test'][0]['first']['1.1'][20] = 'coucou';
+
+        $this->assertEquals($expected, $vars); // give nice diff in case of failuer
+        $this->assertSame($expected, $vars);   // strictly assert the premise
+    }
+
+    /**
+     * This is a regression test to test that resolve() does
+     * merge the path if the base path is empty as the opposite
+     * was reported as Bug #19176 on 2011-12-31 02:07 UTC
+     *
+     * @return void
+     */
+    public function test19176()
+    {
+        $foo  = new Net_URL2('http://www.example.com');
+        $test = $foo->resolve('test.html')->getURL();
+        $this->assertEquals('http://www.example.com/test.html', $test);
+    }
+
+    /**
+     * This is a regression test that removeDotSegments('0') is
+     * working as it was reported as not-working in Bug #19315
+     * on 2012-03-04 04:18 UTC.
+     *
+     * @return void
+     */
+    public function test19315()
+    {
+        $actual = Net_URL2::removeDotSegments('0');
+        $this->assertSame('0', $actual);
+
+        $nonStringObject = (object)array();
+        try {
+            Net_URL2::removeDotSegments($nonStringObject);
+        } catch (PHPUnit_Framework_Error $error) {
+            $this->addToAssertionCount(1);
+        } catch (Throwable $error) {
+            $this->addToAssertionCount(1);
+        }
+
+        if (!isset($error)) {
+            $this->fail('Failed to verify that error was given.');
+        }
+        unset($error);
+    }
+
+    /**
+     * This is a regression test to test that recovering from
+     * a wrongly encoded URL is possible.
+     *
+     * It was requested as Request #19684 on 2011-12-31 02:07 UTC
+     * that redirects containing spaces should work.
+     *
+     * @return void
+     */
+    public function test19684()
+    {
+        // Location: URL obtained Thu, 25 Apr 2013 20:51:31 GMT
+        $urlWithSpace = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS N'
+            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
+            . '48+219853269+219853286';
+
+        $urlCorrect = 'http://www.sigmaaldrich.com/catalog/search?interface=CAS%20N'
+            . 'o.&term=108-88-3&lang=en&region=US&mode=match+partialmax&N=0+2200030'
+            . '48+219853269+219853286';
+
+        $url = new Net_URL2($urlWithSpace);
+
+        $this->assertTrue($url->isAbsolute());
+
+        $urlPart = parse_url($urlCorrect, PHP_URL_PATH);
+        $this->assertSame($urlPart, $url->getPath());
+
+        $urlPart = parse_url($urlCorrect, PHP_URL_QUERY);
+        $this->assertSame($urlPart, $url->getQuery());
+
+        $this->assertSame($urlCorrect, (string)$url);
+
+        $input    = 'http://example.com/get + + to my nose/';
+        $expected = 'http://example.com/get%20+%20+%20to%20my%20nose/';
+        $actual   = new Net_URL2($input);
+        $this->assertEquals($expected, $actual);
+        $actual->normalize();
+    }
+
+    /**
+     * data provider of list of equivalent URLs.
+     *
+     * @see testNormalize
+     * @see testConstructSelf
+     * @return array
+     */
+    public static function provideEquivalentUrlLists()
+    {
+        return array(
+            // String equivalence:
+            array('http://example.com/', 'http://example.com/'),
+
+            // Originally first dataset:
+            array('http://www.example.com/%9a', 'http://www.example.com/%9A'),
+
+            // Example from RFC 3986 6.2.2.:
+            array('example://a/b/c/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d'),
+
+            // Example from RFC 3986 6.2.2.1.:
+            array('HTTP://www.EXAMPLE.com/', 'http://www.example.com/'),
+
+            // Example from RFC 3986 6.2.3.:
+            array(
+                'http://example.com', 'http://example.com/',
+                'http://example.com:/', 'http://example.com:80/'
+            ),
+
+            // Bug #20161: URLs with "0" as host fail to normalize with empty path
+            array('http://0/', 'http://0'),
+
+            // Bug #20473: Normalize query and fragment broken
+            array('foo:///?%66%6f%6f#%62%61%72', 'foo:///?foo#bar'),
+        );
+    }
+
+    /**
+     * This is a coverage test to invoke the normalize()
+     * method.
+     *
+     * @return void
+     *
+     * @dataProvider provideEquivalentUrlLists
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideEquivalentUrlLists')]
+    public function testNormalize()
+    {
+        $urls = func_get_args();
+
+        $this->assertGreaterThanOrEqual(2, count($urls));
+
+        $last = null;
+
+        foreach ($urls as $index => $url) {
+            $url = new Net_Url2($url);
+            $url->normalize();
+            if ($index) {
+                $this->assertSame((string)$last, (string)$url);
+            }
+            $last = $url;
+        }
+    }
+
+    /**
+     * This is a coverage test to invoke __get and __set
+     *
+     * @covers Net_URL2::__get
+     * @covers Net_URL2::__set
+     * @return void
+     */
+    public function testMagicSetGet()
+    {
+        $url = new Net_URL2('');
+
+        $property       = 'authority';
+        $url->$property = $value = 'value';
+        $this->assertEquals($value, $url->$property);
+
+        $property       = 'unsetProperty';
+        $url->$property = $value;
+        $this->assertEquals(false, $url->$property);
+    }
+
+    /**
+     * data provider of uri and normal URIs
+     *
+     * @return array
+     * @see testComponentRecompositionAndNormalization
+     */
+    public static function provideComposedAndNormalized()
+    {
+        return array(
+            array(''),
+            array('http:g'),
+            array('user@host'),
+            array('mailto:user@host'),
+        );
+    }
+
+    /**
+     * Tests Net_URL2 RFC 3986 5.3. Component Recomposition in the light
+     * of normalization
+     *
+     * This is also a regression test to test that a missing authority works well
+     * with normalization
+     *
+     * It was reported as Bug #20418 on 2014-10-02 22:10 UTC that there is an
+     * Incorrect normalization of URI with missing authority
+     *
+     * @param string $uri URI
+     *
+     * @return       void
+     * @covers       Net_URL2::getUrl()
+     * @covers       Net_URL2::normalize()
+     * @dataProvider provideComposedAndNormalized
+     * @link         https://pear.php.net/bugs/bug.php?id=20418
+     * @see          testExampleUri
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideComposedAndNormalized')]
+    public function testComponentRecompositionAndNormalization($uri)
+    {
+        $url = new Net_URL2($uri);
+        $this->assertSame($uri, $url->getURL());
+        $url->normalize();
+        $this->assertSame($uri, $url->getURL());
+    }
+
+    /**
+     * Tests Net_URL2 ctors URL parameter works with objects implementing
+     * __toString().
+     *
+     * @dataProvider provideEquivalentUrlLists
+     * @coversNothing
+     * @return void
+     */
+    #[PHPUnit\Framework\Attributes\DataProvider('provideEquivalentUrlLists')]
+    public function testConstructSelf()
+    {
+        $urls = func_get_args();
+        foreach ($urls as $url) {
+            $urlA = new Net_URL2($url);
+            $urlB = new Net_URL2($urlA);
+            $this->assertSame((string)$urlA, (string)$urlB);
+        }
+    }
+
+    /**
+     * This is a feature test to see that the userinfo's data is getting
+     * encoded as outlined in #19684.
+     *
+     * @covers Net_URL2::setAuthority
+     * @covers Net_URL2::setUserinfo
+     * @return void
+     */
+    public function testEncodeDataUserinfoAuthority()
+    {
+        $url = new Net_URL2('http://john doe:secret@example.com/');
+        $this->assertSame('http://john%20doe:secret@example.com/', (string)$url);
+
+        $url->setUserinfo('john doe');
+        $this->assertSame('http://john%20doe@example.com/', (string)$url);
+
+        $url->setUserinfo('john doe', 'pa wd');
+        $this->assertSame('http://john%20doe:pa%20wd@example.com/', (string)$url);
+    }
+
+    /**
+     * This is a regression test to test that using the
+     * host-name "0" does work with getAuthority()
+     *
+     * It was reported as Bug #20156 on 2013-12-27 22:56 UTC
+     * that setAuthority() with "0" as host would not work
+     *
+     * @covers Net_URL2::setAuthority
+     * @covers Net_URL2::getAuthority
+     * @covers Net_URL2::setHost
+     * @return void
+     */
+    public function test20156()
+    {
+        $url  = new Net_URL2('http://user:pass@example.com:127/');
+        $host = '0';
+        $url->setHost($host);
+        $this->assertSame('user:pass@0:127', $url->getAuthority());
+
+        $url->setHost(false);
+        $this->assertSame(false, $url->getAuthority());
+
+        $url->setAuthority($host);
+        $this->assertSame($host, $url->getAuthority());
+    }
+
+    /**
+     * This is a regression test to test that setting "0" as path
+     * does not break normalize().
+     *
+     * It was reported as Bug #20157 on 2013-12-27 23:42 UTC that
+     * normalize() with "0" as path would not work.
+     *
+     * @covers Net_URL2::normalize
+     * @return void
+     */
+    public function test20157()
+    {
+        $subject = 'http://example.com';
+        $url     = new Net_URL2($subject);
+        $url->setPath('0');
+        $url->normalize();
+        $this->assertSame("$subject/0", (string)$url);
+    }
+
+    /**
+     * This is a regression test to ensure that fragment-only references can be
+     * resolved to a non-absolute Base-URI.
+     *
+     * It was reported as Bug #20158 2013-12-28 14:49 UTC that fragment-only
+     * references would not be resolved to non-absolute base URI
+     *
+     * @covers Net_URL2::resolve
+     * @covers Net_URL2::_isFragmentOnly
+     * @return void
+     */
+    public function test20158()
+    {
+        $base     = new Net_URL2('myfile.html');
+        $resolved = $base->resolve('#world');
+        $this->assertSame('myfile.html#world', (string)$resolved);
+    }
+
+    /**
+     * This is a regression test to ensure that authority and path are properly
+     * combined when the path does not start with a slash which is the separator
+     * character between authority and path.
+     *
+     * It was reported as Bug #20159 2013-12-28 17:18 UTC that authority
+     * would not be terminated by slash
+     *
+     * @covers Net_URL2::getUrl
+     * @return void
+     */
+    public function test20159()
+    {
+        $url = new Net_URL2('index.html');
+        $url->setHost('example.com');
+        $this->assertSame('//example.com/index.html', (string)$url);
+    }
+
+    /**
+     * This is a regression test to test that using the file:// URI scheme with
+     * an empty (default) hostname has the empty authority preserved when the
+     * full URL is build.
+     *
+     * It was reported as Bug #20304 on 2014-06-21 00:06 UTC
+     * that file:// URI are crippled.
+     *
+     * Tests with a default authority for the "file" URI scheme
+     *
+     * @covers Net_URL2::getURL
+     * @return void
+     * @link https://pear.php.net/bugs/bug.php?id=20304
+     */
+    public function test20304()
+    {
+        $file = 'file:///path/to/file';
+        $url = new Net_URL2($file);
+        $this->assertSame($file, (string) $url);
+
+        $file = 'file://localhost/path/to/file';
+        $url = new Net_URL2($file);
+        $this->assertSame($file, (string) $url);
+
+        $file = 'file://user@/path/to/file';
+        $url = new Net_URL2($file);
+        $this->assertSame($file, (string) $url);
+
+        $file = 'FILE:///path/to/file';
+        $url = new Net_URL2($file);
+        $this->assertSame($file, (string) $url);
+    }
+}
diff -pruN 2.2.1-0.2/debian/changelog 2.2.3-1/debian/changelog
--- 2.2.1-0.2/debian/changelog	2021-01-01 23:34:46.000000000 +0000
+++ 2.2.3-1/debian/changelog	2025-09-18 15:11:32.000000000 +0000
@@ -1,3 +1,34 @@
+php-net-url2 (2.2.3-1) unstable; urgency=medium
+
+  * QA upload.
+
+  [ Jelmer Vernooĳ ]
+  * Migrate repository from alioth to salsa.
+
+  [ William Desportes ]
+  * New upstream version 2.2.3
+  * Add d/gbp.conf
+  * Use debhelper-compat 13
+  * Update Standards-Version to 4.7.2
+  * Update d/copyright {Format,Source} to https
+  * Style fixes on d/copyright
+  * Update d/watch to version 4 and https
+  * Set "Rules-Requires-Root: no"
+  * Set "Multi-Arch: foreign"
+  * Use dh-sequence-phppear
+  * Add dh_auto_test and DEP-8 tests
+  * Add d/clean
+  * Simplify d/copyright
+  * Build depend on phpunit
+  * Update the tests patch
+  * Add netbase to Build-Depends and Recommends
+  * Add my copyright to d/copyright and bump upstream copyright year
+  * Remove now default Priority: optional
+  * Remove now default Rules-Requires-Root: no
+  * Maintain in the QA group
+
+ -- William Desportes <williamdes@wdes.fr>  Thu, 18 Sep 2025 17:11:32 +0200
+
 php-net-url2 (2.2.1-0.2) unstable; urgency=medium
 
   * Non maintainer upload by the Reproducible Builds team.
@@ -58,7 +89,7 @@ php-net-url2 (2.0.7-1) unstable; urgency
   * New upstream release (2.0.7)
   * debian/copyright:
     - Fix invalid short name in DEP5 copyright (s/BSD/BSD-3-clause/g)
-    - Redefine license file matching as 'Net_URL2-*/*' to include ALL 
+    - Redefine license file matching as 'Net_URL2-*/*' to include ALL
       upstream files under BSD-3-clause license.
 
  -- Dario Minnucci <midget@debian.org>  Thu, 18 Sep 2014 01:40:28 +0200
diff -pruN 2.2.1-0.2/debian/clean 2.2.3-1/debian/clean
--- 2.2.1-0.2/debian/clean	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/debian/clean	2025-09-08 16:28:26.000000000 +0000
@@ -0,0 +1 @@
+Net_URL2-*/package.xml
diff -pruN 2.2.1-0.2/debian/compat 2.2.3-1/debian/compat
--- 2.2.1-0.2/debian/compat	2016-11-28 14:53:07.000000000 +0000
+++ 2.2.3-1/debian/compat	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-9
diff -pruN 2.2.1-0.2/debian/control 2.2.3-1/debian/control
--- 2.2.1-0.2/debian/control	2016-11-28 14:53:07.000000000 +0000
+++ 2.2.3-1/debian/control	2025-09-18 15:11:32.000000000 +0000
@@ -1,17 +1,21 @@
 Source: php-net-url2
 Section: php
-Priority: optional
-Maintainer: Dario Minnucci <midget@debian.org>
-Build-Depends: debhelper (>= 9), pkg-php-tools
-Standards-Version: 3.9.6
+Maintainer: Debian QA Group <packages@qa.debian.org>
+Build-Depends: debhelper-compat (= 13),
+               dh-sequence-phppear,
+               netbase,
+               phpunit,
+               pkg-php-tools
+Standards-Version: 4.7.2
 Homepage: http://pear.php.net/package/Net_URL2
-Vcs-Git: git://anonscm.debian.org/collab-maint/php-net-url2.git
-Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/php-net-url2.git
+Vcs-Git: https://salsa.debian.org/debian/php-net-url2.git
+Vcs-Browser: https://salsa.debian.org/debian/php-net-url2
 
 Package: php-net-url2
 Architecture: all
+Multi-Arch: foreign
 Depends: ${misc:Depends}, ${phppear:Debian-Depends}
-Recommends: ${phppear:Debian-Recommends}
+Recommends: netbase, ${phppear:Debian-Recommends}
 Breaks: ${phppear:Debian-Breaks}
 Description: ${phppear:summary}
  ${phppear:description}
diff -pruN 2.2.1-0.2/debian/copyright 2.2.3-1/debian/copyright
--- 2.2.1-0.2/debian/copyright	2016-11-28 14:53:07.000000000 +0000
+++ 2.2.3-1/debian/copyright	2025-09-08 16:35:01.000000000 +0000
@@ -1,10 +1,9 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: Net_URL2
-Source: http://pear.php.net/package/Net_URL2/download
-
+Source: https://pear.php.net/package/Net_URL2/download
 
 Files: package.xml Net_URL2-*/*
-Copyright: Copyright 2007-2009, Peytz & Co. A/S
+Copyright: Copyright 2007-2024, Peytz & Co. A/S
 License: BSD-3-clause
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
@@ -31,27 +30,10 @@ License: BSD-3-clause
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
 Files: debian/*
 Copyright: Copyright 2012-2015, Dario Minnucci <midget@debian.org>
+           Copyright 2025, William Desportes <williamdes@wdes.fr>
 License: GPL-2+
- This program is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later
- version.
- .
- This program is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE.  See the GNU General Public License for more
- details.
- .
- You should have received a copy of the GNU General Public
- License along with this package; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- Boston, MA  02110-1301 USA
- .
- On Debian systems, the full text of the GNU General Public
- License version 2 can be found in the file
- `/usr/share/common-licenses/GPL-2'.
+ On Debian systems the full text of the GNU General Public
+ License can be found in the `/usr/share/common-licenses/GPL-2`
+ file.
diff -pruN 2.2.1-0.2/debian/gbp.conf 2.2.3-1/debian/gbp.conf
--- 2.2.1-0.2/debian/gbp.conf	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/debian/gbp.conf	2025-09-08 15:49:25.000000000 +0000
@@ -0,0 +1,3 @@
+[DEFAULT]
+pristine-tar = True
+debian-branch = debian
diff -pruN 2.2.1-0.2/debian/patches/0001-Fix-tests-for-PHPUnit-12.patch 2.2.3-1/debian/patches/0001-Fix-tests-for-PHPUnit-12.patch
--- 2.2.1-0.2/debian/patches/0001-Fix-tests-for-PHPUnit-12.patch	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/debian/patches/0001-Fix-tests-for-PHPUnit-12.patch	2025-09-08 16:28:26.000000000 +0000
@@ -0,0 +1,119 @@
+From: William Desportes <williamdes@wdes.fr>
+Date: Mon, 8 Sep 2025 16:06:05 +0200
+Subject: Fix tests for PHPUnit 12
+
+Origin: vendor
+Forwarded: https://github.com/pear/Net_URL2/pull/22
+---
+ Net_URL2-2.2.3/tests/Net/URL2Test.php | 58 ++++++++++++++++++-----------------
+ 1 file changed, 30 insertions(+), 28 deletions(-)
+
+diff --git a/Net_URL2-2.2.3/tests/Net/URL2Test.php b/Net_URL2-2.2.3/tests/Net/URL2Test.php
+index 9df68bf..ec6c614 100644
+--- a/Net_URL2-2.2.3/tests/Net/URL2Test.php
++++ b/Net_URL2-2.2.3/tests/Net/URL2Test.php
+@@ -21,7 +21,7 @@
+  * @version  Release: 2.2.3
+  * @link     https://pear.php.net/package/Net_URL2
+  */
+-class Net_URL2Test extends PHPUnit_Framework_TestCase
++class Net_URL2Test extends PHPUnit\Framework\TestCase
+ {
+     /**
+      * Tests setting a zero-length string and false as authority
+@@ -827,28 +827,30 @@ class Net_URL2Test extends PHPUnit_Framework_TestCase
+     {
+         return array(
+             // String equivalence:
+-            array('http://example.com/', 'http://example.com/'),
++            array('http://example.com/', 'http://example.com/', true),
+ 
+             // Originally first dataset:
+-            array('http://www.example.com/%9a', 'http://www.example.com/%9A'),
++            array('http://www.example.com/%9a', 'http://www.example.com/%9A', false),
+ 
+             // Example from RFC 3986 6.2.2.:
+-            array('example://a/b/c/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d'),
++            array('example://a/b/c/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d', false),
+ 
+             // Example from RFC 3986 6.2.2.1.:
+-            array('HTTP://www.EXAMPLE.com/', 'http://www.example.com/'),
++            array('HTTP://www.EXAMPLE.com/', 'http://www.example.com/', false),
+ 
+             // Example from RFC 3986 6.2.3.:
+             array(
+-                'http://example.com', 'http://example.com/',
+-                'http://example.com:/', 'http://example.com:80/'
++                'http://example.com', 'http://example.com/', false
++            ),
++            array(
++                'http://example.com:/', 'http://example.com:80/', false
+             ),
+ 
+             // Bug #20161: URLs with "0" as host fail to normalize with empty path
+-            array('http://0/', 'http://0'),
++            array('http://0/', 'http://0', false),
+ 
+             // Bug #20473: Normalize query and fragment broken
+-            array('foo:///?%66%6f%6f#%62%61%72', 'foo:///?foo#bar'),
++            array('foo:///?%66%6f%6f#%62%61%72', 'foo:///?foo#bar', false),
+         );
+     }
+ 
+@@ -861,22 +863,19 @@ class Net_URL2Test extends PHPUnit_Framework_TestCase
+      * @dataProvider provideEquivalentUrlLists
+      */
+     #[PHPUnit\Framework\Attributes\DataProvider('provideEquivalentUrlLists')]
+-    public function testNormalize()
++    public function testNormalize(string $urlOne, string $urlTwo, bool $identical)
+     {
+-        $urls = func_get_args();
++        $urlOne = new Net_Url2($urlOne);
++        $urlTwo = new Net_Url2($urlTwo);
+ 
+-        $this->assertGreaterThanOrEqual(2, count($urls));
++        if (! $identical) {
++            $this->assertNotSame($urlOne->__toString(), $urlTwo->__toString());
++        }
+ 
+-        $last = null;
++        $urlOne->normalize();
++        $urlTwo->normalize();
+ 
+-        foreach ($urls as $index => $url) {
+-            $url = new Net_Url2($url);
+-            $url->normalize();
+-            if ($index) {
+-                $this->assertSame((string)$last, (string)$url);
+-            }
+-            $last = $url;
+-        }
++        $this->assertSame($urlOne->__toString(), $urlTwo->__toString());
+     }
+ 
+     /**
+@@ -952,14 +951,17 @@ class Net_URL2Test extends PHPUnit_Framework_TestCase
+      * @return void
+      */
+     #[PHPUnit\Framework\Attributes\DataProvider('provideEquivalentUrlLists')]
+-    public function testConstructSelf()
++    public function testConstructSelf(string $urlOne, string $urlTwo, bool $identical)
+     {
+-        $urls = func_get_args();
+-        foreach ($urls as $url) {
+-            $urlA = new Net_URL2($url);
+-            $urlB = new Net_URL2($urlA);
+-            $this->assertSame((string)$urlA, (string)$urlB);
+-        }
++        $urlOne = new Net_Url2($urlOne);
++        $urlOneExtended = new Net_Url2($urlOne);
++
++        $this->assertSame($urlOne->__toString(), $urlOneExtended->__toString());
++
++        $urlTwo = new Net_Url2($urlTwo);
++        $urlTwoExtended = new Net_Url2($urlTwo);
++
++        $this->assertSame($urlTwo->__toString(), $urlTwoExtended->__toString());
+     }
+ 
+     /**
diff -pruN 2.2.1-0.2/debian/patches/series 2.2.3-1/debian/patches/series
--- 2.2.1-0.2/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/debian/patches/series	2025-09-08 16:28:26.000000000 +0000
@@ -0,0 +1 @@
+0001-Fix-tests-for-PHPUnit-12.patch
diff -pruN 2.2.1-0.2/debian/rules 2.2.3-1/debian/rules
--- 2.2.1-0.2/debian/rules	2016-11-28 14:53:07.000000000 +0000
+++ 2.2.3-1/debian/rules	2025-09-08 16:28:26.000000000 +0000
@@ -2,8 +2,11 @@
 #export DH_VERBOSE=1
 
 %:
-	dh $@ --buildsystem=phppear --with phppear
+	dh $@ --buildsystem=phppear
 
 override_dh_install:
 	dh_install
 	rm -fv $(CURDIR)/debian/php-net-url2/usr/share/doc/php-net-url2/docs/BSD-3-CLAUSE-Heyes
+
+override_dh_auto_test:
+	phpunit --do-not-cache-result --bootstrap ./Net_URL2-*/Net/URL2.php --no-coverage ./Net_URL2-*/tests/
diff -pruN 2.2.1-0.2/debian/tests/control 2.2.3-1/debian/tests/control
--- 2.2.1-0.2/debian/tests/control	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.3-1/debian/tests/control	2025-09-18 11:36:09.000000000 +0000
@@ -0,0 +1,2 @@
+Test-Command: phpunit --do-not-cache-result --bootstrap /usr/share/php/Net/URL2.php --no-coverage ./Net_URL2-*/tests/
+Depends: netbase, phpunit, @
diff -pruN 2.2.1-0.2/debian/watch 2.2.3-1/debian/watch
--- 2.2.1-0.2/debian/watch	2016-11-28 14:53:07.000000000 +0000
+++ 2.2.3-1/debian/watch	2025-09-08 15:49:25.000000000 +0000
@@ -1,2 +1,3 @@
-version=3
-http://pear.php.net/package/Net_URL2/download http://download.pear.php.net/package/Net_URL2-([\d.]+)\.tgz
+version=4
+https://pear.php.net/package/Net_URL2/download \
+https?://download.pear.php.net/package/Net_URL2-@ANY_VERSION@@ARCHIVE_EXT@
diff -pruN 2.2.1-0.2/package.xml 2.2.3-1/package.xml
--- 2.2.1-0.2/package.xml	2016-04-18 22:35:49.000000000 +0000
+++ 2.2.3-1/package.xml	2025-03-24 08:21:14.000000000 +0000
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+<package packagerversion="1.10.12" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0                              http://pear.php.net/dtd/tasks-1.0.xsd                              http://pear.php.net/dtd/package-2.0                              http://pear.php.net/dtd/package-2.0.xsd">
  <name>Net_URL2</name>
  <channel>pear.php.net</channel>
  <extends>Net_URL</extends>
@@ -24,10 +24,10 @@
   <email>schmidt@php.net</email>
   <active>no</active>
  </lead>
- <date>2016-04-18</date>
- <time>22:35:49</time>
+ <date>2025-03-24</date>
+ <time>08:21:14</time>
  <version>
-  <release>2.2.1</release>
+  <release>2.2.3</release>
   <api>2.1.0</api>
  </version>
  <stability>
@@ -36,21 +36,22 @@
  </stability>
  <license uri="https://spdx.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
  <notes>
-* Fix: Correct earlier regex delimiter
-* Fix: Travis missing hhvm-nightly
-* Fix: Travis PHP 5.2
-* Fix: Correct case of method call name
+* Fix: Remove executable bit on *.php files
+* Fix: libpcre2 10.45 compat: _encodeData \x shorthand for \x00 (Request #29032)
+* Fix: PHP 8.4 compat: URL2: Make $array non optional in _queryArrayByBrackets (Bug #28649)
+* Imp: Update CI to GitHub Actions
+* Imp: Exclude dev files from Composer package
  </notes>
  <contents>
   <dir name="/">
    <file baseinstalldir="Net" md5sum="f7b6eb4ad5d4c485e702c887b788588b" name="docs/example.php" role="doc" />
    <file baseinstalldir="Net" md5sum="250f2fe2b0553c05f3de2f330d36ee61" name="docs/6470.php" role="doc" />
    <file baseinstalldir="Net" md5sum="a812699bcaecdb7a4ad8d849ebcc9280" name="docs/BSD-3-CLAUSE-Heyes" role="doc" />
-   <file md5sum="b2e951eddb8ff13cf0abf57c1c897ee5" name="tests/Net/URL2Test.php" role="test">
+   <file md5sum="731b6113a61905a0415432d517d21362" name="tests/Net/URL2Test.php" role="test">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
    <file md5sum="17cb79734eb0584894d2bfea2a8eda42" name="tests/AllTests.php" role="test" />
-   <file md5sum="90b692860cdbae2ed3b5031db36dbf94" name="Net/URL2.php" role="php">
+   <file md5sum="487cc5a089956dd38ed5f5319400e993" name="Net/URL2.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
   </dir>
@@ -68,6 +69,42 @@
  <phprelease />
  <changelog>
   <release>
+   <date>2025-03-24</date>
+   <time>00:00:00</time>
+   <version>
+    <release>2.2.3</release>
+    <api>2.1.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <license uri="https://spdx.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+* Fix: Remove executable bit on *.php files
+* Fix: libpcre2 10.45 compat: _encodeData \x shorthand for \x00 (Request #29032)
+* Fix: PHP 8.4 compat: URL2: Make $array non optional in _queryArrayByBrackets (Bug #28649)
+* Imp: Update CI to GitHub Actions
+* Imp: Exclude dev files from Composer package
+   </notes>
+  </release>
+  <release>
+   <date>2017-08-25</date>
+   <time>00:00:00</time>
+   <version>
+    <release>2.2.2</release>
+    <api>2.1.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <license uri="https://spdx.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+* Fix: Set composer include path to keep other packages working
+   </notes>
+  </release>
+  <release>
    <date>2016-04-19</date>
    <time>00:00:00</time>
    <version>
