首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP URL 解析與查詢字串操作完全指南:parse_url、http_build_query、PSR-7 Uri、修改/刪除/合併參數

     編輯:PHP 綜合知識

URL 處理是 Web 開發高頻需求:解析元件、取得/設定查詢參數、建立重導向 URL、合併多組參數、移除追蹤參數。本文對比原生函數、PSR-7 `UriInterface`、第三方庫 (league/uri) 的適用場景,並提供可重用的 `UrlQuery` 工具類。

一、原生函數對比

函數用途回傳注意
parse_url()分解 URL 為關聯陣列['scheme','host','path','query','fragment',...]不解析 query 字串,僅回傳原始字串
parse_str()解析 query 字串填入陣列void (填入參考變數)會覆蓋同名鍵,建議用 `parse_str($q, $arr)`
http_build_query()陣列編碼為 query 字串string支援巢狀陣列 `foo[bar]=baz`,`PHP_QUERY_RFC3986` 空格編碼為 %20
urldecode()/rawurldecode()解碼string`raw` 版不將 + 轉空格,符合 RFC 3986

二、基礎操作範例

<?php
$url = 'https://example.com/path?a=1&b=2&c=3#section';

// 1. 取得查詢參數陣列
parse_str(parse_url($url, PHP_URL_QUERY), $query);
// $query = ['a'=>'1','b'=>'2','c'=>'3']

// 2. 修改/新增參數
$query['b'] = '20';
$query['d'] = '4';

// 3. 重建 URL
$newUrl = parse_url($url, PHP_URL_SCHEME).'://'.parse_url($url, PHP_URL_HOST).
          parse_url($url, PHP_URL_PATH).'?'.http_build_query($query).
          (parse_url($url, PHP_URL_FRAGMENT) ? '#'.parse_url($url, PHP_URL_FRAGMENT) : '');
// https://example.com/path?a=1&b=20&c=3&d=4#section

// 4. 刪除參數
unset($query['c']);
$cleanUrl = ... // 同理重建
?>

三、PSR-7 UriInterface:不可變、鏈式操作

composer require nyholm/psr7
<?php
use Nyholm\Psr7\Factory\Psr17Factory;
use Psr\Http\Message\UriInterface;

$factory = new Psr17Factory();
$uri = $factory->createUri('https://example.com/path?a=1&b=2');

// 取得查詢參數 (需自行 parse_str)
parse_str($uri->getQuery(), $query);

// 修改參數 -> 產生新 Uri 物件
$newUri = $uri->withQuery(http_build_query(array_merge($query, ['b' => '20', 'd' => '4'])));
// 刪除參數
$newUri = $uri->withQuery(http_build_query(array_diff_key($query, ['c' => ''])));

// 解析主機/路徑
echo $uri->getHost(); // example.com
echo $uri->getPath(); // /path
?>

四、通用工具類:UrlQuery

<?php
declare(strict_types=1);

namespace App\Http;

class UrlQuery {
    private array $params = [];
    private string $baseUrl = '';
    private string $fragment = '';

    public static function fromString(string $url): self {
        $self = new self();
        $parts = parse_url($url);
        $self->baseUrl = ($parts['scheme'] ?? '').'://'.($parts['host'] ?? '').($parts['path'] ?? '');
        if (!empty($parts['query'])) parse_str($parts['query'], $self->params);
        $self->fragment = $parts['fragment'] ?? '';
        return $self;
    }

    public static function fromCurrentRequest(): self {
        $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http')
             .'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        return self::fromString($url);
    }

    public function get(string $key, mixed $default = null): mixed {
        return $this->params[$key] ?? $default;
    }

    public function set(string $key, mixed $value): self {
        $clone = clone $this;
        $clone->params[$key] = $value;
        return $clone;
    }

    public function setMultiple(array $data): self {
        $clone = clone $this;
        $clone->params = array_merge($clone->params, $data);
        return $clone;
    }

    public function remove(string ...$keys): self {
        $clone = clone $this;
        foreach ($keys as $k) unset($clone->params[$k]);
        return $clone;
    }

    public function removeMatching(string $pattern): self {
        $clone = clone $this;
        $clone->params = array_filter($clone->params, fn($k) => !preg_match($pattern, $k), ARRAY_FILTER_USE_KEY);
        return $clone;
    }

    public function toString(): string {
        $query = http_build_query($this->params, '', '&', PHP_QUERY_RFC3986);
        return $this->baseUrl . ($query ? '?'.$query : '') . ($this->fragment ? '#'.$this->fragment : '');
    }

    public function __toString(): string { return $this->toString(); }
}

// 使用
$url = UrlQuery::fromString('https://shop.com/list?cat=12&page=3&sort=price#top')
    ->set('page', 5)
    ->remove('sort')
    ->removeMatching('/^utm_/'); // 移除追蹤參數
echo $url; // https://shop.com/list?cat=12&page=5#top
?>

五、進階場景

  1. 合併多個來源:`$merged = array_merge($defaultParams, $userParams, $requestParams);`
  2. 分頁保持其他參數:``
  3. OAuth 回調重建:保留 `state`、`code`,移除 `error` 等。
  4. API 簽名參數排序:`ksort($params); $signStr = http_build_query($params, '', '&', PHP_QUERY_RFC3986);`

六、常見坑

  • parse_str 不支援巢狀陣列 `a[b][c]=1` (會變成 `a_b_c`),需手動解析或用 `league/uri`。
  • http_build_query 預設空格編碼為 `+`,API 簽名需 `PHP_QUERY_RFC3986` 產生 `%20`。
  • URL 片段 `#fragment` **不會傳送到伺服器**,純前端路由使用。
  • 國際化域名 (IDN) 需 `idn_to_ascii()` / `idn_to_utf8()` 轉換。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved