parse_url

(PHP 4, PHP 5, PHP 7, PHP 8)

parse_url解析 URL 并返回其组件

描述

parse_url(string $url, int $component = -1): int|string|array|null|false

此函数解析 URL 并返回一个关联数组,其中包含 URL 中存在的各种组件。数组元素的值 *未* 进行 URL 解码。

此函数 *并非* 用于验证给定的 URL,它只是将其分解成下面列出的部分。部分和无效 URL 也被接受,parse_url() 会尽力正确解析它们。

参数

url

要解析的 URL。

component

指定 PHP_URL_SCHEMEPHP_URL_HOSTPHP_URL_PORTPHP_URL_USERPHP_URL_PASSPHP_URL_PATHPHP_URL_QUERYPHP_URL_FRAGMENT 以检索特定 URL 组件作为 string(除非给出 PHP_URL_PORT,在这种情况下返回值将是 int)。

返回值

对于严重格式错误的 URL,parse_url() 可能会返回 false

如果省略了 component 参数,则会返回一个关联的 array。数组中至少会存在一个元素。此数组中可能的键是

  • scheme - 例如 http
  • host
  • port
  • user
  • pass
  • path
  • query - 问号 ? 之后
  • fragment - 井号 # 之后

如果指定了 component 参数,parse_url() 将返回一个 string(或者 int,如果是 PHP_URL_PORT)而不是 array。如果给定 URL 中不存在所请求的组件,则将返回 null。从 PHP 8.0.0 开始,parse_url() 区分不存在和空的查询和片段

http://example.com/foo → query = null, fragment = null
http://example.com/foo? → query = "",   fragment = null
http://example.com/foo# → query = null, fragment = ""
http://example.com/foo?# → query = "",   fragment = ""

以前所有情况都会导致查询和片段为 null

请注意,组件中的控制字符(参见 ctype_cntrl())将被替换为下划线 (_)。

变更日志

版本 描述
8.0.0 parse_url() 现在将区分不存在和空的查询和片段。

示例

示例 #1 parse_url() 示例

<?php
$url
= 'http://username:password@hostname:9090/path?arg=value#anchor';

var_dump(parse_url($url));
var_dump(parse_url($url, PHP_URL_SCHEME));
var_dump(parse_url($url, PHP_URL_USER));
var_dump(parse_url($url, PHP_URL_PASS));
var_dump(parse_url($url, PHP_URL_HOST));
var_dump(parse_url($url, PHP_URL_PORT));
var_dump(parse_url($url, PHP_URL_PATH));
var_dump(parse_url($url, PHP_URL_QUERY));
var_dump(parse_url($url, PHP_URL_FRAGMENT));
?>

上面的示例将输出

array(8) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(8) "hostname"
  ["port"]=>
  int(9090)
  ["user"]=>
  string(8) "username"
  ["pass"]=>
  string(8) "password"
  ["path"]=>
  string(5) "/path"
  ["query"]=>
  string(9) "arg=value"
  ["fragment"]=>
  string(6) "anchor"
}
string(4) "http"
string(8) "username"
string(8) "password"
string(8) "hostname"
int(9090)
string(5) "/path"
string(9) "arg=value"
string(6) "anchor"

示例 #2 带有缺失方案的 parse_url() 示例

<?php
$url
= '//www.example.com/path?googleguy=googley';

// 在 5.4.7 之前,这将显示路径为 "//www.example.com/path"
var_dump(parse_url($url));
?>

上面的示例将输出

array(3) {
  ["host"]=>
  string(15) "www.example.com"
  ["path"]=>
  string(5) "/path"
  ["query"]=>
  string(17) "googleguy=googley"
}

注意

警告

此函数可能无法针对相对或无效 URL 提供正确的结果,并且结果可能与 HTTP 客户端的常见行为不匹配。如果需要解析来自不受信任输入的 URL,则需要额外的验证,例如,使用 filter_var() 以及 FILTER_VALIDATE_URL 过滤器。

注意:

此函数专门用于解析 URL,而不是 URI。但是,为了符合 PHP 的向后兼容性要求,它对 file:// 方案做出了例外,其中允许使用三个斜杠 (file:///...)。对于任何其他方案,这都是无效的。

参见

添加笔记

用户贡献的笔记 37 个笔记

thomas at gielfeldt dot com
12 年前
[如果你还没有] 找到从解析的 URL 转换回字符串的简单方法,这里是一个示例

<?php

$url
= 'http://usr:[email protected]:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment';
if (
$url === unparse_url(parse_url($url))) {
print
"YES, they match!\n";
}

function
unparse_url($parsed_url) {
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return
"$scheme$user$pass$host$port$path$query$fragment";
}

?>
lauris () lauris ! lv
10 年前
这是一个基于 “laszlo dot janszky at gmail dot com” 工作的兼容 utf-8 的 parse_url() 替代函数。原始代码错误地处理了包含 user:pass 的 URL。还使其兼容 PHP 5.5(去掉了现在已弃用的正则表达式 /e 修饰符)。

<?php

/**
* 支持 UTF-8 的 parse_url() 替代函数。
*
* @return array
*/
function mb_parse_url($url)
{
$enc_url = preg_replace_callback(
'%[^:/@?&=#]+%usD',
function (
$matches)
{
return
urlencode($matches[0]);
},
$url
);

$parts = parse_url($enc_url);

if(
$parts === false)
{
throw new
\InvalidArgumentException('Malformed URL: ' . $url);
}

foreach(
$parts as $name => $value)
{
$parts[$name] = urldecode($value);
}

return
$parts;
}

