PHP Conference Japan 2024

parse_url

(PHP 4、PHP 5、PHP 7、PHP 8)

parse_url解析 URL 並傳回其元件

說明

parse_url(字串 $url, 整數 $component = -1): 整數|字串|陣列|null|false

此函式解析 URL 並傳回一個包含 URL 各種元件的關聯陣列。陣列元素的數值並未經過 URL 解碼。

此函式並非用來驗證給定的 URL,它僅將其分解為以下列出的各個部分。也接受不完整和無效的 URL,parse_url() 會盡力正確解析它們。

注意

此函式可能無法針對相對或無效的 URL 給出正確結果,並且結果甚至可能與 HTTP 用戶端的常見行為不符。如果需要解析來自不受信任輸入的 URL,則需要額外的驗證,例如使用帶有 FILTER_VALIDATE_URL 過濾器的 filter_var()

參數

url

要解析的 URL。

component

指定 PHP_URL_SCHEMEPHP_URL_HOSTPHP_URL_PORTPHP_URL_USERPHP_URL_PASSPHP_URL_PATHPHP_URL_QUERYPHP_URL_FRAGMENT 其中之一,以僅擷取特定的 URL 元件作為 字串(除了給定 PHP_URL_PORT 的情況外,在這種情況下,傳回值將為 整數)。

傳回值

對於嚴重格式錯誤的 URL,parse_url() 可能會傳回 false

如果省略 component 參數,則會傳回關聯的 陣列。陣列中至少會存在一個元素。此陣列中可能的鍵包括:

  • scheme - 例如 http
  • host
  • port
  • user
  • pass
  • path
  • query - 問號 ? 之後
  • fragment - 井字號 # 之後

如果指定了 component 參數,則 parse_url() 會傳回 字串(或在 PHP_URL_PORT 的情況下,傳回 整數),而不是 陣列。如果請求的元件在給定的 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:缺少 scheme 的 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,而不是 URI。但是,為了符合 PHP 的向後相容性要求,它會對 file:// scheme 進行例外處理,其中允許使用三個斜線 (file:///...)。對於任何其他 scheme,這都是無效的。

參見

新增註解

使用者貢獻的註解 38 則註解

193
thomas at gielfeldt dot com
13 年前
[如果您還沒有]找到從已解析 URL 轉換回字串的簡單方法,這裡有一個範例

<?php

$url
= 'http://usr:pss@example.com: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";
}

?>
44
lauris () lauris ! lv
10 年前
這是基於 "laszlo dot janszky at gmail dot com" 的作品,一個與 UTF-8 相容的 parse_url() 替換函式。原始碼不正確地處理了帶有 user:pass 的 URL。同時也相容於 PHP 5.5(去除了現在已棄用的 regex /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('格式錯誤的 URL: ' . $url);
}

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

return
$parts;
}

?>
41
jerome at chaman dot ca
9 年前
值得提醒的是,#fragment 的值永遠不會被傳送到伺服器。錨點處理完全是在客戶端進行的。
3
nospam at spellingcow dot com
16 年前
相對 URL 的查詢字串中的 URL 會導致問題

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

解析為
http://www.foo.com/page.php?foo=bar&url=http://www.example.com
3
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:從基本路徑中刪除檔案
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);
}
?>
46
james at roundeights dot com
14 年前
我正在編寫單元測試,需要讓此函式拋出錯誤並返回 FALSE,以測試特定的執行路徑。如果有人需要強制失敗,可以使用以下輸入

<?php
parse_url
("http:///example.com");
parse_url("http://:80");
parse_url("http://user@:80");
?>
17
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!"; // 定界符號

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

return
$out;
}
print_r ( parseUrl ( 'me:you@sub.site.org:29000/pear/validate.html?happy=me&sad=you#url' ) );
?>

這會回傳
陣列
(
[0] => me:you@sub.site.org: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
)

所以可以使用具名和編號的陣列鍵值。

這相當進階,但我認為它在任何情況下都有效... 如果不是,請告訴我...
5
pjpawel
2 年前
很遺憾地,parse_url() 無法正確解析沒有協定或 '//' 的 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'
4
therselman at gmail
12 年前
支援 UTF-8 的 parse_url() 替代方案。

我發現即使 UTF-8 字元在 URL 中是不允許的,我仍然需要處理大量的 UTF-8 字元,而 parse_url() 會出錯。

我主要根據 "mallluhuct at gmail dot com" 的成果,加入了與 parse_url() 相容的「具名值」,這使得陣列值的處理更加容易(而不是僅僅使用數字)。我也實作了連接埠、使用者名稱/密碼的偵測,以及更好的反向參考,以偵測像這樣的 URL://en.wikipedia.com
...雖然這在技術上是無效的 URL,但在像維基百科這樣的網站中,錨點標籤的 href 中廣泛使用,這在瀏覽器中是有效的(這是你在網頁爬取時必須支援的 URL 類型之一)。這將被準確地偵測為主機名稱,而不是像其他範例中的「路徑」。

