News for hackers. Stuff that matters.
Re:PHP 7 deployment at Dailymotion by developer2 on Friday October 14, 2016 @12:56AM (#12706214)
> 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

[2] https://symfony.com/search?q[]=hello

[3] https://packagist.org/search/?q[]=hello

[4] http://www.yiiframework.com/search/?q[]=hello

Re:PHP 7 deployment at Dailymotion by stephenr on Friday October 14, 2016 @03:04AM (#12706524)
> 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.

You know there is an entire extension dedicated to validating and sanitising inputs right?

All your type checking and regexes and double cast comparisons could be replaced with:

    if (($value = filter_var($value, FILTER_VALIDATE_INT)) !== false) { doStuff(); }

> You could try to blame PHP, but really it's the developers

At least we can agree on one thing.

Re:PHP 7 deployment at Dailymotion by seszett on Friday October 14, 2016 @02:58AM (#12706507)
> 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.

Re:PHP 7 deployment at Dailymotion by babyrainbow on Friday October 14, 2016 @03:24AM (#12706581)
>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?

Re:PHP 7 deployment at Dailymotion by marklgr on Friday October 14, 2016 @03:43AM (#12706632)
If 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.
Re:PHP 7 deployment at Dailymotion by babyrainbow on Friday October 14, 2016 @03:54AM (#12706665)
Well, 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...

Re:PHP 7 deployment at Dailymotion by marklgr on Friday October 14, 2016 @07:38AM (#12707417)
It's more about automatic type conversion than the API, though; numerics magically get converted to strings and vice-versa. This is convenient in some cases, especially for beginners who don't have to think about types, but it eventually bites you if you never realize what happens in your back.
Re:PHP 7 deployment at Dailymotion by Zarel on Friday October 14, 2016 @03:33PM (#12710504)
The problem is that ctype_digit does not magically get converted to a string, it instead just returns gibberish.

If ctype_digit(100) magically got converted to ctype_digit('100'), that would not be a problem.

Re:PHP 7 deployment at Dailymotion by mastre_ on Monday October 17, 2016 @09:32PM (#12731327)
This is not so much a PHP thing as it is a different way of thinking about things. If you know something is supposed to be an integer, you can simply force it to an integer before you do anything with it:

  $id = intval(@$_POST['id']);
  if (!empty($id)) { ... }
Note: 0 shouldn't be a valid value for something called 'id', since it's likely a db id; if it is, use something other than an empty() check.
Re:PHP 7 deployment at Dailymotion by jwdunne on Friday October 14, 2016 @03:14AM (#12706551)
In your example, 123e4 is a valid PHP number.

That said, input is a problem. In a dynamically typed language, it's easy for beginners to expect HTTP and requests in PHP work the same way. In reality, you will be coercing from string to wherever you are working with, which could also be an array of strings, or vice versa.

Input rules would be nice. For example, we always want id to always be an unsigned integer in this context and email will always be... and so on.

Dynamic typing makes, in this case, two types look like either plain old dynamic typing or leads to believing input has a homogeneous type.

In any case, I'm going to take a mag glass to some of our code today. Thanks!

Re:PHP 7 deployment at Dailymotion by babyrainbow on Friday October 14, 2016 @03:09AM (#12706538)
>try passing integer values. ctype_digit(50) === true, but ctype_digit(100) === false.

That is hilarious! I love how even stuff that is supposed to fix other stuff itself end up being completely broken. But hey, it is documented.

Learning Php is like taking a massive loan. It get you started easily, but causes eternal suffering in the long run...

Re:PHP 7 deployment at Dailymotion by developer2 on Friday October 14, 2016 @08:08PM (#12711963)
It is in fact documented; what I didn't explain is that ctype_digit treats integers < 127 as chr() equivalents. It's designed to juggle both strings and integers, which indeed works against php's usual method of type juggling. This is because ctype is a port or wrapper around the C lib which behaves as such.
Re:PHP 7 deployment at Dailymotion by Chyzwar on Friday October 14, 2016 @04:13AM (#12706730)
Yes, The worst part is that it will make you worse developer. It is like drinking a lot of soft drinks, side-effects will kill you.