JSONP Ajax Error Jquery(Number String) Not Called - php

Since moving my site to https, the mailchimp api no longer works with the standard json ajax calls. These calls now render a same origin policy error. I don't know why this is the case though, because I'm calling a url on my own server. After some investigating, I've surmised that JSONP is my only option. The following script posts correctly to mailchimp but Im unable to get a successful response.
$.ajax({
type:"GET",
url:"https://mysite/book_subscription_process.php?jsonp=?",
data:{fname: $('#fNBookId').val(), lname: $('#lNBookId').val(), email: $('#eBookId').val()},//only input
dataType: "jsonp",
cache: false,
async: false,
jsonp: false,
success: function(data){
console.log('success');
if(data.message == 'failure')
{
alert('Error','There was an error processing your subscription. Please try again.');
}else if(data.message == 'success')
{
alert('success');
}else{
console.log(data.message);
}
},
error: function (xhr, ajaxOptions, thrownError, data) {
// console.log(data.message);
console.log('failure');
alert(xhr.status);
alert(thrownError);
}
});
Server side:
<?php
header("content-type: text/javascript");
if(isset($_GET['jsonp']))
{
$obj->fname = $_GET['fname'];
$obj->lname = $_GET['lname'];
$obj->email = $_GET['email'];
$obj->success = 'success';
$obj->failure = 'failure';
}
header("Content-type: application/json");
$MailChimp = new \Drewm\MailChimp($api_key);
$book = array('id' => $group_id, 'groups' => array('Book'));
$merge_vars = array('FNAME'=> $obj->fname,
'LNAME'=>$obj->lname,
'GROUPINGS'=>array($book)
);
$result = $MailChimp->call('lists/subscribe', array(
'id' => $list_id,
'email' => array('email'=>$obj->email),
'merge_vars' => $merge_vars,
'double_optin' => false,
'update_existing' => true,
'replace_interests' => false,
'send_welcome' => false,
));
if ( ! empty( $result['leid'] ) ) {
echo json_encode($obj->success);
}
else{
echo json_encode($obj->failure);
}
?>
As I said above the info is correctly posted to mailchimp. Each time however, the ajax call errors. I get a 200 OK but get a Jquery[bunch of numbers] not called. The json_encode success statement is executed on the server. Is there a special way that I'm supposed to handle the server side response? Or am I supposed to do something differently on the client side? Thanks in advance.

Same Origin means that the page making the request and the destination server need to have identical protocol, server, and port. For this particular situation, MailChimp isn't either of those -- the page making the request is your HTML page and the server is https://mysite/book_subscription_process.php.
Since you said this corresponds to your move to HTTPS, my guess is that you've moved one end but not the other. Since the code above looks like the front-end page is calling https://mysite, I'd triple check to make sure that the HTML and all scripts are also being served from https://mysite.
I don't think you should need JSONP in this scenario -- it sounds like you are attempting to work from the same origin, you just need to be sure you're doing that properly.

Related

Getting 409 error when calling php from my React application

I am trying to call a simple php file from my React application which will send an email with the details from a contact form. For some reason when the React code executes the fetch of the PHP file, it returns a 409. However, if I manually post the URL into another tab it works as expected, and subsequent calls from my React application then work as expected!
This is my React code:
var url = '/backend/sendmail.php?subject=New Website Enquiry&to=info#site.co.uk&msg=' + msg
console.log(url)
console.log('sending')
fetch(url,
{
'headers': {
'Accept': 'text/html',
'Content-Type': 'text/html'
},
'method': 'GET',
})
.then(
(result) => {
console.log(result.status)
if (result.status === 200) {
console.log('success')
this.togglePop();
this.setState({
name: "",
email: "",
phone: "",
message: "",
terms: false,
})
} else {
console.log('failed')
this.setState({ openError: true })
}
},
(error) => {
console.log('ERROR')
console.log(error)
this.setState({ openError: true })
}
)
And this is my PHP file:
<?php
//header("Access-Control-Allow-Origin: *");
header('Content-Type: text/html');
// error handler function
function customError($errno, $errstr) {
error_log($errstr);
http_response_code(500);
}
// set error handler
set_error_handler("customError");
http_response_code(200);
// send email
mail($_GET["to"],$_GET["subject"],$_GET["msg"],"From: donot.reply#site.co.uk","-f donot.reply#site.co.uk");
error_log($_GET["subject"].":\n".$_GET["msg"], 0);
echo 'OK';
?>
I have spent several days trying to figure out why this is happening. My htaccess file seems OK as once I have made one succesful call to the PHP file it works after that!
It's not a CORS issue as the file is on the same domain.
Anyone got any ideas?
You are sending the wrong request to the server, and that's why you get a 409 error. You should encode the URL params before sending a request
const url = '/backend/sendmail.php?subject=New Website Enquiry&to=info#site.co.uk&msg=' + msg;
const encoded = encodeURI(url);
console.log(encoded)
// expected correct URI: "/backend/sendmail.php?subject=New%20Website%20Enquiry&to=info#site.co.uk&msg="
You can read more about it here

