內容審核、評論過濾常需判斷用戶輸入是否包含外站連結。本文提供 all_external_link() 函數,提取字串中所有 HTTP(S) 連結的域名,與當前域名 ($_SERVER['HTTP_HOST']) 比對,若存在不同域名則視為有外鏈。
function all_external_link($text = '', $host = '') {
if (!$host) $host = $_SERVER['HTTP_HOST'];
// 匹配 http(s)://domain 部分
$pattern = '/https?:\/\/((?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,})/i';
if (!preg_match_all($pattern, $text, $matches)) {
return true; // 無連結視為無外鏈
}
foreach ($matches[1] as $domain) {
// 允許子域名 (如 api.example.com vs example.com)
if (strcasecmp($domain, $host) !== 0 && !endsWith($domain, '.' . $host)) {
return false; // 發現外鏈
}
}
return true;
}
// 輔助函數
function endsWith($haystack, $needle) {
return $needle === '' || substr($haystack, -strlen($needle)) === $needle;
}
// 測試
$text = '歡迎訪問 https://example.com 和 https://evil.com';
var_dump(all_external_link($text, 'example.com')); // false (含 evil.com)
var_dump(all_external_link($text, 'evil.com')); // false (含 example.com)
var_dump(all_external_link('只有 https://api.example.com', 'example.com')); // true (子域名允許)
$whitelist 參數,允許特定合作夥伴域名。example.com/share/... 但阻擋 example.com/phishing。t.cn、bit.ly 等短網址發 HEAD 請求獲取真實域名 (需非同步/快取)。preg_match_all 一次性提取,避免循環正則。example.com (無協定) 不會被檢測,可視需求補充匹配裸域名。