php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #81685 Using json_decode with an integer as first parameter doesn't return NULL
Submitted: 2021-12-01 14:40 UTC Modified: 2022-03-28 19:10 UTC
From: joaquimsb89 at gmail dot com Assigned: bukka (profile)
Status: Closed Package: JSON related
PHP Version: 7.4.26 OS: Debian & Arch
Private report: No CVE-ID: None
 [2021-12-01 14:40 UTC] joaquimsb89 at gmail dot com
Description:
------------
When using the json_decode() function and passing an integer as the first parameter, or with the strval() function, the return value is the integer itself instead of an expected NULL, expecting "Syntax error" as the error description.

Behaviour observed in the following environments:
PHP 7.4.26, debian 10/buster, installed via deb sury repo
PHP 8.0.13, Arch Linux, installed via pacman -S php
PHP 8.1.0, debian 11/bullseye, installed via deb sury repo

Test script:
---------------
<?php

var_dump(json_decode('', true));
var_dump(json_last_error_msg());
echo "\n";
var_dump(json_decode(123, true));
var_dump(json_last_error_msg());
echo "\n";
var_dump(json_decode(strval(123), true));
var_dump(json_last_error_msg());
echo "\n";
var_dump(json_decode('{"a":123}', true));
var_dump(json_last_error_msg());

Expected result:
----------------
NULL
string(12) "Syntax error"

NULL
string(12) "Syntax error"

NULL
string(12) "Syntax error"

array(1) {
  ["a"]=>
  int(123)
}
string(8) "No error"

Actual result:
--------------
NULL
string(12) "Syntax error"

int(123)
string(8) "No error"

int(123)
string(8) "No error"

array(1) {
  ["a"]=>
  int(123)
}
string(8) "No error"

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-12-01 15:18 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2021-12-01 15:18 UTC] cmb@php.net
See <https://datatracker.ietf.org/doc/html/rfc8259#section-2>:

| A JSON text is a serialized value.  Note that certain previous
| specifications of JSON constrained a JSON text to be an object or
| an array.

So the actual behavior of json_decode() looks good to me.
 [2021-12-01 15:41 UTC] me at davidgarcia dot cat
On the same web link that was shared previously:

https://datatracker.ietf.org/doc/html/rfc8259#section-2

A JSON text is a sequence of tokens.  The set of tokens includes six
structural characters, strings, numbers, and three literal names.

----

Wikipedia definition

https://en.wikipedia.org/wiki/JSON

JSON [...] is an open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays (or other serializable values) [...]

----

JSON

https://www.json.org/json-en.html

(similar description and detailed chart to explain in detail)

====

To me, passing an integer or a non-formatted JSON string means there's a bug here...
 [2021-12-01 15:46 UTC] cmb@php.net
RFC 8259 is a standards document; neither that Wikipedia page nor
that json.org page are.  And besides, adhering Postel's law is
almost never a bad idea.
 [2021-12-01 16:16 UTC] me at davidgarcia dot cat
I am not aiming to start an argument, so I won't post more messages. But I believe some clarification might help. Thanks for your understanding,

----

Won't this behaviour cause, then, a potential error when processing external requests (like API calls) as we won't be able to retrieve a "valid JSON object" that can be converted to an object via json_decode($payload, false) or to an array via json_code($payload, true)?

Even the official PHP website does not have an example for any input payload that is not a JSON-parsed string format, including {} and / or [] and bearing in mind the "key":"value" format.

https://www.php.net/json_decode

If the RFC 8259 is implemented as expected, then it looks like there's a lack of documentation on the PHP website (that leads to confusion) to cover these cases.

Also, the PHP website points that the implemented logic is for RFC 7159 - which is being adjusted by the RFC 8259, so it's unfair point to "another RFC" than the one mentioned on the website.

Extra reading would be appreciated here. Would be possible getting directions on where other examples can be found, please, so it's possible to contrast this specific case?
 [2021-12-01 16:24 UTC] cmb@php.net
-Status: Not a bug +Status: Open -Type: Bug +Type: Documentation Problem -Assigned To: cmb +Assigned To:
 [2021-12-30 10:40 UTC] a at b dot c dot de
Isn't this just bog-standard type juggling? Passed an integer argument to a string parameter, it recast the integer as a string?


declare(strict_types=1);

$v = json_decode(123, true);
var_dump($v);
var_dump(json_last_error_msg());
 [2021-12-30 10:42 UTC] a at b dot c dot de
Oh:

"The JSON Data Interchange Syntax"
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/
 [2021-12-30 11:04 UTC] a at b dot c dot de
'Also, the PHP website points that the implemented logic is for RFC 7159 - which is being adjusted by the RFC 8259, so it's unfair point to "another RFC" than the one mentioned on the website.'

The differences between the two are documented in Appendix A of RFC 8259; none of them affect the grammar, and the only one that has any impact on implementation is that JSON must be UTF-8 encoded to be valid. I don't know if this has any impact on PHP's parsing, but I doubt it, as the only legitimate non-ASCII characters would be inside JSON string values.

For further examples of JSON values, see either RFC (they have the same examples). The ECMA published standard describes the grammar in terms of railroad diagrams basically copied from JSON.org. Note that all of them allow a plain number or string as a "JSON value" (as well as objects, arrays, null, true, and false).

'A JSON text is a sequence of tokens.  The set of tokens includes six
structural characters, strings, numbers, and three literal names.'

Yes, and '123' is a number. The next paragraph after the one you quoted says: 

' A JSON text is a serialized value. Note that certain previous
   specifications of JSON constrained a JSON text to be an object or an
   array.  Implementations that generate only objects or arrays where a
   JSON text is called for will be interoperable in the sense that all
   implementations will accept these as conforming JSON texts.'
 [2022-03-28 19:10 UTC] bukka@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: bukka
 [2022-03-28 19:10 UTC] bukka@php.net
As noted above, this is just a type juggling. If you want to be sure that passing number fails, declare strict types.

Without that declared, the example

var_dump(json_decode(123, true)); 

is basically just

var_dump(json_decode('123', true));
 
PHP Copyright © 2001-2023 The PHP Group
All rights reserved.
Last updated: Tue Jan 31 04:03:46 2023 UTC