I'm building an API in php. This API processes json messages from a third party API.
I want to log invalid pretty printed json messages.
So I did this:
error_log("test\n" . json_encode($json_string, JSON_PRETTY_PRINT));
However, when I look at my logs, the json string is not pretty printed:
$ tailf error.log
2015-07-13 10:20:03: (mod_fastcgi.c.2701) FastCGI-stderr: test
"{\"info\":{\"status\":200,\"msg\":\"OK\"},\"response\":{\"foo\":\"bar\"}"
I want to see something like:
$ tailf error.log
2015-07-13 10:20:03: (mod_fastcgi.c.2701) FastCGI-stderr: test
{
"info": {
"status": 200,
"msg ": "OK"
},
"response": {
"foo": "bar"
}
}
How can I achive this result?
error_log("test\n" . json_encode($json_string, JSON_PRETTY_PRINT));
json_encode() will actually not necessarily produce JSON: it will produce something that can be read by javascript. If you give it an array or an object, it will produce JSON; if you give it a string, it will produce a javascript string. And that’s what you’re doing, so that’s what you’re getting.
To be clear, $json_string is a string: (as far as PHP is concerned, it’s a string; if you passed that same string to javascript, it would be interpreted as an object). You pass that through json_encode() and all you’re going to get is another string (a string of doubly-encoded JSON).
JSON_PRETTY_PRINT is having no effect here, because you’re not producing JSON: you’re producing something that javascript too would see as a string.
Savvy?
So what you need to do is to (a) turn $json_string back into a PHP array, and then (b) reencode that as JSON, this time using the JSON_PRETTY_PRINT flag.
$log_array = json_decode($json_string, true);
$json_pretty_string = json_encode($log_array, JSON_PRETTY_PRINT);
error_log('test' . PHP_EOL . $json_pretty_string);
Rather than converting it back to a PHP array and then back to JSON, it would be better to add the JSON_PRETTY_PRINT flag to wherever you’re getting $json_string from in the first place, if possible.
Alternatively, just log $json_string directly (no need to encode it: it’s already a string, you can pass it to error_log() as it is), and worry about prettifying it only when you need to read your logs. This will make your logs considerably smaller.
Common unix error logs are not supposed to contain human-readable json or other unescaped characters. Many syslog/logging implementations are limited by character width and automatically add encoding (like \") or remove new line characters, PHP's error_log is not binary safe either - the behaviour when encountering a unicode character is unpredictable tho (not sure).
You should not be using the native syslog/error log functions, instead,
build your own logger, dedicated to json logging.
Personally I use MongoDB for logging json, because it's the kind of data MongoDB is supposed to work with.
You have two options in this case,
if you can use a str_replace like:
error_log("test\n" . str_replace('\"',"\n",json_encode($json_string, JSON_PRETTY_PRINT)));
or like #Karoly Horvath said:
You encode a string already encoded in a JSON. Your $json_string is already encoded. So you need to decode your first JSON and re-encode it with good parameters
error_log("test\n" . json_encode(json_decode($json_string), JSON_PRETTY_PRINT));
and give credit to #Karoly.
Related
For example i have json strings like this ( from the first place ). And It's not formatted.
{"data":[{"id":"14","memo_kondisi":"Kekurangan
pekerjaan","total_row":"5","nilai_temuan":"1.000.000","data_sebab":[{"id":"15","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[{"id":"25","id_rekomendasi":"10","id_sub_rekomendasi":"","id_s_sub_rekomendasi":"","nilai_rekomendasi":"0"},{"id":"26","id_rekomendasi":"10","id_sub_rekomendasi":"","id_s_sub_rekomendasi":"","nilai_rekomendasi":"0"},{"id":"31","id_rekomendasi":"10","id_sub_rekomendasi":"","id_s_sub_rekomendasi":"","nilai_rekomendasi":"0"}]},{"id":"16","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[{"id":"34","id_rekomendasi":"10","id_sub_rekomendasi":"","id_s_sub_rekomendasi":"","nilai_rekomendasi":"0"},{"id":"35","id_rekomendasi":"10","id_sub_rekomendasi":"","id_s_sub_rekomendasi":"","nilai_rekomendasi":"0"}]}]},{"id":"15","memo_kondisi":"Kekurangan
pekerjaan","total_row":"2","nilai_temuan":"1.000.000","data_sebab":[{"id":"5","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[]},{"id":"10","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[]}]},{"id":"16","memo_kondisi":"","total_row":"2","nilai_temuan":"0","data_sebab":[{"id":"9","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[]},{"id":"12","id_sebab":"","id_sub_sebab":"","memo_sebab":"coba","data_rekomendasi":[]}]}]}
I see some similar question that you have to use json_decode and i have to encode again and using json_encode($json,JSON_PRETTY_PRINT)
Is there a way for make json readable without decode the JSON first and encode it again in PHP ?
Note : I expect the result is still in JSON
Not really. Using someone else's parser lib won't make any difference, as they'll call json_decode() too.
You could create a little function that you could call:
function prettify($json)
{
$array = json_decode($json, true);
$json = json_encode($array, JSON_PRETTY_PRINT);
return $json;
}
Then echo prettify($jsonString); would be easier than constantly decoding and re-encoding. See here https://3v4l.org/CcJlf
Only a parser can understand the JSON, so you can either do what you proposed or write your own parser. If you have access to the origin of the JSON, make it pretty in the first place.
I'm building a specification validator that is based on json format in a PHP environment.
At some point, I considered creating a text editor which would help users directly edit and create their json.
In order to do that, I need the catch which errors are thrown when the json cannot be output (json_decode($myjson) returns NULL).
I've tried using both json_last_error() and json_last_error_msg() builtin functions but they neither provides the granularity I need.
What I want is to actually catch which character (or at least which line) is preventing the json from being decoded so that I can highlight it in the editor.
I've read that PHP does not nativly handle this. Is there a lib that do? If not, how would you tackle that issue? Do I need to code my own json encoder/decoder? If so, would you use regex on the string to explode it into subsets of arrays before recomposing the final object? Any other idea (maybe JS natively handles json decoding errors better than PHP does? :)
Cheers,
So I'm quite new to programming, and I have nothing else to describe it but a live script, so please correct me with the official term. Anyway, a while ago, I made this bot in php and ran it locally in my browser using xampp on my mac. I could very easily use echo and print_r to print arrays and whatever to the webpage. The script would only run if I reloaded the page, so this is what i'm talking about as 'not live'. Now I have started trying to make a messenger bot in PHP, and i'm using cloud9. I also see the script in a browser, but here, I can only see products of echo and print if they are simple strings I have entered, for example:
print_r("stack overflow is life");
This will print as expected in my browser. However, this is where me talking about 'live' script runs comes into play. Instead of reloading the page, it runs live. The messenger bot will always be active on the server, and it instantly replies to a message sent to it as wanted. I use this code:
/* receive and send messages */
$input = json_decode(file_get_contents('php://input'), true);
file_put_contents("fb.txt", file_get_contents('php://input'));
echo ("<pre>"); print_r($input);
echo ("</pre>");
Now, in this case, the $input is not printed. I see nothing. Now I don't know if this is to do with live server response, or what, but I need to know how to see this is the browser. And I have tested to see if there actually is a successfully converted JSON to array, because I am able to use the info in $input to reply to my facebook messaged and the bot works. I can also output the JSON to a txt file, and see it there, but there is no <pre> tags so it is hard to read, and I want the nice clean array to see in the browser. All code revolves around this, so it is very important.
So you are writing the raw input to the file and json decoding it separately. So it is quite possible you are not actually getting valid json.
If you do pass invalid json, json_decode returns NULL which is why you see that when you var_dump - so you have to call json_last_error to be sure it worked.
From Docs:
http://php.net/manual/en/function.json-decode.php
Returns the value encoded in json in appropriate PHP type. Values true, false and null 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.
You should really check if json_decode works, here is an example to demonstrate:
<?php
$badjson = '{bad:"json"}';
$decoded = json_decode($badjson);
if(json_last_error()!==JSON_ERROR_NONE){
echo "Json Decode Failed: ".json_last_error_msg();
}else{
var_dump($decoded);
}
echo "\n---\n";
$goodjson = '{"property":"value"}';
$decoded = json_decode($goodjson);
if(json_last_error()!==JSON_ERROR_NONE){
echo "Json Decode Failed: ".json_last_error_msg();
}else{
var_dump($decoded);
}
See it in action here: http://sandbox.onlinephpfunctions.com/code/3a07e57f4cd01bd63d2945d5e367bbb0a6158195
See PHP Docs: http://php.net/manual/en/function.json-last-error.php
You can use a syntax checker to find the problem with your json e.g. http://jsonlint.com/
A common issue if the json is manually created is failing to wrap properties in double quotes e.g. {property:"value"} is invalid while {"property":"value"} is valid.
Note the reason you have to check json_last_error, and can't rely on NULL meaning it failed is because json_decode('NULL'); would return NULL and that would be correct.
Not sure what is cloud9.
For debug you can try var_dump() function. It will print onto your browser data type and data values, because there could be different type of "nothing". It's not a better way for debugging but a naive one. For better: check debug and breakpoint possibilities in this cloud9.
var_dump() can eat as many arguments as you like, so it's handy to dump everything with php input too to check what comes and how it changes.
Well, I'm trying to retrieve some info, from the Google Suggest tool.
The thing is, the json returned after the request, doesn't seem decode-able (using json_decode) + JSONLint sees it as "invalid".
What's wrong?
{
e: "GooDUs7lFIeXO63LgBA",
c: 0,
u: "https://www.google.com/s?gs_rn\x3d24\x26gs_ri\x3dpsy-ab\x26tok\x3dt8ORbtI13MEFLoCQjPSv6w\x26cp\x3d2\x26gs_id\x3d3i\x26xhr\x3dt\x26q\x3dtemplate\x26es_nrs\x3dtrue\x26pf\x3dp\x26safe\x3doff\x26sclient\x3dpsy-ab\x26oq\x3d\x26gs_l\x3d\x26pbx\x3d1\x26bav\x3don.2,or.r_cp.r_qf.\x26bvm\x3dbv.50500085,d.bGE\x26fp\x3dc513cf9c63a02102\x26biw\x3d1304\x26bih\x3d437\x26tch\x3d1\x26ech\x3d20\x26psi\x3dFYkDUs-xCsrT4QTD9YGwDw.1375963413783.1",
p: true,
d: "[\x22template\x22,[[\x22template\\u003cb\\u003es\\u003c\\/b\\u003e\x22,0],[\x22template\\u003cb\\u003e monster\\u003c\\/b\\u003e\x22,0],[\x22template\\u003cb\\u003e c++\\u003c\\/b\\u003e\x22,0],[\x22template\\u003cb\\u003es for pages\\u003c\\/b\\u003e\x22,0]],{\x22t\x22:{\x22bpc\x22:false,\x22tlw\x22:false},\x22q\x22:\x22YjrI_EdhVrEkZrkqZwaGIJ_Ih4c\x22,\x22j\x22:\x223i\x22}]"
}
That's what JSONLint gives as an error :
Parse error on line 1:
{ e: "GooDUs7lFIeXO63L
-----^
Expecting 'STRING', '}'
P.S. Even after editing it like "e": and so on, it still gives out error regarding the value of u and claiming that it was expecting a STRING or NUMBER etc... :S
The code given in the question is not valid JSON.
In order to be valid JSON, it would be required to have the field named in quotes. There are no quotes around the e variable name, or any of the others.
This is what the JSON decoder is complaining about: It is expecting to see "e", not e.
In addition, JSON does not accept the \x escaping format (character reference in hex); it can only use the \u format (unicode character reference in decimal). The code you've provided includes escaped characters in both formats.
The question is, are you using an official Google API? Because they're usually pretty good at providing valid JSON. This isn't valid JSON, so it may be that you're not using the correct API. Another clue is that the variable names aren't very meaningful; offical APIs would normally give more meaningful variable names. If it is the correct API, you should try raising a ticket with Google to fix it; broken JSON is not good, but it should be pretty trivial for them to fix.
Assuming you can't get them to fix it and we can't find an alternative API location that does give valid data, how do we deal with what we've got?
While this code may not be valid JSON, it is valid as a Javascript object (the JSON rules are stricter that those of plain Javascript). It could therefore be run in a Javascript interpreter using eval(), if you trusted it enough for that.
The only other alternativate is to fix the string prior to parsing it so that the variable names are quoted. That's a bit of a pain, but would be do-able if the output was consistent. You'll have problems though if it ever changes (and again, if it's an unofficial API, that could happen at any time without warning).
The problem is with the backslashes in the strings (used for the escape characters)
In PHP 5.4, you can use JSON_UNESCAPED_SLASHES:
echo json_encode(JSON_STRING, JSON_UNESCAPED_SLASHES);
Otherwise, you can do the replacement-
str_replace('\\/', '/', json_encode(JSON_STRING));
Since \/ is a valid way to represent /
OK, so this is what I ended up doing (not elegant at all but it works) :
$content = preg_replace_callback(
"(\\\\x([0-9a-f]{2}))i",
function($a) {return chr(hexdec($a[1]));},
$content
);
$content = str_replace("e:","\"e\":",$content);
$content = str_replace("c:","\"c\":",$content);
$content = str_replace("u:","\"u\":",$content);
$content = str_replace("p:","\"p\":",$content);
$content = str_replace("d:","\"d\":",$content);
$content = str_replace("\"[","[",$content);
$content = str_replace("]\"","]",$content);
$content = json_decode($content);
Could some one please help me out on this I have the following json string
string(1223) "YAHOO.Finance.SymbolSuggest.ssCallback({"ResultSet":{"Query":"google","Result":[{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S","exchDisp":"NASDAQ","typeDisp":"Equity"},{"symbol":"GOOG.MX","name": "GOOGLE-A","exch": "MEX","type": "S","exchDisp":"Mexico","typeDisp":"Equity"},{"symbol":"GGQ1.F","name": "GOOGLE-A","exch": "FRA","type": "S","exchDisp":"Frankfurt","typeDisp":"Equity"}]}})"
But I cannot seem to get anywhere with it. Basically I want to just loop out the the results which are
[{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S","exchDisp":"NASDAQ","typeDisp":"Equity"},{"symbol":"GOOG.MX","name": "GOOGLE-A","exch": "MEX","type": "S","exchDisp":"Mexico","typeDisp":"Equity"},{"symbol":"GGQ1.F","name": "GOOGLE-A","exch": "FRA","type": "S","exchDisp":"Frankfurt","typeDisp":"Equity"}]
Sorry my question is how can I loop or even print the first result for example
{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S","exchDisp":"NASDAQ","typeDisp":"Equity"}
Your string is not JSON, it is JSON-in-Script. Notice the fragment that says:
YAHOO.Finance.SymbolSuggest.ssCallback(...)
When a browser receives the above mentioned script (actually a javascript code) it will call the YAHOO.Finance.SymbolSuggest.ssCallback function, passing the JSON data as the argument.
You did not mention if you want to access the JASON data on the server side or client? It its server side (PHP) then you can use regular expressions or string replacement functions to extract the portion you like. The you can use json_decode() function to convert the resulting string into an associative array.
Edit ----
A quick and dirty hack for converting JSONP to JSON:
<?php
$text = 'YAHOO.Finance.SymbolSuggest.ssCallback({"ResultSet":{"Query":"google","Result":[{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S","exchDisp":"NASDAQ","typeDisp":"Equity"},{"symbol":"GOOG.MX","name": "GOOGLE-A","exch": "MEX","type": "S","exchDisp":"Mexico","typeDisp":"Equity"},{"symbol":"GGQ1.F","name": "GOOGLE-A","exch": "FRA","type": "S","exchDisp":"Frankfurt","typeDisp":"Equity"}]}})';
# //CONVERT JSONP to JSON\\
$text = preg_replace('/.+?({.+}).+/', '$1', $text);
# \\CONVERT JSONP to JSON//
$data = json_decode($text);
var_dump($data);
var_dump($data->ResultSet->Result[0]);
var_dump($data->ResultSet->Result[0]->symbol);
var_dump($data->ResultSet->Result[0]->name);
# etc etc
?>
Your result is not just a JSON string, it's a JSON string prepended by a call to a JSON function. This is quite certainly a JSONP call.
You must write the YAHOO.Finance.SymbolSuggest.ssCallback(data) javascript function and get the Json there. Check the JSONP query, you should be able to alter the name of this backreference function if you want another name, it's usually on of the parameter in the GET query.
Now you are maybe calling it directly from PHP and you are not in js envirronment. so you must write something in your PHP code to remove the YAHOO.Finance.SymbolSuggest.ssCallback( part and the ) at the end before parsing it as JSON data..