PHP实现自定义关键字过滤的两种实用方法

闻溪
闻溪
发布时间:2026-10-14| 6人浏览过
原创

在进行内容发布或数据入库前,屏蔽违禁关键字是许多后端项目的核心需求。本文将深入剖析使用 PHP 实现该功能的两种主流方案:一是利用 file_get_contents 读取列表并结合循环遍历检测,二是通过正则表达式动态构建匹配合集。我们将修正原示例代码中存在的逻辑错误,并针对中文等多字节编码场景提供适配说明。

方案一:基于数组遍历与 strpos 函数的基础过滤

这是最直观的实现方式。其核心逻辑是将所有需要屏蔽的关键字存储在一个外部文本文件中(每行一个),然后在程序运行中读取该文件,将其转换为数组,最后逐一比对用户输入的内容。

第1步:准备关键字配置文件

创建一个名为 keyWords.txt 的文件,在其中列出所有禁止出现的关键字,保持每行一个,无需特殊符号:

# keyWords.txt
敏感词1
违规短语
不良信息

第2步:编写检测函数

以下是修正后的 PHP 检测逻辑。原代码中存在变量作用域混淆的问题(例如在函数内使用了未定义的 $str),在此已做修复:

<?php
function checkKeyWord($content) {
    // 去除首尾空白字符
    $content = trim($content);
    
    // 1. 读取关键字文本
    // 建议使用绝对路径或确保相对路径正确
    $wordsContent = @file_get_contents('keyWords.txt');
    if ($wordsContent === false) {
        return false;
    }
    
    // 2. 转换成数组,按换行符分割
    // 注意:不同系统的换行符可能不同,这里主要针对 \n 处理
    $arr = explode("\n", $wordsContent);
    
    // 3. 遍历并检测
    foreach ($arr as $item) {
        $keyword = trim($item); // 清理单行可能的空格
        
        // 跳过空行
        if ($keyword === '') {
            continue;
        }
        
        // 4. 核心判断:strpos 返回的是索引位置或 false
        // 必须使用 !== false 进行严格比较
        if (strpos($content, $keyword) !== false) {
            return $keyword; // 发现第一个匹配的关键字即停止
        }
    }
    
    return false;
}

// --- 测试示例 ---
$userInput = '这是一段正常的文本';
$hitWord = checkKeyWord($userInput);

if ($hitWord) {
    echo "检测失败,包含关键字: " . htmlspecialchars($hitWord);
} else {
    echo "通过检测,可以安全入库";
}

方案二:基于正则表达式的批量匹配(进阶)

当关键字较多时,循环遍历会产生性能损耗。另一种高效的方式是将关键字合并为一个正则表达式。需要注意的是,直接拼接线性的关键字存在安全风险(如注入正则引擎崩溃的重回溯攻击),因此必须对关键字进行转义。

核心逻辑分析

banwordCheck 函数接收两个参数:待检测字符串和关键字文件路径。它将读取到的所有内容合并为单个字符串,并使用 preg_match 进行一次性匹配。

代码示例与优化

<?php
/**
 * 基于正则的多关键字检测函数
 *
 * @param string $string   待检测字符串
 * @param string $fileName 关键字文件路径
 * @return bool|string     命中返回关键字,否则返回false
 */
function banWordCheck($string, $fileName) {
    // 读取配置
    $keywords = file_get_contents($fileName);
    if ($keywords === false) {
        return false; // 或抛出自定义异常
    }
    
    // 清理关键词:去除空行、去重、并转义特殊字符
    $lines = array_filter(array_map('trim', explode("\n", $keywords)));
    if (empty($lines)) {
        return false;
    }
    
    // 对关键字中的正则元字符进行转义,防止语法错误
    $escapedWords = array_map(function($word) {
        return preg_quote($word, '/');
    }, $lines);
    
    // 使用 '|' 连接作为“或”的关系,开启不区分大小写 i 模式
    // u 模式用于支持 UTF-8 多字节字符
    $pattern = '/(' . implode('|', $escapedWords) . ')/iu';
    
    // 执行匹配
    if (preg_match($pattern, $string, $matches)) {
        return $matches[1]; // 返回实际命中的那个关键字
    }
    
    return false;
}

// 测试
$inputText = "这是一个包含违规词汇的例子";
$result = banWordCheck($inputText, 'keyWords.txt');

if ($result) {
    echo "命中规则: " . $result;
} else {
    echo "安全";
}

关键技术细节与排错

1. 关于 strpos 的陷阱

在判断是否包含子串时,很多开发者习惯用 if (strpos($haystack, $needle))。这在 $needle 出现在 $haystack 头部(即索引为 0)时会发生致命错误,因为 0 会被视作 false。务必写成:
if (strpos($haystack, $needle) !== false)

2. 中文编码兼容性

如果使用正则表达式方案,且环境为 PHP 7.4 以下版本,或者为了兼容性强,建议加上 u (UTF-8) 修饰符。如果原始 keyWords.txt 文件的编码与服务器页面输出编码不一致,可能导致匹配失效(尤其是中文)。请确保文件保存为 UTF-8 无 BOM 格式,并在脚本开头声明 header('Content-Type: text/html; charset=utf-8');。

3. 性能考量

对于极高频的并发请求,每次调用都去读取磁盘文件 (file_get_contents) 是不合理的。建议在应用启动时将关键字加载到全局变量或 Redis/Memcached 中缓存,避免重复 I/O 操作。

以上就是PHP屏蔽过滤指定关键字方法的详细内容,更多关于PHP程序设计参考资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。