Is variable's value back-slashing available in PHP? - php

When we check:
dir1/dir2/../file.txt ==== this is same as =====> dir1/file.txt
I am interested is something same thing available in PHP, like:
$name= "Hello ". $variable . "World";
if i had $variable = "../Hi" (or anything like that) so, it removed (like backslashing) the previous part, printed Hi World ?
(p.s. I dont control the php file, I ask about how attackers can achieve that).
(p.s.2. I dont have words to downvoters for closing this. I think you have problems with analysing of questions before you close).

In PHP there exist no special ../ (or any other string) that when concatenated to another string generates any string other than the combine original string concatenated with the new string. Concatenation, regardless of content of strings always results in:
"<String1><String2>" = "<String1>"."<String2>";
Nothing will not 'erase' prior tokens in a string or anything like that and is completely harmless.
Caveat!!!! Of course if the string is being used somewhere that interprets it in some specific way where any character or group of characters in the ../ is treated special such as:
In a string used for regex pattern
In a string used as a file path (in that case, when it's evaluated it will do exactly what you'd expect if you'd typed it.
A string used in a SQL query without properly escaping (as with binding params/values via prepared statements)
etc...
Now, if you want to remove the word prior to each occurence of ../ starting a word in a sentence, sort-of replicating how the .. in a path means, go up one level (in effect undoing the step made to the directory in the path prior to it).
Here's a basic algorithm to start you out (if you are able to change the source code) :
Use explode with delimiter " " on the string.
Create a new array
Iterate the returned array, if not ../ insert at end of new array
if entry starts with ../, remove the end element of the 2nd array
insert the the ../somestring with the ../ string replaced with empty string "" on the end of the 2nd array
Once at end of array (all strings processed), implode() with delimiter " "
Here's an example:
<?php
$variable = "../Hi";
$string = "Hello ". $variable . " World"; // Note: I added a space prior to the W
$arr = array();
foreach(explode(" ", $string) as $word) {
if (substr( $word, 0, 3 ) === "../") {
if(!empty($arr)){
array_pop($arr);
}
$arr[] = str_replace("../", "", $word);
} else {
$arr[] = $word;
}
}
echo implode(" ", $arr);

Related

preg_replace with a word in an array

I am trying to use certain words in a array called keywords, which will be used to be replaced in a string by "as".
for($i = 0; $i<sizeof($this->keywords[$this->lang]); $i++)
{
$word = $this->keywords[$this->lang][$i];
$a = preg_replace("/\b$word\b/i", "as",$this->code);
}
It works with if I replace the variable $word with something like /\bhello\b/i, which then would replace all hello words with "as".
Is the approach am using even possible?
Before to be a pattern, it's a double quoted string, so variables will be replaced, it's not the problem.
The problem is that you use a loop to change several words and you store the result in $a:
the first iteration, all the occurences of the first word in $this->code are replaced and the new string is stored in $a.
but the next iteration doesn't reuse $a as third parameter to replace the next word, but always the original string $this->code
Result: after the for loop $a contains the original string but with only the occurences of the last word replaced with as.
When you want to replace several words with the same string, a way consists to build an alternation: word1|word2|word3.... It can easily be done with implode:
$alternation = implode('|', $this->keywords[$this->lang]);
$pattern = '~\b(?:' . $alternation . ')\b~i';
$result = preg_replace($pattern, 'as', $this->code);
So, when you do that, the string is parsed only once and all the words are replaced in one shot.
If you have a lot of words and a very long string:
Testing a long alternation has a significant cost. Even if the pattern starts with \b that highly reduces the possible positions for a match, your pattern will have hard time to succeed and more to fail.
Only in this particular case, you can use this another way:
First you define a placeholder (a character or a small string that can't be in your string, lets say §) that will be inserted in each positions of word boundaries.
$temp = preg_replace('~\b~', '§', $this->code);
Then you change all the keywords like this §word1§, §word2§ ... and you build an associative array where all values are the replacement string:
$trans = [];
foreach ($this->keywords[$this->lang] as $word) {
$trans['§' . $word . '§'] = 'as';
}
Once you have do that you add an empty string with the placeholder as key. You can now use the fast strtr function to perform the replacement:
$trans['§'] = '';
$result = strtr($temp, $trans);
The only limitation of this technic is that it is case-sensitive.
it will work if you keep it like bellow:
$a = preg_replace("/\b".$word."\b/i", "as",$this->code);

very large php string magically turns into array

I am getting an "Array to string conversion error on PHP";
I am using the "variable" (that should be a string) as the third parameter to str_replace. So in summary (very simplified version of whats going on):
$str = "very long string";
str_replace("tag", $some_other_array, $str);
$str is throwing the error, and I have been trying to fix it all day, the thing I have tried is:
if(is_array($str)) die("its somehow an array");
serialize($str); //inserted this before str_replace call.
I have spent all day on it, and no its not something stupid like variables around the wrong way - it is something bizarre. I have even dumped it to a file and its a string.
My hypothesis:
The string is too long and php can't deal with it, turns into an array.
The $str value in this case is nested and called recursively, the general flow could be explained like this:
--code
//pass by reference
function the_function ($something, &$OFFENDING_VAR, $something_else) {
while(preg_match($something, $OFFENDING_VAR)) {
$OFFENDING_VAR = str_replace($x, y, $OFFENDING_VAR); // this is the error
}
}
So it may be something strange due to str_replace, but that would mean that at some point str_replace would have to return an array.
Please help me work this out, its very confusing and I have wasted a day on it.
---- ORIGINAL FUNCTION CODE -----
//This function gets called with multiple different "Target Variables" Target is the subject
//line, from and body of the email filled with << tags >> so the str_replace function knows
//where to replace them
function perform_replacements($replacements, &$target, $clean = TRUE,
$start_tag = '<<', $end_tag = '>>', $max_substitutions = 5) {
# Construct separate tag and replacement value arrays for use in the substitution loop.
$tags = array();
$replacement_values = array();
foreach ($replacements as $tag_text => $replacement_value) {
$tags[] = $start_tag . $tag_text . $end_tag;
$replacement_values[] = $replacement_value;
}
# TODO: this badly needs refactoring
# TODO: auto upgrade <<foo>> to <<foo_html>> if foo_html exists and acting on html template
# Construct a regular expression for use in scanning for tags.
$tag_match = '/' . preg_quote($start_tag) . '\w+' . preg_quote($end_tag) . '/';
# Perform the substitution until all valid tags are replaced, or the maximum substitutions
# limit is reached.
$substitution_count = 0;
while (preg_match ($tag_match, $target) && ($substitution_count++ < $max_substitutions)) {
$target = serialize($target);
$temp = str_replace($tags,
$replacement_values,
$target); //This is the line that is failing.
unset($target);
$target = $temp;
}
if ($clean) {
# Clean up any unused search values.
$target = preg_replace($tag_match, '', $target);
}
}
How do you know $str is the problem and not $some_other_array?
From the manual:
If search and replace are arrays, then str_replace() takes a value
from each array and uses them to search and replace on subject. If
replace has fewer values than search, then an empty string is used for
the rest of replacement values. If search is an array and replace is a
string, then this replacement string is used for every value of
search. The converse would not make sense, though.
The second parameter can only be an array if the first one is as well.

Regex to match double quoted strings without variables inside php tags

Basically I need a regex expression to match all double quoted strings inside PHP tags without a variable inside.
Here's what I have so far:
"([^\$\n\r]*?)"(?![\w ]*')
and replace with:
'$1'
However, this would match things outside PHP tags as well, e.g HTML attributes.
Example case:
Here's my "dog's website"
<?php
$somevar = "someval";
$somevar2 = "someval's got a quote inside";
?>
<?php
$somevar3 = "someval with a $var inside";
$somevar4 = "someval " . $var . 'with concatenated' . $variables . "inside";
$somevar5 = "this php tag doesn't close, as it's the end of the file...";
it should match and replace all places where the " should be replaced with a ', this means that html attributes should ideally be left alone.
Example output after replace:
Here's my "dog's website"
<?php
$somevar = 'someval';
$somevar2 = 'someval\'s got a quote inside';
?>
<?php
$somevar3 = "someval with a $var inside";
$somevar4 = 'someval ' . $var . 'with concatenated' . $variables . 'inside';
$somevar5 = 'this php tag doesn\'t close, as it\'s the end of the file...';
It would also be great to be able to match inside script tags too...but that might be pushing it for one regex replace.
I need a regex approach, not a PHP approach. Let's say I'm using regex-replace in a text editor or JavaScript to clean up the PHP source code.
tl;dr
This is really too complex complex to be done with regex. Especially not a simple regex. You might have better luck with nested regex, but you really need to lex/parse to find your strings, and then you could operate on them with a regex.
Explanation
You can probably manage to do this.
You can probably even manage to do this well, maybe even perfectly.
But it's not going to be easy.
It's going to be very very difficult.
Consider this:
Welcome to my php file. We're not "in" yet.
<?php
/* Ok. now we're "in" php. */
echo "this is \"stringa\"";
$string = 'this is \"stringb\"';
echo "$string";
echo "\$string";
echo "this is still ?> php.";
/* This is also still ?> php. */
?> We're back <?="out"?> of php. <?php
// Here we are again, "in" php.
echo <<<STRING
How do "you" want to \""deal"\" with this STRING;
STRING;
echo <<<'STRING'
Apparently this is \\"Nowdoc\\". I've never used it.
STRING;
echo "And what about \\" . "this? Was that a tricky '\"' to catch?";
// etc...
Forget matching variable names in double quoted strings.
Can you just match all of the string in this example?
It looks like a nightmare to me.
SO's syntax highlighting certainly won't know what to do with it.
Did you consider that variables may appear in heredoc strings as well?
I don't want to think about the regex to check if:
Inside <?php or <?= code
Not in a comment
Inside a quoted quote
What type of quoted quote?
Is it a quote of that type?
Is it preceded by \ (escaped)?
Is the \ escaped??
etc...
Summary
You can probably write a regex for this.
You can probably manage with some backreferences and lots of time and care.
It's going to be hard and your probably going to waste a lot of time, and if you ever need to fix it, you aren't going to understand the regex you wrote.
See also
This answer. It's worth it.
Here's a function that utilizes the tokenizer extension to apply preg_replace to PHP strings only:
function preg_replace_php_string($pattern, $replacement, $source) {
$replaced = '';
foreach (token_get_all($source) as $token) {
if (is_string($token)){
$replaced .= $token;
continue;
}
list($id, $text) = $token;
if ($id === T_CONSTANT_ENCAPSED_STRING) {
$replaced .= preg_replace($pattern, $replacement, $text);
} else {
$replaced .= $text;
}
}
return $replaced;
}
In order to achieve what you want, you can call it like this:
<?php
$filepath = "script.php";
$file = file_get_contents($filepath);
$replaced = preg_replace_php_string('/^"([^$\{\n<>\']+?)"$/', '\'$1\'', $file);
echo $replaced;
The regular expression that's passed as the first argument is the key here. It tells the function to only transform strings to their single-quoted equivalents if they do not contain $ (embedded variable "$a"), { (embedded variable type 2 "{$a[0]}"), a new line, < or > (HTML tag end/open symbols). It also checks if the string contains a single-quote, and prevents the replacement to avoid situations where it would need to be escaped.
While this is a PHP solution, it's the most accurate one. The closest you can get with any other language would require you to build your own PHP parser in that language to some degree in order for your solution to be accurate.

I need to get a value in PHP "preg_match_all" - Basic (I think)

I am trying to use a License PHP System…
I will like to show the status of their license to the users.
The license Server gives me this:
name=Service_Name;nextduedate=2013-02-25;status=Active
I need to have separated the data like this:
$name = “Service_Name”;
$nextduedate = “2013-02-25”;
$status = “Active”;
I have 2 days tring to resolve this problem with preg_match_all but i cant :(
This is basically a query string if you replace ; with &. You can try parse_str() like this:
$string = 'name=Service_Name;nextduedate=2013-02-25;status=Active';
parse_str(str_replace(';', '&', $string));
echo $name; // Service_Name
echo $nextduedate; // 2013-02-25
echo $status; // Active
This can rather simply be solved without regex. The use of explode() will help you.
$str = "name=Service_Name;nextduedate=2013-02-25;status=Active";
$split = explode(";", $str);
$structure = array();
foreach ($split as $element) {
$element = explode("=", $element);
$$element[0] = $element[1];
}
var_dump($name);
Though I urge you to use an array instead. Far more readable than inventing variables that didn't exist and are not explicitly declared.
It sounds like you just want to break the text down into separate lines along the semicolons, add a dollar sign at the front and then add spaces and quotes. I'm not sure you can do that in one step with a regular expression (or at least I don't want to think about what that regular expression would look like), but you can do it over multiple steps.
Use preg_split() to split the string into an array along the
semicolons.
Loop over the array.
Use str_replace to replace each '=' with ' = "'.
Use string concatenation to add a $ to the front and a "; to the end of each string.
That should work, assuming your data doesn't include quotes, equal signs, semicolons, etc. within the data. If it does, you'll have to figure out the parsing rules for that.

Using preg_replace to back reference array key and replace with a value

I have a string like this:
http://mysite.com/script.php?fruit=apple
And I have an associative array like this:
$fruitArray["apple"] = "green";
$fruitArray ["banana"] = "yellow";
I am trying to use preg_replace on the string, using the key in the array to back reference apple and replace it with green, like this:
$string = preg_replace('|http://mysite.com/script.php\?fruit=([a-zA-Z0-9_-]*)|', 'http://mysite.com/'.$fruitArray[$1].'/', $string);
The process should return
http://mysite.com/green/
Obviously this isn’t working for me; how can I manipulate $fruitArray[$1] in the preg_replace statement so that the PHP is recognised, back referenced, and replaced with green?
Thanks!
You need to use the /e eval flag, or if you can spare a few lines preg_replace_callback.
$string = preg_replace(
'|http://mysite.com/script.php\?fruit=([a-zA-Z0-9_-]*)|e',
' "http://mysite.com/" . $fruitArray["$1"] ',
$string
);
Notice how the whole URL concatenation expression is enclosed in single quotes. It will be interpreted as PHP expression later, the spaces will vanish and the static URL string will be concatenated with whatever is in the fruitArray.

Categories