?>
jerome at chaman dot ca
9 年前
值得提醒的是,#fragment 的值永远不会发送到服务器。锚点处理完全是客户端完成的。
nospam at spellingcow dot com
15 年前
相对 URL 的查询字符串中的 URL 会导致问题

失败
/page.php?foo=bar&url=http://www.example.com

解析
http://www.foo.com/page.php?foo=bar&url=http://www.example.com
adrian-php at sixfingeredman dot net
17 年前
以下函数根据 RFC 2396 第 5.2 节实现了解析相对 URL。当然,还有更高效的实现,但为了清晰起见,此实现尽量贴近标准。它依赖于一个名为 “unparse_url” 的函数来实现第 7 节,留给读者自行练习(或者你可以用前面发布的 “glue_url” 函数替换它)。

<?php
/**
* 解析相对于基本路径的 URL。这恰好也适用于 POSIX
* 文件名。这基于 RFC 2396 第 5.2 节。
*/
function resolve_url($base, $url) {
if (!
strlen($base)) return $url;
// 第 2 步
if (!strlen($url)) return $base;
// 第 3 步
if (preg_match('!^[a-z]+:!i', $url)) return $url;
$base = parse_url($base);
if (
$url{0} == "#") {
// 第 2 步(片段)
$base['fragment'] = substr($url, 1);
return
unparse_url($base);
}
unset(
$base['fragment']);
unset(
$base['query']);
if (
substr($url, 0, 2) == "//") {
// 第 4 步
return unparse_url(array(
'scheme'=>$base['scheme'],
'path'=>$url,
));
} else if (
$url{0} == "/") {
// 第 5 步
$base['path'] = $url;
} else {
// 第 6 步
$path = explode('/', $base['path']);
$url_path = explode('/', $url);
// 第 6a 步:从 base 中删除文件
array_pop($path);
// 第 6b、6c、6e 步:追加 url 并从
// 目录部分删除 "." 和 ".."
$end = array_pop($url_path);
foreach (
$url_path as $segment) {
if (
$segment == '.') {
// 跳过
} else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') {
array_pop($path);
} else {
$path[] = $segment;
}
}
// 第 6d、6f 步:从文件部分删除 "." 和 ".."
if ($end == '.') {
$path[] = '';
} else if (
$end == '..' && $path && $path[sizeof($path)-1] != '..') {
$path[sizeof($path)-1] = '';
} else {
$path[] = $end;
}
// 第 6h 步
$base['path'] = join('/', $path);

}
// 第 7 步
return unparse_url($base);
}
?>
pjpawel
2 年前
不幸的是,parse_url() 无法正确解析没有 scheme 或 '//' 的 URL。例如,'www.xyz.com' 被认为是路径,而不是主机

代码
<?php
var_dump
(parse_url('www.xyz.com'));
?>
输出
array(1) {
["path"]=>
string(10) "www.xyz.com"
}

要获得更好的输出,请将 url 更改为
'//www.xyz.com' 或 'http://www.xyz.com'
james at roundeights dot com
14 年前
我正在编写单元测试,需要让这个函数抛出一个错误并返回 FALSE,以便测试特定的执行路径。如果其他人需要强制失败,以下输入将起作用

<?php
parse_url
("http:///example.com");
parse_url("http://:80");
parse_url("http://user@:80");
?>
to1ne at hotmail dot com
16 年前
基于 "jbr at ya-right dot com" 的想法,我一直在开发一个新的函数来解析 URL

<?php
function parseUrl($url) {
$r = "^(?:(?P<scheme>\w+)://)?";
$r .= "(?:(?P<login>\w+):(?P<pass>\w+)@)?";
$r .= "(?P<host>(?:(?P<subdomain>[\w\.]+)\.)?" . "(?P<domain>\w+\.(?P<extension>\w+)))";
$r .= "(?::(?P<port>\d+))?";
$r .= "(?P<path>[\w/]*/(?P<file>\w+(?:\.\w+)?)?)?";
$r .= "(?:\?(?P<arg>[\w=&]+))?";
$r .= "(?:#(?P<anchor>\w+))?";
$r = "!$r!"; // Delimiters

preg_match ( $r, $url, $out );

return
$out;
}
print_r ( parseUrl ( 'me:[email protected]:29000/pear/validate.html?happy=me&sad=you#url' ) );
?>

这将返回
数组
(
[0] => me:[email protected]:29000/pear/validate.html?happy=me&sad=you#url
[scheme] =>
[1] =>
[login] => me
[2] => me
[pass] => you
[3] => you
[host] => sub.site.org
[4] => sub.site.org
[subdomain] => sub
[5] => sub
[domain] => site.org
[6] => site.org
[extension] => org
[7] => org
[port] => 29000
[8] => 29000
[path] => /pear/validate.html
[9] => /pear/validate.html
[file] => validate.html
[10] => validate.html
[arg] => happy=me&sad=you
[11] => happy=me&sad=you
[anchor] => url
[12] => url
)

因此,命名和编号的数组键都是可能的。

它非常先进,但我认为无论如何它都能正常工作... 如果它没有正常工作,请告诉我...
therselman at gmail
12 年前
支持 UTF-8 的 parse_url() 替换函数。

我意识到,即使 UTF-8 字符在 URL 中不允许使用,但我必须处理大量这样的字符,而 parse_url() 会出现故障。

在很大程度上基于 "mallluhuct at gmail dot com" 的工作,我添加了 parse_url() 兼容的 "命名值",这使得数组值更容易处理(而不是仅仅是数字)。我还实现了对端口、用户名/密码的检测以及反向引用,以更好地检测像这样的 URL://en.wikipedia.com
... 虽然这在技术上是一个无效的 URL,但在像维基百科这样的网站上,它在锚标签的 href 属性中广泛使用,在浏览器中它是有效的(您在抓取页面时必须支持的 URL 类型之一)。这将被准确地检测为主机名,而不是像其他所有示例那样检测为 "path"。