Ajax Call Back and Laravel

I have created an API which my AJAX post send values to it. AJAX does post and my laravel API does process the values. My issues is with the callback returning the value back to my AJAX post. My AJAX doesn't return the results in the success section when I do console log. I would like the results from my api to can use data to make my condition. At the moment, the console log doesn't even return a value. But in my chrome inspector under preview it shows the response from my API but not in the success section.
AJAX
var fname = "Joe";
var lname = "Test";
var processUrl = "api.example.com/z1";
$.ajax({
type: 'POST',
url: processUrl,
data: {"name": fname,"surname": lname},
dataType: 'json',
success: function(res){
console.log(res);
if(res.length >= 1){
$('#display').val(res.name);
}
}
});
PHP
public function checkResults(Request $request){
$name = $request->name." ".$request->surname;
$result = array();
$result['name'] = [$name];
return response()->json($result,201);
}
For first it will be good to return with 200 OK response code (instead of 201).
Note: If you want to just immediately get the answer for your question only, you can see the last part of this answer (usage of "done/fail" construct instead of "success/error").
Additional:
There is many patterns which are used by Client(Frontend)<->API<->Server(Backend) developers.
Approximately all APIs built without any 500 server error codes. But there is exists also many differences between APIs structures.
One of them is to send response like this (this is the only one example of response):
return response()->json([
'success' => true, // true or false
'message' => "Message about success!",
], 200); // 200, 401, 403, 404, 409, etc
The other approach is to always sending 200 OK, but message can be also about error:
return response()->json([
'success' => false, // true or false
'code' => 404,
'message' => "Resource not found!",
], 200);
This kind of methods will written under try{}catch() and will return only 200, but that messages can imitated also as an error (as in example).
The other (appropriate approach for you) is to change your Frontend AJAX functionality like this:
$.ajax({
type: 'POST',
url: processUrl,
data: {
{{--_token: "{{ csrf_token() }}",--}}
name: fname,
surname: lname
},
dataType: 'json'
}).done(function(res) {
console.log(res);
if(res.length >= 1) {
$('#display').val(res.name);
}
}).fail(function(jqXHR, textStatus, errorThrown) {
console.log("Error: " + textStatus);
});
AJAX .done() function replaces method .success() which was deprecated in jQuery 1.8. This is an alternative construct for the success callback function (like before: "success: function(){...}").
AJAX .fail() function replaces method .error() which was deprecated in jQuery 1.8. This is an alternative construct for the complete callback function (like before: "error: function(){...}").
Note: .error() callback is called on HTTP errors, but also if JSON parsing on the response fails. This is what's probably happening if response code is 200/201 but you still are thrown to error callback.
I believe this is happening because you are sending status code 201 (Created), but you need to send status code 200 (OK) to trigger the success callback.
public function checkResults(Request $request){
$name = $request->name." ".$request->surname;
$result = array();
$result['name'] = [$name];
return response()->json($result,200);
}
I couldn't find it specifically in the jQuery docs, but this SO question addresses it.
Due to the asynchronous nature of Ajax calls, do not put them in the normal execution flow of your program. See this post to get more insight.
A quick fix for your problem is to include the ajax call in a function and call that function anytime you want to interact with the server asynchronously.
var fname = "Joe";
var lname = "Test";
var processUrl = "api.example.com/z1";
ajaxCall();
function ajaxCall() {
$.ajax({
type: 'POST',
url: processUrl,
data: {"name": fname,"surname": lname},
dataType: 'json',
success: function(res){
console.log(res);
if(res.length >= 1){
$('#display').val(res.name);
}
},
error: function() {
console.log('error');
}
});
}
In addition, include an error function in the ajax call settings to handle cases where the ajax request fails. See this answer for alternative styles of doing this.

