PHP项目内容相似度如何比对查重检测

wen PHP项目 30

本文目录导读:

PHP项目内容相似度如何比对查重检测

  1. 方案一:基于 Token 的代码哈希(适用于纯文本抄袭)
  2. 方案二:抽象语法树 (AST) 比对(适用于逻辑结构抄袭)
  3. 方案三:基于 CS(克隆检测)工具的集成方案(生产环境推荐)
  4. 方案四:混合比对策略(高精度,推荐用于关键检测)
  5. 为什么不推荐只用简单的文本 diff(如 similar_text)?
  6. 如果你的具体需求是

针对 PHP 项目的相似度比对和查重检测,通常需要结合 代码结构分析逻辑抽象文本相似度算法 来综合判断,单纯的字符串匹配容易误判(如变量名不同但逻辑相同)。

以下是几种主流且有效的实现方案,从简单到复杂,按需选择:


基于 Token 的代码哈希(适用于纯文本抄袭)

这是最基础的方法,将代码转化为标记流后进行比对,能抵抗格式(空格、换行)和部分注释的干扰。

核心原理

  1. 词法分析:将 PHP 代码解析成 Token 数组(使用 token_get_all 函数)。
  2. 归一化:剔除所有空白符、注释;将所有变量名(T_VARIABLE)替换为统一占位符(如 $VAR),将所有字符串(T_CONSTANT_ENCAPSED_STRING)替换为占位符(如 STR)。
  3. 哈希分片:使用 MinHash 或 SimHash 对归一化后的 Token 序列生成指纹,计算 Jaccard 相似度。

PHP 实现示例(核心逻辑)

function phpCodeSimHash($code) {
    $tokens = token_get_all($code);
    $normalized = [];
    foreach ($tokens as $token) {
        if (is_array($token)) {
            $name = $token[0];
            // 忽略注释、空白
            if (in_array($name, [T_COMMENT, T_DOC_COMMENT, T_WHITESPACE])) continue;
            // 归一化变量、方法名、字符串
            if ($name === T_VARIABLE) {
                $normalized[] = 'VAR';
            } elseif ($name === T_STRING) { // 函数名、类名
                $normalized[] = 'FUNC';
            } elseif ($name === T_CONSTANT_ENCAPSED_STRING) {
                $normalized[] = 'STR';
            } else {
                $normalized[] = $token[1]; // 保留关键字、运算符
            }
        } else {
            $normalized[] = $token; // 标点符号如 {}(); 
        }
    }
    // 使用 SimHash 计算指纹(需引入hash计算库)
    return simhash(implode(' ', $normalized));
}

优点:速度快,适合大规模检测。
缺点:无法检测逻辑结构等价但语法重写的代码(如 ifswitch,循环改递归)。


抽象语法树 (AST) 比对(适用于逻辑结构抄袭)

通过解析 PHP 语法树,比较其结构特征,可以识别将 for 改为 while、或者调整代码顺序的抄袭。

核心原理

  1. 使用 php-ast 扩展或 nikic/php-parser 库生成 AST。
  2. 遍历 AST 节点,提取 结构向量(如:语句类型频率、控制流深度、操作符使用模式)。
  3. 计算两个结构向量之间的 余弦相似度欧氏距离

使用 nikic/php-parser 的快速示例

use PhpParser\{ParserFactory, NodeTraverser, NodeVisitorAbstract};
class StructureExtractor extends NodeVisitorAbstract {
    public $features = ['if_count' => 0, 'for_count' => 0, 'assign_count' => 0, 'depth' => 0];
    public function enterNode(Node $node) {
        if ($node instanceof Node\Stmt\If_) $this->features['if_count']++;
        if ($node instanceof Node\Expr\Assign) $this->features['assign_count']++;
        // ... 可以统计更多结构特征
    }
}
function comparePhpStructure($code1, $code2) {
    $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
    $traverser = new NodeTraverser();
    $visitor = new StructureExtractor();
    $traverser->addVisitor($visitor);
    try {
        $ast1 = $parser->parse($code1);
    } catch (\Exception $e){ return 0; }
    $features1 = $traverser->traverse($ast1); 
    $visitor->features = ['if_count'=>0,'for_count'=>0,'assign_count'=>0];
    $features2 = ...; // 解析第二份代码
    // 计算余弦相似度
    return cosineSimilarity($features1, $features2);
}

优点:抗重构能力强,能检测变量重命名、逻辑结构调整。
缺点:PHP语法复杂,解析大项目时性能较差。


基于 CS(克隆检测)工具的集成方案(生产环境推荐)

如果你需要处理整个 PHP 项目(含多个文件、框架代码),建议直接使用成熟的第三方工具,它们已经整合了词法分析、AST、以及机器学习模型。

推荐工具

  1. JPlag (支持 PHP)

    • 德国卡尔斯鲁厄理工学院开发,支持多种语言。
    • 架构:将 PHP 代码通过内部解析器转换为 Token 流,然后使用 Greedy String Tiling 算法进行比对。
    • 输出HTML报告,高亮相似代码段。
  2. MOSS (Measure Of Software Similarity)

    • 斯坦福大学开发,支持PHP。
    • 原理:使用 Winnowing 算法(选取文档特征指纹),提交到服务器比对,适合做最终的查重验证,但需要网络权限且源代码需上传。
  3. Simian

    • 轻量级重复代码检测工具,支持PHP。
    • 原理:基于行的令牌匹配,可以配置最小重复行数。

使用 JPlag 检测 PHP 项目示例

# 下载 JPlag.jar,运行命令比较两个目录
java -jar jplag.jar -l php /path/to/project1 /path/to/project2 -r /path/to/report

混合比对策略(高精度,推荐用于关键检测)

结合 代码结构运行时行为 的指纹,能够精准识别深层抄袭(如重命名全部标识符、改写控制流但逻辑等价)。

流程设计

  1. 第一层:符号归一化 Hash 过滤
    快速淘汰完全不同代码(相似度 < 30%),减少后续计算量。
  2. 第二层:AST 子树匹配
    处理经过变量重命名和微小结构调整的代码(相似度 60%-80%)。
  3. 第三层:动态数据流分析(可选)
    • 使用工具如 PHP Opcache 编译为 opcode。
    • 比较 Opcode 序列的编辑距离 (Levenshtein Distance)。
    • 如果操作码序列高度相似,则几乎可以判定为逻辑等价。

为什么不推荐只用简单的文本 diff(如 similar_text)?

  • 误伤率高:第三方 PHP 框架(如 Laravel)的标准模板、以及 PHP 语法关键字(如 <?php, function)会产生大量重复。
  • 无法抵抗格式化差异:缩进、换行、注释都会造成文本差异,但代码逻辑完全相同。
  • 速度慢:对大型项目进行字符串矩阵比对 O(n²),不可行。

如果你的具体需求是

场景 推荐方案
教学作业快速查重 方案一 Token SimHash + JPlag 命令行
公司内部代码安全审计 方案二 AST结构向量 + 方案三 MOSS
需要 100% 保证 没有漏报(高风险场景) 方案四混合策略 + Opcode级比对
仅需重复代码块检测 使用 Simian 或 PHP CodeSniffer 的重复代码嗅探器

最终建议:对于 PHP 项目,除非是简单的函数或脚本,否则不要依赖单一算法。最佳实践是先使用 JPlag(免费且经过多年验证)得到一个初步结果,再对高相似度的对组进行人工 Review

抱歉,评论功能暂时关闭!