Should you use htmlspecialchars() before isset() and empty(), or after? - php

I was wondering what is the correct procedure when it comes to security and practicality. Should you use htmlspecialchars() on a variable before you check if it's set and empty?
Examples:
Use htmlspecialchars() on use or storage of post data:
$field = $_POST['field'];
if(isset($field)){
//store or use: htmlspecialchars($field);
}
Or should you use htmlspecialchars() on retrieval of the post data:
$field = htmlspecialchars($_POST['field']);
if(isset($field)){
//store or use: $field
}
This is probably a silly question, but I wanted to know which is correct.

Well, think about it this way. Why do we use isset in the first place? The answer is to protect our code from trying to do things with something that doesn't exist.
For example, using php -a in your console, you can see:
php > $temp
php > echo htmlspecialchars($temp);
Parse error: parse error in php shell code on line 2
php >
Clearly you don't want your code throwing parse errors. So, you need to check that the value exists first (using isset), then do things with that value.

You should use both isset and empty if you want to make your condition fully secure, Because isset checks that variable is defined or not and empty checks for the value of variable is empty or not.
So you should use your if condition like this,
$field = $_POST['field'];
if(isset($field) && !empty($field)){
//store or use: htmlspecialchars($field);
}

Related

php validating output with htmlspecialchars

I set a php cookie
setcookie('pr','gulfstream',time()...etc...)
My validation page has arrays and statements as below.
$planes = array('gulfstream','Piper','Citation');
$abc = isset($_COOKIE['pr']) && in_array($_COOKIE['pr'],$planes) ? $_COOKIE['pr']:0;
My visitor pages use:
echo $abc;
Question: is the above safe to output to the page or should I further validate the statement with:
$abc = isset($_COOKIE['pr']) && in_array($_COOKIE['pr'],$planes) ? htmlspecialchars($_COOKIE['pr']):0;
I don't think there's a way to exploit this code in this example.
Anyway I think you have to be aware that it's is to make it exploitable by possibility of type juggling (usually cast to integer 0).
That's why I suggest you to use strict mode of in_array like
in_array($_COOKIE['pr'],$planes, true); //third parameter enforces type checking
Even if you've validated the cookie, it's still meant to contain text, and not HTML code. You should always use htmlspecialchars before outputting text in an HTML document.

isset($_POST) is correct usage or not?

