核心邏輯
function ensure_http_scheme(string $url): string {
$url = trim($url);
if ($url === '') return '';
// 檢測是否已有協議
if (!preg_match('~^(?:https?|ftp)://~i', $url)) {
$url = 'https://' . $url;
}
return $url;
}
// 表單處理範例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$url = ensure_http_scheme($_POST['url'] ?? '');
// 後續驗證、存儲...
}
正則詳解
~^ # 字符串開頭
(?: # 非捕獲組
https? # http 或 https
|ftp # 或 ftp
):// # 後接 ://
~i # 不區分大小寫
進階:URL 格式驗證與標準化
function normalize_url(string $url): ?string {
$url = trim($url);
if ($url === '') return null;
// 補全協議
if (!preg_match('~^[a-z][a-z0-9+.-]*://~i', $url)) {
$url = 'https://' . $url;
}
// 解析並重建(移除默認端口、規範化路徑等)
$parts = parse_url($url);
if ($parts === false) return null;
$scheme = $parts['scheme'] ?? 'http';
$host = strtolower($parts['host'] ?? '');
$port = $parts['port'] ?? '';
$path = $parts['path'] ?? '/';
$query = isset($parts['query']) ? '?' . $parts['query'] : '';
$frag = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
// 移除默認端口
if (($scheme === 'http' && $port === 80) || ($scheme === 'https' && $port === 443)) {
$port = '';
}
$portStr = $port ? ':' . $port : '';
// 路徑規範化:移除多餘 /./, /../ 等(可選)
// $path = normalize_path($path);
return "$scheme://$host$portStr$path$query$frag";
}
安全考量
- 補全
https:// 可能導致 HTTPS 站點降級;建議優先嘗試 HTTPS 或由用戶明確選擇。
- 存儲前務必 驗證 URL 可達性 (HEAD 請求) 或至少語法合法。
- 輸出到 HTML 時使用
htmlspecialchars() 防 XSS。
- 資料庫欄位長度建議 2048 (RFC 3986 建議)。
HTML5 表單原生支援
<input type="url" name="url" placeholder="https://example.com" required>