1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category  Zend
16 * @package   Zend_Uri
17 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license   http://framework.zend.com/license/new-bsd     New BSD License
19 * @version   $Id$
20 */
21
22/**
23 * Abstract class for all Zend_Uri handlers
24 *
25 * @category  Zend
26 * @package   Zend_Uri
27 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
28 * @license   http://framework.zend.com/license/new-bsd     New BSD License
29 */
30abstract class Zend_Uri
31{
32    /**
33     * Scheme of this URI (http, ftp, etc.)
34     *
35     * @var string
36     */
37    protected $_scheme = '';
38
39    /**
40     * Global configuration array
41     *
42     * @var array
43     */
44    static protected $_config = array(
45        'allow_unwise' => false
46    );
47
48    /**
49     * Return a string representation of this URI.
50     *
51     * @see    getUri()
52     * @return string
53     */
54    public function __toString()
55    {
56        try {
57            return $this->getUri();
58        } catch (Exception $e) {
59            trigger_error($e->getMessage(), E_USER_WARNING);
60            return '';
61        }
62    }
63
64    /**
65     * Convenience function, checks that a $uri string is well-formed
66     * by validating it but not returning an object.  Returns TRUE if
67     * $uri is a well-formed URI, or FALSE otherwise.
68     *
69     * @param  string $uri The URI to check
70     * @return boolean
71     */
72    public static function check($uri)
73    {
74        try {
75            $uri = self::factory($uri);
76        } catch (Exception $e) {
77            return false;
78        }
79
80        return $uri->valid();
81    }
82
83    /**
84     * Create a new Zend_Uri object for a URI.  If building a new URI, then $uri should contain
85     * only the scheme (http, ftp, etc).  Otherwise, supply $uri with the complete URI.
86     *
87     * @param  string $uri       The URI form which a Zend_Uri instance is created
88     * @param  string $className The name of the class to use in order to manipulate URI
89     * @throws Zend_Uri_Exception When an empty string was supplied for the scheme
90     * @throws Zend_Uri_Exception When an illegal scheme is supplied
91     * @throws Zend_Uri_Exception When the scheme is not supported
92     * @throws Zend_Uri_Exception When $className doesn't exist or doesn't implements Zend_Uri
93     * @return Zend_Uri
94     * @link   http://www.faqs.org/rfcs/rfc2396.html
95     */
96    public static function factory($uri = 'http', $className = null)
97    {
98        // Separate the scheme from the scheme-specific parts
99        $uri            = explode(':', $uri, 2);
100        $scheme         = strtolower($uri[0]);
101        $schemeSpecific = isset($uri[1]) === true ? $uri[1] : '';
102
103        if (strlen($scheme) === 0) {
104            throw new Zend_Uri_Exception('An empty string was supplied for the scheme');
105        }
106
107        // Security check: $scheme is used to load a class file, so only alphanumerics are allowed.
108        if (ctype_alnum($scheme) === false) {
109            throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted');
110        }
111
112        if ($className === null) {
113            /**
114             * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the
115             * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown.
116             */
117            switch ($scheme) {
118                case 'http':
119                    // Break intentionally omitted
120                case 'https':
121                    $className = 'Zend_Uri_Http';
122                    break;
123
124                case 'mailto':
125                    // TODO
126                default:
127                    throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported");
128                    break;
129            }
130        }
131
132        try {
133            Zend_Loader::loadClass($className);
134        } catch (Exception $e) {
135            throw new Zend_Uri_Exception("\"$className\" not found");
136        }
137
138        $schemeHandler = new $className($scheme, $schemeSpecific);
139
140        if (! $schemeHandler instanceof Zend_Uri) {
141            throw new Zend_Uri_Exception("\"$className\" is not an instance of Zend_Uri");
142        }
143
144        return $schemeHandler;
145    }
146
147    /**
148     * Get the URI's scheme
149     *
150     * @return string|false Scheme or false if no scheme is set.
151     */
152    public function getScheme()
153    {
154        if (empty($this->_scheme) === false) {
155            return $this->_scheme;
156        } else {
157            return false;
158        }
159    }
160
161    /**
162     * Set global configuration options
163     *
164     * @param Zend_Config|array $config
165     */
166    static public function setConfig($config)
167    {
168        if ($config instanceof Zend_Config) {
169            $config = $config->toArray();
170        } elseif (!is_array($config)) {
171            throw new Zend_Uri_Exception("Config must be an array or an instance of Zend_Config.");
172        }
173
174        foreach ($config as $k => $v) {
175            self::$_config[$k] = $v;
176        }
177    }
178
179    /**
180     * Zend_Uri and its subclasses cannot be instantiated directly.
181     * Use Zend_Uri::factory() to return a new Zend_Uri object.
182     *
183     * @param string $scheme         The scheme of the URI
184     * @param string $schemeSpecific The scheme-specific part of the URI
185     */
186    abstract protected function __construct($scheme, $schemeSpecific = '');
187
188    /**
189     * Return a string representation of this URI.
190     *
191     * @return string
192     */
193    abstract public function getUri();
194
195    /**
196     * Returns TRUE if this URI is valid, or FALSE otherwise.
197     *
198     * @return boolean
199     */
200    abstract public function valid();
201}
202