簡體   English   中英

eval() 替代方法來獲取字符串的 output,例如“(0 AND 1 OR 1)”

[英]eval() alternative to get output of the string like “(0 AND 1 OR 1)”

我有來自數據庫的字符串格式的邏輯表達式數據 -

"(id1 OR id2) AND (id3 OR id3)"

這可以是任何類型的組合,因為它是基於用戶輸入的動態字符串。 從數據庫中獲取此信息后,我根據某些邏輯將所有 Ids 值替換為 0/1,這種刺痛變為 -

"(1 OR 1) AND (0 OR 1)"

現在我想將此字符串作為 PHP 代碼運行,並期望它的 output 作為 Boolean。 但問題是我使用了eval() PHP function 出於安全原因這並不好。

$op = "(1 OR 1) AND (0 OR 1)";
$op = eval('return '.$op.';');

我不得不使用 eval 的唯一原因是字符串類型。 如果我運行這個echo (1 OR 1) AND (0 OR 1)那么我會得到預期的 output。

那么有人可以幫我解決這個問題嗎? 有什么更好的方法呢?

單數格式

如果它始終采用相同的格式,您可以使用正則表達式並格式化您自己的表達式......

if(preg_match("/\((\d) OR (\d)\) AND \((\d) OR (\d)\)/", $string, $matches))
    var_dump( ($matches[1] || $matches[2]) && ($matches[3] || $matches[4]));

多種格式

警告如果格式不正確,以下內容不會捕獲每個表達式。 例如表達式:

AND 1

將導致兩種方法都失敗...您可以通過定義其他匹配規則在正則表達式中解決此問題,例如:

Pattern         Replacement

/^\s*AND\s*1/   0
/^\s*AND\s*0/   0
/^\s*OR\s*0/    0

/^\s*OR\s*1/    1

但是要涵蓋所有內容將意味着一長串規則。

示例表達式

$expressions  = [
    "1 AND 0",
    "1 AND 1",
    "0 OR 0",
    "0 OR 1",
    "1 OR 1",
    "0 AND (1 OR 1) AND (0 OR 0) OR 0",
    "(1 OR 1) AND (0 OR 1)",
    "(1 AND 0 OR 1 ) OR (0 OR 1 OR 1) AND 1",
    "(1 OR 0) DELETE EVERYTHING!"
];

方法一: eval

雖然人們傾向於討厭使用eval (因為它可能允許執行流氓代碼),但只要您清理輸入,就沒有理由不使用它。

所以讓我們做一個簡單的 function:

function cleanBooleanExpression($string){                
    $string = preg_replace("/OR/i", "O", $string);       // Replace instances of OR with the letter O; i flag makes it case insensitive
    $string = preg_replace("/AND/i", "A", $string);      // Replace instances of AND with the letter A; i flag makes it case insensitive
    $string = preg_replace("/[^OA01() ]/", "", $string);  // Strip all non-legal characters
    $string = preg_replace("/O/", "OR", $string);         // Re-instate OR
    $string = preg_replace("/A/", "AND", $string);        // Re-instate AND
    return $string;                                       // Return the updated string
}

然后,您可以在eval中使用經過消毒的 output :

foreach($expressions as $input){
    $input = cleanBooleanExpression($input);
    eval("var_dump({$input});");
}

/* Output:

bool(false)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(true)

*/

方法二:定制function

或者,如果您真的不想使用eval ,您可以使用正則表達式來評估輸入:

function evalBooleanString($string){
    $string = preg_replace('/
        (
        \(1\)|
        [01]*1[01]+|
        [01]+1[01]*|
        \(*\s*1\s*OR\s*[01]\s*\)*|
        \(*\s*[01]\s*OR\s*1\s*\)*|
        \(*\s*1\s*AND\s*1\s*\)*
        )
        /x', 1, $string);
    $string = preg_replace('/
        (
        \(\)|
        \(0\)|
        00+|
        \(*\s*0\s*OR\s*0\s*\)*|
        \(*\s*[01]\s*AND\s*0\s*\)*|
        \(*\s*0\s*AND\s*[01]\s*\)*
        )
        /x', 0, $string);

    $string = trim($string);

    if($string === "1" || $string === "0"){
        return (bool)$string;
    }
    return evalBooleanString($string);
}

並像這樣使用它:

foreach($expressions as $input){
    $input = cleanBooleanExpression($input);
    var_dump(evalBooleanString($input));
}

/* Output:

bool(false)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(true)

*/

也許有幫助

function tmp_function($body)
{
    $tmp_file = tempnam(sys_get_temp_dir(), "tmp_func");
    file_put_contents($tmp_file, "<?php return function() { return $body };");
    $function = include($tmp_file);
    unlink($tmp_file);

    return $function;
}

$op = "(1 OR 1) AND (0 OR 1);";
$call_me = tmp_function($op);
var_dump($call_me());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM