URL 標準僅允許 ASCII 字元。中文、空格、&、=、+、%、# 等特殊字元直接放入 URL 會導致解析錯誤、參數截斷、資安風險(XSS、SQL Injection)。不同瀏覽器對空格編碼為 + 或 %20 行為不一,伺服端接收更不穩定。
<?php
$text = '中文 & 特殊字元';
$url = 'target.php?data=' . urlencode($text);
// 輸出:target.php?data=%E4%B8%AD%E6%96%87+%26+%E7%89%B9%E6%AE%8A%E5%AD%97%E5%85%83
// 接收端
$data = urldecode($_GET['data'] ?? '');
?>
base64 產生的 +、/、= 在 URL 中有特殊含義,需替換為安全字元。
<?php
function urlSafeBase64Encode($str)
{
$encoded = base64_encode($str);
// 替換 URL 不安全字元
return strtr($encoded, '+/=', '-_,');
}
function urlSafeBase64Decode($str)
{
// 還原
$decoded = strtr($str, '-_,', '+/=');
return base64_decode($decoded);
}
// 使用
$original = 'user_id=1001&role=admin&permissions=read,write,delete';
$encoded = urlSafeBase64Encode($original);
$url = "api.php?token=$encoded";
// 解碼
$decoded = urlSafeBase64Decode($_GET['token'] ?? '');
?>
strtr 效能優於 str_replace,單次替換多字元。+ → -、/ → _、= → ,(或任意不衝突字元)。<?php
$data = ['uid' => 1001, 'roles' => ['admin', 'editor'], 'exp' => time()+3600];
$token = urlSafeBase64Encode(json_encode($data, JSON_UNESCAPED_UNICODE));
// 傳遞 $token
$received = json_decode(urlSafeBase64Decode($_GET['token']), true);
?>
若傳遞資料需防偽造,請使用 firebase/php-jwt 簽署 Token,而非單純編碼。
| 錯誤做法 | 後果 | 正確做法 |
|---|---|---|
直接拼接中文 url.php?name=中文 | 瀏覽器編碼不一、伺服端亂碼 | urlencode() |
| base64 後直接放入 URL | + 被解析為空格、/ 切斷路徑、= 截斷參數 | 替換不安全字元(strtr) |
用 rawurlencode 編碼空格為 %20 但伺服端用 urldecode(預期 +) | 空格解碼失敗 | 統一用 urlencode/urldecode 或 rawurlencode/rawurldecode |
| GET 請求傳遞大量資料(>2KB) | 超過瀏覽器/伺服器 URL 長度限制 | 改用 POST + Body 傳輸 |
| 函式 | 空格編碼 | 適用場景 |
|---|---|---|
urlencode | + | 表單資料、查詢字串 |
rawurlencode | %20 | 路徑片段、符合 RFC 3986 |
urldecode | 解碼 + 為空格 | 搭配 urlencode |
rawurldecode | 不處理 + | 搭配 rawurlencode |