json_encode returns 200 and undefined

I'd like to have a code to add or remove from database bookmarks.
The code is ready and it adds and removes from database bookmarks correctly, but when I call the function it keeps returning the json error instead json success even if the code works.
I'd like to know what's wrong with the code (that I got and adapt from somewhere else) because the client side is not receiving the correct values true or false, it only triggers the json beforeSending and json error.
server side:
if($isFavorite) {
// if it's favorite, remove from bookmarks
return json_encode(array("status" => true, "added" => false));
} else {
// if it's not favorite, include into bookmarks
return json_encode(array("status" => false, "added" => true));
}
client side:
<script>
function addItemToUsersList(userId, type, itemId) {
jQuery.ajax({
'url': 'xxx',
'type': 'GET',
'dataType': 'json',
'data': {userid: userId, type: type, itemid: itemId},
'success': function(data) {
console.log('json success');
},
'beforeSend': function() {
console.log('json beforeSending');
},
'error': function(data) {
console.log('json error');
console.log(data.status + ' ' + data.added);
}
});
}
</script>
The console.log(data.status + ' ' + data.added); line logs 200 undefined
How may I return the correct values true or false for both "status" and "added"?
Edit:
The json success is never logged on console, so I don't know what happened on server side. I need to know this because I need to change the class of an element to display an empty or yellow star.
If you are returning the result and not doing anything with that return elsewhere, you will not get any response to your ajax call, so it's undefined. As #MikeC says, you must echo it at some point.
If you are not already echoing it elsewhere, try:
$response = array(
'status' => $isFavourite,
'added' => !$isFavourite
);
echo json_encode($response);
My suggestion is also if 'status' and 'added' are really just the opposite of each other every time, then you probably only need to send 'status' on its own. In your JS you can just check 'status' and reverse the boolean as I've done above, if you want to know what the value of added would be.
var added = !data.status;
Update
If your ajax request is coming back to the error function, the request itself is probably failing.
Change your error function to this, to debug what has happened:
'error': function(jqXHR, status, error) {
console.log(status);
console.log(error);
}
You might have an error in server-side code somewhere or you're calling the wrong PHP script perhaps?

How to use ajax to execute php function that will push a file to the browser?

