JSON.parse fails in jQuery when PHP response-header contains "application/json" - php

I'm getting a bit of a headache trying to figure this one out. To request some json-data from a PHP-script via Ajax, I'm using the jQuery function:
$.ajax({
type: 'GET',
cache: 'false',
url: ajaxUrl,
data: dataString,
success: updatePage
});
If I don't set content-type in the PHP header to:
header('Content-type: application/json');
Then my response from the server looks like this:
{"content":"new content"}
And the content-type is automatically set to text/html. When dataType in the jQuery ajax options is unset, it uses a default of 'intelligent guessing'. I'm strongly assuming that jQuery recognizes the response-data as json because updatePage is parsed an object. updatePage uses the JSON js library(json2.js), and does this:
function updatePage(data) {
$dataObj = JSON.parse(data);
}
When the function is called upon ajax succes, everything works fine. No errors.
Here's the strange thing, if I set my header to application/json as above, JSON.parse suddenly reports an error. The exact same error happens if i set my dataType to 'json' in the jQuery ajax request. The response I get from the PHP script when changing these things looks exactly like the one above. The error looks like this in Firebug:
JSON.parse
$dataObj = JSON.parse(data);
Kind of a long one, sorry, but If anyone knows what is wrong their help is greatly appreciated. Thanks for your time.

It's because you end up trying to double-parse the return value.
Both the explicit json data type and usage of the application/json MIME type cause jQuery to parse the returned string into a JavaScript object for you.
So, your usage of JSON.parse(), in these cases, is superfluous.

Related

Cross Origin Resource Sharing using AJAX methods and PHP

I just started to work on calls to a php file which is present in a different server. I am aware of CORS which is essential for cross domain requests. I have been trying to call this file through ajax methods refering to other websites and tutorials and I have seen discussions to find a solution but they are not working for me. Please help.
here is my calling method:
$.ajax({
type: "GET",
url: "http://cs-server.usc.edu:27952/ResponseProg.php?callback=?", //Relative or absolute path to response.php file
datatype: "jsonp",
data: dataInput,
jsonp:'jsoncallback',
crossDomain:true,
success: function(data)
{
JSONObj = jQuery.parseJSON(data);
contentProvider("#rtrn");
if(JSONObj.ack != "No results found")
{
var paginate=setPager(0);
$("#pgn").html(paginate);
}
},
error: function() {
$("#rtrn").html("Data not retrieved successfully");
}
});
Here is my PHP code snippet:
<?php
#code for data processing...
$rsltjson = json_encode($result,JSON_UNESCAPED_SLASHES);
echo $_GET['jsoncallback']."(".$rsltjson.");";
?>
I am trying to accomplish this by using JSONP. Should I have any headers?
Are there any errors in my code?....How can I accomplish this? dataInput is the serialized form of form data
The CORS way
You need to put the appropriate header in your php script and output only the JSON:
<?php
header('Access-Control-Allow-Origin: *');
// rest of the code
// output JSON only
echo $rsltjson;
?>
Then using a XMLHttpRequest/ajax call should retrieve the data just fine as JSON without resorting to JSONP.
Mozilla has plenty to read about it
The JSONP way
Since the whole point of JSONP is to bypass cross-domain restrictions, calling a JSONP resource with XMLHttpRequest/ajax, a method in which cross-domain security is fully applied (presumably), is completely useless.
JSONP works by injecting code directly into your page, calling a function that you defined, which is why a JSONP url takes an argument. Therefore, the correct way to call your JSONP url is this:
<script>
function myDataFunc(data) {
JSONObj = jQuery.parseJSON(data);
contentProvider("#rtrn");
if(JSONObj.ack != "No results found") {
var paginate=setPager(0);
$("#pgn").html(paginate);
}
}
</script>
<script src="http://cs-server.usc.edu:27952/ResponseProg.php?jsoncallback=myDataFunc"></script>
The JSONP url will return something that looks like this:
myDataFunc({"a":"fhsfg","b":"qfdgers","c":"difgij"});
Since it is included as a script, it will be executed directly in your page, calling the function myDataFunc() that you defined earlier.
Also note that your php file use the GET parameter jsoncallback while your javascript calls the url with the parameter callback, which would not work.
Finally, you use jQuery.parseJSON(), which produces this error from your code:
SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
The reason can be found in the jQuery docs:
jQuery.parseJSON( json )
Description: Takes a well-formed JSON string and returns the resulting JavaScript value.
Passing in a malformed JSON string results in a JavaScript exception being thrown.
Your php script feeds your callback with a JSON object
{"a":"fhsfg","b":"qfdgers","c":"difgij"}
rather than a string representing a JSON object
'{"a":"fhsfg","b":"qfdgers","c":"difgij"}'
Note the surrounding quotes, which makes this data a string. We fix this in php by adding the quotes around the data:
echo $_GET['jsoncallback']."('".$rsltjson."');";
Obviously if your JSON data contains single quotes, you will have to escape them.