我将提交我的完整函数(而不是仅仅是正则表达式),它几乎可以作为 parse_url() 的直接替换。它返回一个清理后的数组(或 false),其中包含与 parse_url() 兼容的值。我本来可以告诉 preg_match() 不要存储未使用的额外值,但这会使正则表达式变得复杂,并使它更难阅读、理解和扩展。检测 UTF-8 字符的关键是在 preg_match() 中使用 "u" 参数。

<?php
function parse_utf8_url($url)
{
static
$keys = array('scheme'=>0,'user'=>0,'pass'=>0,'host'=>0,'port'=>0,'path'=>0,'query'=>0,'fragment'=>0);
if (
is_string($url) && preg_match(
'~^((?P<scheme>[^:/?#]+):(//))?((\\3|//)?(?:(?P<user>[^:]+):(?P<pass>[^@]+)@)?(?P<host>[^/?:#]*))(:(?P<port>\\d+))?' .
'(?P<path>[^?#]*)(\\?(?P<query>[^#]*))?(#(?P<fragment>.*))?~u', $url, $matches))
{
foreach (
$matches as $key => $value)
if (!isset(
$keys[$key]) || empty($value))
unset(
$matches[$key]);
return
$matches;
}
return
false;
}
?>

可以使用/应该使用此函数在提取后 "规范化" UTF-8 URL。
mys5droid at gmail dot com
8 年前
我为我的一个项目编写了一个将相对 URL 转换为绝对 URL 的函数。考虑到我在其他地方找不到它,我决定把它发布到这里。

以下函数接受 2 个参数,第一个参数是您想要从相对 URL 转换为绝对 URL 的 URL,第二个参数是绝对 URL 的示例。

目前它不解析 URL 中的 '../',仅仅是因为我不需要它。大多数 Web 服务器会为您解析它。如果您希望它解析路径中的 '../',只需进行少量修改即可。

<?php

function relativeToAbsolute($inurl, $absolute) {
// 获取所有部分,避免重复获取
$absolute_parts = parse_url($absolute);
// 检查URL是否已经是绝对地址(包含主机名或以 '/' 开头)
if ( (strpos($inurl, $absolute_parts['host']) == false) ) {
// 定义 $tmpurlprefix 防止后面的错误
$tmpurlprefix = "";
// 构建URL前缀(方案)
if (!(empty($absolute_parts['scheme']))) {
// 将方案添加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['scheme'] . "://";
}
// 构建URL前缀(用户名,密码)
if ((!(empty($absolute_parts['user']))) and (!(empty($absolute_parts['pass'])))) {
// 将用户名:密码添加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['user'] . ":" . $absolute_parts['pass'] . "@";
}
// 构建URL前缀(主机名,端口号)
if (!(empty($absolute_parts['host']))) {
// 将主机名添加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['host'];
// 检查端口号是否存在,如果存在则添加
if (!(empty($absolute_parts['port']))) {
// 将端口号添加到 tmpurlprefix
$tmpurlprefix .= ":" . $absolute_parts['port'];
}
}
// 构建URL前缀(路径),并且仅当图片路径不包含 './' 时添加
if ( (!(empty($absolute_parts['path']))) and (substr($inurl, 0, 1) != '/') ) {
// 获取路径部分
$path_parts = pathinfo($absolute_parts['path']);
// 将路径添加到 tmpurlprefix
$tmpurlprefix .= $path_parts['dirname'];
$tmpurlprefix .= "/";
}
else {
$tmpurlprefix .= "/";
}
// 移除 '/'
if (substr($inurl, 0, 1) == '/') { $inurl = substr($inurl, 1); }
// 移除 './'
if (substr($inurl, 0, 2) == './') { $inurl = substr($inurl, 2); }
return
$tmpurlprefix . $inurl;
}
else {
// 路径已经是绝对地址。直接返回
return $inurl;
}
}

// 定义一个示例绝对URL
$absolute = "http://" . "user:[email protected]:8080/path/to/index.html"; // 只是为了避开 php.net 的垃圾邮件过滤器,我不确定为什么 example.com 会被认为是垃圾邮件...

/* EXAMPLE 1 */
echo relativeToAbsolute($absolute, $absolute) . "\n";
/* EXAMPLE 2 */
echo relativeToAbsolute("img.gif", $absolute) . "\n";
/* EXAMPLE 3 */
echo relativeToAbsolute("/img.gif", $absolute) . "\n";
/* EXAMPLE 4 */
echo relativeToAbsolute("./img.gif", $absolute) . "\n";
/* EXAMPLE 5 */
echo relativeToAbsolute("../img.gif", $absolute) . "\n";
/* EXAMPLE 6 */
echo relativeToAbsolute("images/img.gif", $absolute) . "\n";
/* EXAMPLE 7 */
echo relativeToAbsolute("/images/img.gif", $absolute) . "\n";
/* EXAMPLE 8 */
echo relativeToAbsolute("./images/img.gif", $absolute) . "\n";
/* EXAMPLE 9 */
echo relativeToAbsolute("../images/img.gif", $absolute) . "\n";

?>

输出
http :// user:[email protected]:8080/path/to/index.html
http :// user:[email protected]:8080/path/to/img.gif
http :// user:[email protected]:8080/img.gif
http :// user:[email protected]:8080/path/to/img.gif
http :// user:[email protected]:8080/path/to/../img.gif
http :// user:[email protected]:8080/path/to/images/img.gif
http :// user:[email protected]:8080/images/img.gif
http :// user:[email protected]:8080/path/to/images/img.gif
http :// user:[email protected]:8080/path/to/../images/img.gif

