PHP 检测字符串是否包含外部链接的方法
在 Web 开发中,检测用户输入或文章内容是否包含指向其他域名的“外链”是常见的安全需求,常用于防止钓鱼攻击、引流跳转或垃圾信息注入。本文将展示如何使用 PHP 的正则表达式功能 `preg_match_all` 来高效识别字符串中的外部链接,并提供一个完整的函数实现。
核心逻辑与目标
检测外链的核心在于两个步骤:首先是 提取,即从混杂的文本中找出所有符合 URL 格式的字符串;其次是 校验,即对比提取出的 URL 域名是否与当前网站(本站)域名一致。如果存在不一致的域名,则该字符串包含外链。
准备条件
- PHP 环境:确保服务器已启用 PHP 并支持 `preg_*` 系列正则函数。
- 获取当前域名:通常使用超级全局变量
$_SERVER['HTTP_HOST']获取当前请求的主机名。
具体操作步骤
第1步:构建正则匹配规则
我们需要一个能够匹配常见 HTTP 和 HTTPS 协议的通用正则表达式。该表达式应能捕获协议头以及后续的域名部分。
$reg = '/http(?:s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}/';
http(?:s?)?:匹配 http 或 https。\/\/:匹配双斜杠。(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}:匹配域名主体及顶级域名(如 .com, .cn 等)。
第2步:提取所有匹配的 URL
使用 preg_match_all 函数在目标字符串中进行全局搜索,将所有匹配到的结果存入数组。我们将重点分析 $data[0](完整匹配串)或根据分组提取的子串。
preg_match_all($reg, $text, $data);
注意:原文代码中使用了 $data[1],但在上述正则中并未定义捕获组(括号),因此 $data[0] 才是完整匹配的 URL 列表。若需精确到域名,建议修改正则为带捕获组的格式,例如:'/http(?:s?):\/\/((?:[A-za-z0-9-]+\.)+[A-za-z]{2,4})/',此时 $data[1] 即为域名部分。
第3步:遍历比对域名
定义一个函数 has_external_link,接收待检测字符串和可选的目标域名参数。逻辑如下:
- 默认主机设置:若未传入域名参数,默认使用
$_SERVER['HTTP_HOST']作为本站域名。 - 空值检查:若字符串为空或无匹配项,直接返回不包含外链(
true)。 - 逐个比对:遍历提取出的每一个域名,若发现任一域名不等于本站域名,立即返回
false(表示有外链)。 - 安全结论:若遍历结束未发现不同域名,则返回
true(表示无外链)。
第4步:完整代码实现
结合上述逻辑,优化后的健壮代码如下:
/**
* 检测字符串是否包含外部链接
*
* @param string $text 待检测的文本内容
* @param string $current_host 当前站点域名,默认为 $_SERVER['HTTP_HOST']
* @return bool true 表示仅包含内部链接或无链接;false 表示包含外部链接
*/
function has_no_external_link($text = '', $current_host = '') {
// 如果没有提供主机名,尝试从服务器环境变量获取
if (empty($current_host)) {
$current_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
}
// 如果无法确定主机名,且需要严格检测,可能需调整策略
// 此处假设只要能获取 host 就进行比对
if (empty($current_host)) {
return false; // 保守起见,无法确认时视为有风险或需特殊处理
}
// 优化后的正则:明确捕获域名部分,方便后续比对
// 匹配 http:// 或 https:// 后跟随的域名
$pattern = '/https?:\/\/([a-zA-Z0-9\-]+\.)*[a-zA-Z]{2,}/';
preg_match_all($pattern, $text, $matches);
if (empty($matches[0])) {
return true; // 没有 URL,当然没有外链
}
foreach ($matches[0] as $url) {
// 从完整 URL 中提取域名部分进行比对
// 简单做法:移除协议头,截取第一个斜杠前的部分
$parsed_url = parse_url($url);
if ($parsed_url && isset($parsed_url['host'])) {
$host_in_text = $parsed_url['host'];
// 去除 www. 前缀以便更宽松地匹配(可选)
$clean_current_host = preg_replace('/^www\./', '', $current_host);
$clean_text_host = preg_replace('/^www\./', '', $host_in_text);
if ($clean_text_host !== $clean_current_host) {
return false; // 发现外链
}
}
}
return true; // 所有链接均为内部链接
}
// 示例用法
$text_content = "欢迎访问本站 http://example.com 或者查看外部资源 https://github.com";
$my_domain = "example.com";
if (has_no_external_link($text_content, $my_domain)) {
echo "内容为纯内部链接。";
} else {
echo "检测到外部链接!";
}
完成判断与维护
当函数返回 true 时,表示提供的字符串中不存在指向其他域名的链接,可以用于通过审核、保存数据等操作。若返回 false,则需根据业务逻辑决定是拦截、标记还是替换为相对路径。
注意事项:
- 协议兼容性:现代网站多使用 HTTPS,正则应涵盖
https:。 - 子域名处理:如需区分主域名和子域名(如
a.example.comvsb.example.com),应在比对逻辑中进一步细化域名解析规则。 - 性能考量:对于超长文本,建议使用
pcre.jit=1提升 PCRE JIT 性能,或使用更轻量级的字符串查找替代复杂正则。
以上就是PHP检查字符串中是否有外链的详细内容,更多关于PHP正则表达式应用与内容安全的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