我將提交我的完整函式(而不僅僅是 RegExp),這幾乎是 parse_url() 的「直接替換」。它會回傳一個清理過的陣列(或 false),其值與 parse_url() 相容。我可以告訴 preg_match() 不要儲存未使用的額外值,但這會使 RegExp 複雜化,並使其更難以閱讀、理解和擴展。偵測 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 可以/應該被「正規化」。
1
theking2(at)king.ma
10 個月前
在 URL 中使用雙斜線 ('//') 會被視為無法解析的字串,並會回傳 NULL

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

// $result = null

?>

已使用 PHP 8.1.27 測試
6
mys5droid at gmail dot com
8 年前
我為我的一個專案編寫了一個函式,將相對 URL 轉換為絕對 URL。考慮到我在其他地方找不到它,我想我應該把它貼在這裡。

以下函式接收兩個參數,第一個參數是您要從相對 URL 轉換為絕對 URL 的 URL,第二個參數是絕對 URL 的範例。

目前它不會解析 URL 中的 '../',只是因為我不需要它。大多數網路伺服器會為您解析這個。如果您希望它解析路徑中的 '../',只需進行少量修改即可。

<?php

function relativeToAbsolute($inurl, $absolute) {
// 取得所有部分,避免多次取得 :)
$absolute_parts = parse_url($absolute);
// 測試 URL 是否已為絕對路徑 (包含主機名稱,或以 '/' 開頭)
if ( (strpos($inurl, $absolute_parts['host']) == false) ) {
// 定義 $tmpurlprefix 以避免以下錯誤
$tmpurlprefix = "";
// 建立 URL 前綴 (SCHEME)
if (!(empty($absolute_parts['scheme']))) {
// 將 scheme 加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['scheme'] . "://";
}
// 建立 URL 前綴 (USER, PASS)
if ((!(empty($absolute_parts['user']))) and (!(empty($absolute_parts['pass'])))) {
// 將 user:port 加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['user'] . ":" . $absolute_parts['pass'] . "@";
}
// 建立 URL 前綴 (HOST, PORT)
if (!(empty($absolute_parts['host']))) {
// 將 host 加到 tmpurlprefix
$tmpurlprefix .= $absolute_parts['host'];
// 檢查是否有 port,如果存在則加入
if (!(empty($absolute_parts['port']))) {
// 將 port 加到 tmpurlprefix
$tmpurlprefix .= ":" . $absolute_parts['port'];
}
}
// 建立 URL 前綴 (PATH) 並且只有在圖片路徑不包含 ./ 時才加入
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:pass@example.com:8080/path/to/index.html"; // 只是為了避免 php.net 的垃圾郵件過濾器,不確定 example.com 為何是垃圾郵件...

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

?>

輸出結果
http:// user:pass@example.com:8080/path/to/index.html
http:// user:pass@example.com:8080/path/to/img.gif
http:// user:pass@example.com:8080/img.gif
http:// user:pass@example.com:8080/path/to/img.gif
http:// user:pass@example.com:8080/path/to/../img.gif
http:// user:pass@example.com:8080/path/to/images/img.gif
http:// user:pass@example.com:8080/images/img.gif
http:// user:pass@example.com:8080/path/to/images/img.gif
http:// user:pass@example.com:8080/path/to/../images/img.gif

如果以上程式碼不是你喜歡的風格,或者你覺得它「雜亂」,或是你認為有更好的方法來完成它,請見諒。我盡可能地移除了空白。

歡迎改進 :)
2
Michael
5 年前
這個函式有一個怪癖,如果前面有空格,它會將主機名稱回傳為「路徑」。

<?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
)
*/

?>
7
utilmind
11 年前
如果沒有指定協定,parse_url 無法運作。這似乎是標準,即使是 YouTube 在產生嵌入程式碼時,也沒有提供協定名稱,看起來像 "//youtube.com/etc"。

因此,為了避免錯誤,你必須總是檢查提供的 URL 是否有協定,如果沒有(以兩個斜線開頭)-- 加入 "http:" 前綴。
3
demerit
7 年前
PHP 7 中有一個變更(我從 5.3 升級到 7.1 時注意到),如果密碼部分包含井字號 (#),在 7.1 中解析會失敗,但在 5.3 中會成功。
1
boctulus @ gmail co!m
5 年前
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;
}
}
16
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;
}

// show youtube on my page
$url='http://www.youtube.com/watch?v=yvTd6XxgCBE';
youtube($url, 560, 315, true);
?>