如果您觉得上面的代码不是您的风格,或者您觉得它很“混乱”,或者您认为有更好的方法,请告诉我。我已经尽可能地删除了空白。

欢迎改进! :)
Michael
5年前
这个函数有一个怪癖,如果在URL前面有一个空格,它会将主机名返回为“路径”。

<?php

$url
= ' https://foobar.com:80/mypath/myfile.php';

print_r(parse_url($url));
/*
Array
(
[path] => https://foobar.com:80/mypath/myfile.php
)
*/

print_r(trim(parse_url($url)));
/*
Array
(
[scheme] => https
[host] => foobar.com
[port] => 80
[path] => /mypath/myfile.php
)
*/

?>
utilmind
11年前
如果协议没有指定,parse_url 无法正常工作。 这似乎是标准行为,即使 Youtube 在生成嵌入代码时也不会提供协议名称,这些代码看起来像 "//youtube.com/etc"。

因此,为了避免错误,您必须始终检查提供的 URL 是否包含协议。 如果没有(以两个斜杠开头),则需要添加 "http:" 前缀。
demerit
7年前
在 PHP 7 中有一个变化(我在从 5.3 升级到 7.1 时注意到了),如果密码部分包含井号 (#),则解析在 7.1 中会失败,而在 5.3 中则会成功。
boctulus @ gmail co!m
4年前
parse_url() 无法解析一些明显的错误,所以我创建了一个补充函数

function url_check(string $url){
$sym = null;

$len = strlen($url);
for ($i=0; $i<$len; $i++){
if ($url[$i] == '?'){
if ($sym == '?' || $sym == '&')
return false;

$sym = '?';
}elseif ($url[$i] == '&'){
if ($sym === null)
return false;

$sym = '&';
}
}
return true;
}
}
ivijan dot stefan at gmail dot com
10 年前
以下是如何使用 parse_url() 获取 Youtube 链接的示例。
我在许多项目中使用了此函数。

<?php
function youtube($url, $width=560, $height=315, $fullscreen=true)
{
parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars );
$youtube= '<iframe allowtransparency="true" scrolling="no" width="'.$width.'" height="'.$height.'" src="//www.youtube.com/embed/'.$my_array_of_vars['v'].'" frameborder="0"'.($fullscreen?' allowfullscreen':NULL).'></iframe>';
return
$youtube;
}

// 在我的页面上显示 YouTube 视频
$url='http://www.youtube.com/watch?v=yvTd6XxgCBE';
youtube($url, 560, 315, true);
?>

parse_url () 函数分配一个唯一的 YouTube 代码并将其放入 iframe 链接,然后在你的页面上显示。你可以自己选择视频的大小。

享受!
laszlo dot janszky at gmail dot com
12 年前
创建另一个兼容 UTF-8 的 parse_url 函数。
<?php
function mb_parse_url($url) {
$encodedUrl = preg_replace('%[^:/?#&=\.]+%usDe', 'urlencode(\'$0\')', $url);
$components = parse_url($encodedUrl);
foreach (
$components as &$component)
$component = urldecode($component);
return
$components;
}
?>
simbappo
3 年前
从传入的或当前 URL 中删除查询变量。

function unsetqueryvar($var, $url=null) {
if (null == $url) $url = $_SERVER['REQUEST_URI'];
// 转换成列表
$url = parse_url($url);
$rq = [];
parse_str($url['query'], $rq);
unset($rq[$var]);
return $url['scheme'].$url['host'].$url['path'].'?'.http_build_query($rq).$url['fragment'];
}
ap dot public1 at gmail dot com
15 年前
一个简单的静态库,允许轻松操作 URL 参数。

<?php
/**
* 文件提供了操作 URL 参数的简便方法
* @author Alexander Podgorny
*/

class Url {
/**
* 将 URL 分解成一个数组,包含以下部分:
* [scheme]://[user]:[pass]@[host]/[path]?[query]#[fragment]
* 此外,它还添加了 'query_params' 键,包含 URL 解码的键值对数组
*
* @param String $sUrl URL
* @return Array 解析后的 URL 部分
*/
public static function explode($sUrl) {
$aUrl = parse_url($sUrl);
$aUrl['query_params'] = array();
$aPairs = explode('&', $aUrl['query']);
DU::show($aPairs);
foreach(
$aPairs as $sPair) {
if (
trim($sPair) == '') { continue; }
list(
$sKey, $sValue) = explode('=', $sPair);
$aUrl['query_params'][$sKey] = urldecode($sValue);
}
return
$aUrl;
}
/**
* 从 URL 部分数组(由 explodeUrl 返回)中编译 URL
* 如果存在 'query_params',则忽略 'query'
*
* @param Array $aUrl URL 部分数组
*/
public static function implode($aUrl) {
//[scheme]://[user]:[pass]@[host]/[path]?[query]#[fragment]

$sQuery = '';

// 编译查询
if (isset($aUrl['query_params']) && is_array($aUrl['query_params'])) {
$aPairs = array();
foreach (
$aUrl['query_params'] as $sKey=>$sValue) {
$aPairs[] = $sKey.'='.urlencode($sValue);
}
$sQuery = implode('&', $aPairs);
} else {
$sQuery = $aUrl['query'];
}

// 编译 URL
$sUrl =
$aUrl['scheme'] . '://' . (
isset(
$aUrl['user']) && $aUrl['user'] != '' && isset($aUrl['pass'])
?
$aUrl['user'] . ':' . $aUrl['pass'] . '@'
: ''
) .
$aUrl['host'] . (
isset(
$aUrl['path']) && $aUrl['path'] != ''
? $aUrl['path']
:
''
) . (
$sQuery != ''
? '?' . $sQuery
: ''
) . (
isset(
$aUrl['fragment']) && $aUrl['fragment'] != ''
? '#' . $aUrl['fragment']
:
''
);
return
$sUrl;
}
/**
* 解析 URL 并返回 URL 参数的键值对数组
*
* @param String $sUrl
* @return Array
*/
public static function getParams($sUrl) {
$aUrl = self::explode($sUrl);
return
$aUrl['query_params'];
}
/**
* 删除现有的 URL 参数并将它们设置为 $aParams 中指定的参数
*
* @param String $sUrl URL
* @param Array $aParams 要设置的 URL 参数的键值对数组
* @return String 新编译的 URL
*/
public static function setParams($sUrl, $aParams) {
$aUrl = self::explode($sUrl);
$aUrl['query'] = '';
$aUrl['query_params'] = $aParams;
return
self::implode($aUrl);
}
/**
* 更新现有 URL 参数的值,或添加(如果未设置)$aParams 中指定的参数
*
* @param String $sUrl URL
* @param Array $aParams 要设置的 URL 参数的键值对数组
* @return String 新编译的 URL
*/
public static function updateParams($sUrl, $aParams) {
$aUrl = self::explode($sUrl);
$aUrl['query'] = '';
$aUrl['query_params'] = array_merge($aUrl['query_params'], $aParams);
return
self::implode($aUrl);
}
}

