PHP 获取 URL 信息

本页内容

本文将阐述如何用PHP以正确的姿势获取URL的信息,并将其封装成类,方便复用。

URL

首先来了解一下URL的文法:

scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]

中括号表示的是可选项。

NameExplanation
scheme传输协议
user, password访问资源需要的凭证信息
host服务器
port端口
path路径
query查询
fragment片段
 1                        hierarchical part
 2            ┌───────────────────┴─────────────────────┐
 3                        authority               path
 4            ┌───────────────┴───────────────┐┌───┴────┐
 5      abc://username:[email protected]:123/path/data?key=value&key2=value2#fragid1
 6      └┬┘   └───────┬───────┘ └────┬────┘ └┬┘           └─────────┬─────────┘ └──┬──┘
 7    scheme  user information     host     port                  query         fragment
 8    
 9      urn:example:mammal:monotreme:echidna
10      └┬┘ └──────────────┬───────────────┘
11    scheme              path

函数

在了解URL的文法之后,我们很容易编写函数去获取URL的信息,但是本文并不打算编写独立的函数,
因为PHP已经提供了内置的函数 parse_urlparse_str 来实现这一目的。

parse_url

1mixed parse_url ( string $url [, int $component = -1 ] )

parse_url 解析一个URL,并返回一个包含URL各种组成部分的关联数组(键名和URL文法中的一致,比如:schemehostport等)。

当指定了第二个参数 component,则会返回指定组成部分的值,此时返回的是字符串或者数值(PHP_URL_PORT)。

官方文档:https://secure.php.net/manual/zh/function.parse-url.php

parse_str

1void parse_str ( string $encoded_string [, array &$result ] )

parse_str 将字符串解析成多个变量,第二个参数 $result 用于存储变量的键值。

这里有点小疑惑,因为可以看到 $result 是可选的,且该函数没有返回值,如果不设置 $result,那么这函数的意义是什么呢?

不过官方文档也标注了:极度不建议不设置 $result 的情况下使用该函数,并且在 PHP 7.2 中将废弃不设置参数的行为。

官方文档:https://secure.php.net/manual/zh/function.parse-str.php

实现

通过上述的 parse_urlparse_str 函数,可以轻松的获取URL的信息:

 1// URL
 2$url = 'https://example.com/user?name=foo';
 3
 4// 获取URL组成部分
 5$components = parse_url($url);
 6print_r($components);
 7
 8// 获取查询字符串
 9$query = isset($components['query']) ? $components['query'] : '';
10print_r($query);
11
12// 获取查询参数数组
13parse_str($query, $params);
14print_r($params);

输出

 1    Array
 2    (
 3        [scheme] => https
 4        [host] => example.com
 5        [path] => /user
 6        [query] => name=foo
 7    )
 8    
 9    name=foo
10    
11    Array
12    (
13        [name] => foo
14    )

Class

最后,将此封装成类,方便复用。

 1/**
 2 * Class URL
 3 *
 4 * @property string|null scheme
 5 *
 6 * @property string|null user
 7 *
 8 * @property string|null pass
 9 *
10 * @property string|null host
11 *
12 * @property integer|null port
13 *
14 * @property string|null path
15 *
16 * @property string|null query
17 *
18 * @property string|null fragment
19 */
20class URL
21{
22    private $data;
23
24    private $queryParams;
25
26    public function __construct($url)
27    {
28        $this->data = parse_url($url);
29        if ($this->data === false) {
30            throw new \InvalidArgumentException("invalid 
31        }
32    }
33
34    public function __get($name)
35    {
36        return isset($this->data[$name]) ? $this->data[$name] : null;
37    }
38
39    public function getQueryParams()
40    {
41        if ($this->queryParams === null) {
42            $query = $this->query;
43            if (empty($query)) {
44                $this->queryParams = [];
45            } else {
46                parse_str($query, $this->queryParams);
47            }
48        }
49
50        return $this->queryParams;
51    }
52}