parse_url () 會配置一個獨特的 YouTube 代碼,並將其放入 iframe 連結中,顯示在您的頁面上。影片的尺寸可以自行選擇。

請享用。
4
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;
}
/**
* 從各部分陣列 (由 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);
}
}

?>
8
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;
}
?>
7
nirazuelos at gmail dot com
15 年前
您好,由於某些奇怪的原因,當輸入的 URL 中未提供協定時,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
?>

你可以嘗試任何東西!它會傳回主機(如果存在,包含子網域)。

希望對您有幫助。
2
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:從基本路徑中捨棄檔案
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);
}
1
vbrazas15 at gmail dot com
3 年前
我對「thomas at gielfeldt dot com」著名的 `unparse_url` 函式進行了一些微小的改進

```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";
}
```
1
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/
2
Rob
9 年前
我一直在開發一個通用的類別,可以讓 URI 解析/建構更容易一些。

Composer 套件在此:https://packagist.org/packages/enrise/urihelper

儲存庫在此:https://github.com/Enrise/UriHelper

用法範例

<?php
$uri
= new \Enrise\Uri('http://usr:pss@example.com: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:pss@example.com/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment
?>
5
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

希望這對某些人有幫助!
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']);
?>
2
vdklah at hotmail dot com
16 年前
一些判斷 URL 連接埠的範例。
當未指定連接埠時,它會從方案中推導出來。

<?php
function getUrlPort( $urlInfo )
{
if( isset(
$urlInfo['port']) ) {
$port = $urlInfo['port'];
} else {
// 沒有指定 port;取得預設 port
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; // 錯誤;不支援的 scheme
break;
}
} else {
$port = 0; // 錯誤;未知的 scheme
}
}
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 的 port:'.$urlPort;
} else {
print
'錯誤:無法在 URL 中找到 port:'.$url;
}
?>
1
simbappo
4 年前
從傳入或目前的 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'];
}
3
jesse at example dot com
14 年前
@ 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;
}
?>
1
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;
}

// 頁面網址:「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
?>
2
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"));
?>
2
simohammed dot sd at gmail dot com
3 個月前
請考慮以下提示和案例

1. 處理片段標識符

parse_url() 會處理片段標識符 (#section),但片段不會傳送到伺服器,僅在客戶端使用。當依賴片段資料時請謹慎,因為它可能無法在伺服器端處理中使用。

2. URL 編碼和解碼問題

parse_url() 不會解碼路徑中 URL 編碼的字元。如果涉及特殊字元,請確保正確處理編碼和解碼。

例如
$url = 'https://www.primeogroup.com/es/servicios-de-configuraci%C3%B3n-instalaci%C3%B3n-y-an%C3%A1lisis-de-google-analytics/';
// /es/servicios-de-configuraci%C3%B3n-instalaci%C3%B3n-y-an%C3%A1lisis-de-google-analytics/
$path = parse_url($url, PHP_URL_PATH);
// /es/servicios-de-configuración-instalación-y-análisis-de-google-analytics/
$decoded_path = urldecode($path);

3. 不尋常的埠號

parse_url() 無法正確處理有效範圍 (1-65535) 以外的埠號。

parse_url 將返回:bool(false)
0
info at canadiancybertech dot com
9 個月前
雖然與上述內容沒有直接關聯,我發現這個頁面正在尋找如何存取 REST 樣式的 domain.com?key1=value1&key2=value2 類型參數。閱讀此頁面和評論後,我想新增此內容以幫助其他可能在這裡尋求相同解決方案的人。

給定:domain.com?key1=value1&key2=value2

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

我認為 PHP 使這比幾乎任何其他語言都更容易。
1
xellisx
16 年前
我需要從 referrer 中解析出查詢字串,所以我建立了這個函式。

<?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;
}
?>
0
kibblewhite+php at live dot com
3 年前
這個函式 'parse_rebuild_url' 會解析並使用 'overwrite_parsed_url_array' 提供的新值將您的 URL 重新組裝回去。
也可以通過鍵名覆寫 URL 元件,並合併或覆寫查詢參數。
<?php

$test_url
= 'http://usr:pss@example.com: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 );

}
-2
JosephDor
1 年前
哈囉!<a href=https://stromectolxf.online/>ivermectin 24 毫克</a> 很棒的網站 https://stromectolrf.top
0
bramg dot net1 at gmail dot com
6 年前
這是我的 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
-5
Anonymous
6 年前
您好,由於某些奇怪的原因,當輸入的 URL 中未提供協定時,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/
-3
Anonymous
7 年前
若要取得參數(網址查詢字串)作為關聯陣列,請使用此函式

<?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