source: branches/version-2_13-dev/data/module/Net/URL.php @ 23141

Revision 23141, 14.9 KB checked in by m_uehara, 11 years ago (diff)

#2275
影響が大きいため、2.13.0では対応を行わない r23125 r23128 r23133 を差し戻します。

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Copyright (c) 2002-2004, Richard Heyes                                |
4// | All rights reserved.                                                  |
5// |                                                                       |
6// | Redistribution and use in source and binary forms, with or without    |
7// | modification, are permitted provided that the following conditions    |
8// | are met:                                                              |
9// |                                                                       |
10// | o Redistributions of source code must retain the above copyright      |
11// |   notice, this list of conditions and the following disclaimer.       |
12// | o Redistributions in binary form must reproduce the above copyright   |
13// |   notice, this list of conditions and the following disclaimer in the |
14// |   documentation and/or other materials provided with the distribution.|
15// | o The names of the authors may not be used to endorse or promote      |
16// |   products derived from this software without specific prior written  |
17// |   permission.                                                         |
18// |                                                                       |
19// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
20// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
21// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
23// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
25// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
28// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
30// |                                                                       |
31// +-----------------------------------------------------------------------+
32// | Author: Richard Heyes <richard at php net>                            |
33// +-----------------------------------------------------------------------+
34//
35// $Id$
36//
37// Net_URL Class
38
39
40class Net_URL
41{
42    var $options = array('encode_query_keys' => false);
43    /**
44    * Full url
45    * @var string
46    */
47    var $url;
48
49    /**
50    * Protocol
51    * @var string
52    */
53    var $protocol;
54
55    /**
56    * Username
57    * @var string
58    */
59    var $username;
60
61    /**
62    * Password
63    * @var string
64    */
65    var $password;
66
67    /**
68    * Host
69    * @var string
70    */
71    var $host;
72
73    /**
74    * Port
75    * @var integer
76    */
77    var $port;
78
79    /**
80    * Path
81    * @var string
82    */
83    var $path;
84
85    /**
86    * Query string
87    * @var array
88    */
89    var $querystring;
90
91    /**
92    * Anchor
93    * @var string
94    */
95    var $anchor;
96
97    /**
98    * Whether to use []
99    * @var bool
100    */
101    var $useBrackets;
102
103    /**
104    * PHP4 Constructor
105    *
106    * @see __construct()
107    */
108    function Net_URL($url = null, $useBrackets = true)
109    {
110        $this->__construct($url, $useBrackets);
111    }
112
113    /**
114    * PHP5 Constructor
115    *
116    * Parses the given url and stores the various parts
117    * Defaults are used in certain cases
118    *
119    * @param string $url         Optional URL
120    * @param bool   $useBrackets Whether to use square brackets when
121    *                            multiple querystrings with the same name
122    *                            exist
123    */
124    function __construct($url = null, $useBrackets = true)
125    {
126        $this->url = $url;
127        $this->useBrackets = $useBrackets;
128
129        $this->initialize();
130    }
131
132    function initialize()
133    {
134        $HTTP_SERVER_VARS  = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
135
136        $this->user        = '';
137        $this->pass        = '';
138        $this->host        = '';
139        $this->port        = 80;
140        $this->path        = '';
141        $this->querystring = array();
142        $this->anchor      = '';
143
144        // Only use defaults if not an absolute URL given
145        if (!preg_match('/^[a-z0-9]+:\/\//i', $this->url)) {
146            $this->protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
147
148            /**
149            * Figure out host/port
150            */
151            if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) &&
152                preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches))
153            {
154                $host = $matches[1];
155                if (!empty($matches[3])) {
156                    $port = $matches[3];
157                } else {
158                    $port = $this->getStandardPort($this->protocol);
159                }
160            }
161
162            $this->user        = '';
163            $this->pass        = '';
164            $this->host        = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
165            $this->port        = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
166            $this->path        = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
167            $this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
168            $this->anchor      = '';
169        }
170
171        // Parse the url and store the various parts
172        if (!empty($this->url)) {
173            $urlinfo = parse_url($this->url);
174
175            // Default querystring
176            $this->querystring = array();
177
178            foreach ($urlinfo as $key => $value) {
179                switch ($key) {
180                    case 'scheme':
181                        $this->protocol = $value;
182                        $this->port     = $this->getStandardPort($value);
183                        break;
184
185                    case 'user':
186                    case 'pass':
187                    case 'host':
188                    case 'port':
189                        $this->$key = $value;
190                        break;
191
192                    case 'path':
193                        if ($value{0} == '/') {
194                            $this->path = $value;
195                        } else {
196                            $path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
197                            $this->path = sprintf('%s/%s', $path, $value);
198                        }
199                        break;
200
201                    case 'query':
202                        $this->querystring = $this->_parseRawQueryString($value);
203                        break;
204
205                    case 'fragment':
206                        $this->anchor = $value;
207                        break;
208                }
209            }
210        }
211    }
212    /**
213    * Returns full url
214    *
215    * @return string Full url
216    * @access public
217    */
218    function getURL()
219    {
220        $querystring = $this->getQueryString();
221
222        $this->url = $this->protocol . '://'
223                   . $this->user . (!empty($this->pass) ? ':' : '')
224                   . $this->pass . (!empty($this->user) ? '@' : '')
225                   . $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
226                   . $this->path
227                   . (!empty($querystring) ? '?' . $querystring : '')
228                   . (!empty($this->anchor) ? '#' . $this->anchor : '');
229
230        return $this->url;
231    }
232
233    /**
234    * Adds or updates a querystring item (URL parameter).
235    * Automatically encodes parameters with rawurlencode() if $preencoded
236    *  is false.
237    * You can pass an array to $value, it gets mapped via [] in the URL if
238    * $this->useBrackets is activated.
239    *
240    * @param  string $name       Name of item
241    * @param  string $value      Value of item
242    * @param  bool   $preencoded Whether value is urlencoded or not, default = not
243    * @access public
244    */
245    function addQueryString($name, $value, $preencoded = false)
246    {
247        if ($this->getOption('encode_query_keys')) {
248            $name = rawurlencode($name);
249        }
250
251        if ($preencoded) {
252            $this->querystring[$name] = $value;
253        } else {
254            $this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
255        }
256    }
257
258    /**
259    * Removes a querystring item
260    *
261    * @param  string $name Name of item
262    * @access public
263    */
264    function removeQueryString($name)
265    {
266        if ($this->getOption('encode_query_keys')) {
267            $name = rawurlencode($name);
268        }
269
270        if (isset($this->querystring[$name])) {
271            unset($this->querystring[$name]);
272        }
273    }
274
275    /**
276    * Sets the querystring to literally what you supply
277    *
278    * @param  string $querystring The querystring data. Should be of the format foo=bar&x=y etc
279    * @access public
280    */
281    function addRawQueryString($querystring)
282    {
283        $this->querystring = $this->_parseRawQueryString($querystring);
284    }
285
286    /**
287    * Returns flat querystring
288    *
289    * @return string Querystring
290    * @access public
291    */
292    function getQueryString()
293    {
294        if (!empty($this->querystring)) {
295            foreach ($this->querystring as $name => $value) {
296                // Encode var name
297                $name = rawurlencode($name);
298
299                if (is_array($value)) {
300                    foreach ($value as $k => $v) {
301                        $querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
302                    }
303                } elseif (!is_null($value)) {
304                    $querystring[] = $name . '=' . $value;
305                } else {
306                    $querystring[] = $name;
307                }
308            }
309            $querystring = implode(ini_get('arg_separator.output'), $querystring);
310        } else {
311            $querystring = '';
312        }
313
314        return $querystring;
315    }
316
317    /**
318    * Parses raw querystring and returns an array of it
319    *
320    * @param  string  $querystring The querystring to parse
321    * @return array                An array of the querystring data
322    * @access private
323    */
324    function _parseRawQuerystring($querystring)
325    {
326        $parts  = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
327        $return = array();
328
329        foreach ($parts as $part) {
330            if (strpos($part, '=') !== false) {
331                $value = substr($part, strpos($part, '=') + 1);
332                $key   = substr($part, 0, strpos($part, '='));
333            } else {
334                $value = null;
335                $key   = $part;
336            }
337
338            if (!$this->getOption('encode_query_keys')) {
339                $key = rawurldecode($key);
340            }
341
342            if (preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
343                $key = $matches[1];
344                $idx = $matches[2];
345
346                // Ensure is an array
347                if (empty($return[$key]) || !is_array($return[$key])) {
348                    $return[$key] = array();
349                }
350
351                // Add data
352                if ($idx === '') {
353                    $return[$key][] = $value;
354                } else {
355                    $return[$key][$idx] = $value;
356                }
357            } elseif (!$this->useBrackets AND !empty($return[$key])) {
358                $return[$key]   = (array)$return[$key];
359                $return[$key][] = $value;
360            } else {
361                $return[$key] = $value;
362            }
363        }
364
365        return $return;
366    }
367
368    /**
369    * Resolves //, ../ and ./ from a path and returns
370    * the result. Eg:
371    *
372    * /foo/bar/../boo.php    => /foo/boo.php
373    * /foo/bar/../../boo.php => /boo.php
374    * /foo/bar/.././/boo.php => /foo/boo.php
375    *
376    * This method can also be called statically.
377    *
378    * @param  string $path URL path to resolve
379    * @return string      The result
380    */
381    function resolvePath($path)
382    {
383        $path = explode('/', str_replace('//', '/', $path));
384
385        for ($i=0; $i<count($path); $i++) {
386            if ($path[$i] == '.') {
387                unset($path[$i]);
388                $path = array_values($path);
389                $i--;
390
391            } elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
392                unset($path[$i]);
393                unset($path[$i-1]);
394                $path = array_values($path);
395                $i -= 2;
396
397            } elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
398                unset($path[$i]);
399                $path = array_values($path);
400                $i--;
401
402            } else {
403                continue;
404            }
405        }
406
407        return implode('/', $path);
408    }
409
410    /**
411    * Returns the standard port number for a protocol
412    *
413    * @param  string  $scheme The protocol to lookup
414    * @return integer         Port number or NULL if no scheme matches
415    *
416    * @author Philippe Jausions <Philippe.Jausions@11abacus.com>
417    */
418    function getStandardPort($scheme)
419    {
420        switch (strtolower($scheme)) {
421            case 'http':    return 80;
422            case 'https':   return 443;
423            case 'ftp':     return 21;
424            case 'imap':    return 143;
425            case 'imaps':   return 993;
426            case 'pop3':    return 110;
427            case 'pop3s':   return 995;
428            default:        return null;
429       }
430    }
431
432    /**
433    * Forces the URL to a particular protocol
434    *
435    * @param string  $protocol Protocol to force the URL to
436    * @param integer $port     Optional port (standard port is used by default)
437    */
438    function setProtocol($protocol, $port = null)
439    {
440        $this->protocol = $protocol;
441        $this->port     = is_null($port) ? $this->getStandardPort($protocol) : $port;
442    }
443
444    /**
445     * Set an option
446     *
447     * This function set an option
448     * to be used thorough the script.
449     *
450     * @access public
451     * @param  string $optionName  The optionname to set
452     * @param  string $value       The value of this option.
453     */
454    function setOption($optionName, $value)
455    {
456        if (!array_key_exists($optionName, $this->options)) {
457            return false;
458        }
459
460        $this->options[$optionName] = $value;
461        $this->initialize();
462    }
463
464    /**
465     * Get an option
466     *
467     * This function gets an option
468     * from the $this->options array
469     * and return it's value.
470     *
471     * @access public
472     * @param  string $opionName  The name of the option to retrieve
473     * @see    $this->options
474     */
475    function getOption($optionName)
476    {
477        if (!isset($this->options[$optionName])) {
478            return false;
479        }
480
481        return $this->options[$optionName];
482    }
483
484}
485?>
Note: See TracBrowser for help on using the repository browser.