?>
nirazuelos at gmail dot com
14 年前
您好,出于某种奇怪的原因,当输入 URL 中没有提供 scheme 时,parse_url 会将主机(例如 example.com)作为路径返回。所以我写了一个快速函数来获取真实的主机。

<?php
function getHost($Address) {
$parseUrl = parse_url(trim($Address));
return
trim($parseUrl[host] ? $parseUrl[host] : array_shift(explode('/', $parseUrl[path], 2)));
}

getHost("example.com"); // 返回 example.com
getHost("http://example.com"); // 返回 example.com
getHost("www.example.com"); // 返回 www.example.com
getHost("http://example.com/xyz"); // 返回 example.com
?>

你可以尝试任何东西!它会返回主机(包括子域,如果存在)。

希望它对你有帮助。
spam at paulisageek dot com
17 年前
回复 adrian,

非常感谢你的函数。你的相对协议函数存在一个小问题。你需要在将 url 设为路径时移除 //。以下是新的函数。

function resolve_url($base, $url) {
if (!strlen($base)) return $url;
// 步骤 2
if (!strlen($url)) return $base;
// 步骤 3
if (preg_match('!^[a-z]+:!i', $url)) return $url;
$base = parse_url($base);
if ($url{0} == "#") {
// 步骤 2 (片段)
$base['fragment'] = substr($url, 1);
return unparse_url($base);
}
unset($base['fragment']);
unset($base['query']);
if (substr($url, 0, 2) == "//") {
// 步骤 4
return unparse_url(array(
'scheme'=>$base['scheme'],
'path'=>substr($url,2),
));
} else if ($url{0} == "/") {
// 步骤 5
$base['path'] = $url;
} else {
// 步骤 6
$path = explode('/', $base['path']);
$url_path = explode('/', $url);
// 步骤 6a: 从 base 中移除文件
array_pop($path);
// 步骤 6b, 6c, 6e: 添加 url 并从目录部分移除 "." 和 ".."
// the directory portion
$end = array_pop($url_path);
foreach ($url_path as $segment) {
if ($segment == '.') {
// 跳过
} else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') {
array_pop($path);
} else {
$path[] = $segment;
}
}
// 步骤 6d, 6f: 从文件部分移除 "." 和 ".."
if ($end == '.') {
$path[] = '';
} else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') {
$path[sizeof($path)-1] = '';
} else {
$path[] = $end;
}
// 步骤 6h
$base['path'] = join('/', $path);

}
// 步骤 7
return unparse_url($base);
}
vbrazas15 at gmail dot com
3 年前
我对著名的 `unparse_url` 函数(由 "thomas at gielfeldt dot com" 提供)进行了一些谦逊的改进。

```php
/**
* @param array $parsedUrl -- 库函数 `parse_url()` 的结果
*
* @return string
*/
function unparseUrl(array $parsedUrl): string
{
// PHP_URL_SCHEME
$scheme = empty($parsedUrl[PHP_URL_SCHEME]) ? '' : (rtrim($parsedUrl['scheme'], ':/') . '://');

$user = empty($parsedUrl[PHP_URL_USER]) ? '' : rtrim($parsedUrl['user'], '@:');
$pass = empty($parsedUrl[PHP_URL_PASS]) ? '' : (':' . trim($parsedUrl['pass'], '@:'));

$pass = !$user ? '' : ($pass . '@');

$host = empty($parsedUrl[PHP_URL_HOST]) ? '' : rtrim($parsedUrl['host'], '/');
$port = empty($parsedUrl[PHP_URL_PORT]) ? '' : (':' . (int)ltrim($parsedUrl['port'], ':'));
$path = empty($parsedUrl[PHP_URL_PATH]) ? '' : ('/' . ltrim($parsedUrl['path'], '/'));

$host = ($host && !$port && !$path) ? $parsedUrl['host'] : $host;
$path = ($path && !$host && !$port) ? $parsedUrl['path'] : $path;

$query = empty($parsedUrl[PHP_URL_QUERY]) ? '' : ('?' . ltrim($parsedUrl['query'], '?'));
$fragment = empty($parsedUrl[PHP_URL_FRAGMENT]) ? '' : ('#' . ltrim($parsedUrl['fragment'], '#'));

return "$scheme$user$pass$host$port$path$query$fragment";
}
```
Anonymous
6 年前
此函数将尝试解析相对 URL,但依赖于它可能会产生意外行为,导致一些难以追踪的错误。(以下结果来自 PHP 5.5.19)