I'm trying to write a method in a php class that will use ajax to execute a php function that will push a file back to the browser.
It seems like its trying to write the file to the modx log, getting a lot of binary garbage in there.
Here is the method:
public function pushDocuments($formdata){
$data = $formdata['formdata'];
$file = MODX_PROTECTED_STORAGE . $data['target'];
$file_name = basename($file);
if (file_exists($file)) {
header("Content-Disposition: attachment; filename=\"$file_name\"");
header("Content-Length: " . filesize($file));
header("Content-Type: application/octet-stream;");
readfile($file);
};
$output = array(
'status' => 'success',
'error_messages' => array(),
'success_messages' => array(),
);
$output = $this->modx->toJSON($output);
return $output;
}
and here is the jquery:
$('.btn-get-document').click(function(){
var target = $(this).attr('data-target');
var postdata = {"snippet":"DataSync", "function":"pushDocuments", "target": target}; // data object ~ not json!!
console.log('target = ' + target + postdata );
$.ajax({
type: "POST",
url: "processors/processor.ajax.generic/",
dataType : "json",
cache : false,
data: postdata, // posting object, not json
success: function(data){
if(data.status == 'success'){
console.log("SUCCESS status posting data");
}else if(data.status == 'error'){
console.log("error status posting data");
}
},
error: function(data){
console.log("FATAL: error posting data");
}
});
});
it's running through the scripts and giving a success in the console [because I am forcing success] but no file is prompted for download and the binary garbage shows up in the modx log
What am I doing wrong?
In order to download a file, you'd have to use JS to redirect to the file's location. You can't pull the file contents through AJAX and direct the browser to save those contents as a file.
You would need to structurally change your setup. For instance, your PHP script can verify the existence of the file to be downloaded, then send a link to JS in order to download the file. Something like this:
if ( file_exists( $file )) {
$success_message = array(
'file_url' => 'http://example.com/file/to/download.zip'
);
}
$output = array(
'status' => 'success',
'error_messages' => array(),
'success_messages' => $success_message
);
Then modify the "success" portion of your AJAX return like this:
success: function( data ) {
if ( data.status == 'success' ) {
location.href = data.success_messages.file_url;
} else if ( data.status == 'error' ) {
console.log( 'error status posting data' );
}
},
Since you're directing to a file, the browser window won't actually go anywhere, so long as the file's content-disposition is set to attachment. Typically this would happen if you directed to any file the browser didn't internally handle (like a ZIP file). If you want control over this so that it downloads all files (including things the browser may handle with plugins), you can direct to another PHP script that would send the appropriate headers and then send the file (similar to the way you're sending the headers and using readfile() in your example).
#sean-kimball,
You might want to extend MODX's class based processor instead:
https://github.com/modxcms/revolution/blob/master/core/model/modx/processors/browser/file/download.class.php
It does the download from any media source and also access checking if you want.
Its implementation on manager side is:
https://github.com/modxcms/revolution/blob/master/manager/assets/modext/widgets/system/modx.tree.directory.js#L553
Back to your case, these examples might bring you some ideas.
JS Example:
$.ajax({
type: "POST",
// read my note down below about connector file
url: "assets/components/mypackage/connectors/web.php",
dataType : "json",
cache : false,
data: {
action: 'mypath/to/processor/classfile'
}
success: function(data){
},
error: function(data){
console.log("FATAL: error posting data");
}
});
Processor example:
<?php
require_once MODX_CORE_PATH . 'model/modx/processors/browser/file/download.class.php';
class myDownloadProcessor extends modBrowserFileDownloadProcessor {
// override things in here
}
return 'myDownloadProcessor';
For this, I also suggest you to use MODX's index.php main file as the AJAX's connector so the $modx object in processor inherits the access permission as well.
http://www.virtudraft.com/blog/ajaxs-connector-file-using-modxs-main-index.php.html

ajax always runs success even when error is returned

I have an AJAX script that should insert data into a mysql database when users are logged in. However it is currently running the success function, even when 'success' => 'false' is returned in the console.
Her is my code
$(document).ready(function() {
$("#addfav").click(function() {
var form_data = {heading: $("#vidheading").text(), embed : $("#vidembed").text()};
jQuery.ajax({
type:"POST",
url:"http://localhost/stumble/Site/add_to_fav",
dataType: "json",
data: form_data,
success: function (data){
alert("This Video Has Been Added To Your Favourites");
console.log(data.status);
},
error: function (data){
if(data.success == false){
alert("You Must Be Logged In to Do That");
console.log(data.status);
};
}
});
})
})
here is the php, bear in mind my project is in codeigniter.
public function add_to_fav(){
header('Content-Type: application/json');
$this->load->model('model_users');
$this->model_users->add_favs();
}
and this is the actual model for adding data to db
public function add_favs(){
if($this->session->userdata('username')){
$data = array(
'username' => $this->session->userdata('username'),
'title' => $this->input->post('heading'),
'embed' => $this->input->post('embed')
);
$query = $this->db->insert('fav_videos',$data);
echo json_encode(array('success'=>'true'));
} else {
echo json_encode(array('success'=>'false'));
}
}
Thank you for any suggestions!
You aren't returning an error.
You are returning a 200 OK with the data {"success": "false"}.
You can either handle that in your jQuery success function or send a different status code (it looks like a 403 error would fit here).
You have to remember error that occurs for asynchronous requests and errors that occur for PHP backend are different. Your error occurs at PHP-level, and PHP returns valid HTML as far as the javascript frontend is concerned. You need to check if the "success" variable in the returned JSON is true.

Categories