在PHP开发中,处理URL地址是高频操作,其中提取URL的基础域名(Base URL)和Host信息是基础需求,比如做域名白名单校验、统计不同域名的访问量等场景都需要用到这类能力。不过很多开发者初期会尝试用字符串分割、正则匹配的方式处理,这类方式在面对复杂URL时很容易出现错误,比如URL带端口、带锚点、协议写法不规范时,手动处理很容易遗漏边界情况。
PHP内置的URL解析函数
PHP提供了parse_url函数专门用来解析URL,这个函数可以把完整的URL拆分成多个组成部分,我们可以直接从解析结果中获取Host信息,不需要手动处理字符串。该函数的返回值是一个关联数组,包含协议、主机、端口、路径、查询参数、锚点等各个部分。
parse_url函数的基本用法
我们先看一个简单的使用示例:
<?php $url = "https://www.ippipp.com:8080/path/to/page?name=test#anchor"; $parseResult = parse_url($url); // 打印解析结果 print_r($parseResult); ?>
运行上面的代码,输出的结果如下:
Array
(
[scheme] => https
[host] => www.ippipp.com
[port] => 8080
[path] => /path/to/page
[query] => name=test
[fragment] => anchor
)
从结果可以看到,Host信息就存储在host键对应的值中,我们可以直接获取这个值作为URL的主机名。如果URL没有带端口,那么解析结果中就不会有port键,这时候host的值就是完整的主机信息。
提取基础域名和Host的完整实现
根据上面的解析结果,我们可以封装一个专门提取Host的函数,同时处理异常情况,比如URL格式不正确的情况。
提取Host的实现代码
<?php
/**
* 从URL中提取Host信息
* @param string $url 待解析的URL
* @return string|false 成功返回Host字符串,失败返回false
*/
function getUrlHost($url) {
// 先校验URL格式
if (empty($url) || !is_string($url)) {
return false;
}
$parseResult = parse_url($url);
// 如果解析失败或者没有host键,返回false
if ($parseResult === false || !isset($parseResult['host'])) {
return false;
}
return $parseResult['host'];
}
// 测试不同场景的URL
$testUrls = [
"https://www.ipipp.com/path",
"http://blog.ipipp.com:9090/post/1",
"ftp://files.ipipp.com/download",
"https://user:pass@api.ipipp.com/v1/data",
"invalid-url-test"
];
foreach ($testUrls as $url) {
$host = getUrlHost($url);
echo "URL: {$url} 的Host是:" . ($host === false ? "解析失败" : $host) . PHP_EOL;
}
?>
运行上面的测试代码,输出结果如下:
URL: https://www.ipipp.com/path 的Host是:www.ipipp.com URL: http://blog.ipipp.com:9090/post/1 的Host是:blog.ipipp.com URL: ftp://files.ipipp.com/download 的Host是:files.ipipp.com URL: https://user:pass@api.ipipp.com/v1/data 的Host是:api.ipipp.com URL: invalid-url-test 的Host是:解析失败
关于基础域名(Base URL)的说明
很多开发者会把Base URL和基础域名混淆,Base URL指的是URL的基础部分,通常包含协议和Host,部分场景下还会包含端口。如果需要获取Base URL,可以把协议和Host拼接起来,如果带端口的话还要加上端口信息。
提取Base URL的实现
<?php
/**
* 从URL中提取Base URL(协议+Host+端口)
* @param string $url 待解析的URL
* @return string|false 成功返回Base URL字符串,失败返回false
*/
function getBaseUrl($url) {
$parseResult = parse_url($url);
if ($parseResult === false || !isset($parseResult['scheme']) || !isset($parseResult['host'])) {
return false;
}
$baseUrl = $parseResult['scheme'] . "://" . $parseResult['host'];
// 如果有端口,拼接端口
if (isset($parseResult['port'])) {
$baseUrl .= ":" . $parseResult['port'];
}
return $baseUrl;
}
// 测试
$testUrl = "https://www.ipipp.com:8080/path?a=1";
echo getBaseUrl($testUrl); // 输出 https://www.ipipp.com:8080
?>
注意事项
parse_url函数仅做URL的结构拆分,不会校验URL的合法性,比如传入一个不符合URL格式的字符串,可能也会返回部分解析结果,所以最好先自己做基础的格式校验。- 如果URL中包含认证信息(比如
user:pass@host的形式),parse_url会解析出user和pass键,不会影响Host的提取。 - 如果URL没有携带协议,比如
www.ipipp.com/path,parse_url会把www.ipipp.com识别为path,不会识别为host,这种场景下需要提前给URL补全协议再解析。
如果需要提取主域名(比如从www.ipipp.com提取ipipp.com),还需要额外处理域名的层级,这部分逻辑和URL解析无关,需要结合域名的规则单独实现。