尝试解析如下 URL
http://example.com/entities/GOA:98/?search=8989157d1f22
正确地返回
<?php
array (
'scheme' => 'http',
'host' => 'example.com',
'path' => '/entities/GOA:98/',
'query' => 'search=8989157d1f22',
);
?>

然而,尝试解析相对 URL
entities/GOA:98/?search=8989157d1f22
<?php
array (
'host' => 'entities',
'port' => 98,
'path' => '/GOA:98/',
'query' => 'search=8989157d1f22',
)
?>
如果我将 :98 更改为 :A98,parse_url 会正确解析 URL 如下
<?php
array (
'path' => 'entities/GOA:A98/',
'query' => 'search=8989157d1f22',
)
?>
总之,除非你测试过预期的输入并确定 parse_url 能很好地处理它们,否则避免使用 parse_url 解析相对 URL。

https://forums.hawacastle.com/
Rob
9 年前
我一直致力于一个通用类,它可以使 URI 解析/构建更加容易。

Composer 包在这里:https://packagist.org.cn/packages/enrise/urihelper

仓库在这里:https://github.com/Enrise/UriHelper

使用方法示例

<?php
$uri
= new \Enrise\Uri('http://usr:[email protected]:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment');
echo
$uri->getScheme(); // http
echo $uri->getUser(); // usr
echo $uri->getPass(); // pss
echo $uri->getHost(); // example.com
echo $uri->getPort(); // 81
echo $uri->getPath(); // /mypath/myfile.html
echo $uri->getQuery(); // a=b&b[]=2&b[]=3
echo $uri->getFragment(); // myfragment
echo $uri->isSchemeless(); // false
echo $uri->isRelative(); // false

$uri->setScheme('scheme:child:scheme.VALIDscheme123:');
$uri->setPort(null);

echo
$uri->getUri(); //scheme:child:scheme.VALIDscheme123:usr:[email protected]/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment
?>
zappascripts at gmail com
7年前
这里是我的一个简单的类,它利用了 parse_url。
我需要一种方法让页面保留 GET 参数,同时也能编辑或添加参数。
我还有一些页面需要相同的 GET 参数,所以我添加了一种方法来改变路径。

<?php
class Paths{

private
$url;
public function
__construct($url){
$this->url = parse_url($url);
}

public function
returnUrl(){
$return = $this->url['path'].'?'.$this->url['query'];
$return = (substr($return,-1) == "&")? substr($return,0,-1) : $return;
$this->resetQuery();
return
$return;
}

public function
changePath($path){
$this->url['path'] = $path;
}

public function
editQuery($get,$value){
$parts = explode("&",$this->url['query']);
$return = "";
foreach(
$parts as $p){
$paramData = explode("=",$p);
if(
$paramData[0] == $get){
$paramData[1] = $value;
}
$return .= implode("=",$paramData).'&';

}

$this->url['query'] = $return;
}

public function
addQuery($get,$value){
$part = $get."=".$value;
$and = ($this->url['query'] == "?") ? "" : "&";
$this->url['query'] .= $and.$part;
}

public function
checkQuery($get){
$parts = explode("&",$this->url['query']);

foreach(
$parts as $p){
$paramData = explode("=",$p);
if(
$paramData[0] == $get)
return
true;
}
return
false;

}

public function
buildQuery($get,$value){
if(
$this->checkQuery($get))
$this->editQuery($get,$value);
else
$this->addQuery($get,$value);

}

public function
resetQuery(){
$this->url = parse_url($_SERVER['REQUEST_URI']);
}




}
?>

用法

Test.php?foo=1

<?php
$path
= new Paths($_SERVER['REQUEST_URI']);
$path->changePath("/baz.php");
$path->buildQuery("foo",2);
$path->buildQuery("bar",3);
echo
$path->returnUrl();
?>

返回: /baz.php?foo=2&bar=3

希望这对某些人有用!
need_sunny at yahoo dot com
14 年前
感谢 xellisx 的 parse_query 函数。我在其中一个项目中使用了它,它工作良好。但它有一个错误。我修正了错误并稍作改进。这是我的版本

<?php
// 原作者 xellisx
function parse_query($var)
{
/**
* 使用此函数解析 parse_url() 输出中的查询数组元素。
*/
$var = parse_url($var, PHP_URL_QUERY);
$var = html_entity_decode($var);
$var = explode('&', $var);
$arr = array();

foreach(
$var as $val)
{
$x = explode('=', $val);
$arr[$x[0]] = $x[1];
}
unset(
$val, $x, $var);
return
$arr;
}
?>

在第一行,原本是 parse_query($val),我把它改成了 $var。在修复之前,它会返回一个空数组。

我添加了 parse_url 行。因此,现在该函数只关注查询部分,而不是整个 URL。如果执行以下操作,这将很有用
<?php
$my_GET
= parse_query($_SERVER['REQUEST_URI']);
?>
vdklah at hotmail dot com
15 年前
一些确定 URL 端口的示例。
当未指定端口时,它会从方案中推断出来。

<?php
function getUrlPort( $urlInfo )
{
if( isset(
$urlInfo['port']) ) {
$port = $urlInfo['port'];
} else {
// 没有指定端口;获取默认端口
if (isset($urlInfo['scheme']) ) {
switch(
$urlInfo['scheme'] ) {
case
'http':
$port = 80; // http 的默认端口
break;
case
'https':
$port = 443; // https 的默认端口
break;
case
'ftp':
$port = 21; // ftp 的默认端口
break;
case
'ftps':
$port = 990; // ftps 的默认端口
break;
default:
$port = 0; // 错误;不支持的协议
break;
}
} else {
$port = 0; // 错误;未知协议
}
}
return
$port;
}

