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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: juzna dot cz at gmail dot com
New email:
PHP Version: OS:

 

 [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: Fri Nov 22 23:01:29 2024 UTC