代码之家  ›  专栏  ›  技术社区  ›  treyBake user1850175

将字符串作为条件求值

  •  2
  • treyBake user1850175  · 技术社区  · 6 年前

    我有一个自定义的验证规则模块,基本上允许用户设置CSV验证。我的问题是我把它放到这个数组中:

    Array(
        [field_name] => 'is_int(324230435)',
        [some_other_field] => 'strlen("some str") > 25'
    )
    

    我做了些调查,发现了 eval() 功能。

    How to use string in IF condition in PHP

    评估() 由于安全问题(参考: When is eval evil in php?

    虽然它并没有严格地说eval是邪恶的,但我仍然希望有一个替代方法。

    评估() -也许我该逃走利用 评估() 还是有更好的办法?

    2 回复  |  直到 6 年前
        1
  •  2
  •   deceze    6 年前

    执行任意代码 eval 这将允许您在不执行PHP代码的情况下执行PHP代码。

    明智的做法是定义一个 DSL 它为你的用户提供了一种编写有限表达式的方法 哪些不是PHP代码 ,您将使用特定的有限功能对其进行解析和评估。

    这样做的好图书馆是 Symfony's ExpressionLanguage component . 除此之外,您将进入语言解析器领域。

        2
  •  0
  •   treyBake user1850175    6 年前

    只是离开@deceze的答案和建议使用Symfony的ExpressionLanguage组件。

    我通过Composer将其安装到我的项目中,并认为对于任何在文章中遇到障碍的人来说,看到它工作可能会有所帮助(与我的问题相关):

    # build array for testing rows against rules
    $test = [];
    
    # foreach csv row
    foreach ($csv as $keey => $row)
    {
        # 10000s of rows, just for simplicity - break after 3
        if ($keey == 0) {continue;}
        if ($keey >= 3) {continue;}
    
        # get array keys for 
        $keys = array_keys($row);
    
        foreach ($keys as $key)
        {
            # if row key is in the $conditions array, add to $test array for testing
            if (in_array($key, array_map('strtolower', array_keys($conditions)))) {
                $conditionType = array_keys($conditions[$key]);
                $conditionType = $conditionType[0];
    
                if ($conditionType === 'condition_suffix') {
                    $brokenCondition = explode(' ', $conditions[$key][$conditionType]);
    
                    # build array to pass into ->evaluate()
                    $test[$key]['evaluate'] = 'field '. $brokenCondition[0] .' required'; # expression to actually test
                    $test[$key]['pass'] = [ # works like pdo, pass in the names and give them a value
                        'field' => strlen($row[$key]),
                        'required' => $brokenCondition[1]
                    ];
                } else {
                    $test[$key]['evaluate'] = 'field == required';
                    $test[$key]['pass'] = [
                        'field' => is_numeric($row[$key]),
                        'required' => true
                    ];
                }
            }
        }
    }
    
    echo '#----------------------------------------------------------------------------#';
    
    # show test arr for reference
    echo '<pre>';
    print_r($test);
    echo '</pre>';
    
    # foreach test row, check against the condition
    foreach ($test as $key => $item)
    {
        echo '<pre>';
        var_dump($key. ': ' .$expressionLanguage->evaluate(
            $item['evaluate'],
            $item['pass']
        ));
        echo '</pre>';
    
        echo '+----------------------------------------------------------------------------+';
    }
    

    现在,它通过ExpressionLanguage Symfony组件评估我自定义创建的php查询字符串。谢谢@deceze

    参考文献:

    https://symfony.com/doc/current/components/expression_language/syntax.html

    https://symfony.com/doc/current/components/expression_language.html