文字中混雜:
https://example.com → 需轉換<a href="...">...</a> → 不可動<img src="..."> → 不可動<a>、<img> 標籤,暫存原始標籤陣列。<a> 標籤。
function autoLinkUrls(string $text): string {
// 階段 1:保護既有 和
$placeholders = [];
$protected = $text;
// 保護 標籤(含巢狀屬性、單雙引號)
$protected = preg_replace_callback(
'/]*href\s*=\s*["\'][^"\']*["\'][^>]*>.*?<\/a>/is',
function ($m) use (&$placeholders) {
$ph = '{{AUTO_LINK_PLACEHOLDER_A_' . count($placeholders) . '}}';
$placeholders[$ph] = $m[0];
return $ph;
},
$protected
);
// 保護
標籤
$protected = preg_replace_callback(
'/
]*src\s*=\s*["\'][^"\']*["\'][^>]*>/i',
function ($m) use (&$placeholders) {
$ph = '{{AUTO_LINK_PLACEHOLDER_IMG_' . count($placeholders) . '}}';
$placeholders[$ph] = $m[0];
return $ph;
},
$protected
);
// 階段 2:轉換純文字 URL
// 正則:協定可選、www 可選、IP 或域名、埠號、路徑、查詢、片段
$urlRegex = '~
(?: # 協定(可選)
(?:https?|ftps?):// # https:// https:// ftp:// ftps://
| # 或
www\. # www. 開頭
)
(?: # 主機
(?:[a-z0-9-]+\.)+[a-z]{2,} # 標準域名
| # 或
\d{1,3}(?:\.\d{1,3}){3} # IPv4
)
(?::\d+)? # 選擇性埠號
(?:/[^\s<>"\']*)? # 選擇性路徑(不含空白、<、>、引號)
(?:\?[^\s<>"\']*)? # 選擇性查詢字串
(?:#[^\s<>"\']*)? # 選擇性片段
~ix';
$linked = preg_replace_callback($urlRegex, function ($m) {
$url = $m[0];
// 確保有協定
if (!preg_match('~^https?://|ftps?://~i', $url)) {
$url = 'https://' . $url;
}
return '' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '';
}, $protected);
// 階段 3:還原佔位符
foreach ($placeholders as $ph => $original) {
$linked = str_replace($ph, $original, $linked);
}
return $linked;
}
// 測試
$text = '訪問 https://example.com 和 www.google.com,但保留 既有連結 和
圖片。';
echo autoLinkUrls($text);
~ix 修飾符:i 大小寫不敏感、x 忽略正則內空白與註解(可讀性)。(?:https?|ftps?)://|www\. 涵蓋常見協定與無協定 www 開頭。[^\s<>"\'] 避免吞噬 HTML 標籤屬性、引號、空白。htmlspecialchars 防 XSS,rel="noopener noreferrer" 安全新分頁。$urlRegex,避免重複編譯。autolinker.js 前端渲染,減輕後端壓力。「保護 → 轉換 → 還原」三階段佔位符法,能完美解決「不破壞既有標籤」的核心需求。搭配嚴謹的 URL 正則、XSS 防護、效能優化,即可在論壇、評論、CMS 內容中安全部署自動連結功能。