Could someone point out what I'm mistaking here? :)
<?php
$q = $_GET[q];
$acuman = <<<PARSE
input: (contains: "hello"){
output: "hello";
}
PARSE;
$acuman = str_replace("input: (contains: ", 'if(strpos(', $acuman);
$acuman = str_replace("){", ', $q) !== false) {', $acuman);
$acuman = str_replace("output: ", '$output = ', $acuman);
eval($acuman);
?>
I'm attempting to execute the string $acuman, a heredoc which has been altered by various str_replace functions. However, it is not doing what I intend it to do, and I am confused as of what to do as I've tried many different things.
Since many people seemed confused: My intention is for the code in the string $acuman to be executed as code properly. I just want the eval function to work. I know that eval is evil, please, stop: I'm just asking for help for solving the problem at hand.
Edit: When I echo the string $acuman, this is what I get:
if(strpos("hello", $q) !== false) { $output = "hello"; }
You have the arguments in the wrong order:
if(strpos($q, "hello") !== false) { $output = "hello"; }
strpos() takes the "haystack" (string being searched) as the first argument and the "needle" (string to find as within the "haystack") as the second argument.
Ok, so... $acuman appears to contain the following:
if(strpos("hello", $q) !== false) {
echo "hello";
}
Which indicates that $q needs to contain a portion of "hello" to echo the string "hello".
I don't see any problem here, EXCEPT that $q = $_GET[q]; won't work with any modern version because q is treated like a constant, not a variable nor a string literal array index. See this PHP documentation on the subject.
Upon changing to $q = $_GET['q']; instead (note the quotes), it seems like this code actually works. It will output "hello" whenever passing any portion of "hello" to the URL parameter (which gets passed to the PHP code).
Needless to say: Do not use this code for production. The code as it is is very vulnerable and allows a user to pass raw PHP code through to your script to execute. The function of this code can be completely re-written in a much safer manner, but you have expressed the desire to continue using eval(); so please be careful.
Enjoy.
Related
I'm using the following code to return true or false if a string contains a substring in PHP 8.0.
<?php
$username = "mothertrucker"; // This username should NOT be allowed
$banlistFile = file_get_contents("banlist.txt"); //Contains the word "trucker" in it
$banlist = explode("\n", $banlistFile); // Splits $banlistFile into an array, split by line
if (contains($username, $banlist)) {
echo "Username is not allowed!";
} else {
echo "Username is allowed";
}
function contains($str, array $arr)
{
foreach($arr as $a) { // For each word in the banlist
if (stripos($str, $a) !== false) { // If I change $a to 'trucker', it works. "trucker" does not
return true;
}
}
return false;
}
?>
This is to detect if an inappropriate word is used when creating a username. So for example, if someone enters the username "mothertrucker", and "trucker" is included in the ban list, I want it to deny it.
Right now with this code, If I just type in the word "trucker" as a username, it is found and blocks it. Cool. However if there's more to the string than just "trucker", it doesn't detect it. So the username "mothertrucker" is allowed.
I discovered that if I explicitly type in 'trucker' instead of $a in the stripos function, it works perfectly. However, if I explicitly type in "trucker" (with double quotes), it stop working, and only blocks if that's the only thing the user entered.
So what I'm seeing, is it looks like the string $a that I'm passing it is being interpreted by PHP as a double quoted string, when in order for this to detect it properly, it needs to be a single quoted string. But as far as I can tell, I have no control over how php passes passing the variable.
Can I somehow convert it to a single quoted string? Perhaps the explode command I'm using in line 2 is causing it? Is there another way I can pull the data from a txt document and have it be interpreted as a single quote string? Hopefully I'm made sense with my explanation, but you can copy and paste the code and see it for yourself
Thanks for any help!
One potential problem would be any whitespace (which includes things like \r) could stop the word matching, so just trimming the word to compare with can tidy that up...
stripos($str, $a)
to
stripos($str, trim($a))
I do not know what your file actually contains so i dont know what the result of explode is.
Anyways my suggestion is (depending on the speed you want to perform this and also the length of the banlist file also your level of banning) to not explode the file and just look into it as a whole.
<?php
$username = "allow"; // This username should be allowed
$banlist = "trucker\nmotherfucker\n donot\ngoodword";
var_dump(contains($username, $banlist));
function contains($str, $arr)
{
if (stripos($arr, $str) !== false) return true;
else return false;
}
?>
Otherwise if you are going to allow say good which is an allowed word but since it is in the file with goodword it will not (using my example), you should not use stripos but instead use your example and use strcasecmp
Basically the problem I am having is I need to write this function that can take a URL like www.stackoverflow.com and just return the "com". But I need to be able to return the same value even if the URL has a period at the end like "www.stackoverflow.com."
This is what I have so far. The if statement is my attempt to return the point in the array before the period but I dont think I am using the if statement correctly. Otherwise the rest of the code does exactly what is supposed to do.
<?php
function getTLD($domain)
{
$domainArray = explode("." , $domain);
$topDomain = end($domainArray);
if ($topDomain == " ")
$changedDomain = prev(end($domainArray));
return $changedDomain;
return $topDomain;
}
?>
Don't use a regex for simple cases like that, it is cpu costly and unreadable. Just remove the final dot if it exists:
function getTLD($domain) {
$domain = rtrim($domain, '.');
return end(explode('.', $domain));
}
The end function is returning an empty string "" (without any spaces). You are comparing $topDomain to single space character so the if is not evaluating to true.
Also prev function requires array input and end($domainArray) is returning a string, so, $changedDomain = prev(end($domainArray)) should throw an E_WARNING.
Since end updates the internal pointer of the array $domainArray, which is already updated when you called $topDomain = end($domainArray), you do not need to call end on $domainArray inside the if block.
Try:
if ($topDomain == "") {
$changedDomain = prev($domainArray);
return $changedDomain; // Will output com
}
Here is the phpfiddle for it.
Use regular expressions for something like this. Try this:
function getTLD($domain) {
return preg_replace("/.*\.([a-z]+)\.?$/i", "$1", $domain );
}
A live example: http://codepad.org/km0vCkLz
Read more about regular expressions and about how to use them: http://www.regular-expressions.info/
I would like to know if it's possible to execute the php code in a string. I mean if I have:
$string = If i say <?php echo 'lala';?> I wanna get "<?php echo 'dada'; ?>";
Does anybody knows how?
[EDIT] It looks like nobody understood. I wanna save a string like
$string = If i say <?php count(array('lala'));?>
in a database and then render it. I can do it using
function render_php($string){
ob_start();
eval('?>' . $string);
$string = ob_get_contents();
ob_end_clean();
return $string;
}
The problem is that I does not reconize php code into "" (quotes) like
I say "<?php echo 'dada'; ?>"
$string = ($test === TRUE) ? 'lala' : 'falala';
There are lots of ways to do what it looks like you're trying to do (if I'm reading what you wrote correctly). The above is a ternary. If the condition evaluates to true then $string will be set to 'lala' else set to 'falala'.
If you're literally asking what you wrote, then use the eval() function. It takes a passed string and executes it as if it were php code. Don't include the <?php ?> tags.
function dropAllTables() {
// drop all tables in db
}
$string = 'dropAllTables();';
eval($string); // will execute the dropAllTables() function
[edit]
You can use the following regular expression to find all the php code:
preg_match_all('/(<\?php )(.+?)( \?>)/', $string, $php_code, PREG_OFFSET_CAPTURE);
$php_code will be an array where $php_code[0] will return an array of all the matches with the code + <?php ?> tags. $php_code[2] will be an array with just the code to execute.
So,
$string = "array has <?php count(array('lala')); ?> 1 member <?php count(array('falala')); ?>";
preg_match_all('/(<\?php )(.+?)( \?>)/', $string, $php_code, PREG_OFFSET_CAPTURE);
echo $php_code[0][0][0]; // <?php count(array('lala')); ?>
echo $php_code[2][0][0]; // count(array('lala'));
This should be helpful for what you want to do.
Looks like you are trying to concatenate. Use the concatenation operator "."
$string = "if i say " . $lala . " I wanna get " . $dada;
or
$string = "if i say {$lala} I wanna get {$dada}.";
That is what I get since your string looks to be a php variable.
EDIT:
<?php ?> is used when you want to tell the PHP interpreter that the code in those brackets should be interpreted as PHP. When working within those PHP brackets you do not need to include them again. So as you would just do this:
// You create a string:
$myString = "This is my string.";
// You decide you want to add something to it.
$myString .= getMyNameFunction(); // not $myString .= <?php getMyNameFunction() ?>;
The string is created, then the results of getMyNameFunction() are appended to it. Now if you declared the $myString variable at the top of your page, and wanted to use it later you would do this:
<span id="myString"><?php echo $myString; ?></span>
This would tell the interpreter to add the contents of the $myString variable between the tags.
Use token_get_all() on the string, then look for a T_OPEN_TAG token, start copying from there, look for a T_CLOSE_TAG token and stop there. The string between the token next to T_OPEN_TAG and until the token right before T_CLOSE_TAG is your PHP code.
This is fast and cannot fail, since it uses PHP's tokenizer to parse the string. You will always find the bits of PHP code inside the string, even if the string contains comments or other strings which might contain ?> or any other related substrings that will confuse regular expressions or a hand-written, slow, pure PHP parser.
I would consider not storing your PHP code blocks in a database and evaluating them using eval. There is usually a better solution. Read about Design Pattern, OOP, Polymorphism.
You could use the eval() function.
This is a follow-up question to the one I posted here (thanks to mario)
Ok, so I have a preg_replace statement to replace a url string with sometext, insert a value from a query string (using $_GET["size"]) and insert a value from a associative array (using $fruitArray["$1"] back reference.)
Input url string would be:
http://mysite.com/script.php?fruit=apple
Output string should be:
http://mysite.com/small/sometext/green/
The PHP I have is as follows:
$result = preg_replace('|http://www.mysite.com/script.php\?fruit=([a-zA-Z0-9_-]*)|e', ' "http://www.mysite.com/" .$_GET["size"]. "/sometext/" .$fruitArray["$1"]. "/"', $result);
This codes outputs the following string:
http://mysite.com/small/sometext//
The code seems to skip the value in $fruitArray["$1"].
What am I missing?
Thanks!
Well, weird thing.
Your code work's perfectly fine for me (see below code that I used for testing locally).
I did however fix 2 things with your regex:
Don't use | as a delimiter, it has meaning in regex.
Your regular expression is only giving the illusion that it works as you're not escaping the .s. It would actually match http://www#mysite%com/script*php?fruit=apple too.
Test script:
$fruitArray = array('apple' => 'green');
$_GET = array('size' => 'small');
$result = 'http://www.mysite.com/script.php?fruit=apple';
$result = preg_replace('#http://www\.mysite\.com/script\.php\?fruit=([a-zA-Z0-9_-]*)#e', ' "http://www.mysite.com/" .$_GET["size"]. "/sometext/" .$fruitArray["$1"]. "/"', $result);
echo $result;
Output:
Rudis-Mac-Pro:~ rudi$ php tmp.php
http://www.mysite.com/small/sometext/green/
The only thing this leads me to think is that $fruitArray is not setup correctly for you.
By the way, I think this may be more appropriate, as it will give you more flexibility in the future, better syntax highlighting and make more sense than using the e modifier for the evil() function to be internally called by PHP ;-) It's also a lot cleaner to read, IMO.
$result = preg_replace_callback('#http://www\.mysite\.com/script\.php\?fruit=([a-zA-Z0-9_-]*)#', function($matches) {
global $fruitArray;
return 'http://www.mysite.com/' . $_GET['size'] . '/sometext/' . $fruitArray[$matches[1]] . '/';
}, $result);
i write it again, i don't understand good where is the error, the evaluation of preg results is very weird in php
preg_replace(
'|http\://([\w\.-]+?)/script\.php\?fruit=([\w_-]+)|e'
, '"http://www.$1/".$_GET["size"]."/sometext/".$fruitArray["$2"]."/";'
, $result
);
It looks like you have forgotten to escape the ?. It should be /script.php\?, with a \? to escape properly, as in the linked answer you provided.
$fruitArray["\$1"] instead of $fruitArray["$1"]
For reasons I'd rather not get into right now, I have a string like so:
<div>$title</div>
that gets stored in a database using mysql_real_escape_string.
During normal script execution, that string gets parsed and stored in a variable $string and then gets sent to a function($string).
In this function, I am trying to:
function test($string){
$title = 'please print';
echo $string;
}
//I want the outcome to be <div>please print</div>
This seems like the silliest thing, but for the life of me, I cannot get it to "interpret" the variables.
I've also tried,
echo html_entity_decode($string);
echo bin2hex(html_entity_decode($string)); //Just to see what php was actually seeing I thought maybe the $ had a slash on it or something.
I decided to post on here when my mind kept drifting to using EVAL().
This is just pseudocode, of course. What is the best way to approach this?
Your example is a bit abstract. But it seems like you could do pretty much what the template engines do for these case:
function test($string){
$title = 'please print';
$vars = get_defined_vars();
$string = preg_replace('/[$](\w{3,20})/e', '$vars["$1"]', $string);
echo $string;
}
Now actually, /e is pretty much the same as using eval. But at least this only replaces actual variable names. Could be made a bit more sophisticated still.
I don't think there is a way to get that to work. You are trying something like this:
$var = "cute text";
echo 'this is $var';
The single quotes are preventing the interpreter from looking for variables in the string. And it is the same, when you echo a string variable.
The solution will be a simple str_replace.
echo str_replace('$title', $title, $string);
But in this case I really suggest Template variables that are unique in your text.
You just don't do that, a variable is a living thing, it's against its nature to store it like that, flat and dead in a string in the database.
If you want to replace some parts of a string with the content of a variable, use sprintf().
Example
$stringFromTheDb = '<div>%s is not %s</div>';
Then use it with:
$finalString = sprintf($stringFromTheDb, 'this', 'that');
echo $finalString;
will result in:
<div>this is not that</div>
If you know that the variable inside the div is $title, you can str_replace it.
function test($string){
$title = 'please print';
echo str_replace('$title', $title, $string);
}
If you don't know the variables in the string, you can use a regex to get them (I used the regex from the PHP manual).
function test($string){
$title = 'please print';
$vars = '/(?<=\$)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
preg_match_all($vars, $string, $replace);
foreach($replace[0] as $r){
$string = str_replace('$'.$r, $$r, $string);
}
echo $string;
}