如何获取使条件为 TRUE 的 if 条件的值

How to get the value of if condition that make the condition TRUE

我正在尝试获取使条件为真的 if 条件的值,我有以下示例:

(code.php)

<?php

$a = 'USERNAME';
$b = 'LASTNAME';
if(substr($a, 0, strlen("<SCRIPT"))=== "<SCRIPT Abdalla $a " ) {
    }

?>

在上面的示例中,我试图在不使用双引号的情况下获取值 <SCRIPT。我尝试了一些步骤,但它仍然得到带有值 (<SCRIPT) 的双引号。然后我计划将值 <SCRIPT 分配给另一个变量。下一个代码显示了我的代码以获得结果,但它仍然无法正常工作:

(test.php)


<?php

$file='';
$handle = fopen('code.php','r+');
if ($handle) {
    while (($buffer=fgets($handle, 4096)) !== false) {
        $file.=$buffer."\n";
    }
    if (!feof($handle)) {
       die('error');
    }
    fclose($handle);
}

//take note of the use of single quotes to wrap this regex, as we do not want PHP parser to eval the $ in the regex string
preg_match_all('/\s*?($[\S]+?)\s*?\=(\"?[\S]+?\"?);/',$file,$matches, PREG_SET_ORDER);
$varval=array();
foreach($matches as $match){
    $tmp=$match[2];
    if(substr($tmp,0,1)=='"' && substr($tmp,-1,1)=='"'){    
        //evaluate variables in string. we can evaluate with the current object as the variable should be declared first as of proper PHP syntax
        $tmp=substr($tmp, 1,-1); //remove quotes
        $tmp=replaceFromObject($tmp, $varval);
    }
    $varval[$match[1]]=$tmp; //we do not need to check if exists, because we should replace with the latest value.
}

/* 
The below stores all quoted text and replace them with our own special variable %var0%, %var1%, %var2%.... %varN%. 
This is because there could be cases like if("test == 3" == $a) or even worse if("if(test=3)" == $a), which will make regex/parsing tricky if we do not substitute these quoted text out just like a parser/compiler would.

Note: Something I didn't do. We should really first scan the whole text using preg_match to find if there are any text using this format of variables as well, to prevent collisions! 
If there are, we can set a loop to check and append some character to our own special variable like %varrN%, %varrrN%, %varrrrN%... 
until we find no collisions and it is safe to use. I will leave this simple regex exercise for you to do on your own. Create the regex to find the file for %varN%...
*/
preg_match_all("/\"([\s\S]*?)\"/", $file, $matches, PREG_SET_ORDER);
$stringvars=array();
$key="%var";
$count=0;
foreach($matches as $match){
    if(!in_array($match[1], $stringvars)){
        $stringvars[$key.$count.'%']=$match[1];
        $file=preg_replace("/\"".preg_quote($match[1])."\"/", $key.$count.'%', $file); //take note of the change to preg_quote
        $count++;
    }
}


// now we parse the whole text for if(subject anycomparator value)
preg_match_all("/if\s*?\(([\s\S]*?)([\=|\>|\<][\=]{0,2})\s*?([\S\s]*?)\s*?\)/", $file, $matches,PREG_SET_ORDER);
$conditionals=array();
foreach($matches as $match){
    $conditionals[]=array(
        'subject'=>replaceFromObject(replaceFromObject(trim($match[1]),$stringvars),$varval), 
        //the order does matter, we replace the string first, then the variables, as there might be variables in the double quoted strings which we should evaluate
        'comparator'=>$match[2],
        'value'=>replaceFromObject(replaceFromObject(trim($match[3]),$stringvars),$varval),
    );
}

foreach ($conditionals as $c){
   // echo htmlspecialchars($c['subject']).' ';    
   // echo htmlspecialchars($c['comparator']).' ';        
    echo htmlspecialchars($c['value']); 
    echo "<br/>";
}


/* now this function can be used to replace both the quoted strings AND the variables */
function replaceFromObject($s, $obj){
    foreach($obj as $key=>$value){
        $s=preg_replace('/'.preg_quote($key).'/', $value, $s); //take note of the preg_quote as the string may contain regex keywords
    }
    return $s;
}


