Cannot json_decode a GET parameter - php

All,
I'm trying to pass a stringified json object as a GET parameter but the receiving URL seems unable to decode it, I am not sure why.
Here is the relevant code:
Client side Json object production (works fine):
function createJson(){
// This works fine. It creates a json objects with three elements, the third being an array.
//(omitted code for brevity)
return jsonData;
}
Client side ajax call (works fine):
function recordSetGet(jsonData){
request = createRequest();
var rawSet=JSON.stringify(jsonData);
var encodedSet=encodeURIComponent(rawSet);
var params="set="+encodedSet;
var url= "Ajax_recordSetGet.php?"+params;
request.open("GET", url, true);
request.onreadystatechange = function(){}
request.send(null);
}
This yield the following URL: Ajax_recordSetGet.php?set=%7B%22setTitle%22%3A%22test%22%2C%22setTags%22%3A%22test%20%22%2C%22set%22%3A%5B%7B%22first%22%3A%22Joe%22%2C%22last%22%3A%22Doe%22%2C%22checked%22%3Atrue%7D%5D%7D"
Server side treatment:
<?php
header('Content-Type:text/html; charset=UTF-8');
if(!session_id()){
session_start();
}
if(isset($_GET['set'])){
$set=$_GET['set'];//This is the URI encoded string
var_dump ($set);
var_dump (json_decode($set));
var_dump ("Json last error is ".json_last_error());
}
?>
The result of the var_dumps are:
string '{"setTitle":"test","setTags":"test ","set":[{"first":"Joe","last":"Doe","checked":true}]}"' (length=90)
null
string 'Json last error is 4' (length=20)
So why is json_decode() failing here? The json_last_error() result suggests a syntax error.
Edit: Note that json_decode also fails if I send a non encoded string:
If I build the param string without encoding it like this:
var rawSet=JSON.stringify(jsonData);
var params="set="+rawSet;
var url= "Ajax_recordSetGet.php?"+params;
Then the URL becomes Ajax_recordSetGet.php?set={"setTitle":"test","setTags":"test ","set":[{"first":"Joe","last":"Doe","checked":true}]}"
And the receiving URL var_dump yield the same error:
string '{"setTitle":"test","setTags":"test ","set":[{"first":"Joe","last":"Doe","checked":true}]}"' (length=90)
null
string 'Json last error is 4' (length=20)

I don't know why, but you have a trailing double quote in your URL that messes up the JSON decode process.
...%7D%5D%7D" <- Trailing double quote
This quote also shows up in your dump of the set variable:
...true}]}"' (length=90) <- double quote is inside the string, the single quote is part of the var_dump output.
This double quote must be introduced in the Javascript code, although I cannot see a spot where that should happen. But your debugging should take place in that part of the system.
Note that you MUST NOT urldecode the string passed as the "set" parameter, as PHP has done the decoding for you already. But with the trailing double quote you cannot call json_decode().
As a quick proof of concept, try using $set = rtrim($set, '"') in your PHP code before decoding to remove that quote character.

http://php.net/manual/en/function.urldecode.php
The superglobals $_GET and $_REQUEST are already decoded. Using urldecode() on an element in $_GET or $_REQUEST could have unexpected and dangerous results.
Try a different way. I suggest base64-encoding the json string.
Instead of this:
var rawSet=JSON.stringify(jsonData);
var encodedSet=encodeURIComponent(rawSet);
var params="set="+encodedSet;
var url= "Ajax_recordSetGet.php?"+params;
do this:
var rawSet=JSON.stringify(jsonData);
var encodedSet=btoa(rawSet);
var params="set="+encodedSet;
var url= "Ajax_recordSetGet.php?"+params;
But pay attention to the caveats!
And in your serverside:
$decodedSet=json_decode(base64_decode($set));

Related

angularJS - POST array after JSON.stringify()

I want to POST 3 parameters to my PHP web service. One of which is an array, so I used JSON.stringify() first and then added it as the parameter. The problem is, PHP isn't receiving the stringify'ed parameter.
My array is created by fetching IDs of each element in an object.
Converting it into a string:
var cid = JSON.stringify(cids);
Output as in the console for cid:
["1","2","3"]
And my $http.post call:
var dataObj = {
wid: wid,
type: type,
cid: cid
};
$http.post("my.php", dataObj);
From what I understand, the array gets converted into a string, which must get POSTed alike other strings, but when I echo back $_POST['cid'], it turns out to be blank; while the wid & type are proper.
From my understanding all post data is converted to JSON anyway. Manually changing your array to JSON and including is just the same as:
$http.post("my.php", {
wid: wid,
type: type,
cid: [1, 2, 3]
}
At the other side of the connection the JSON is converted back to objects(arrays) if possible. PHP doesn't print anything because arrays aren't converted to strings that well. Although you should expect the string 'array'. Try echo'ing $_POST['cid'][0]
EDIT:
As stated in the comments and this post the following code is required to get PHP and AngularJS to play together:
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);

