You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PHP解析含嵌套括号的自定义简单搜索查询?

嵌套条件搜索查询的解析方案

核心思路

嵌套括号的本质是层级结构,用递归+栈的方式处理最直接:先定位所有匹配的括号对,递归解析括号内的子表达式,再将子结果整合到外层表达式中,最终得到你需要的嵌套数组结构。

具体实现步骤

1. 解析嵌套括号(递归处理层级)

通过栈跟踪括号的开启与闭合,遇到闭合括号时提取内部子表达式,递归解析后替换回原位置:

function parseNestedQuery($query) {
    $stack = [];
    $resultParts = [];
    $currentSegment = '';
    $queryLen = strlen($query);

    for ($i = 0; $i < $queryLen; $i++) {
        $char = $query[$i];
        if ($char === '(') {
            // 先把当前积累的非括号内容存入结果
            if (!empty(trim($currentSegment))) {
                $resultParts[] = trim($currentSegment);
                $currentSegment = '';
            }
            array_push($stack, count($resultParts)); // 记录括号起始位置
            $resultParts[] = '(';
        } elseif ($char === ')') {
            if (!empty(trim($currentSegment))) {
                $resultParts[] = trim($currentSegment);
                $currentSegment = '';
            }
            $startIdx = array_pop($stack);
            // 提取括号内的所有元素,递归解析子表达式
            $subExprParts = array_slice($resultParts, $startIdx + 1);
            array_splice($resultParts, $startIdx, count($subExprParts) + 1);
            $resultParts[] = parseNestedQuery(implode(' ', $subExprParts));
        } else {
            $currentSegment .= $char;
        }
    }
    // 处理剩余的非括号内容
    if (!empty(trim($currentSegment))) {
        $resultParts[] = trim($currentSegment);
    }

    // 解析当前层级的平级表达式(拆分条件与运算符)
    return parseFlatExpression($resultParts);
}

2. 解析平级表达式(拆分条件与运算符)

将无嵌套的表达式拆分为你需要的Condition+Operator结构:

function parseFlatExpression($parts) {
    $expression = [];
    $currentCondition = '';
    $lastOperator = null;

    foreach ($parts as $part) {
        $upperPart = strtoupper($part);
        if ($upperPart === 'AND' || $upperPart === 'OR') {
            if (!empty(trim($currentCondition))) {
                $expression[] = [
                    'Condition' => trim($currentCondition),
                    'Operator' => $upperPart
                ];
                $currentCondition = '';
            }
            $lastOperator = $upperPart;
        } else {
            if (is_array($part)) {
                // 子表达式结果直接加入,同时处理前置运算符
                if (!empty(trim($currentCondition))) {
                    $expression[] = [
                        'Condition' => trim($currentCondition),
                        'Operator' => $lastOperator
                    ];
                    $currentCondition = '';
                }
                $expression[] = $part;
            } else {
                $currentCondition .= ($currentCondition ? ' ' : '') . $part;
            }
        }
    }

    // 加入最后一个无后续运算符的条件
    if (!empty(trim($currentCondition))) {
        $expression[] = ['Condition' => trim($currentCondition)];
    }

    return $expression;
}

3. 安全求值(替代eval避免注入风险)

直接使用eval处理用户输入存在严重安全漏洞,建议用白名单验证+规则匹配的方式求值,同时实现短路逻辑:

// 单个条件求值
function evaluateSingleCondition($condition, $userPassword, $userDate) {
    $condition = trim($condition);
    // 处理DATE BEFORE条件
    if (preg_match('/^DATE BEFORE "([^"]+)"$/', $condition, $matches)) {
        $targetDate = DateTime::createFromFormat('d-m-Y H:i', $matches[1]);
        $userDateTime = new DateTime($userDate);
        return $userDateTime < $targetDate;
    }
    // 处理DATE AFTER条件
    elseif (preg_match('/^DATE AFTER "([^"]+)"$/', $condition, $matches)) {
        $targetDate = DateTime::createFromFormat('d-m-Y H:i', $matches[1]);
        $userDateTime = new DateTime($userDate);
        return $userDateTime > $targetDate;
    }
    // 处理PASSWORD IS条件
    elseif (preg_match('/^PASSWORD IS "([^"]+)"$/', $condition, $matches)) {
        return $userPassword === $matches[1];
    }
    // 处理PASSWORD IS NOT条件
    elseif (preg_match('/^PASSWORD IS NOT "([^"]+)"$/', $condition, $matches)) {
        return $userPassword !== $matches[1];
    }
    return false;
}

// 递归求值整个表达式(支持短路逻辑)
function evaluateExpression($expression, $userPassword, $userDate) {
    $finalResult = null;
    $currentOperator = null;

    foreach ($expression as $item) {
        if (is_array($item)) {
            $currentValue = isset($item['Condition']) 
                ? evaluateSingleCondition($item['Condition'], $userPassword, $userDate)
                : evaluateExpression($item, $userPassword, $userDate);

            if ($finalResult === null) {
                $finalResult = $currentValue;
            } else {
                if ($currentOperator === 'AND') {
                    if (!$currentValue) return false; // AND短路:假则直接返回
                    $finalResult = $finalResult && $currentValue;
                } elseif ($currentOperator === 'OR') {
                    if ($currentValue) return true; // OR短路:真则直接返回
                    $finalResult = $finalResult || $currentValue;
                }
            }
            $currentOperator = $item['Operator'] ?? null;
        }
    }
    return $finalResult ?? false;
}

使用示例

// 测试查询字符串
$query = '((PASSWORD IS "welcome" OR PASSWORD IS "1234") AND DATE BEFORE "01-11-2022") OR PASSWORD = "admin"';
// 解析为嵌套数组结构
$parsed = parseNestedQuery($query);
// 模拟用户参数
$userPassword = '1234';
$userDate = '01-10-2022 10:00';
// 求值
$result = evaluateExpression($parsed, $userPassword, $userDate);
var_dump($result); // 输出bool(true)

内容的提问来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:50:27