POST data not appearing in CakePHP controller

I'm using AJAX on a knockout.js form to post some information that CakePHP should receive, however, Cake doesn't seem to find anything. Also, the alert isn't appearing despite a 200 status (OK) from the POST.
Here's the AJAX
$.ajax({
url: "/orders/finalize_payment",
type: "POST",
dataType: "json",
contentType: "json",
data: JSON.stringify({"customer": customer_id}),
success: function(){
alert("success");
}
});
Here's the corresponding action in the orders controller. Right now, I completely stripped it to just the bare minimum.
function finalize_payment($id = null){
$this->layout = false;
$this->autoRender = false;
if($this->request->is('post')){ //the user has submitted which status to view
print_r($this->request->data);
echo "test"; //just to make sure it's reaching this point
}
}
When I open up the network tab in chrome, it shows the request payload as
customer: 1
The POST shows as success, status 200. I checked the response headers and it just shows
array
(
)
test
Despite chrome showing a payload being sent, CakePHP isn't finding it apparently.
Update
I changed the request from AJAX to $.post and it worked. I still have no clue why
$.post("/orders/finalize_payment",{"customer_id":customer_id},function(data){
alert('success');
});
Don't encode post data as json
The code in the question won't appear in any php script, the reason is this:
contentType: "json"
It's not a form-url-encoded request, so e.g. the following code:
print_r($_POST);
print_r(file_get_contents('php://input'));
will output:
Array()
'{"customer":123}'
If you want to submit data as json, you'll need to read the raw request body:
$data = json_decode(file_get_contents('php://input'));
There might be times when that's desirable (api usage), but that isn't the normal way to use $.post.
The normal way
The normal way to submit data, is to let jQuery take care of encoding things for you:
$.ajax({
url: "/orders/finalize_payment",
type: "POST",
dataType: "json", // this is optional - indicates the expected response format
data: {"customer": customer_id},
success: function(){
alert("success");
}
});
This will submit the post data as application/x-www-form-urlencoded and be available as $this->request->data in the controller.
Why $.post works
I changed the request from AJAX to $.post and it worked. I still have no clue why
Implicitly with the updated code in the question you have:
removed the JSON.stringify call
changed from submitting json to submitting application/x-www-form-urlencoded
As such, it's not that $.post works and $.ajax didn't ($.post infact just calls $.ajax) - it's that the parameters for the resultant $.ajax call are correct with the syntax in the question.
As you're using CakePHP you may find adding RequestHandler to your components fixes the problem.
public $components = array([snip], 'RequestHandler');
Doing this allowed me to transparently access JSON posted data using $this->request->data. The other answer's advice to not encode POST data as JSON becomes a bit awkward, given that certain JS frameworks, such as Angular, post JSON as default.
Using raw data and json you can use:
$data = $this->request->input('json_decode');
**Data is an object now, not an array.
Then you can use:
$this->MyModel->save($data).
Nicely formatted question :)
I'm pretty sure I have the answer, though I could be wrong... Basically, $this->request is an object in Cake, and $this->request->data is a variable/array that's a property of the object.
The data you're sending to Cake is going straight into the object (if this is even possible), not into the data array. This is why when Cake generates forms using the HtmlHelper, the names are, for example data[User][username].
I think, if you put JSON.stringify({"customer": customer_id}) into a 'data' array and send that, it should work.
Have a look at this post. You're data string probably isn't correct. Therefore CakePHP might not be able to put it in $this->request->data.
Use print_r($this->request->params);
function finalize_payment($id = null){
$this->layout = false;
$this->autoRender = false;
if($this->request->is('post')){ view
print_r($this->request->params);
} }

Get - Request , to display results in Alert()

