php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #63004 errors json_encode do NOT call error handler
Submitted: 2012-09-03 22:14 UTC Modified: 2012-09-04 06:01 UTC
From: juzna dot cz at gmail dot com Assigned:
Status: Not a bug Package: JSON related
PHP Version: 5.4.6 OS: Ubuntu 10.04
Private report: No CVE-ID: None
 [2012-09-03 22:14 UTC] juzna dot cz at gmail dot com
Description:
------------
When there is an error within json_encode (e.g. due to invalid utf8), E_WARNING 
should be raised. However, that doesn't happen in some cases.

It doesn't happen when display_errors is set to On.
In latest snapshot of 5.4 it does not happen at all.

Test script:
---------------
<?php
/**
 * WTF? Error handler is not called, when display_errors=On
 *
 * _errorHandler must be called in each case, but it's not.
 *
 * Results differ on different PHP versions.
 */


function _errorHandler($severity, $message, $file, $line, $context) {
	$GLOBALS['err'] = func_get_args();
//	echo "Error ($severity) $message in $file:$line\n";
}
set_error_handler('_errorHandler');


// display_errors = Off, works fine
{
	ini_set('display_errors', 0);


	// Calls error handler, fine
	$err = NULL;
	$tmp = substr(new stdClass(), 1, 1);
	var_dump($err[0], $err[1]);


	// Calls error handler, fine
	$err = NULL;
	$tmp = json_encode(array("bad utf\xFF"));
	var_dump($err[0], $err[1]);
}



// display_errors = On, WTF???
{
	ini_set('display_errors', 1);


	// Calls error handler, fine
	$err = NULL;
	$tmp = substr(new stdClass(), 1, 1);
	var_dump($err[0], $err[1]);


	// Does NOT call error handler, WTF???
	$err = NULL;
	$tmp = json_encode(array("bad utf\xFF"));
	var_dump($err[0], $err[1]);
}


Expected result:
----------------
int(2)
string(55) "substr() expects parameter 1 to be string, object given"
int(2)
string(49) "json_encode(): Invalid UTF-8 sequence in argument"
int(2)
string(55) "substr() expects parameter 1 to be string, object given"
int(2)
string(49) "json_encode(): Invalid UTF-8 sequence in argument"


Actual result:
--------------
On 5.4.6:

int(2)
string(55) "substr() expects parameter 1 to be string, object given"
int(2)
string(49) "json_encode(): Invalid UTF-8 sequence in argument"
int(2)
string(55) "substr() expects parameter 1 to be string, object given"
NULL
NULL



On 5.4-latest:

int(2)
string(55) "substr() expects parameter 1 to be string, object given"
NULL
NULL
int(2)
string(55) "substr() expects parameter 1 to be string, object given"
NULL
NULL


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-09-03 22:15 UTC] juzna dot cz at gmail dot com
Actually, a similar bug (52397) has been known for more than 2 years. In latest 
snapshot of PHP 5.4 it just got worse :/
 [2012-09-03 23:36 UTC] rasmus@php.net
json_encode() now checks for valid utf-8. It makes no sense to generate warnings 
for core functionality of the function. You can check json_last_error() for 
JSON_ERROR_UTF8 if you want to programmatically catch invalid utf-8.
 [2012-09-03 23:36 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2012-09-04 03:17 UTC] david at grudl dot com
This is the only one function in whole PHP with this behaviour. So is it a new way of error handling or bug?
 [2012-09-04 03:28 UTC] rasmus@php.net
It isn't a new mechanism for PHP. We have had things like mysql_error(), 
socket_last_error(), oci_error(), ldap_error(), pg_last_error(), 
libxml_get_errors(), preg_last_error(), curl_error() and many money for a very 
long time.

The main reason to not surface a warning here is that the only way to avoid it 
would be to call iconv('utf-8','utf-8',$str) on all strings to be encoded. This 
is a huge hassle to do, it is slow, and this is something we actually do 
internally in json_encode() to validate utf-8 anyway, so it would be entirely 
redundant. And since in many cases you end up passing user data or at least 3rd-
party data directly to json_encode() you would have to always add this redundant 
check.
 [2012-09-04 06:01 UTC] nikic@php.net
By the way, in PHP 5.5 the behavior here changes and there is no warning at all. The error will be available via json_last_error() and a second function which returns a human readable string instead of an error code.
 [2012-09-04 12:03 UTC] david at grudl dot com
Common way to avoid warnings in PHP is to use shut-up operator:

$handle = @fopen($file, 'r');

It is not ideal solution, but it is used in whole PHP. Standard. With just one exception:

$old = ini_set('display_errors', 1); 
$json = json_encode($args);
ini_set('display_errors', $old);


Why json_encode() is exception?
 [2012-09-04 12:22 UTC] david at grudl dot com
ad "in PHP 5.5 the behavior here changes …  error will be available via json_last_error()"

Functions like  mysql_error(), socket_last_error(), preg_last_error() etc are very unreliable because:

1) you are never sure the error-code was correctly reseted.

example 1:
json_decode('***'); // error, json_last_error() returns 4
json_decode(''); // correct, but it resets json_last_error() only since PHP 5.3.7

example 2:
preg_match('#.#u', "\xCA"); // error, preg_last_error() returns 4
preg_match("#\xCA#u", ''); // error too, but it DO NOT (re)set preg_last_error()
echo preg_last_error(); // preg_last_error() still returns 4

2) sometimes it is impossible to say what is "last" error

$s = preg_replace_callback($pattern, $callback, $s);
if (preg_last_error()) { 
   // was error in this preg_replace_callback or was PCRE used in $callback? Nobody knows...
}

Everything can be solved by converting warnings to exceptions via set_error_handle(). So I hope it will possible in PHP 5.5.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 06:01:30 2024 UTC