The problem I'm facing is quite common I suppose but I didn't see a single thread in internet.
If I use isset($_POST),
Will it always return true?
Does the response depend on the version of PHP I use?
Is $_POST is a variable? (it's a super global 'variable' after all). Because in php.net documentation, it is mentioned
isset() only works with variables as passing anything else will result in a parse error.
Will it always return true?
Yes, even if the page was opened using GET method or nothing was POSTed.
Does the response depend on the version of PHP I use?
No it does not (not sure about very old versions of PHP).
Is $_POST is a variable?
Yes
isset() only works with variables as passing anything else will result in a parse error.
This is explicitly mentioned in the manual so that people do not try to do cheaky stuff. These won't work for example:
function getVarName() { return '_POST'; }
isset(getVarName());
isset('$_POST');
Now, why would you want to check if $_POST is set. Perhaps want to check if a certain variable (e.g. email) was posted, in that case you need to check:
isset($_POST["email"])
isset($_POST); will always return true. If you want to check if it contains something use empty($_POST);
Does the response depend on the version of PHP I use?
No
Is $_POST is a variable ?
Yes
Whether or not you posted any data $_POST will always be set as an array. What you are probably looking for is the empty() method to see if any data was actually posted, like:
if(!empty($_POST)) {
// POST data was set
}
I would recommend using one of the following:
if($_POST){
}
if(!empty($_POST)){
}
1, Will it always return true?
isset($_POST) will always return true. If $_POST is empty it will return false.
2, Does the response depend on the version of PHP I use?
I'm not sure about versions below 4.* but the response has always been the same.
3, Is $_POST is a variable?
Yes, it is considered a superglobal like: $GLOBALS, $_SESSION, $_POST, $_GET
Will it always return true?
Yes it would always be true
Does the response depend on the version of PHP I use?
No tested on PHP 4.3.0 - 5.4.10
Is $_POST is a variable?
Definitely Yes
Better way to validate $_POST is to use empty
Isset()
return true only if it contains some value (it can be Zero 0).
If it doesn't have any value then it returns false.
If you want to prevent from (0) use
if(isset($_POST) && $_POST)
This will be true if only it has non-zero value
$_POST is global array
Response doesn't depend upon the version of PHP

isset or !empty for $_GET[var]

i recently had to do a "test" for a job, and i got feed back saying that this statement was incorrect:
$images = $flickr->get_images(5, !empty($_GET['pg']) ? $_GET['pg'] : 1);
The "supposed" error was generated via the ternary operator on the first time the page was loaded, as there was no "?pg=1" (or whatever) passed via the query string.
The feed back said i should have used isset instead. I have looked at various posts both here (question 1960509) and blogs, but cannot find any definitive answer.
Is this really an error? How can i replicate this issue? do i need to put on E_STRICT or something in my php.ini file? Or might this be due to an older version of php?
Note: please don't tell me about how i should validate things.. i know this... it was a test to just see if i could use the flickr api calls.
This is perfectly fine. empty is not an actual function, it's a language construct. It does not issue a warning if a variable is not set (in that case the variable is considered empty, thus the 'function' returns TRUE just as you want), and additionally it checks for empty or zero values.
You could see empty as a normal isset check with an additional loose comparison to FALSE:
empty($var) === (!isset($var) || $var == FALSE)
$images = $flickr->get_images(5, (isset($_GET['pg']&&($_GET['pg']))) ? $_GET['pg'] : 1);
without isset you'll get error so combine them
I'd use
$images = $flickr->get_images(5, array_key_exists('pg', $_GET) ? $_GET['pg'] : 1);
Combine with !empty($_GET['pg']) if needed (i.e. array_key_exists('pg', $_GET) && !empty($_GET['pg'])), but array_key_exists is the intended function for this job.
I think in a situation like this isset is the correct function to use as it is checking the existence of the array element rather than checking if the value of the element has been set. As Martin notes, the best thing to do here is combine them as this will only check the value if the element exists, meaning that the error will not occur on the first page load.
Also, I think this will only give a warning if E_NOTICE is on (or perhaps E_WARNING as well)
The reason you would get an error is because the empty function is designed to check the value of an existing variable, whearas isset() is designed to tell you whether a variable has been instantiated, however because empty() is a language construct technically it doesn't throw an error or create a warning so most people don't see the difference.
From the docs:
empty() is the opposite of (boolean) var, except that no warning is generated when the variable is not set.
isset — Determine if a variable is set and is not NULL. So "isset" is the correct function to use for checking for value is set or not.
More details :http://php.net/manual/en/function.isset.php

I'm confused about the flow of $_POST[] variables and regular variables

I have a simple form I created, and in it I have the following checkbox:
<input type="checkbox" name="test">
Note: this form is being submitted to itself.
Above the form, I have the following PHP:
if (empty($_POST['test'])) {
$thevalue = 0;
} else {
$thevalue = 1;
}
var_dump($thevalue);
When I process the form, I get what I would expect. If I check the box and submit, I get int(1) if I leave it unchecked I get int(0).
In the first line of my PHP code, I wanted to replace $_POST['test'] with some simple variable.
So I added the following line above my code:
$simplevar = $_POST['test']
I then replaced the condition in my if statement to be empty($simplevar)
But when I submit the form, I get a "Notice: Undefined index:" error message
Why is this happening?
Assuming it's possible to achieve what I was after (i.e. insert $_POST into $simplevar), how might I go about it?
Thanks in advance for your help!
PS: I may have a follow up to this question, but didn't want to clutter things by jamming it all in here.
Thanks again... oh, and Merry Christmas! ;-)
This happens because when you don't check the checkbox, the browser does not send any value to server for that control when the form is submitted. Because of this, $_POST['test'] is not defined, and you tried to use it without a check as to whether it existed, so you get a warning. One of the checks that empty() does is to see whether the value is set. So, when you use the $_POST keys directly in empty(), you don't get an error, but when you try and use it in an assignment without this check, you will get the error.
You can do roughly what you want to do, you just have to change the logic slightly. If you do:
$simplevar = !empty($_POST['test']);
// You could also do
// $simplevar = isset($_POST['test']);
if ($simplevar) {
// The box was checked
} else {
// The box was not checked
}
...it will do what you want without the error. Using this approach, $simplevar always holds a boolean indicating whether or not the box was checked.
When a checkbox is unchecked, it's not added to the $_POST array as a key, which is why $simplevar = $_POST['test'] returns the error you posted. Using empty() gets past this problem by empty() handling errors better (well, silently at any rate).
You haven't specified whether you get that error when the checkbox is checked or not, but the above explanation is the only one I can give. If you're unsure, try doing print_r($_POST) to see what $_POST actually contains.
A solution to your problem would be to use a ternary expression to handle the error a little better:
$simplevar = isset($_POST['test']) ? 0 : 1;
This will assign 0 to $simplevar if $_POST['test'] isn't set (checkbox isn't checked), or 1 otherwise.
Do make sure all your form processing code is put inside
if(!empty($_POST)) {
// Code
}
So that it's not executed every time the page loads, otherwise your error will show every time.
Checkbox values are only transmitted if the checkbox was checked. This means that unchecked checkboxes won't appear in the $_POST array.
A way to suppress the notice from PHP is to use a reference instead of a variable:
$simplevar =& $_POST['test'];
if(empty($simplevar)) $thevalue = 1;
else $thevalue = 0;
That's expected behaviour. If you are assigning the variable like this:
$simplevar = $_POST['test'];
Then the $_POST variable might be absent. The Zend runtime then assigns the NULL value, but gives you a useful debug hint, should that not be what you wanted.
When you used empty() before, the check for variable existence was built in. empty() is a language construct. Like isset() it's often used to eschew such notices. The cumbersome syntax to emulate such language behaviour is:
$simplevar = empty($_POST['test']) ? NULL : $_POST['test'];
The language built-in for is:
$simplevar = #( $_POST['test'] );
Now, I will get roasted for mentioning it. (Using # is useful if you want to bring the debug notices back at some point, while the empty and isset constructs eternally suppress them.)
First, you should always check that variables in $_POST, $_REQUEST, and $_GET are set before attempting to use them. Always handle the condition where they are not set even if you simply output an error.
Because the error is an undefined index it seem the error is in test not being set in $_POST, though that doesn't make a lot of sense. I would add a check, maybe an echo or var dump to check $_POST. If it is set the other problem could be an issue with scope. $_POST is something called a super global which makes it available in any scope. Variables you set you may need to make global by defining them as such if you want to access them across scopes.

How can I get all submitted form values in PHP and automatically assign them to variables?

I'm trying to migrate a website from one host to another. On the first host, when you submit a form, all of the form values are automatically stuck into variables with the input name (this is PHP). On the new host, these values are all null unless I do this:
$data = $_GET['data'];
Is there a PHP configuration setting that is causing this? If there isn't, is there an easy way to loop through all of the $_GET variables and automatically assign their values to a variable with the same name?
Thanks!
The setting is register_globals, but it is now deprecated and strongly advised against using it because it is a security risk. Anyone can set variables in your script which might interact in a negative or unexpected way with your code.
If you absolutely must, you can do it like this:
foreach ($_GET as $key=>$value) {
$$key = $value;
}
or, more simply:
import_request_variables("g");
or, to make it a little safer:
import_request_variables("g", "myprefix_"); // This way forces you to use "myprefix_"
// in front of the variables, better ensuring you are not unaware
// of the fact that this can come from a user
extract($_GET) could also work, as someone else pointed out, and it also allows specification (via extra arguments) of adding a prefix or what to do if your extraction conflicts with an already existing variable (e.g., if you extracted after you defined some other variables).
Look at the extract function : http://www.php.net/manual/en/function.extract.php
You could do something like this:
foreach ($_GET["data"] as $name => $value){
$$name = $value;
}
The issue with this is that it makes it easy for people to fiddle with the variables in your script. I could visit http://yoursite.com/?sql=DELETE+FROM...
I'd advise against doing this and just sticking to using $_GET.
Your question infers you are not doing any filtering or validation when assigning $_GET['data'] to $data, unless you are doing these kind of checks further down your script.
From what I have seen most programmers would do this first, in an effort to fail early if expected data did not match expectations, so that the above assignment in the case of expecting a positive int would become something like:
if( isset($_GET['data']) && (int)$_GET['data'] === 0){
//fail
}else{
$data = $_GET['data'];
}
So seeing just plain
$data = $_GET['data']
makes me wince.

Categories