How do I convert numeric values to strings?

I have a JS function which I'm passing some JSON. I produce this JSON with PHP:
<?php
$array[] = array('hello','123','456');
echo json_encode($array);
?>
This gives me something neat for JS like:
[["hello","123","456"]]
My JS function seems to like this format.
The problem I have however is when I produce a similar array directly in JS like so:
var json = [[text_var,number_var,number_var]]; // these vars established earlier in the code
var json_stringify = JSON.stringify(json);
I wind up with something that looks like this:
[["hello",123,456]]
So basically, it isn't encapsulating my numbers with quotes. I wouldn't think it would matter, but without them I get a Uncaught RangeError: Maximum call stack size exceeded
I tried doing something like preparing the JSON myself with:
var json = '[["'+place_name+'","'+longitude+'","'+latitude+'"]]';
But passing that it doesn't like either - maybe it isn't feeling it as a JSON var, and I've tried parsing that through JSON.stringify but I end up with backslashes before every quote and it doesn't like that either.
What is my feeble mind not seeing here?
EDIT: My PHP array is in another array hence the result of [["hello',"123","456"]] and not single brackets [ ]
Convert numbers to strings:
var json = [[text_var,number_var.toString(),number_var.toString()]];
JSON supports numbers (without quotes) and strings (with quotes). To force it to use strings, try:
var json = [[text_var,number_var + "",number_var + ""]];

convert JSON object to query string and then back to an object

I know this has been asked a few times but please bear with me.
I have a google maps object which is rather complex (it contains various nodes, coordinates, etc) and I am trying to pass it as a query string.
I need a play javascript/jQuery solution.
I have tried the .param method which gives a jQuery error. The only thing that works is the "stringify" method which then creates a string that when appearing as a url looks a bit like this: %7B%5C"shape_1%5C"%3A%7B%5C"color%5C"%3A%5C"%237F0000%5C"%2C%5C"data%5C"%3A%7B%5C"b%5C"%3A%5B%7B%5C"Na%5C"%3A51.56727431757122%2C%5C"Oa%5C"%3A-0.10462402858888709%7D%2C....
php translates that as:
{\\"shape_1\\":{\\"color\\":\\"#7F0000\\",\\"data\\":{\\"b\\":[{\\"Na\\":51.56727431757122,\\"Oa\\":-0.10462402858888709},...
but having said that I don't want to use PHP, I am just showing you what it does in case it helps you see what stringify did to the object.
After I unescape with Javascript it looks a bit more normal like:
{\"shape_1\":{\"color\":\"#7F0000\",\"data\":{\"b\":[{\"Na\":51.56727431757122,\"Oa\":-0.10462402858888709},..
So as you can see, the unescaped sequence has these slashes everywhere.
When I try to evaluate that into a JSON object I get "Illegal token \". The parse method also fails. I just can't find any way to put this string back into the complex JSON object that it was.
I have looked online for various suggestions but they fail. I also don't understand why stringify injects all these slashes which simply shouldn't be there.
If anyone has an idea how to take that object, put it in a query string and then parse it back I would be very grateful.
Nick
Update:
The answer is this:
encodeURIComponent(JSON.stringify(myObject));
And then on the receiving end:
var a = querySt("data");
var b = decodeURIComponent(a);
var c = unescape(b);
var d = JSON.parse(c);
or all in one line
JSON.parse(unescape(decodeURIComponent(querySt("data"))));
Nick
See http://php.net/manual/de/security.magicquotes.php - you have to turn off magic quotes. They are old, deprecated stuff, they are insecure and break stuff.
Magic Quotes is a process that automagically escapes incoming data to the PHP script. It's preferred to code with magic quotes off and to instead escape the data at runtime, as needed.
Howto: http://www.php.net/manual/de/security.magicquotes.disabling.php
Try this to convert query string into json object
var queryStringToJSON = function (url) {
if (url === '')
return '';
var pairs = (url || location.search).slice(1).split('&');
var result = {};
for (var idx in pairs) {
var pair = pairs[idx].split('=');
if (!!pair[0])
result[pair[0].toLowerCase()] = decodeURIComponent(pair[1] || '');
}
return result;
}
You can use jQuery.param method to covert json object back to query string

JQuery .get() only passing first two data parameters in url

I have a $.get() call to a PHP page that takes 4 GET parameters. For some reason, despite giving the $.get() call all 4, it only passes the first two. When I look at the dev console in chrome, it shows the URL that gets called, and it only passes action and dbname. Heres the code:
$.get('util/util.php', { action: 'start', dbname: db, url: starturl, crawldepth: depth }, function(data) {
if (data == 'true') {
status = 1;
$('#0').append(starturl + "<ul></ul>");
$('#gobutton').hide();
$('#loading').show("slow");
while(status == 1) {
setTimeout("update()",10000);
}
} else {
show_error("Form data incomplete!");
}
});
and heres the URL that I see in the developer console:
http://localhost/pci/util/util.php?action=start&dbname=1hkxorr9ve1kuap2.db
** EDIT **
I have been informed that I need to encode the URL that I am trying to pass through the header. How would I go about encoding it in javascript, and decoding it in php?
Are you sure that the starturl and depth variables are defined? A simple alert() before the $.get() will be enough to check.
In regards to your edit, you can encode strings in JavaScript with the encodeURIComponent function. And decode it back again in the PHP with urldecode. They both take one string argument.
Probably you will need to check whether your input strings are properly quoted. Internally jQuery will build the paramter string out of the parameter map you specified using its param() method. This method will construct an object of the keys and values, which will likely not be parseable if you quoted your keys and values incorrectly.
# Felix Kling: jQuery automatically encodes keys and values of the parameter string with encodeURIComponent.

To JSON and json_decode in PHP and JavaScript

I'm trying to pass a JavaScript object to a PHP script through jquery.ajax(), basically:
var bigArray = new Object();
//Dode
//Start loop
bigArray[x] = {name: exname, id: exID, order:e, set: setBox, inc: incBox, example: exampleBox, day: i};
So it's pretty much an array of these objects.
var anotherTest = $.toJSON(bigArray);
var ajxFile = "routineajax.php";
$.ajax({
type: 'POST',
processData: false,
url: ajxFile,
data: anotherTest,
success: function(data) {
$('#result').html(data);
alert('Load was performed.');
}
});
});
The PHP side script
print_r($_POST);
$params = json_decode($_POST);
print_r($params)
The Ajax call is going through, and I can see in Firebug, but print_r($_POST) is returning an empty array. While if I change it to $_GET in both the $.ajax function and PHP script it works. My main problem is I'm getting this error message:
Warning: json_decode() expects parameter 1 to be string, array given in
How do I fix this problem?
After adding this snippet to the PHP file
$data = file_get_contents('php://input');
var_dump($data);
var_dump(json_decode($data));
I'm getting this output
string'{"0"{"name":"Decline`Abs","id":"54","order":0,"set":"","inc":"","example":"","day":1}}' (length=87)`
object(stdClass)[2]
public '0' =>
object(stdClass)[4]
public 'name' => string 'Decline Abs' (length=11)
public 'id' => string '54' (length=2)
public 'order' => int 0
public 'set' => string '' (length=0)
public 'inc' => string '' (length=0)
public 'example' => string '' (length=0)
public 'day' => int 1
So at least it's going through, I'm not sure how to access it though, a step in the right direction!
I think the problem is that normally POST data is sent encoded as key=value&key2=value2, and you're sending it as JSON. Try accessing the raw post data as follows:
$data = file_get_contents('php://input');
var_dump($data);
var_dump(json_decode($data));
and see if that works. If not, please post in your question what it returns, if anything.
Based on the comment below and additions to the OP.
Did the var_dump of $data copy-paste correctly? The reason I ask is that this: string'{"0"{"name" does not look right to me. That isn't valid JSON or a properly encoded POST string. It might be that some of the characters got encoded when you copied and pasted.
Either way, you're now getting the result you need. The stdClass is just a blank container that it puts the data into, which you can access using the normal object syntax. In this case, you'd have to do $data->{0}->name I think, because of that 0. If you do $data = json_decode($data, true) it will be an associative array, and you can access the POST'ed data as $data[0]['name'].
If you want to keep exploring this, it might be helpful to show the results of doing window.console.dir(data) right before you do the ajax request, and make sure when you var_dump(data), you view the source of the page to copy and paste. window.console.dir(data) will show data's properties in the Firebug window (you are using Firebug, right?). It also works in Chrome's debugger, and maybe others as well. Like I said though, it looks like you're probably getting what you need already, so investigating isn't necessary.
Turn processData to true. I don't believe your JSON is being passed through correctly. Also note that it won't come through as a json, but rather the key value pairs of your JSON will be the contents of $_POST when you get to it.
Also, are the values of your bigArray easily convertable to string? If you're passing in DOM elements or something, you're going to have issues.
Isn't it clear enough? json_decode() expects parameter one to be string, not array. But $_POST and $_GET are always arrays. You can pass a member of this array to json_decode().
To see an array's contents, use this snippet:
echo "<pre>";
print_r($_GET);
echo "</pre>";

Categories