将字符串作为条件PHP求值

将字符串作为条件PHP求值,php,eval,Php,Eval,我有一个自定义的验证规则模块,基本上允许用户设置CSV验证。我的问题是我将它放到这个数组中: Array( [field_name] => 'is_int(324230435)', [some_other_field] => 'strlen("some str") > 25' ) 我做了一些研究,发现了eval()函数 参考文献: 但是,由于安全问题,我确实不想使用eval()(参考:) 虽然它并没有严格地说eval是邪恶的,但我仍然希望有一种替代方法 我是否

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

Array(
    [field_name] => 'is_int(324230435)',
    [some_other_field] => 'strlen("some str") > 25'
)
我做了一些研究,发现了
eval()
函数

参考文献:

但是,由于安全问题,我确实不想使用
eval()
(参考:)

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


我是否对
eval()
的使用过于谨慎?也许我应该退出并使用
eval()
,或者有更好的方法吗?

好吧,在代码中执行任意字符串需要注意的是,无论以何种方式执行,都是在执行任意代码。除了
eval
之外,没有更好的选择可以让您在不执行PHP代码的情况下执行PHP代码

明智的做法是定义一个函数,它为您的用户提供了一种编写某些有限表达式的方法,这些表达式不是PHP代码,您将使用特定的有限功能对其进行解析和计算


这样做的好图书馆是。除此之外,您还将进入语言解析器的领域。

仅从@deceze答案和建议出发,使用Symfony的ExpressionLanguage组件

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

#根据规则构建用于测试行的数组
$test=[];
#foreach csv行
foreach($csv为$keey=>$row)
{
#10000行,仅为简单起见-3后中断
如果($keey==0){continue;}
如果($keey>=3){继续;}
#获取的数组键
$keys=数组_键($row);
foreach($key作为$key)
{
#如果行键位于$conditions数组中,则添加到$test数组中进行测试
if(在数组中($key,数组映射('strtolower',数组密钥($conditions))){
$conditionType=array_key($conditions[$key]);
$conditionType=$conditionType[0];
如果($conditionType==='condition\u后缀'){
$brokenCondition=explode(“”,$conditions[$key][$conditionType]);
#生成要传递到->evaluate()中的数组
$test[$key]['evaluate']='field'.$brokenCondition[0].'required'.#要实际测试的表达式
$test[$key]['pass']=[#与pdo类似,传入名称并给它们一个值
'field'=>strlen($row[$key]),
“必需”=>$brokenCondition[1]
];
}否则{
$test[$key]['evaluate']='field==required';
$test[$key]['pass']=[
“字段”=>是数字($row[$key]),
“必需”=>true
];
}
}
}
}
回音“#----------------------------------------------------------------#”;
#显示测试arr以供参考
回声';
打印(测试);
回声';
#对于每个测试行,对照条件进行检查
foreach($testas$key=>$item)
{
回声';
变量转储($key.:'。$expressionLanguage->evaluate(
$item['evaluate'],
$item['pass']
));
回声';
回显'+----------------------------------------------------------------------------------------+';
}
现在,它通过ExpressionLanguage Symfony组件计算自定义创建的php查询字符串。谢谢@deceze

参考文献:


嗯,您希望以代码的形式执行字符串<代码>评估执行此操作。此操作有一个基本警告,即您希望以代码形式执行任意字符串,这意味着您需要信任这些字符串。这里的另一种选择是为自己的迷你DSL创建自己的解析器和求值器,在这种方法中,您只能形成特定的有效表达式,而不能向任何任意PHP代码开放自己,。所以最好不要使用它。原因有二:输入恶意代码和输入错误语法破坏脚本。您最好在下拉列表中允许php函数,然后选择它们并添加值,然后在服务器端安全地执行它们。所以你只需要有一个不同的数组结构数组([field_name]=>[[func'=>'is_int',value'=>324230435]])@deceze-ah我明白了。。。嗯,我从来都不喜欢相信用户哈哈,但我喜欢Symfony组件的外观-可以尝试一下。^TY您可以解构字符串,然后使用
# 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 '+----------------------------------------------------------------------------+';
}