0

It seems PHP's error suppressor @ is still triggering my custom error handler although it doesn't show error's on screen.

Example:

@json_decode(array());

This will not output error messages on screen but it will still run my error handler (e.g., log the error, send me email, terminate script execution, as if there was a "real" error).

Is there a way for @ to totally be silent?

IMB
  • 13,681
  • 17
  • 70
  • 124
  • 2
    You actually deserve a -1 for using @ in the first place – w00 Aug 11 '12 at 19:25
  • @w00 You deserve -1 because there is no other way, look here http://stackoverflow.com/questions/2348152/detect-bad-json-data-in-php-json-decode +1 for me :-) – IMB Aug 11 '12 at 19:27
  • wtf are you talking about. In that topic the OP clearly has the problem the he passes an `array` to the `json_decode` function instead of a string. No wonder it spits out an error. Just make sure the $variable is actually of type string. -2 for you :-) – w00 Aug 11 '12 at 19:39
  • @w00 The example is just to demonstrate an error, the URL showed to you if you read it, is similar to what is being solved here, it uses `@` too in detecting valid json data. The topic is very much related. BTW I am the OP. -2 for you :-) – IMB Aug 11 '12 at 19:43
  • nothing is solved with @ You dont need it. Also not in this case. If i were at home i'd show you how to do this properly. ill save that for later. still -wees for you. – w00 Aug 11 '12 at 19:52
  • @w00 How do you suggest we detect valid JSON data without triggering custom error handlers? I will wait for your answer, if it's awesome I will accept all your -1's and accept defeat. – IMB Aug 11 '12 at 19:58
  • You don't need to detect valid JSON. `json_decode` won't throw an error if you pass it a string containing invalid JSON. Just make sure you pass it a string. – Quentin Aug 11 '12 at 21:31
  • @Quentin There is a need to detect valid JSON if you are making an API. You have to know if the data the client sent to you is valid JSON first before you do anything with it. – IMB Aug 11 '12 at 21:46
  • @IMB — After establishing that it is a string, you can put it straight into `json_decode` (if there is a security exploit based around that function that I'm not aware of, then the security exploit needs to be fixed at the root rather then worked around). `json_decode` will not blow up if it isn't valid JSON. If you get `null` back, then it wasn't valid JSON, but you don't need to detect that *before* you try to decode it, as the act of trying to decode it will detect it for you. – Quentin Aug 11 '12 at 21:57

2 Answers2

4

If you're trying to detect valid json then atleat make sure the "param" you pass to json_decode is of type string.

Quote from php.net:

Returns the value encoded in json in appropriate PHP type. Values true, false and null (case-insensitive) are returned as TRUE, FALSE and NULL respectively. NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit.

So it's NULL that we're looking for if the JSON cannot be decoded. Thus, invalid JSON. But again, just make sure you pass in a string and not some other type, like an array or boolean or something. Because that will never work.

And i understand your problem. The @ sign suppresses the error message, but not the actual code flow. It still exits when it goes wrong. But you really just have to let go of the @ sign.

So anyway, you'd probably have some sort of function that you call which does some stuff including the json_decode. This is just an example, but it should give you an idea of what i mean.

<?php

// will fail, because it's not a string
$str1 = array ( "nooblol" ); 

// Will succeed. This is valid json
$str2 = '{"example":"value"}';

// Will fail, is of type string, but still an invalid json format
$str3 = 'invalid json string';

function saveData ( $json )
{
    // Check if the variable that we're about to pass
    // to json_decode() is an actual string. Otherwise we
    // have invalid json data anyway.
    if ( !is_string ( $json ) )
    {
        echo 'Invalid json (or invalid type)';
        return;
    }

    if ( !$obj = json_decode ( $json ) )
    {
        echo 'fail';
        return;
    }

    // Print json object
    print_r($obj);
}

saveData ( $str3 );

?>

Live example: http://codepad.viper-7.com/KJL8st Change the saveData param to $str1 or $str2 to see the different results.

This is the way to check if you have valid json. Don't solely depend on the json_decode() function to tell you wether it's valid data or not. it's a function and it simply expects a string. So make sure you pass in a string. Only then it can tell you wether it's valid json or not.

w00
  • 25,022
  • 28
  • 99
  • 146
  • These are valid json too but will fail in your example `$str = '';` or `$str = null;` – IMB Aug 11 '12 at 21:43
  • @IMB — Those examples are not valid JSON. The outermost layer of a JSON text must be an array or an object. See paragraph two of section two (JSON Grammar) of [the specification](http://www.ietf.org/rfc/rfc4627.txt). – Quentin Aug 11 '12 at 21:58
  • @Quentin To be clear0 `json_encode($str)` makes them valid JSON. Now when you run it in the script above they will fail. – IMB Aug 12 '12 at 08:45
  • @IMB — No, `json_encode('')` and `json_encode(null)` do not output valid JSON. You can confirm this by reading the part of the specification I referenced earlier, or by copy/pasting the output into [JSON Lint](http://jsonlint.com). – Quentin Aug 12 '12 at 09:04
  • Like Quentin already said, check the Json specification. You could always check and see how PHP handles empty strings: http://codepad.viper-7.com/FcN625 --- As you can see PHP follows the specifications perfectly by saying empty strings or null values are invalid. – w00 Aug 12 '12 at 09:12
  • I wouldn't go so far as to say that PHP follows the specifications perfectly — http://codepad.viper-7.com/e12fw5 — but you can detect that what you get back from `json_decode` isn't something that could be created from JSON (so you still don't need to detect that something is JSON before you pass it to `json_decode`). – Quentin Aug 12 '12 at 10:47
2

I don't believe you can prevent the error handler from seeing errors that were suppressed by @.

You can however isolate those errors and ignore them at your own risk.

Put the following code in your error handler:

// get the current error reporting level
$level = error_reporting();

// if error was supressed or $errno not set in current error level
if ($level == 0 || ($level & $errno) == 0) {
    return true;
}

Note that $errno is the first argument to the error handler callback.

drew010
  • 67,054
  • 11
  • 128
  • 154