将字符串评估为条件 PHP
Evaluate string as condition PHP
我有一个自定义验证规则模块,基本上允许用户设置 CSV 验证。我的问题是我把它放到这个数组中:
Array(
[field_name] => 'is_int(324230435)',
[some_other_field] => 'strlen("some str") > 25'
)
我做了一些研究,发现了 eval()
函数。
参考文献:
但是,由于安全问题,我真的不想使用 eval()
(参考:When is eval evil in php?)
虽然没有严格说eval是邪恶的,但如果有其他方法,我还是会更喜欢。
我是不是对 eval()
的使用过于谨慎了 - 也许我应该逃避并使用 eval()
或者有更好的方法吗?
好吧,作为代码执行任意字符串需要注意的是,无论您采用哪种方式,您都在执行任意代码。没有比 eval
更好的替代方法,它可以让您执行 PHP 代码而无需……执行 PHP 代码。
明智的做法是定义一个 DSL,让您的用户可以编写某些有限的表达式 ,这不是 PHP 代码 ,您将使用特定的有限功能对其进行解析和评估。
一个很好的图书馆是 Symfony's ExpressionLanguage component。除此之外,您将进入语言解析器领域。
刚刚结束@deceze 的回答和使用 Symfony 的 ExpressionLanguage 组件的建议。
我通过 Composer 将它安装到我的项目中,并认为对于任何绊倒 post 的人来说,看到它工作(以及关于我的问题)可能会有所帮助:
# 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
我有一个自定义验证规则模块,基本上允许用户设置 CSV 验证。我的问题是我把它放到这个数组中:
Array(
[field_name] => 'is_int(324230435)',
[some_other_field] => 'strlen("some str") > 25'
)
我做了一些研究,发现了 eval()
函数。
参考文献:
但是,由于安全问题,我真的不想使用 eval()
(参考:When is eval evil in php?)
虽然没有严格说eval是邪恶的,但如果有其他方法,我还是会更喜欢。
我是不是对 eval()
的使用过于谨慎了 - 也许我应该逃避并使用 eval()
或者有更好的方法吗?
好吧,作为代码执行任意字符串需要注意的是,无论您采用哪种方式,您都在执行任意代码。没有比 eval
更好的替代方法,它可以让您执行 PHP 代码而无需……执行 PHP 代码。
明智的做法是定义一个 DSL,让您的用户可以编写某些有限的表达式 ,这不是 PHP 代码 ,您将使用特定的有限功能对其进行解析和评估。
一个很好的图书馆是 Symfony's ExpressionLanguage component。除此之外,您将进入语言解析器领域。
刚刚结束@deceze 的回答和使用 Symfony 的 ExpressionLanguage 组件的建议。
我通过 Composer 将它安装到我的项目中,并认为对于任何绊倒 post 的人来说,看到它工作(以及关于我的问题)可能会有所帮助:
# 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