$url = "http://nl3.php.net/manual/en/function.parse-url.php";
$urlInfo = parse_url( $url );
$urlPort = getUrlPort( $urlInfo );
if(
$urlPort !== 0 ) {
print
'找到 URL 端口:'.$urlPort;
} else {
print
'错误:无法在 URL 中找到端口:'.$url;
}
?>
bramg dot net1 at gmail dot com
5年前
这是我的 404 错误页面,可以吗?还是需要改进?

<?php
/**
* 404.php
*
* 用于显示 404 页面(未找到)的模板
*
* @author BetterStudio
* @package Publisher
* @version 2.0.2
*/

get_header();

// 显示面包屑导航
if ( publisher_show_breadcrumb() ) {
Better_Framework()->breadcrumb()->generate( array(
'before' => '<div class="container bf-breadcrumb-container">',
'after' => '</div>',
'custom_class' => 'bc-top-style'
) );
}

?>
<div class="content-wrap">
<main <?php publisher_attr( 'content', '' ); ?>>

<div class="container layout-1-col layout-no-sidebar">
<div class="row main-section">

<div class="content-column content-404">

<div class="row first-row">

<div class="col-lg-12 text-404-section">
<p class="text-404 heading-typo">404</p>
</div>

<div class="col-lg-12 desc-section">
<h1 class="title-404"><?php publisher_translation_echo( '404_not_found' ); ?></h1>
<p><?php publisher_translation_echo( '404_not_found_message' ); ?></p>
<div class="action-links clearfix">

<script type="text/javascript">
if (document.referrer) {
document.write('<div class="search-action-container"><a href="' + document.referrer + '"><i class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_previous_page' ); ?></a></div>');
}
</script>

<div class="search-action-container">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><i
class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_homepage' ); ?>
</a>
</div>
</div>
</div>

</div><!-- .first-row -->

<div class="row second-row">
<div class="col-lg-12">
<div class="top-line">
<?php get_search_form(); ?>
</div>
</div>
</div><!-- .second-row -->

</div><!-- .content-column -->

</div><!-- .main-section -->
</div> <!-- .layout-1-col -->

</main><!-- main -->
</div><!-- .content-wrap -->

<?php get_footer(); ?>

https://bramg.net
jesse at example dot com
13 年前
@ solenoid: 你的代码非常有用,但在当前 URL 没有查询字符串时会失败(它会在查询之前附加 '&' 而不是 '?')。以下是修正后的版本,它可以捕获此边缘情况并进行修正。

<?php
function modify_url($mod)
{
$url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$query = explode("&", $_SERVER['QUERY_STRING']);
if (!
$_SERVER['QUERY_STRING']) {$queryStart = "?";} else {$queryStart = "&";}
// 修改/删除数据
foreach($query as $q)
{
list(
$key, $value) = explode("=", $q);
if(
array_key_exists($key, $mod))
{
if(
$mod[$key])
{
$url = preg_replace('/'.$key.'='.$value.'/', $key.'='.$mod[$key], $url);
}
else
{
$url = preg_replace('/&?'.$key.'='.$value.'/', '', $url);
}
}
}
// 添加新数据
foreach($mod as $key => $value)
{
if(
$value && !preg_match('/'.$key.'=/', $url))
{
$url .= $queryStart.$key.'='.$value;
}
}
return
$url;
}
?>
solenoid at example dot com
14 年前
以下代码片段用于修改、替换或删除 URL 查询。这通常用于分页场景中,其中除了页面之外还有更多参数。

<?php
function modify_url($mod)
{
$url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$query = explode("&", $_SERVER['QUERY_STRING']);
// 修改/删除数据
foreach($query as $q)
{
list(
$key, $value) = explode("=", $q);
if(
array_key_exists($key, $mod))
{
if(
$mod[$key])
{
$url = preg_replace('/'.$key.'='.$value.'/', $key.'='.$mod[$key], $url);
}
else
{
$url = preg_replace('/&?'.$key.'='.$value.'/', '', $url);
}
}
}
// 添加新数据
foreach($mod as $key => $value)
{
if(
$value && !preg_match('/'.$key.'=/', $url))
{
$url .= '&'.$key.'='.$value;
}
}
return
$url;
}

// 页面 URL: "http://www.example.com/page.php?p=5&show=list&style=23"

$url = modify_url(array('p' => 4, 'show' => 'column'));

// $url = "http://www.example.com/page.php?p=4&show=column&style=23"
?>
admin at griefer1999 dot uhostfull dot com
9 年前
<?php
function url_parse($url){
$sflfdfldf=$url;
if(
strpos($url,"?")>-1){
$a=explode("?",$url,2);
$url=$a[0];
$query=$a[1];
}
if(
strpos($url,"://")>-1){
$scheme=substr($url,0,strpos($url,"//")-1);
$url=substr($url,strpos($url,"//")+2,strlen($url));
}
if(
strpos($url,"/")>-1){
$a=explode("/",$url,2);
$url=$a[0];
$path="/".$a[1];
}
if(
strpos($url,":")>-1){
$a=explode(":",$url,2);
$url=$a[0];
$port=$a[1];
}
$host=$url;
$url=null;
foreach(array(
"url","scheme","host","port","path","query") as $var){
if(!empty($
$var)){
$return[$var]=$$var;
}
}
//return array("url"=>$sflfdfldf,"scheme"=>$scheme,"host"=>$host,"port"=>$port,"path"=>$path,"query"=>$query,"a"=>$url);
return $return;
}
?>