?>

我想要一种方法来打印使 if 条件为真的值,即 (

所以实际上您的代码不会在我的服务器上输出任何内容 (test.php)。因此,我尝试了另一种至少适用于您的 code.php 的方法,但是,它不像您自己的代码那样非常稳定,因为它没有考虑以下几点。

没想到的逻辑运算符:

  • <<=>>====

不支持多行

我的方法实际上既不拆分字符串也不剥离任何内容,但是它唯一要做的就是替换字符串文字。

<?php
    $file = file_get_contents("test.php");
    $curIdx = 0; 

    while($curIdx < strlen($file))
    {
        $ifIndex = strpos($file,"if", $curIdx);


        if($ifIndex === false)
        {
            break;
        }

        $curIdx = $ifIndex+1;

        $equalsIdx = strpos($file,"=",$curIdx);

        if($equalsIdx === false)
        {
            break;
        }

        $curIdx = $equalsIdx+1;

        for($i = $curIdx; $i<strlen($file); $i++)
        {
            if($file[$i] !== "=" && $file[$i] !== " ")
            {
                $curIdx = $i;
                break;
            }
        }


        $condition = substr($file,$curIdx,strpos($file,")",$curIdx)-$curIdx);
        $condition = str_replace('"','',$condition);
        echo htmlspecialchars($condition);
    }

这输出:<SCRIPT

对于您的脚本,我发现了几个问题:

if(strpos($value, 'if') !== false) 

必须有双==

除此之外,您将获得以下输出:

= "<SCRIPT"

要摆脱这个,只需检查 pos1 之后的字符是否是另一个 =

        if($value[$pos1] === "=")
        {
            $pos1++;
        }

然后我们实际上可以完全删除对 sanitize_recursive 的调用,因为 substr 永远不会 returns 数组。

现在要摆脱,只需在 between 字符串上调用 str_replace

        $between = substr($value, $startIndex, $length);
        $between = str_replace('"','',$between);

        echo htmlspecialchars($between);

我们的输出为 &lt;SCRIPT- 需要调用 htmlspecialchars,否则您的浏览器将开始解释此标记。

这给我们留下了以下文件:

<?php
$file = file_get_contents("test.php"); // Code.php the page that include the if condition 
$lines = explode("\n", $file); // get each line of source code and store it in array ($lines)

foreach ($lines as $key => &$value) {
    if(strpos($value, 'if') !== false) // check if the line have if statement 
    {
        if(strpos($value, '==') !== false )  // check if the line compare two values
        {
            $pos1 =  strpos($value, '==') + 2; // get the existence position of '==' + 2 

            if($value[$pos1] === "=")
            {
                $pos1++;
            }

            $pos2 =  strrpos($value, ')'); // get the position of last ) in the line

            $startIndex = min($pos1, $pos2);
            $length = abs($pos1 - $pos2);

            $between = substr($value, $startIndex, $length);
            $between = str_replace('"','',$between);

            echo htmlspecialchars($between); // will print: "<SCRIPT" with double quotation
        }
    }
}

您的目标似乎非常具体,但我们可以解决您的问题。

  1. 您不应该使用 file_get_contents 来阅读 php 文件的实际源代码。您将获得生成的 html 等价物。如果您正在获取源代码,则意味着您已将 allow_url_fopen 设置为 true。这会使您的 Web 应用程序面临潜在的极具破坏性的脚本注入可能性,除非您知道自己在做什么并且小心并与您的代码保持一致。您应该尝试使用 fgets 代替。此代码基本上与您的 file_get_contents.
  2. 相同
$file='';
$handle = fopen('code.php','r+');
if ($handle) {
    while (($buffer=fgets($handle, 4096)) !== false) {
        $file.=$buffer."\n";
    }
    if (!feof($handle)) {
       die('error');
    }
    fclose($handle);
}
  1. 您的代码中存在错误。 if(strpos($value, 'if') != false) 会将位置 0 呈现为 false,这在您的情况下应该是 true,因为 if 位于位置 0。比较器应该是严格的 if(strpos($value, 'if') !== false).
  2. 它正在 return 引用,因为这是您的代码告诉它的。 $pos1 = strpos($value, '==') + 2 指向第一个 = 之后的 2 个字符,从技术上讲,这是您 === 中的最后一个 =。事实上,使用您当前的代码,您将得到 = "<SCRIPT" 作为结果。

现在解决方案

为了解决您的问题,您只需将位置调整为 substr 即可。进行上述修改后(尤其是 2),您将通过更改这两行

来获得没有引号的条件
$pos1 =  strpos($value, '===') + 5; // 5 includes the 3 equal signs, a space and the quote
$pos2 =  strrpos($value, ')') - 2; // 2 includes the space and the quote

虽然这会得到你想要的结果,但它可能不适用于所有用例,因为有时你可能会添加一个 space,有时你可能不会。一个更强大的解决方案是使用正则表达式。在你的情况下,它将是这样的:

foreach ($lines as $line) {
    if(preg_match("/if\s*?\([\s\S]*?\=\=\s*?[\"|']([\S\s]*?)[\"|']\s*?\)/", $line, $matches)){
        echo htmlspecialchars($matches[1]);     
    }
}

这个正则表达式字符串 /if\s*?\([\s\S]*?\=\=\s*?[\"|']([\S\s]*?)[\"|']\s*?\)/ 执行您的代码旨在执行的操作,但以更稳健的方式 = 找到一个字符串 if 可能是 space,(、一些文本、比较器 == 以及引号之间的任何内容 - '".

为了让它更稳健地获取其他条件,严格等于,< or > or <=, >=, 你可以这样做.

$conditionals=array();
foreach ($lines as $line) {
    if(preg_match("/if\s*?\([\s\S]*?([\=|\>|\<][\=]{0,2})\s*?[\"|']([\S\s]*?)[\"|']\s*?\)/", $line, $matches)){
        $conditionals[]=array(
            'comparator'=>$matches[1],
            'value'=>$matches[2]
        );
    }
}

foreach ($conditionals as $c){
    echo htmlspecialchars($c['comparator']).' ';        
    echo htmlspecialchars($c['value']); 
    echo "<br/>";
}

这适用于 code.php 的文件,可能如下所示:

//code.php
<?php

$a = 'Data';
if(substr($a, 0, strlen("<SCRIPT"))=== "<SCRIPT" ) {
   echo TRUE;
}


if(substr($a, 0, strlen("<SCRIPT"))== "equal" ) {
   echo TRUE;
}

if(substr($a, 0, strlen("<SCRIPT"))<= "lesser or equal" ) {
   echo TRUE;
}

if(substr($a, 0, strlen("<SCRIPT"))>= "greater or equal" ) {
   echo TRUE;
}

if(substr($a, 0, strlen("<SCRIPT"))< "lesser" ) {
   echo TRUE;
}

if(substr($a, 0, strlen("<SCRIPT"))>"greater" ) {
   echo TRUE;
}

并将return

=== <SCRIPT
== equal
<= lesser or equal
>= greater or equal
< lesser
> greater

编辑为非引号值提供更强大的代码... 另一个用于捕获变量值并将它们转储回去的编辑。 对单引号变量和变量之间的 space 的另一个编辑

注: 捕获字符串或变量的顺序首先很重要,好像我们不小心可能会陷入粘性循环 -> 变量中有字符串,字符串中有变量,字符串中有变量中有字符串变量等...

想法是我们应该首先捕获变量,评估这些变量中的任何变量(如果它们是双引号字符串),我们不需要担心 string-var 初始问题。

然后我们捕获字符串 -> 然后替换字符串,然后替换变量。

更多注释 我们真正应该检查的是: 由于 PHP 只计算双引号中的变量,我们应该在决定计算之前检查字符串是否被双引号和单引号括起来。我已经为变量完成了。它也可以很容易地转换为字符串——通过捕获引号,然后测试引号是单引号还是双引号(或任何引号)。我将把它作为正则表达式练习留给你。

另外一点是我是故意的。 :p 当前用于捕获变量的正则表达式适用于 $a=3;$a =3; 但不适用于 $a = 3;$a = 3 ;$a= 3 ;,依此类推。添加它很容易,我把它留在这里,这样你就有机会通过添加这个简单的条件来练习你的正则表达式技能。(编辑添加)希望这有帮助..

$file='';
$handle = fopen('code.php','r+');
if ($handle) {
    while (($buffer=fgets($handle, 4096)) !== false) {
        $file.=$buffer."\n";
    }
    if (!feof($handle)) {
       die('error');
    }
    fclose($handle);
}

//take note of the use of single quotes to wrap this regex, as we do not want PHP parser to eval the $ in the regex string
preg_match_all('/\s*?($[\S]+?)\s*?\=\s*?(\"?[\S]+?\"?);/',$file,$matches, PREG_SET_ORDER);
$varval=array();
foreach($matches as $match){
    $tmp=trim($match[2]);
    if(substr($tmp,0,1)=='"' && substr($tmp,-1,1)=='"'){    
        //evaluate variables in string. we can evaluate with the current object as the variable should be declared first as of proper PHP syntax
        $tmp=substr($tmp, 1,-1); //remove quotes
        $tmp=replaceFromObject($tmp, $varval);
    }else if(substr($tmp,0,1)=='\'' && substr($tmp,-1,1)=='\''){ // remove single quotes
        $tmp=substr($tmp, 1,-1);
        //no substitution of variables in single quotes just as PHP syntax
    }
    $varval[$match[1]]=$tmp; //we do not need to check if exists, because we should replace with the latest value.
}


/* 
The below stores all quoted text and replace them with our own special variable %var0%, %var1%, %var2%.... %varN%. 
This is because there could be cases like if("test == 3" == $a) or even worse if("if(test=3)" == $a), which will make regex/parsing tricky if we do not substitute these quoted text out just like a parser/compiler would.

Note: Something I didn't do. We should really first scan the whole text using preg_match to find if there are any text using this format of variables as well, to prevent collisions! 
If there are, we can set a loop to check and append some character to our own special variable like %varrN%, %varrrN%, %varrrrN%... 
until we find no collisions and it is safe to use. I will leave this simple regex exercise for you to do on your own. Create the regex to find the file for %varN%...
*/
preg_match_all("/\"([\s\S]*?)\"/", $file, $matches, PREG_SET_ORDER);
$stringvars=array();
$key="%var";
$count=0;
foreach($matches as $match){
    if(!in_array($match[1], $stringvars)){
        $stringvars[$key.$count.'%']=$match[1];
        $file=preg_replace("/\"".preg_quote($match[1])."\"/", $key.$count.'%', $file); //take note of the change to preg_quote
        $count++;
    }
}


// now we parse the whole text for if(subject anycomparator value)
preg_match_all("/if\s*?\(([\s\S]*?)([\=|\>|\<][\=]{0,2})\s*?([\S\s]*?)\s*?\)/", $file, $matches,PREG_SET_ORDER);
$conditionals=array();
foreach($matches as $match){
    $conditionals[]=array(
        'subject'=>replaceFromObject(replaceFromObject(trim($match[1]),$stringvars),$varval), 
        //the order does matter, we replace the string first, then the variables, as there might be variables in the double quoted strings which we should evaluate
        'comparator'=>$match[2],
        'value'=>replaceFromObject(replaceFromObject(trim($match[3]),$stringvars),$varval),
    );
}

foreach ($conditionals as $c){
    echo htmlspecialchars($c['subject']).' ';    
    echo htmlspecialchars($c['comparator']).' ';        
    echo htmlspecialchars($c['value']); 
    echo "<br/>";
}


/* now this function can be used to replace both the quoted strings AND the variables */
function replaceFromObject($s, $obj){
    foreach($obj as $key=>$value){
        $s=preg_replace('/'.preg_quote($key).'/', $value, $s); //take note of the preg_quote as the string may contain regex keywords
    }
    return $s;
}