5 ms·
> Are you expecting it to be an integer? Easy > if(!ctype_digit($_POST['ID'])) { // throw exception here } ctype_digit is broken. Try passing integer values.
by developer2 10y ago
> Are you expecting it to be an integer? Easy
> if(!ctype_digit($_POST['ID'])) { // throw exception here }
ctype_digit is broken. Try passing integer values. ctype_digit(50) === true, but ctype_digit(100) === false. And "0000001" passes as true, which most people in the majority of scenarios would prefer not to pass. I can't remember what the even-worse-bug is with ctype_digit is, but even if you cast the value to string [ex: ctype_digit((string)$var))], there is some value that still passes for true when it shouldn't - do not use ctype_digit. is_numeric() is also unusable for validation [is_numeric("123e4") === true]. is_int() is a strict type-check so can't solely be used to validate request variables which are always strings (...or arrays, more below).
The only correct ways to verify that a variable contains either a valid numeric string or integer is by comparing type, and then using a regex or a double string-then-int cast.
ex: unsigned database ids: if ((is_int($var) || is_string($var)) && preg_match('/^[1-9]\d*\z/', $var)) { // definitely an int > 0 }
ex: signed integer: if (is_int($var) || (is_string($var) && (string)(int)$var === $var)) { // valid int (including negative values) }
Frankly, developers who don't understand how request variables are handled in PHP have zero chance of properly validating input. Find any site/app written in php, even if built on any of the major frameworks. You can instantly break 30-50% of them by passing an array where a string is expected.
Find an app that takes "?query=hello+world". Instead pass in "?query[]=hello+world". Want an example? Log in to Facebook, then visit this search page[1]. Look at the query string and then what was searched for - and the contents of the search box. Bam, even Facebook gets it wrong! Same thing with Symfony's search[2]. Or Packagist (composer's package manager repository)[3]. More seriously at Yii[4], which exposes an internal error to users as they try to string-trim an array ("Error - trim() expects parameter 1 to be string, array given").
Most developers - including many seniors who have been exclusively coding in php for years - have no clue. You will either cause a 500 Internal Server Error, or your input array will result in an output string of "Array" if they typecast your array to the string they expected. Even the major frameworks, when you pull user-submitted values, simply passthrough the value submitted. Your app expects a string (or a string that contains a numeric value), and instead any user who knows the "[]" syntax can pass in an array.
Really reflect on this fact. Most applications start handling a submitted array value as if it's a string. The bugs this produces are astronomical in some cases.
If you think your framework protects you, think again. The frameworks' request objects also do not have strict type checking. The same goes for their form and model validation classes; if you're using the built-in "integer" or "numeric" validators, you're probably doing things wrong.
It's a nightmare. You could try to blame PHP, but really it's the developers - including the developers of every major well-known framework I've ever touched - that have absolutely no clue.
Related tangent: comparing password and password confirmation fields. Many developers do if ($password == $passwordConfirm) {}. In PHP 5.x, "10" == "0xA" (so type "10" in password field and "0xA" in the confirmation field, and it passes validation). This changed in PHP 7 though. There are only two correct ways to verify that two strings are exact: $password === $passwordConfirm (triple equals), or strcmp($password, $passwordConfirm) === 0.
[1] https://www.facebook.com/search/top/?q[]=hello https://www.facebook.com/search/top/?q[]=hello
[2] https://symfony.com/search?q[]=hello https://symfony.com/search?q[]=hello
[3] https://packagist.org/search/?q[]=hello https://packagist.org/search/?q[]=hello
[4] http://www.yiiframework.com/search/?q[]=hello http://www.yiiframework.com/search/?q[]=hello
- seszett 10y ago> ctype_digit is broken. Try passing integer values. Well, ctype_digit takes strings, not integers. So don't be surprised if you pass the wrong type to a function and it doesn't work as you expected. Some of your criticism is valid, but you can't go around talking about how PHP isn't rigorous enough, and then complain tha some functions don't work as you'd like when you give them a wrong argument type. Your other arguments are more about bad developers as you say it yourself, anyone who actually cares about what he does knows you have to check equality with ===, while the array argument problem is less well known, but actually almost unrelated to PHP: POST or GET is user data that can be any type and should be checked. Only the last of your examples is actually a problem to me.
- babyrainbow 10y ago>Well, ctype_digit takes strings, not integers... The problem is that the behavior is not consistant. Php is some parts c, some parts java and some part perl. That is the problem. It takes a encyclopedic knowledge of the documentation to know what part you are dealing with. And even that might not help you sometimes, because the documentation can be plain wrong at places... >anyone who actually cares about what he does knows you have to check equality with === Can you write php code to store some string to string mapping in a php array and further down, check if a particular key exist in that array?
- marklgr 10y agoIf you know C, you can identify pretty well what are the (thin) PHP wrappers around the C routines. Java influenced the OO design, so you know where to find it, and Perl is mostly, well, PCRE. It's not consistent, but it's not _that_ hard to navigate.
- babyrainbow 10y agoWell, It is not that easy. For example, take the function strlen(). You can see that it is a wrapper for the C function. So can you expect that it will behave like the c function, accepting strings only? No! It now accept both strings and integers. So you have part perl there. Now take another function. ctype_digit(). I don't know where the name come from. You expect it to behave like strlen() accepting both strings and numbers. But no! If you pass it a number, it won't even bat an eye (throw an exception or error), but it will just return gibberish... Hope my point, that these influences are mixed together in a haphazard fashion, is a bit more clear now...