<?php
/* 比较两个输出 */
// 我的
print_r(url_parse("http://login.yahoo.com?.src=ym&.intl=gb&.lang=zh-Hans-HK&.done=https://mail.yahoo.com"));
// 内部
print_r(parse_url("http://login.yahoo.com?.src=ym&.intl=gb&.lang=zh-Hans-HK&.done=https://mail.yahoo.com"));
?>
theking2(at)king.ma
6 个月前
在 URL 中使用双斜杠 (//) 将被视为不可解析的字符串,并将返回 NULL

<?php
$result
= parse_url('http://api.example.com//resource');

// $result = null

?>

在 PHP 8.1.27 上测试
info at canadiancybertech dot com
5 个月前
虽然与上述内容没有直接关系,但我发现这个页面正在寻找如何访问 REST 样式的 domain.com?key1=value1&key2=value2 类型参数的方法。 在阅读了页面和评论后,想添加这一点来帮助可能发现自己在这里寻找相同解决方案的其他人。

假设:domain.com?key1=value1&key2=value2

echo $_GET['key2']; // 输出:'value2'

PHP 使这比任何其他语言都更容易,IMO。
xellisx
15 年前
我需要从引用程序中解析出查询字符串,所以我创建了这个函数。

<?php
function parse_query($val)
{
/**
* 使用此函数从
* parse_url() 的输出中解析出查询数组元素。
*/
$var = html_entity_decode($var);
$var = explode('&', $var);
$arr = array();

foreach(
$var as $val)
{
$x = explode('=', $val);
$arr[$x[0]] = $x[1];
}
unset(
$val, $x, $var);
return
$arr;
}
?>
kibblewhite+php at live dot com
3 年前
此函数 'parse_rebuild_url' 将解析并重新组装您的 URL,其中 'overwrite_parsed_url_array' 提供的新值将被重新组装在一起。
也可以通过键名覆盖 URL 组件,以及合并或覆盖查询参数。
<?php

$test_url
= 'http://usr:[email protected]:81/mypath/myfile.html?a=b&b[]=2&b[]=3&z=9#myfragment';

$new_url_01_overwrite_query_params = parse_rebuild_url( $test_url, array(
'host' => 'new-hostname.tld',
'query' => array(
'test' => 'Hello World',
'a' => array( 'c', 'd' ),
'z' => 8
),
'fragment' => 'new-fragment-value'
), false );

$new_url_02_mergewith_query_params
= parse_rebuild_url( $test_url, array(
'query' => array(
'test' => 'Hello World',
'a' => array( 'c', 'd' ),
'z' => 8
),
'fragment' => 'new-fragment-value'
), true );

function
parse_rebuild_url( $url, $overwrite_parsed_url_array, $merge_query_parameters = true ) {

$parsed_url_array = parse_url( $url );
$parsed_url_keys_array = array(
'scheme' => null,
'abempty' => isset( $parsed_url_array['scheme'] ) ? '://' : null,
'user' => null,
'authcolon' => isset( $parsed_url_array['pass'] ) ? ':' : null,
'pass' => null,
'authat' => isset( $parsed_url_array['user'] ) ? '@' : null,
'host' => null,
'portcolon' => isset( $parsed_url_array['port'] ) ? ':' : null,
'port' => null,
'path' => null,
'param' => isset( $parsed_url_array['query'] ) ? '?' : null,
'query' => null,
'hash' => isset( $parsed_url_array['fragment'] ) ? '#' : null,
'fragment' => null
);

if ( isset(
$parsed_url_array['query'] ) && $merge_query_parameters === true ) {
parse_str( $parsed_url_array['query'], $query_array );
$overwrite_parsed_url_array['query'] = array_merge_recursive( $query_array, $overwrite_parsed_url_array['query'] );
}

$query_parameters = http_build_query( $overwrite_parsed_url_array['query'], null, '&', PHP_QUERY_RFC1738 );
$overwrite_parsed_url_array['query'] = urldecode( preg_replace( '/%5B[0-9]+%5D/simU', '%5B%5D', $query_parameters ) );

$fully_parsed_url_array = array_filter( array_merge( $parsed_url_keys_array, $parsed_url_array, $overwrite_parsed_url_array ) );
return
implode( null, $fully_parsed_url_array );

}
JosephDor
1年前
你好!<a href=https://stromectolxf.online/>ivermectin 24 毫克</a> 优秀网站 https://stromectolrf.top
匿名
6 年前
您好,出于某种奇怪的原因,当输入 URL 中没有提供 scheme 时,parse_url 会将主机(例如 example.com)作为路径返回。所以我写了一个快速函数来获取真实的主机。

<?php
function getHost($Address) {
$parseUrl = parse_url(trim($Address));
return
trim($parseUrl[host] ? $parseUrl[host] : array_shift(explode('/', $parseUrl[path], 2)));
}

getHost("example.com"); // 返回 example.com
getHost("http://example.com"); // 返回 example.com
getHost("www.example.com"); // 返回 www.example.com
getHost("http://example.com/xyz"); // 返回 example.com
?>

你可以尝试任何东西!它会返回主机(包括子域,如果存在)。

希望它对你有帮助。
https://vb.3dlat.com/
匿名
6 年前
要获取参数(URL 查询)作为关联数组,使用此函数

<?php
/**
* 返回 URL 查询作为关联数组
*
* @param string query
* @return array params
*/
function convertUrlQuery($query) {
$queryParts = explode('&', $query);

$params = array();
foreach (
$queryParts as $param) {
$item = explode('=', $param);
$params[$item[0]] = $item[1];
}

return
$params;
}
?>
To Top