PHP validation booleans using filter_var - php

I'm using filter_var to validate boolean values but I did not expect it to not recognize FALSE. Why does this happen?
filter_var(FALSE, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
returns
null

filter_var is new as of PHP 5.2. You've run into a known bug: https://bugs.php.net/bug.php?id=49510
Feel free to vote on or comment on that bug.
You're trying to do something like this:
$v = filter_var($v, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
There are a number of cheap workarounds like this:
$v = $v===FALSE ? FALSE : filter_var($v, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)

It sounds like this is actually how it's supposed to work, strangely enough (yes, my mind was blown by that). From https://bugs.php.net/bug.php?id=51344
This is going to sound insane when you've looked at the underlying
filter code, but this is actually correct according to the
documentation: the default behaviour of filter_input() is to return
NULL for non-existent inputs and false when validation fails, and
FILTER_NULL_ON_FAILURE simply flips that behaviour to false for
non-existent inputs and NULL on validation failure. (No, I don't have
a clue where that would be useful either, and the name of the flag is
unfortunate in the filter_input() context, since it implies that NULL
wouldn't normally be returned. It makes more sense when used with
filter_var(), which doesn't have the non-existent input case.)
[table omitted due to SO formatting]
I'll pop a comment into the filter_input() and filter_input_array()
implementations to note that this is by design, even though the code
does kind of look wrong.
Closing Won't Fix.

This was the behaviour when filter_var was first introduced with version 5.2 and resolved at some point after 5.4 as is seen by this https://3v4l.org/Cv1MZ
Starting from version 5.4 this is what happens:
var_dump(filter_var(FALSE, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE));
bool(false)
which makes much more sense.

According to the documentation
Returns true for "1", "true", "on" and "yes". Returns false otherwise.
Anything different than the values mentioned above is considered falsy. This is not to test if a variable is actually a boolean like with typeof or is_bool(), but more like a mean to test if the input comming from the user (usually an <input type="checkbox"> form) is truthy/falsy.
The behavior of this function could be understand as let it go through if it's correct rather than a mean to test the type of a variable (we have lots of other functions for this). Exemple :
filter_var('435345', FILTER_VALIDATE_INT)
The type is a string, but the result is not true/false as the intention is not to validate the type. So an int would be returned (let go through).

Related

Should my PHP functions actively return the "right" type?

I have made various functions such as "get_current_balance_from_my_bank_account()". It technically returns a string, but it's always a full integer number (as a string) which has never caused problems when its return variable is used directly in calculations.
However, it feels wrong.
Should I be doing something like this?
return (int)$amount_as_a_string;
Instead of the current:
return $amount_as_a_string;
? Or is (int) some archaic/legacy way of doing this? Should I be using some other, better method?
Example of the context:
$my_balance = get_current_balance_from_my_bank_account();
$previous_balance = load_last_balance();
echo 'I have ' . format_money_prettily($my_balance - $previous_balance) . '!' . PHP_EOL;
Again, I rarely if ever run into issues with this because it understands the "real" type. It does still feel wrong that I'm technically returning and sending around strings which in theory could be causing problems sooner or later -- perhaps catastrophic ones in production!
PHP will implicitly type cast in many situations, but not all. Take for example this:
echo json_encode(['balance' => get_current_balance_from_my_bank_account()]);
Now your type propagates to some other system via JSON, where it may cause actual issues if that system isn't so lenient about types. You're making somebody else deal with your incorrect type.
So, yes, your function should always return the type that it claims it returns. PHP implicitly "helping" you when you don't stick to your own type declarations is just sweeping the problem in the rug, but the problem is still there and may eventually cause actual issues.
I don't think that is something you have to worry to much, considering that php has automatic type conversion.
From the docs:
PHP does not require (or support) explicit type definition in variable declaration; a variable's type is determined by the context
in which the variable is used.
Just because the function returns the right data type does not mean that the value is correct or what you expect.
If you want to make sure that the function returns ok value, validating it before returning it much more helpful than simply typecasting it to correct type.
If you want to be more explicit about typing in PHP, have a look at the following from the manual:
default
By default, PHP will coerce values of the wrong type into the expected scalar type if possible.
For example, a function that is given an integer for a parameter that expects a string will get a variable of type string.
Strict mode
It is possible to enable strict mode on a per-file basis. In strict mode, only a variable of exact type of the type declaration will be accepted, or a TypeError will be thrown.
The only exception to this rule is that an integer may be given to a function expecting a float.
Function calls from within internal functions will not be affected by the strict_types declaration.
To enable strict mode, the declare statement is used with the strict_types declaration:
<?php
declare(strict_types=1); // strict type declaration MUST be the very first statement in your script
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
output
int(3)
Fatal error: Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given
Note: Enabling strict mode will also affect return type declarations.
source: php.net
This will never be required in PHP, as it does the type conversion by itself. However you can do this if you want. This depends from project to project, but sometimes a decision is made for a certain project to use explicit types where possible. Also this is a good practice if you are working on a team where some of the people are comfortable with more strict languages.
In your case, depending on the number, there might be a good side in keeping it as a string, as if you convert it to int via casting and the number is bigger than the max_int_size, it will overflow.
As for the other question, casting as int (int) or (integer) is a perfectly good way to do it, even in newer versions. It is not a legacy way whatsoever. This does not mean there aren't other good ways to do that, though. You can also use something like intval() or settype(). In my opinion there isn't one right way to do it. You can decide for yourself on how to do that.

PHP Post_method hacking

I ran into the snippet online
https://www.quora.com/Why-is-PHP-hated-by-so-many-developers
when I was doing some research about PHP, and I simply have no idea how the codes work.
Can anyone kindly explain what happens in the snippet and how one can log in without knowing the password?? or just give me some relevant articles to read. Thanks in advance.
See the manual:
Returns ... 0 if they [strings] are equal.
So, by the snippet logic, you should compare 0 to 0 in the end. But when you send password[]=wrong, you actually send an array, forcing strcmp to throw a warning, completely bypassing the function call and perceive the condition as true
You should always use strict comparison, just in case. So in the snippet above it would be enough to compare strictly by type and value (with ===):
if(strcmp($POST['password'], "sekret") === 0)
In this case password[]=wrong would not work anymore.

Guarding my methods against bad input

I have a method like this:
public function create (array $hash) {
$id = $hash[ID_KEY];
$this->store[$id] = $hash;
}
I want to guard it against bugs caused by bad input.
For instance, my code can mistakenly pass $hash with
$id = '' or $id = null,
in which case it will be stored silently referenced by null. Instead I want to see a warning and revise my code to get rid of it. So I guess the best way is to throw Exception:
if (! $id) throw new Exception("Hash with empty id");
Note that I am using empty strings as default values for several method arguments and for default return values, so this kind of bug can easily occur. (Using null instead of empty string here doesn't seem to change anything, even if it is not recommended by Uncle Bob.)
The problem is -- there are many methods like that. Is it really best practice to guard each of them for each argument that can become null but shouldn't?
For instance, another method does only reading. Then it seems there is no need to guard against null because nothing will ever be stored referenced by null, right? Or shall I still guard defensively, to prepare for the case I may somewhere in the future decide to allow storage referenced by null and forget to adjust the guards?
This sounds kind of the safest way but would clutter all methods with bulks of guarding code for all indices involved there. Is this really the best way?
EDIT.
I put more guards and indeed discovered few bugs that I wouldn't find otherwise. Also my tests didn't spot them.
Furthermore, it helped to better understand the role of read methods - to return value if found or return empty Array if not. The input $id = null goes under not found and hence also returns empty Array. That way the method is clean and consistent.
You can use PHP's is_null() and empty() to easily manage this kind of output.
Also I suggest you to write a list of function used only in debug (since you want to perfectionate your code). Call these function in each method you want to test and set a constant like DEBUG_MODE to handle the debug functions' behavior. All of this could be also done using unit testing, which would require more attention and time. But if you have both or want to learn something new, unit testing is clearly a better choice.
Also it is a good practice to handle ALL CASES you can think of. For instance, if your "reading method" expects not to find a null value (because you think there are none because you eradicated by testing over testing), if this "reading method" happens to find a null value a "ugly" PHP error would be shown somewhere, or worse, if error_report is shut you might never see a problem, or even worse, the code might continue its execution and utterly damage further data.

PHP if() evaluation problem needs a rewrite

I noticed this weird evaluation yesterday after searching for a few hours in my code for an error. i am passing scores into php, sometimes the score=0 which causes an issue.
send php ?blah=blah&score=0
if(!empty($_REQUEST['score']){
//do database update stuff
}else{
// show entire webpage
}
It works great unless the score=0 the if() will evaluate to false and return the entire webpage to my ajax handler and error. I have temporarily changed !empty to isset but this will cause problems in the future because isset evaluates to true even if the score key is in the url string without a value.
ex: (?blah=blah&score=&something=else)
my question is: what is the best way to recode this to work correctly now and in the future?
edit: there are a few working answers here, i appreciate everyones time. it was difficult to choose an answer
As the manual says, a variable is considered empty() if it has an empty or zero value.
So it will treat your variable wrongly as empty even though 0 is a perfectly acceptable value in your case.
If you need score to be a number, you could use isset() in combination with a is_numeric() check instead:
if((isset($_REQUEST['score']) and (is_numeric($_REQUEST['score'])){
Check out the manual page to see the kinds of values is_numeric() accepts. If score is always an integer, you can also use is_int((int)$_REQUEST['score']) but that will convert invalid input values to 0.
Additionally, as #sightofnick says, it's better to use explicit $_GET or $_POST instead of $_REQUEST.
Re your update:
In that case I would
Do check whether the variable is "0" (string "zero")
If it is "0", make it 0 (integer "zero")
If it is not 0, convert it to an integer (int)$_REQUEST["score"])
If the conversion resulted in 0, it was invalid input - exit
You have a valid integer variable.
empty() will return false if a value is zero. Use isset() or array_key_exists() instead, if you want to check if a variable in an array is set:
if (array_key_exists('score', $_REQUEST)) {...}
Try doing
if (isset($_REQUEST['score']) && ($_REQUEST['score'] !== '')) {
...
}
The isset will handle the presence/absence of the query parameter, and the strict string (!==) comparison will handle the case where the 'score' query is present but has no value. PHP treats all data coming from _GET/_POST/_REQUEST as strings, so this test is 100% reliable.
if(isset($_REQUEST['score']) && $_REQUEST['score'] != ''){
//do database update stuff
}else{
// show entire webpage
}
You may be able to solve that with
if (isset($_REQUEST['score']) && is_numeric($_REQUEST['score'])) {}
That of course if scrore can only contain numeric value

What is the difference between null and empty?

I am new to the concept of empty and null. Whilst I have endeavoured to understand the difference between them, I am more confused. I came across an article at http://www.tutorialarena.com/blog/php-isset-vs-empty.php however I still don't see when you would use isset and empty when validating forms. Seeing that I don't grasp the difference, I don't want to be using the incorrect functions as well as not be able to use the functions in other areas. Can someone give examples that will help me understand? I am very new to coding so would appreciate if someone could give me real world examples and at the same time keep it simply enough for noob to follow.
A variable is NULL if it has no value, and points to nowhere in memory.
empty() is more a literal meaning of empty, e.g. the string "" is empty, but is not NULL.
The following things are considered to
be empty:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
var $var; (a variable declared, but without a value in a class)
Source.
Example
$a is NULL.
$a = '' is empty, but not NULL.
Update
If $a='' is empty but not NULL, when do I use the empty() function and when do I use the isset() function.
isset() will return FALSE is the variable is pointing to NULL.
Use empty() when you understand what is empty (look at the list above).
Also when you say it points nowhere in memory, what does that mean exactly?
It means that $str = '' will be in memory as a string with length of 0.
If it were $str = NULL, it would not occupy any memory.
Null is a placeholder that generally means "no data about this is available".
The use of null for this is just a convention, but a rather widespread one, to the point where some programming languages support the convention directly. The reason this convention exists has IMHO historically to do with "pointers";
many times a procedure will be defined to return a pointer to an answer, and will return what is traditionally called a Null pointer if it could not produce an answer for some reason.
Empty means (if this is a set) that it has no members. That's an explicit answer, and it is very different than "no data about this is available".
In the PHP world, apparantly uninitialized variables have the Null value, and isset on such a variable returns FALSE.
For arrays and strings, PHP follows the convention that "empty" means "has no members" although arrays and strings are not technically sets.
PHP apparantly has this funny idea that 0 and 0.0 are also "empty", by PHP design. That's abusive of the concept of "empty" IMHO: Individual numbers are not sets, so 0 can't reasonably by "empty". THis just leads to obscure programming because it violates the principle of least surprise. I'm sure the PHP designers would are that "zero is the empty number" as some kind of vague analogy; but the if analogy is vague, why bother with it? But then PHP is full of silly ideas.
The table below is an easy reference for what these functions will return for different values. The blank spaces means the function returns bool(false).
refer this link for more https://www.virendrachandak.com/techtalk/php-isset-vs-empty-vs-is_null/
NULL is a special value which explicitly states that the variable has not been set to any value yet. Be careful with using the empty() function as you can't just determine that a variable is exactly NULL using it. For example the empty() function will return true if an int is set to 0. If you need to make sure a variable is exactly NULL use if($variable == NULL).
For more info on empty() see http://php.net/manual/en/function.empty.php
There are some good answers here, which I won't repeat. In the case of validating forms, though, when a form is submitted, the value of each form input element is sent to the server in the $_POST variable. You can check for the existence of a particular input by using isset().
isset($_POST['username'])
If this returns true, then this request to the server was the result of posting a form containing an input element named "username". Now that we know that we have a value for that form element, we can see if it has a valid value. empty() will tell us whether the user actually entered any data in the field, or whether they left it empty.
empty($_POST['username'])
If that returns true then the form submitted to the server had a field named "username" but the user didn't enter anything into before submitting the form.
Been awhile since i used PHP but if other languages are anything to go by empty will indicate an existing object/map/array that has no contents while null would indicate a variable that has no meaning/definition at all (uninitialised).
In database SQL, NULL means "no value".
The empty() is a nice fast way to see if the variable holds any useful info... that is for strings empty() returns true for a string of "" as well as a null string.
So you can write something like this:
if (! empty($name)) echo $name;
More info see here: PHP: empty()
isset() returns true if both these conditions are met:
The variable has been defined and has not yet been unset.
The variable has a non-null value in it.
A variable is automatically defined when it gets set to something (including null). This has a direct implication in arrays.
$a=array();
$a['randomKey']=true;
$a['nullKey']=null;
var_dump(isset($a['randomKey'])); // true
var_dump(isset($a['nullKey'])); // true, the key has been set, set to null!
var_dump(isset($a['unsetKey'])); // false !
unset($a['randomKey']);
var_dump(isset($a['randomKey'])); // false ! it's been unset!
From above, you can check if various $_POST fields have been set. For example, a page that has been posted to, stands to reason, has the submit button name in the $_POST field.
empty() on the other hand, tests if the variable holds a non zero value. This means that values that (int) cast to 0, return false too. You can use this to see if a specific $_POST field has data in it.
This concept can be better understood from mathematics. Have you ever tried dividing a number (not zero) by 0 using a calculator e.g 7/0? You will get a result that looks like something this: undefined, not a number, null etc. This means that the operation is impossible, for some reasons (let's leave those reasons to be discussed another day).
Now, perform this: 0/7. You will get the output, 0. This means that the operation is possible and can be executed, but you the answer is just 0 because nothing is left after the division. There is a valid output and that output is zero.
In the first example, not only was the output invalid, the operation was not possible to execute. This is akin to null. The second example is akin to empty.

Categories