-1

I want to send json string encoded data to the PHP backend. For doing so, I am using an GET paremeter with URL encoded json data in it in form of an array like this one: ["mystring1","mystring2"]

When I now try to decode it using php's json_decode function, it returns null. Also, using this input string, doesn't change anything at all: {"mykey":["mystring1","mystring2"]}.

Here's my full code example:

JavaScript:

var myArr = [];
myArr.push('mystring1');
myArr.push('mystring2');
window.location.href = 'example.com/index.php?myparam=' + encodeURIComponent(JSON.stringify(myArr));

PHP backend site:

$jsonStr = filter_input(\INPUT_GET, 'myparam', \FILTER_SANITIZE_STRING);
var_dump($jsonStr);
var_dump(json_decode($jsonStr, true));

The first var_dump prints correctly the json string, the second one returns null. Using the assoc flag (2nd json_encode parameter) doesn't change anything.

What I expected to get:

array(2) { [0]=> string(9) "mystring1" [1]=> string(9) "mystring2" }

What I actually got:

NULL

var_dump for $jsonStr returns the following for me:

string(41) "["mystring1","mystring2"]"
alpham8
  • 1,314
  • 2
  • 14
  • 32
  • 1
    any chance you can use a POST for this and put the JSON in the request body instead? Then you don't have to URI-encode it. Anyway if json_decode returned nothing it probably failed - use this function: http://php.net/manual/en/function.json-last-error-msg.php to find out why. – ADyson Jun 20 '18 at 14:53
  • If you need further help please show the result of `var_dump($jsonStr);` – ADyson Jun 20 '18 at 14:54
  • Using the exmaples given above, there is no error: `$jsonStr = '{"mykey":["mystring1","mystring2"]}'; var_dump(json_decode($jsonStr, true));` prints the expected result. The only reason why this might fail, is that you did not insert a JSON-string. So unless we see the real output of your `$jsonStr` we can't help you. – feeela Jun 20 '18 at 14:55
  • @feeela That's true. But I meant if you use `json_decode('["mystring1","mystring2"]');` it results in `null`. – alpham8 Jun 20 '18 at 14:57
  • @feeela I suspect the issue is that `encodeURIComponent(JSON.stringify(myArr))` results in `%5B%22mystring1%22%2C%22mystring2%22%5D` which of course is not valid JSON, so unless the server has already decoded that, then there will be a problem. It can be reversed I guess, but it would be simpler just to use a POST and put the JSON in the body (or just use normal separate querystring parameters). – ADyson Jun 20 '18 at 14:57
  • @alpham8 `json_decode('["mystring1","mystring2"]');` does not result in NULL - see demo: https://eval.in/1025111 – ADyson Jun 20 '18 at 14:59
  • When I do (an enchanced) `var_dump($jsonStr);` I get `["mystring1","mystring2"]` which looks odd. Of course that seems to be because the `FILTER_SANITIZE_STRING` breaks the JSON – apokryfos Jun 20 '18 at 14:59
  • @alpham8 Nope it doesn't: `var_dump(json_decode('["mystring1","mystring2"]'));` prints the expected array: `array(2) { [0] => string(9) "mystring1" [1] => string(9) "mystring2" }` – feeela Jun 20 '18 at 14:59
  • @feeela Well, indeed, that plain returns just what we expect. But retrieving it from `filter_input` seems to cause the error. If I look at `json_last_error_msg()` it returns `syntax error`, but I'm 100% sure that this is valid json. – alpham8 Jun 20 '18 at 15:05
  • " I'm 100% sure that this is valid json" if there's a syntax error, then whatever you're feeding to json_decode is clearly not valid. It may have started out being valid but it's been through the URI-encoding and filtering processes before it gets to json_decode, so it could easily have changed. Therefore please tell us (as requested already), what does `var_dump($jsonStr);` output? Anyway as I said before, sending JSON on the querystring is not a good idea - problems like this are a frequent occurrence. I strongly suggest changing to a POST request, which is how world+dog sends JSON – ADyson Jun 20 '18 at 15:09
  • **`FILTER_SANITIZE_STRING` will break the JSON** – apokryfos Jun 20 '18 at 15:12
  • @apokryfos Yep, that's it :-) Please post this in answer,so that I can give you the solved check :-) – alpham8 Jun 20 '18 at 15:16
  • `string(41)` is odd because the string printed is only actually 25 characters long...presumably there are some hidden, whitespace, or unprintable characters in there as well which are not considered valid JSON. As apokyrfos says it's likely the result of the filtering, which seems an unnecessary task in this scenario. The URl encoding is also an avoidable complication – ADyson Jun 20 '18 at 15:20

2 Answers2

2

I am tranfering a note from What does FILTER_SANITIZE_STRING do? but the entire accepted answer in that question explains it a lot better:

First - php_filter_strip. It doesn't do much, just takes the flags you pass to the function and processes them accordingly. It does the well-documented stuff.

Then we construct some kind of map and call php_filter_encode_html. It's more interesting: it converts stuff like ", ', & and chars with their ASCII codes lower than 32 and higher than 127 to HTML entities, so & in your string becomes &. Again, it uses flags for this.

Then we get call to php_strip_tags_ex, which just strips HTML, XML and PHP tags (according to its definition in /ext/standard/string.c) and removes NULL bytes, like the comment says.

(Emphasised the important part).

In short FILTER_SANITIZE_STRING will break your JSON because it will encode things that it should not. If you want to validate this input do not use this filter.

The answer here is to not use FILTER_SANITIZE_STRING. The sensible way to validate a JSON string is to do json_decode and check if it's null.

$jsonStr = filter_input(\INPUT_GET, 'myparam'); 
var_dump($jsonStr); 
var_dump(json_decode($jsonStr, true)); 
Community
  • 1
  • 1
apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • Thank you very much for you investigation! :-) – alpham8 Jun 20 '18 at 15:27
  • 1
    I strongly suggest you use Symphony's [VarDumper](https://symfony.com/doc/current/components/var_dumper.html) component when debugging because it will show the string verbatim instead of dumping it in a browser window and letting the browser render it as HTML. – apokryfos Jun 20 '18 at 15:29
  • well, thanks for the tip, but in some of our plain php projects, it's impossoble to integrate composer there. If I will come to the same issue, I will binary compare its content in future. I think that might help, too. – alpham8 Jun 20 '18 at 15:59
0

The mistake here is not about JSON, but lies in the request using encoded URI components.

If you use encodeURIComponent on the JS side, you'll also have to use urldecode on the PHP side.

<?php
$jsonStr = '%5B%22mystring1%22%2C%22mystring2%22%5D';
var_dump(
    json_decode(urldecode($jsonStr), true)
);

See: http://php.net/manual/en/function.urldecode.php

feeela
  • 29,399
  • 7
  • 59
  • 71