I'm trying to get the value of if condition that make the condition TRUE, I have the following example:
(code.php)
<?php
$a = 'USERNAME';
$b = 'LASTNAME';
if(substr($a, 0, strlen("<SCRIPT"))=== "<SCRIPT Abdalla $a " ) {
}
?>
in the above example, I'm trying to get the value <SCRIPT without double quotations. I tried some steps, but it still get the double quotation with the value (<SCRIPT). I plan then to assign the value <SCRIPT to another variable. Next code shows my code to get the result, where it still not working properly:
(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;
}
?>
I want a way to print the value that make the if condition be TRUE, which is (
Note: I know the condition here is not TRUE, so that I want to get the value that make the condition TRUE which is <SCRIPT
The purpose is I want to know what is the value that make the condition TRUE, then later will use this value to do test cases on the code based on this value.
Your goal seems oddly specific, but here's a go at addressing your question.
You should not be using file_get_contents to read the actual source code of the php file. You will be getting the generated html equivalent instead. If you are getting the source code, it means you have your allow_url_fopen set to true. This opens your web application up to potential pretty damaging script injection possibilities, unless you know what you are doing and are careful and consistent with your code. You should try using fgets instead. This code will basically do the same as your file_get_contents.
$file='';
$handle = fopen('code.php','r+');
if ($handle) {
while (($buffer=fgets($handle, 4096)) !== false) {
$file.=$buffer."\n";
}
if (!feof($handle)) {
die('error');
}
fclose($handle);
}
There is a bug in your code. if(strpos($value, 'if') != false) will render position 0 as false, which should be true in your case as if is at position 0. The comparator should be strict if(strpos($value, 'if') !== false).
It is returning the quotation because that is what your code is telling it to. $pos1 = strpos($value, '==') + 2 is pointing to 2 characters after the first =, which is technically your last = in your ===. In fact, with your current code, you would be getting = "<SCRIPT" as the result.
Now for the Solution
To solve it just for your case, you can just adjust the position to substr with. After making the amendments mentioned above (especially 2), you will get your condition without the quotes by changing these 2 lines
$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
Although this will get the result you want, it might not work for all use cases, as sometimes you might add a space, sometimes you might not. A more robust solution will be to use regex. In your case, it will be something along this line:
foreach ($lines as $line) {
if(preg_match("/if\s*?\([\s\S]*?\=\=\s*?[\"|']([\S\s]*?)[\"|']\s*?\)/", $line, $matches)){
echo htmlspecialchars($matches[1]);
}
}
This regex string /if\s*?\([\s\S]*?\=\=\s*?[\"|']([\S\s]*?)[\"|']\s*?\)/ does what your code aims to do, but in a more robust manner = finds a string with if possibly a space, a (, some text, a comparator == and whatever is in between the quotes - either ' or ".
To have it even more robust to pick up other conditions, strict equal, < or > or <=, >=, you can do something like this.
$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/>";
}
This will work for a file of code.php that might look like this:
//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;
}
and will return
=== <SCRIPT
== equal
<= lesser or equal
>= greater or equal
< lesser
> greater
Edit to provide even more robust code for non-quoted values...
Another edit to capture variable values and dump them back in.
Another edit for single quotes variables and space between variables
Note:
The order of capturing strings or variables first matters, as if we are not careful we might be caught in a viscous cycle -> there is string in the variable, there is variable in the string, there is a string in the variable in the string of a variable, etc...
The idea is we should capture the variable first, evaluate whatever variables within these variables (if they are a double quoted string), and we do not need to worry about that string-var inception problem.
We then capture the strings -> and then replace the strings THEN replace the variables.
More Notes
What we should really also check for:
Since PHP only evaluates variables in double quotes, we should check if the string was enclosed in double and single quotes before making the decision to evaluate. I have done it for the variables. It could be easily translated to the strings as well - by capturing the quotes as well, then testing the quotes if it is single or double (or any at all). I will leave this to you as a regex exercise.
The other note is that I did this on purpose. :p The current regex for capturing variables works for $a=3;, $a =3; but not $a = 3; or $a = 3 ; or $a= 3 ;, so on. It is easy to add it in, I left it this way so you have a chance to practice your regex skills by adding this simple conditions in. (Edited to add this in) Hope this helps..
$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;
}
So actually your code doesn't output anything (test.php) on my server. Therefore I've tried another approach which at least works for your code.php, but however, it is not very stable like your own code since it doesn't take a few things into account which would be the following.
Logical operators which weren't thought of:
<, <=, >, >=, ===
No multiline if support
My approch actually doesn't split the string nor does it strip anything, the only thing which it is doing however, is to replace the string literal.
<?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);
}
This outputs: <SCRIPT
For your script, I found several issues:
if(strpos($value, 'if') !== false)
has to have a double ==
with that out of the way, you're getting the following output:
= "<SCRIPT"
To get rid of this, simply check if the char after pos1 is another =
if($value[$pos1] === "=")
{
$pos1++;
}
Then we can actually remove the call to sanitize_recursive completely, because substr never returns an array.
Now to get rid, simply call str_replace on the between string:
$between = substr($value, $startIndex, $length);
$between = str_replace('"','',$between);
echo htmlspecialchars($between);
And we're having an output of <SCRIPT- the call to htmlspecialchars is needed because otherwise your browser would start to interpret this tag.
This leaves us with the following file:
<?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
}
}
}
Right now I use stristr($q, $string) but if
$string = "one monkey can jump 66 times";
$q = "monkey 66";
I want to find out if this string contains both monkey and 66.
How can i do that?
you could use both stristr and strpos.
as it is reported in this post, the second method is faster and less memory intensive.
well, check this lines out:
// here there are your string and your keywords
$string = "one monkey can jump 66 times";
$q = "monkey 66";
// initializate an array from keywords in $q
$q = explode(" ", $q);
// for every keyword you entered
foreach($q as $value) {
// if strpos finds the value on the string and return true
if (strpos($string, $value))
// add the found value to a new array
$found[] = $value;
}
// if all the values are found and therefore added to the array,
// the new array should match the same object of the values array
if ($found === $q) {
// let's go through your path, super-man!
echo "ok, all q values are in string var, you can continue...";
}
if(stristr('monkey', $string) && stristr('66', $string)) {
//Do stuff
}
simply post your variable value by giving them a variable $monkey,$value ($monkey jumps $value) and then fetch its value
You can use the strpos() function which is used to find the occurrence of one string inside another one:
$a = 'How are you?';
if (strpos($a, 'are') !== false) {
echo 'true';
}
Note that the use of !== false is deliberate (neither != false nor === true will work); strpos() returns either the offset at which the needle string begins in the haystack string, or the boolean false if the needle isn't found. Since 0 is a valid offset and 0 is "falsey", we can't use simpler constructs like !strpos($a, 'are').
I am trying to replace the value Event Id in the $fields array with the value that is mapped to (idEvent) in the $aliases array, but PHP's array_search function is returning the wrong position. Note: I am converting the values to all lower case so it should return a match, and it seems like array_search is returning a index, but it should be returning index 2 instead of index 1 since it is the third value in the $fields array.
Unfortunately, if you run the code (e.g. copy and paste it here: http://writecodeonline.com/php/), it returns the wrong value. Could someone please tell me if I am doing something wrong?
$fields = array('Host', 'OS', 'Event Id');
$aliases = array('idEvent' => 'Event ID');
foreach ($aliases as $actual => $alias){
$alias = strtolower($alias);
echo "searching fields(" . implode(',', array_map('strtolower', $fields)) . ") for $alias<br/>";
if ($position = array_search($alias, array_map('strtolower', $fields)) !== FALSE) {
echo "$alias was found at \$fields[$position]";
$fields[$position] = $actual;
}
}
Edit: I added some echo statements so you can what I am trying to do.
It's the order of operations of the if statement that's the problem. The assignment operator has lower precedence than the comparison operator, and the assignment is evaluated from the right first. So add some parenthesis:
if (($position = array_search($alias, array_map('strtolower', $fields))) !== FALSE) {
I find this easier to read:
if (in_array($alias, array_map('strtolower', $fields))) {
array_search($alias, array_map('strtolower', $fields)) !== FALSE
This is true right? Then it translates to $position = 1 and therefor you see it he found the key one but actually returns the value of the equal...
Use parenthesis or store the value of the search beforehand.
$position is getting assigned value of 1 because its the result of comparing your array_search to !== FALSE
use the test at the left side to fix the issue.
if (false !== ($position = array_search($alias, array_map('strtolower', $fields)))) {
echo "$alias was found at {$fields[$position]}";
$fields[$position] = $actual;
}