獲取、解析 URL 參數是 Web 開發高頻需求。PHP 提供多種內置方式,各有適用場景。本文系統梳理四大核心方法、正則補充、最佳實踐與陷阱避坑。
// 僅查詢字符串:name=tank&sex=1
$queryString = $_SERVER['QUERY_STRING'];
// 包含路徑:/index.php?name=tank&sex=1
$requestUri = $_SERVER['REQUEST_URI'];
// 完整 URL(需自行拼協議/域名/端口)
$fullUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http')
. '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$url = "https://localhost/index.php?name=tank&sex=1#top";
$info = pathinfo($url);
/*
Array(
[dirname] => https://localhost
[basename] => index.php?name=tank&sex=1#top
[extension] => php
[filename] => index
)
*/
// 注意:pathinfo 為文件路徑設計,對 URL 查詢/錨點不分離
$url = "https://user:pass@localhost:8080/index.php?name=tank&sex=1#top";
$parts = parse_url($url);
/*
Array(
[scheme] => http
[host] => localhost
[port] => 8080
[user] => user
[pass] => pass
[path] => /index.php
[query] => name=tank&sex=1
[fragment] => top
)
*/
// 解析查詢字符串為關聯數組
parse_str($parts['query'], $queryParams);
/*
Array(
[name] => tank
[sex] => 1
)
*/
parse_str();相對路徑需補全$url = "https://localhost/index.php?name=tank&sex=1#top";
echo basename($url); // index.php?name=tank&sex=1#top
// 同 pathinfo()['basename'],不推薦用於 URL
$query = "name=tank&sex=1&hobby[]=read&hobby[]=code&data[key]=val";
parse_str($query, $params);
/*
Array(
[name] => tank
[sex] => 1
[hobby] => Array([0]=>read, [1]=>code)
[data] => Array([key]=>val)
)
*/
// 自動處理數組語法 name[]、name[key]
// 注意:同名參數後覆蓋前,數組語法除外
$url = "https://localhost/index.php?name=tank&sex=1#top";
// 提取所有 key=value 對(含錨點)
preg_match_all('/([^?&=#]+)=([^]*)/', $url, $matches, PREG_SET_ORDER);
/*
[
['name=tank', 'name', 'tank'],
['sex=1', 'sex', '1'],
// #top 不匹配(無 =)
]
*/
// 提取含錨點
preg_match_all('/([^?&=#]+)=([^]*)|(#\w+)/', $url, $matches);
| 需求 | 推薦方法 | 代碼片段 |
|---|---|---|
| 獲取原始查詢字符串 | $_SERVER['QUERY_STRING'] | $qs = $_SERVER['QUERY_STRING']; |
| 解析完整 URL 結構 | parse_url() | $p = parse_url($url); |
| 查詢字符串轉關聯數組 | parse_str() | parse_str($p['query'], $params); |
| 獲取單個參數值 | $_GET['name'] | $name = $_GET['name'] ?? ''; |
| 構建/修改 URL | http_build_query() + parse_url() | $p['query'] = http_build_query($params); |
| 提取特定模式參數 | 正則 | preg_match_all(...) |
class UrlParser {
public static function parse(string $url): array {
$parts = parse_url($url);
$query = [];
if (isset($parts['query'])) {
parse_str($parts['query'], $query);
}
return array_merge($parts, ['query_params' => $query]);
}
public static function build(array $parts): string {
$query = $parts['query_params'] ?? [];
unset($parts['query_params']);
if ($query) {
$parts['query'] = http_build_query($query);
}
// 簡易重構(生產建議用 League\Uri 或 PSR-7 Uri)
return $parts['scheme'] . '://'
. ($parts['user'] ?? '') . ($parts['pass'] ? ':' . $parts['pass'] : '') . (@$parts['user'] ? '@' : '')
. $parts['host'] . ($parts['port'] ? ':' . $parts['port'] : '')
. $parts['path'] . ($parts['query'] ? '?' . $parts['query'] : '')
. ($parts['fragment'] ? '#' . $parts['fragment'] : '');
}
}
// 使用
$parsed = UrlParser::parse('https://api.com/users?page=2&size=20#list');
$parsed['query_params']['page'] = 3;
$newUrl = UrlParser::build($parsed); // https://api.com/users?page=3&size=20#list
urlencode() → %2520filter[name]=john 會被解析為數組,需手動處理或避免ID ≠ idparse_url('/path?query') 缺 scheme 會解析失敗,需補全掌握 parse_url() + parse_str() 黃金組合,覆蓋 95% URL 解析構建需求。