I would like to create an app that will send out a get request, then take the response and display it on the page,
this is part of my learning process, ultimately i would like to have the response be parsed and turned into
elements etc. but for now i am having trouble accessing the information within the response.
How can i alert() any of the results in the response?
the results of the script below ranged from undefined, to [object ojbect]
<script type="text/javascript">
var bbz;
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: "MyDomain - its defined and on the web",
success: function(response) {
bbz = response;
alert(bbz.length);
alert(bbz);
alert(bbz[0]);
}
});
</script>
It looks to me like you are expecting a JSON response...
I am assuming this because of the way you are accessing properties of the response object -
bbz = response;
alert(bbz.length);
You'll want to set your dataType to "json".
If you set the dataType property to html, you should be able to simply return HTML.
You set dataType: "jsonp" which attempts to parse a jsonp object out of the data that is to be returned. However, what you really want is the markup that is in the file you are requesting data from. In order to do this, you must state the correct return type, so that the AJAX knows what data to give you, i.e. you tell the AJAX how to parse the data.

Sending html to Javascript from PHP via JSON obejct

I'm sending some data from php through ajax to jquery.
If $content="ABC"; everything is OK. I get alert with ABC.
If $content="<div>ABC</div>"; then Houston has a problem. Nothing happens at all.
Here is PHP code
$json = json_encode(array("content" => $content));
echo $json;
And this is Jquery
$('#'+pic_type+'_form_n_'+pic_number).ajaxSubmit({
success: function(responseimage){
result = jQuery.parseJSON(responseimage);
alert(result.content);
Any ideas ?
UPDATE!
I've removed jQuery.parseJSON
so that line has only this code
result = responseimage;
And now I get the result in alert.
The result is the following
{"content":".<div>ABC<\/div>."}</div>
So we can see that JSON is not created well. I;ve tried utf8_encode and trim , but they do nothing to the result. result is strange.
PHP (and JSON) code seems fine, provided that the variable $content actually has any content. Else the PHP script will fail and there's your problem.
Did you define the dataType as "json" in the AJAX request?
$.ajax({
url: 'json.php',
dataType: 'json',
success:function(data){
console.log(data);
}
});
I think you just need to utf8_encode your response before doing json_encode.
Just change this :
$content = utf8_encode("<div>ABC</div>");
You are delivering invalid json somehow - please put your raw response in JSONLint, it will tell you what is wrong.

jQuery.ajax() v1.5 returns "parsererror" for json data

I have this function for getting a server id from a list. The function always returns "parsererror". I have looked at the JSON data returned but I cant seem to get it working, since jQuery have rewritten the ajax in v1.5.
function server_id()
{
$.ajax({
type: "GET",
url: "http://localhost/server_list.php",
dataType: "json",
success: function(data, status) {
alert(status + "\n\n" + data.server_id);
},
complete: function(data, status){
alert(status);
}
});
}
server_list.php
header('Content-type: application/json');
$output['server_id'] = '123';
print json_encode($output);
In firebug Net >> XHR it reads it as JSON as it brings up the tab and the Response tab shows what is below.
{"server_id":"123"}
I have also tried setting the content type header like below but having no luck.
Content-type: application/json
UPDATED
I only get "parsererror" if the validation plugin is loaded from http://bassistance.de/jquery-plugins/jquery-plugin-validation docs.jquery.com/Plugins/Validation v1.7.
If you add the plug jquery automatically adds the jsonp callback to the query string even when you set to false or dont include the parms for jsonp. Very Strange
Any ideas on how to fix?
Thanks
The simple solution here seems to be that jQuery 1.5 is not compatible with 1.7 of the validation plugin. Downgrading to jQuery 1.4.x (or otherwise patching or removing the validation plugin code as philhag suggested) solves the issue.
Huge thanks to those on this thread who identified the conflict. It saved me a bunch of headaches having to debug the jQuery code.
You seem to want regular json communication (dataType is "json" instead of "jsonp" and server_list.php sends json), but you're setting jsonp options. Remove the jsonp and jsonpcallback lines. Setting jsonp to false does not mean you disable it!
When these two lines are commented out, everything seems to work fine.
I suffered for days before finding this thread, thanks to those who pointed at jQuery.validate as the culprit.
In my testing it actually seems to be jquery.validate-vsdoc.js which is causing the issue, not the plugin itself, in case that's of any use to anyone else.

Categories