php: is_numeric treats leading and trailing spaces differently - php

My php version:
➜ ~ php -v
PHP 7.3.1 (cli) (built: Jan 10 2019 13:16:34) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies
I dont understand why spaced value in function is_numeric behaves like this?
➜ ~ php -a
php > var_dump(is_numeric('0012432'));
bool(true)
php > var_dump(is_numeric(' 0012432'));
bool(true)
php > var_dump(is_numeric('0012432 '));
bool(false)

This function handles leading spaces differently than is_int(), is_float(), is_real(), is_long(), and is_double().
is_numeric(" 12345") = true
is_int(" 12345") = false
is_float(" 12345") = false
is_real(" 12345") = false
is_long(" 12345") = false
is_double(" 12345") = false
I found a bug report open for these cases, not sure if they will be working on this,
Bug report

So does every other part of the core PHP language that accepts numeric strings. It's an annoying inconsistency, but it is intentional and has been like this for many years. I am personally intending to fix this in a future version.

Related

Under what circumstances does PHP's openssl_random_pseudo_bytes return false?

The PHP documentation for openssl_random_pseudo_bytes says:
Return Values
Returns the generated string of bytes on success, or false on failure.
What would cause openssl_random_pseudo_bytes to fail? Can this be manually triggered for testing purposes? I tried disabling the entire openssl PHP extension, but as expected that raised an error due to the function not being found.
When PHP cannot quantify the integer in a manner that will encrypt the integer, it will, in fact, return false. It goes without saying, it is ASSUMED php uses whole numbers for this function .. However it appears they left room for non-whole numbers (less than 1) and negative integers .. Just in case.
For example:
<?php
echo test_rando(80); // Passes
echo test_rando(80.1); // Passes
echo test_rando(.9); // Fails
echo test_rando(-1); // Faile
function test_rando($rando_in){
$rando = openssl_random_pseudo_bytes($rando_in);
if ($rando === false){
return "\n\n$rando_in | WAS FALSE\n\n ";
}else{
return "\n\n$$rando_in | $rando\n\n";
}
}
Output:
80 | ghg'O8I*%&E(Et(wX"vUH$0
t|5|衖y䰆rW+;
80.1 | &iGkb s`+[byaqvgөrTE݁ᨈ\Ukfb'
0.9 | WAS FALSE
-1 | WAS FALSE
Version of PHP
PHP 8.0.10 (cli) (built: Aug 26 2021 15:50:07) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.10, Copyright (c) Zend Technologies
with Zend OPcache v8.0.10, Copyright (c), by Zend Technologies
--
PHP 7.0.33-0ubuntu0.16.04.16 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.33-0ubuntu0.16.04.16, Copyright (c) 1999-2017, by Zend Technologies
Because PHP was not able to quantify .9 or -1 (anything less than 1), even though IT IS an integer, it will fail. Although this isn't expressly denoted in the documentation, one can assume this prevents fatal errors (division by zero and such) and presents error handling possibility for anyone who might be doing arithmetic on said integer before it's passed through the openssl_random_pseudo_bytes function.

ip2long("012.012.012.012") returns false on Linux

Suppose there are leading zeros in IPv4 address representation such as 012.012.012.012.
To suppress the leading zeros, I simply write the following code, and it works as I expected on my Mac:
% php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
Command line code:1:
string(11) "12.12.12.12"
% php --version
PHP 7.3.25 (cli) (built: Dec 25 2020 22:03:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.25, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans
But this simple piece of code doesn't work on CentOS 7, it seems like ip2long("012.012.012.012") returns false value:
$ php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
string(7) "0.0.0.0"
$ php --version
PHP 7.3.25 (cli) (built: Nov 24 2020 11:10:55) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
Both PHP versions are identical and I would expect them to return exact same values. I also read the ip2long docs and tried to find if there is any special options/configurations for this behaviour, but no luck.
Could someone lead me in the right direction?
What makes them different? And what should I do?
OK, I found the culprit. Different implementation of inet_pton(3) between LLVM and GCC leads this behaviour, as Russ-san commented. There was a bug report about the exact same problem 6 years ago. It seems PHP v5.2.10 had started using inet_pton instead of inet_addr according to this patch, that's why older versions of PHP treat each chunks as octal.
test.c
#include <stdio.h>
#include <arpa/inet.h>
#define INADDR "012.012.012.012"
int main() {
struct in_addr inaddr;
if (inet_pton(AF_INET, INADDR, &inaddr) == 0) {
printf("Invalid: %s\n", INADDR);
}
else {
printf("Valid: %s\n", INADDR);
}
return 0;
}
Mac
% cc test.cc && ./a.out
Valid: 012.012.012.012
Linux
$ cc test.cc && ./a.out
Invalid: 012.012.012.012
I gave up using ip2long / long2ip built-in functions and now trying to use https://github.com/mlocati/ip-lib
>>> \IPLib\Address\IPv4::fromString("1.2.3.12")->toString(true);
=> "001.002.003.012"
>>> \IPLib\Address\IPv4::fromString("001.002.003.012")->toString();
=> "1.2.3.12"
No problems so far.

Why in PHP printf() "g" type-specifier gives wrong value? [duplicate]

This question already has answers here:
What precisely does the %g printf specifier mean?
(2 answers)
Closed 4 years ago.
As per documentation,
"g - shorter of %e and %f"
I have executed this statement:
printf("e:%1\$.3e\nf:%1\$.3f\ng:%1\$.3g", .123e2);
And this is output:
e:1.230e+1 // long value
f:12.300 // shorter value
g:12.3 // here g gives something else
Why "g" gives something else, am I getting the docs wrong?
$ php -v
PHP 7.1.10 (cli) (built: Oct 19 2017 15:16:13) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
with Xdebug v2.5.1, Copyright (c) 2002-2017, by Derick Rethans
sprintf() eventually delegates to the sprintf(3) C function. From the printf(3) man page:
Precision
[...] This gives ... the maximum number of significant digits for g and G
conversions...
Therefore the PHP documentation is, at best, inaccurate.

Assert is returning true no matter the condition

For example, if I have
assert('2<1');
It turns out that the assertion returns as true. I also copy pasted Example #2 from http://php.net/manual/en/function.assert.php and it also evaluated every single assertion as true, when that's clearly not the case. Any idea what might be causing this?
Edit -
<?php
var_dump(assert('2<1'));
?>
Output is
true
If i run this at http://sandbox.onlinephpfunctions.com/, the assertion fails as expected. Yet this does not happen on my test server.
Edit #2 -
PHP Version:
PHP 7.0.9-1+deb.sury.org~trusty+1 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.0.9-1+deb.sury.org~trusty+1, Copyright (c) 1999-2016, by Zend Technologies
Assert's have 3 settings:
(exert from php.ini):
-1: Do not compile at all
0: Jump over assertion at run-time
1: Execute assertions
...
http://php.net/zend.assertions
-1 being "production", 1 being development and zero being an odd middle-ground that appears to act like production.
Apparently when in non-development mode this means that assert will always return true, effectively bypassing the check.

Is there a PHP setting that sets whether you can index the result of a function?

I have two servers. They are both running php 5.3.3. This code works on one server and returns a syntax error on the other. Is there a php ini setting that affects this behaviour? I can't find anything related in the PHP documentation, but I may be looking in the wrong place.
Server 1
> php -v
PHP 5.3.3 (cli) (built: Sep 23 2010 14:15:16)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
with Xdebug v2.0.3, Copyright (c) 2002-2007, by Derick Rethans
php > echo explode(" ", " foo ")[1];
foo
Server 2
> php -v
PHP 5.3.3 (cli) (built: Jan 31 2011 15:57:29)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
php > echo explode(" ", " foo ")[1];
Parse error: syntax error, unexpected '[', expecting ',' or ';' in php shell code on line 1
Another idea: PHP on both servers is custom-compiled, so it could also be a different compile flag.
No.
PHP doesn't support this syntax. It's on the trunk, but not yet released (as of PHP 5.3.3).
I have no idea how it's working on your first server, but perhaps this "Xdebug" is making a difference?
Aha! I figured it out.
We installed Facebook's XHP to profile our development server. This syntax (which is quite elegant) was added in in the PHP module. Here's a diff of the php.ini file between server 1 and 2:
> ; XHP https://github.com/facebook/xhp/wiki/Building-XHP
> extension=xhp.so
> ; adds support for the [] operator on the return value of a function
> xhp.idx_expr = 1
> ; Tracking errors in XHP applications is very difficult without annotations.
> xhp.include_debug = 1
I like this syntax, so I'll probably install XHP on the other server. Thanks for the help Michas for suggesting I diff the ini files.

Categories