I have some PHP 5 code that is similar to this:
$result = myFunction(...); // return false, or doit action
$reply = array();
if ($result) {
$reply['doit'] = $result;
$reply['status'] = "a status html string";
} else {
$reply['content'] = "Some html text";
$reply['menu'] = "Some other html text";
$reply['status'] = "a different status html string";
}
return $reply;
The caller includes the fragment
$reply = somefunction();
echo json_encode($reply);
This reply is then sent to the client, where jquery passes it to my function
function handleReply(reply) {
if (reply.doit) {
handle action
}
if (reply.content) document.getElementById('content').innerHTML=reply.content;
if (reply.menu) document.getElementById('menu').innerHTML=reply.menu;
if (reply.status) document.getElementById('status').innerHTML=reply.status;
}
What I have been struggling with is that, when the doit branch of the if statement is executed, ($result is a string) the reply given to me by jquery is a string. When the content/menu/status side is taken ($result is false) then reply is an object.
I have added a second second index to the array and the result is the same. Although all strings are ASCII I have tried passing them through UTF8_encode. I have changed the name of the 'doit' index from 'action' in case that was triggering some behaviour in jquery.
Just to be clear, the reply, when it is wrong is (for example).
"{"doit":"obj=session&act=show&ID=3","status":"<p>Nic: Ian<br\/>Reseller: Coachmaster.co.uk<br\/>Status: SysAdmin <\/p>"}"
Which is a string. I expected:
{"doit":"obj=session&act=show&ID=3","status":"<p>Nic: Ian<br\/>Reseller: Coachmaster.co.uk<br\/>Status: SysAdmin <\/p>"}
Which is an object/array. This is also what my logging showed as being echoed.
I'm using php5.4.3 under windows 7 and Apache and php 5.3.10 under linux and nginx with the same results. jquery is version v1.7.2 in both. Also loaded is jQuery UI - v1.10.3 - 2013-07-02.
If it is a bug in jquery, its a very strange one. How can I prove it?
I think you rely on jQuery autodetection. Try:
header('Content-Type: application/json');
Once you get the string into JavaScript, you'd have to eval() it to turn it into a JSON object:
var reply_json = eval( reply );
Then you can access reply_json.content, reply_json.menu, and so on.
Obviously be careful about what it is you're eval'ing, make sure it's from a trusted source and so forth.
Maybe you can try:
jQuery.parseJSON()
Do you use $.getJSON() jquery method or $.ajax()?
When using $.ajax() method, if you don't specify dataType: "json" option when you are making ajax request, jQuery will use "intelligent guess" (by searching for response MIME type) to figure how to interpret server response (xml, html, plain, json object...). If it is unable to figure that automatically it will assume response is plain text and regular string will be returned in success handle.
You should use either $.getJSON() or specify dataType: "json":
$.ajax({
url: "....",
dataType: "json",
success: function(reply) { // success handle
// if not specifying dataType: "json",
// and if not using response headers to specify MIME type "application/json",
// reply will not be object but a string!
}
});
or, as Marek posted in his answer, specify MIME type in response headers.
Related
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.
How would I go around the cross-domain issue when parsing XML from a different server/domain? Could someone provide me with an example? The example doesn't have to be restricted to jQuery only, as JavaScript will also suffice.
To fully understand why pure cross-domain XML will not work, it helps to first look at how cross domain JSON is facilitated.
First, let's look at what happens when you make an AJAX request in jQuery:
$.ajax({
url: '/user.php?userId=123',
success: function(data) {
alert(data); // alerts the response
});
In the above example, the AJAX request is made relative to the domain. We know that if we attempt to add a different domain before the path, the request will fail with a security exception.
However, that's not to say that the browser cannot make requests to another domain. Here is an example that may be familiar to you:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
Based on our knowledge of how to import JavaScript on the page, we see that it is possible to load a resource that exists on another domain!
JSONP is a concept that exploits this knowledge. JSONP stands for "JSON with padding", and it's success hinges on the fact that JavaScript Objects can be expressed using a string notation, and the fact that JavaScript script tags can load and run content from external domains.
Under the hood, jQuery's JSONP looks something like this although it may not be exact:
// programmatically load a script tag on the page using the given url
function loadRemoteData(url) {
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.setAttribute("src", url);
document.getElementsByTagName("head")[0].appendChild(script);
}
Also, on the page somewhere, we define a callback handler:
function processData(jsonResult) {
alert(JSON.stringify(jsonResult)); //alert the JSON as a string
}
Here, we make the request:
// make a request for the data using the script tag remoting approach.
loadRemoteData("http://example.com/users.php?userId=123&callback=processData");
For this to work properly, our PHP script must both return the data in JSON format, and it must also add "padding" around the string in the form of a JavaScript function name that we may pass in as a parameter (i.e. "callback")
Thus, the response from the server may look something like this, if we were to look at it in the Firebug or Chrome NET tab:
processData( { "userId" : "123" , "name" : "James" , "email" : "example#example.com" } );
Because we know JavaScript content runs as soon as it's downloaded, our processData function we defined earlier is immediately called and is passed our JSON string as a parameter. It is then alerted, using JSON.stringify to convert the object back into a string.
Since it's an object, I could also access it's properties, like so:
function processData(jsonResult) {
alert(JSON.stringify(jsonResult)); //alert the JSON as a string
// alert the name and email
alert("User name is " + jsonResult.name + " and email is " + jsonResult.email);
}
Finally, let's move onto the main question: Can JSONP be used to fetch XML, or can we parse XML cross-domain? The answer, as others have pointed out, is a resounding NO, but let's look at why by using an example:
processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example#example.com</email></user>);
Now, what will happen if raw XML is passed into the function? It will break, as JavaScript has no way to convert XML into JSON.
However, suppose we put the XML in quotes:
processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example#example.com</email></user>");
Now, in this example, the jsonResult variable actually takes a string, which we can work with. Using some JavaScript XML parsing utilities, we could load that string into the XML DOM Parser and do stuff with it!
However, it's not pure XML, it's still a JavaScript response under the hood. The response type from the PHP server is still text/javascript, and we're still using a script tag to load what is really just plain JavaScript.
In summary, you could work with "XMLP" or XML with padding (I just made that up, it's not real!), but if you're going to go through all of the trouble of actually modifying your response to return a function callback wrapper, you may as well just convert your output to JSON and let the browser handle conversions automatically and natively and save yourself the trouble of having to use an XML parser.
But if for some reason it's easier to keep your data in XML format, you could modify the response and give it a JavaScript wrapper.
Cases where I could see this being useful might be if you have XML data from a legacy application stored in a database, and you return it to the client-side using script-tag remoting or JSONP calls.
I found a very good solution to retrieve xml from cross domain ajax request.
Since jQuery 1.5 you can use dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/) !
So i used this :
$.ajax({
type: "GET",
url: "http://yoururl",
dataType: "jsonp xml",
success: function(xmlResponse) { // process data }
});
Server side for my Webservices i used to encapsulate the xml string result within the callback created by jQuery:
private static Stream GetXmlPStream(string result, string callback)
{
if (result == null)
result = string.Empty;
result = EncodeJsString(result);
if (!String.IsNullOrEmpty(callback))
result = callback + "(" + result + ");";
byte[] resultBytes = Encoding.UTF8.GetBytes(result);
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(resultBytes);
}
and the magic method (i found it in another Stack thread) that you'll need to sanitize your xml string (so javascript can parse it) :
private static string EncodeJsString(string s)
{
StringBuilder sb = new StringBuilder();
sb.Append("\"");
foreach (char c in s)
{
switch (c)
{
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
default:
int i = (int)c;
if (i < 32 || i > 127)
{
sb.AppendFormat("\\u{0:X04}", i);
}
else
{
sb.Append(c);
}
break;
}
}
sb.Append("\"");
return sb.ToString();
}
Hope this will help !
I realize this is an old question, but I found this while searching. And also, I think the answer is for a slightly different question than the one posted here, so I want to add this answer which should work in at least jQuery 1.12 and later. I haven't tested in earlier versions.
OK, I want to request this URL: http://sample.domain/feeds/itemdata.xml
And I want to find the Item in that looks like this:
<Item>
<ProductItemNo>1228101530</ProductItemNo>
...
</Item>
This works, cross-domain:
$.ajax({
dataType: "xml",
url: "http://sample.domain/feeds/itemdata.xml",
success: function(xml) {
var itemdata = $(xml).find("ProductItemNo:contains('1228101530')").parent();
}
});
Here is my JS:
<script>
dojo.require("dijit.form.Button");
function sendText(){
var button = dijit.byId("submitButton2");
dojo.connect(button, "onClick", function(event){
// The parameters to pass to xhrPost, the message, and the url to send it to
// Also, how to handle the return and callbacks.
var xhrArgs = {
//type: "POST",
url: "http://testjson.php",
content: dojo.toJson({key1:"value1",key2:"value2"},true),
handleAs: "text",
load: function(newContent){
dojo.byId("response2").innerHTML = newContent;
},
error: function(error){
// We'll 404 in the demo, but that's okay. We don't have a 'postIt' service on the
// docs server.
dojo.byId("response2").innerHTML = "Message posted.";
}
}
dojo.byId("response2").innerHTML = "Message being sent..."
// Call the asynchronous xhrPost
var deferred = dojo.xhrPost(xhrArgs);
});
}
dojo.ready(sendText);
</script>
Here is my PHP:
<?php
foreach($_POST as $key => $val) echo '$_POST["'.$key.'"]='.$val.'<br />';
?>
The problem is that nothing is being returned.
If I put content instead of postData I have $_POST[0]='{', $_POST[1]='k' etc character by character, limited to 1000. This is a big problem.
Please can somebody tell me what I'm doing wrong? I got this code right from the dojo website, so it should be alright.
The php $_POST array only shows form encoded data. In your example you are POSTing json, so it won't directly show up in $_POST.
You have a couple options here. You could continue to post the data as json and read the POSTed json directly from the php input stream: $data = json_decode(file_get_contents('php://input'));. This is probably the easiest, and it replaces accessing the $_POST array for the data.
Other options include not POSTing json (just send form encoded data) and POSTing json as form encoded data:
In that case, your content would become something like
content: 'my_post_data='+dojo.toJson({key1:"value1",key2:"value2"}, true), (you may need to change handleAs fyi)
Then on the server side you would likely see something like
$_POST['my_post_data']= '{"key1":"value1","key2":"value2"}' which could be processed by json_decode()
I believe your content is being sent character by character because you are converting your content object into JSON. According to the dojo.xhrPost documentation, the content property is expected to be a JavaScript Object. I hope this helps solve your problem.
It should be noted that this module is deprecated in favor of dojo/request/xhr, so it is better to use that unless you have lower version requirements.
I'm running into some problems with user-entered input that I want to send to PHP as JSON via AJAX that contains special characters, like ", ', etc. I'm sending the contents of an array (used for slickgrid), and everything works fine unless those characters are included. I know that PHP has the handy function mysql_real_escape_string, but is there any sort of jquery analogue? Here is the relevant code:
req = $.ajax({
url: url,
dataType: "text",
data: {"data": $.JSON.encode(data)},
type: "post",
success: onSaveSuccess,
error: onSaveError
});
Here's the PHP it is submitted to:
<?php
//$data = array();
//if (isset($_POST['data']))
//{
//$data = json_decode($_POST['data']);
//}
//header('Content-Type: text/javascript');
//echo json_encode($data);
print_r($_POST);
?>
To be clearer, when special characters are included, neither the success nor error events are triggered.
I looked in firebug and it doesn't appear to send anything at all when the special characters are included... Of course, it does when it's just letters or something.
It was due to the script from here apparently failing on certain kinds of input. Switching to json2.js and using JSON.stringify has solved the problem.
data: {"data": $.JSON.encode(data)},
Passes up a more complex JSON object than you need.
$data = json_decode($_POST['data']);
Is looking for a serialized JSON object but jQuery is doing a lot of work for you in the background.
Try this
data: $.JSON.encode(data),
In your AJAX call. Then in PHP
$data['myPostValue'] = $_POST['myPostValue'];
You're sending a JSON object to the $.ajax call, and it is changing it into the name value pair that the server would normally get from a post.
javascript has an escape() function. you can $.JSON.encode(escape(data)) might work
My jQuery/AJAX script posts to a php file in hopes of returning XML. When I print if the data I get all the html source code returned and the xml is not properly parsed in IE 8 or less. The code works in IE 9 and all other browsers. If anyone has a suggesion to what is goin on or a solution to my problem?
jQuery:
$.post("load-content/", {type: "POST", img: placeholder, dataType: "XML", selection: $(this).html()}, function(xml) {
// format and output result
// alert(placeholder+' && '+$(this).html());
nshow = $("content", xml).text() ;
$("div p.p2").html(
$("content", xml).text()
);
alert("HERE IE 9+ "+xml.length);
});
php:
if(isset($_REQUEST["img"]) && isset($_REQUEST["selection"])) {
$xml='<ratings><content>test</content></ratings>';
echo $xml;
*FYI this code is being run in Zencart folder
Solved.
There were two problems here.
As the above answer suggested there was a problem with headers.
Again as the answer above suggested there was a problem with the datatype... code for older IE browsers should look something like
$.post("/load-content/", {type: "POST", img: showcase, menuv: aname}, function(response) { ...
Actually i think your problem is making the ajax call itself. You are using $.post but youre supplying the options hash as if it is $.ajax. The two are different...
$.post takes the url, data, callback and response type as the arguments. You are supplying a hash similar to the one you would supply to $.ajax as your second argument which is not what it wants.
If you are going to use $.post it shoudl look like this:
$.post("load-content/", {img: placeholder, selction: whatever}, function(), 'xml');
Additionally its not obivous what the contex of your call is... this may not exist unless this is inside an event handler or jQuery.each iteration so using selection: $(this).html() may not make sense.
Have you tried setting the proper header for your response and exiting immeadiately?
if(isset($_REQUEST["img"]) && isset($_REQUEST["selection"])) {
header('Content-type: application/xml');
$xml='<ratings><content>test</content></ratings>';
echo $xml;
exit(0);
}