Use FormData after passing it to a new function - javascript

I'm not sure if this question is worth asking but I can't seem to find a workaround so here I am.
I have a Flask app in which I submit a form that uploads an image to the server. I send the image using FormData that is created this way:
$( "#myform" ).submit(function(event) {
event.preventDefault();
var $form = $(this),
formObject = $('form')[0],
formData = new FormData(formObject);
// other stuff
The FormData is then sent via an AJAX POST request to the sever. This operation works perfectly when the POST request is inside the submit function.
The problem is that in an other view, I need to use the same code but I moved the AJAX POST requests out of the submit function. So when I pass either my formObject or formData to the function that contains the AJAX requests, let's call it fctA, they are undefined.
I think I see the problem, since the submit function has a "particular status" (as you can use $(this) to get the form) but I can't find a way to pass the formData to an other function. I don't want to get rid of fctA since it saves me from duplicating a lot of code (because of client-side verifications)
Is there a way to pass FormData through different function calls?
Thanks in advance.
//Edit: Here's the code where I want to pass the FormData
//(I'm having trouble indenting it here)
$.ajax({
url: "url",
type: "GET",
dataType: "json",
success: function(data) {
//Create a JSON object to send other form inputs
/*
fctA is used to avoid duplicating AJAX POST requests since I
need to send the data only when meeting some expectations and
I must display error messages otherwise.
*/
fctA(json, formObject)
/*
The image is correctly sent if I have a POST request that
uses formData right here instead of passing it to fctA.
As soon as the POST request leaves the submit function to go to fctA though,
formData is undefined when I execute the code.
I tried passing formObject or formData, they are both undefined.
*/
},
error: function() {
//Display an error message
}
});

I am not sure why exactly it does not work, but it is probably caused by your variable scopes. formObject and formData are global variables because you don't declare them with var. fctA is called by the ajax-success-handler in case of a successful ajax-request. formObject is passed to fctA. Where does formObject come from? One might expect that it is available in the global scope. This seems not to be true for some reason.
I recommend to declare variables locally using var and I guess most people will agree. Global variables allow influences between arbitrary pieces of code that are hard to overlook, hard to govern and in effect hard to maintain. Global variables also increase the risk of accidently giving two variables the same name that are meant be distinct variables.
If you declare your variables locally then you can wrap your call to $.ajax in a function with formObject as parameter and call this function in the submit-handler. formObject will also be available in the ajax-success-handler because Javascript supports closures. So, if you use variable scopes the recommended way there is a good chance that you won't have the problem any more.

Alright I found the solution, the problem was that I passed my formData to a function which had a keyword argument as last parameter so the formData was the value of the keyword argument (since the default value was used in that call) and of course, the argument where I expected my formData to be was undefined.
Should I delete the whole question since it's almost no more than a typo problem? The warning that tells you your account may be blocked if you delete too many questions kinds of puts me off.

Related

how can protect javascript functions from console?

I have a function called 'delete' like this :
<div onclick="delete($post_id, $_SESSION['id']">somelink</div>
function delete(post_id, session_id) {
var p_id = post_id;
var s_id = session_d;
$.ajax({
url:"delete.php",
type:"POST",
data: {
p_id: p_id,
s_id: s_id
},
});
})
delete.php is a page to delete the post = p_id which was added from user id = s_id.
My problem is any user can delete any post for only the console when typing in it the function 'delete();' with parameters it called and delete posts!
Any ideas, please.
You can not. Nor should you.
You should always assume that data from the client side is corrupted and should be treated accordingly. That includes form data, or in this case, a AJAX request.
This means that you have to apply validation at the server side, let PHP do it for you. E.g.: Limit the number of posts you can delete per X time. And double check that the post actually belongs to the person who is deleting it.
The reason you can't do this, is because you create javascript which is clientside. If you create a function to prevent changing the code, the client can alter the code on their machine to ignore that. You could make a function to check of the function to check is changed, but again; client can change it.
Unfortunately you can't. What you need to make sure though is making the function safe on the server which, in simple terms, boils down to
Validating every request and input parameters on the server so that people won't be able to manipulate or change server side data from client side.
make sure all data that you send to the client is originated from server as well.
one of the ways to prevent calling a function from client side is NOT to expose your methods in the global scope. and remember if your code is very critical and important, always move it to server-side. it is not a good practice to cover application design issues with programming workarounds. calling functions from client side shouldn't be an issue if the program is designed right.
First of all, this is bad. You should have authentication.
However, you can do that:
(function() {
$('#BUTTON_ID').on('click', function(post_id, session_id) {
var p_id = post_id;
var s_id = session_d;
$.ajax({
url:"delete.php",
type:"POST",
data: {
p_id: p_id,
s_id: s_id
},
});
})
})();
And add "BUTTON_ID" as id for your button.
Not that even that way, it is still not secure.
With this way, you can't call delete from the console. But someone can look into the source code and copy your ajax call and paste it into his console and it will works. It is not a good way to prevent people deleting your posts.
You should read about web application security. You should have an authentication process with tokens that expires after x time. Tokens will authenticate the user and from here, you can check if the user have the right to delete post. If the user do not have the right, you don't show the button. Then if the user call it from it console, he will get an error from the backend server.

Passing multiple arguments through HTTP GET

I have an HTML file referencing a PHP script to perform various functions. One of the ways the HTML file calls the PHP script is through an HTTP GET. The GET request should pass three parameters and return a list of all saved events as a JSON-encoded response.
So far, I have the following but I'm not sure how to pass the three arguments through the HTTP GET. Also, I'm not sure if I am returning the JSON-encoded response correctly:
if($_SERVER['REQUEST_METHOD'] == 'GET'){
echo json_encode(events.json); }
GET requests are done through the URL... So if you want to pass three GET requests you would do...
http://www.domain.com/target.php?param1=whatever&param2=whatever&param3=whatever
target.php represents the PHP script file you want to send the information to. You can have as many variables as you want but just keep in mind that every other GET request has to be separated by an & symbol. The first param simply has to be started off with a ? symbol.
If you want to use Javascript, I would recommend using JQuery. You can do something like this
$.get('target.php?param1='+whatever+'&param2='+whatever2, function(data) {
alert(data);
});
Or you can use window.location to send a link with the appropriate link above.
If you want to use AJAX specifically, here is a way of doing it with JQuery (there are ways with Javascript that I could update later if necessary:
$.ajax({
type: "GET",
url: "http://www.domain.com/target.php",
data: { param1 : "whatever", param2 : "whatever", param3 : "whatever" },
success: function(result){
//do something with result
}
})
If you want to access the variables, you can call $_GET['param1'] or $_REQUEST['param1'] to get access to them in PHP. Simply change the name in the brackets to the desired variable you want and store it in a variable.
If you want to access the params with Javascript... well the most efficient way is to go and decode the URL that was used and pull them out. See here
Hope this helps!
You can access the parameters from the URL via the $_GET superglobal in PHP.
For example, if your URL is http://example.com/test.php?param1=foo&param2=bar, then you could access them in PHP like so:
$param1 = $_GET['param1'];
$param2 = $_GET['param2'];
See http://www.php.net/manual/en/reserved.variables.get.php for more details.
As for returning a valid JSON response, you can check out this answer. It uses PHP's header function.

Prototype AJAX Post Parameters missing randomly

Alright, so i have a .NET application that uses the Prototype library to make AJAX calls to webmethods in the page-behind to retrieve data. This application has been up and running for quite awhile with no issues. Recently a new user began using the application and experiencing some weird issues.
Basically, what happens is he can use the application fine for awhile and then it just starts throwing errors on AJAX calls stating parameters are missing to the webmethod. Here is the error:
System.InvalidOperationException - Unable to perform the requested action: Invalid web service call, missing value for parameter: 'fleet'.
at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary'2 parameters)
at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary'2 parameters)
AT SYSTEM.WEB.SCRIPT.SERVICES.RESTHANDLER.INVOKEMETHOD(HTTPCONTEXT CONTEXT, WEBSERVICEMETHODDATA METHODDATA, IDICTIONARY`2 RAWPARAMS)
at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)
It isn't just one call that messes up but any ajax call randomnly and it always seems to be the first parameter in the webmethod that is called "missing." leading me to believe the post data isn't gettin back somehow? (related?: JQuery Ajax post parameters sometimes not sent on IE).
I have never been able to recreate this issue, nor has any other user experienced it. This leads me to believe it is something specific on this users system that is causing the issue. Unfortunately they are a rather important user so i need to attempt to solve this problem. The user has IE8 as their browser. Here is the code that makes the ajax call using prototype:
function gAjax(url, params, onSuccess, onError, onException, onComplete) {
new Ajax.Request(url,
{
method:'post', //Post
contentType:"application/json; charset=utf-8", //As JSON
postBody:Object.toJSON(params), //Post Body is JSON string
sanitizeJSON:true, //Sanitize the JSON
onComplete:onComplete, //Set user on complete
onSuccess:onSuccess, //Set user on success
onFailure:onError, //Set user on error
onException:onException //Set user on exception
});
}
onComplete, onSuccess, onError, onException are function callbacks. params is an object like the following:
{'fleet':'fleetVal','bin':1234}
Url is the method, such as Bin.aspx/LoadBinInfo. This method is defined in the backend as follows:
<System.Web.Services.WebMethod()> _
Public Shared Function LoadBinInfo(ByVal fleet As String, ByVal bin As Integer) As Dictionary(Of String, Object)
'.....
'Returns a dictionary of info
End Function
If anyone has any ideas as to what is happening i would greatly appreciate any input! I can't seem to find any information in my research to lead me to the possible cause. Again it seems to only happen to this one user, so maybe its a browser setting on his end (any ideas what setting?). But then again its sporadic for him even, but once it starts happening it happens constantly until he closes out the browser and starts over.
I'm answering here because it seems I don't have enough reputation as to comment rather than answering.
It's not very clear what is missing from the request, but I'd go on checking the web logs (or setting some sort of logging) to see what the system is actually receiving. According to your description of the problem, the request is somehow missing the 'fleet' parameter. But you are not sending such value isolated in the request, you're sending all data in the post body as a serialized JSON string.
So, either the data passed to gAjax is not correct/complete, or something strange is happening on your server.
I obviously suspect that it's the former, but anyway you should try to log and debug on both ends.
For a start, I'd do something like this:
function gAjax(url, params, onSuccess, onError, onException, onComplete) {
params['debug']=Object.toJSON(params);
new Ajax.Request(url,
//....
That will add the JSON string to the request so you can check exactly what is being sent.
Hope this helps!

Synchronous jQuery calls, without putting everything in the callback

Is it possible to get a JSON in jQuery synchronously without using the async: false option (which apparently has been deprecated)? I also would prefer not to put everything into the success function.
No, there is no other option than async: false. I wouldn't recommend it if there were.
For the success function, you can simply pass another function that will be executed.
For example:
$.ajax( {
url: myUrl,
type: 'POST',
success: myFunc
} );
function myFunc( datas ) {
// do what you should do in a success function
}
Since ajax methods on jQuery return a Deferred Object (jQuery 1.5+) you could also write
$.ajax({
url: myUrl,
type: 'POST'
}).done(function() {
// do what you should do in a success function
});
Not reasonably. Trying to force the request to be Synchronous without using asyc:false is possible, but a waste of effort in my opinion. In pretty much every scenario you want to use async:true, you will be able to accomplish all of the same things with async:true as you can with async:false. It's just a matter of how you structure your code.
If you look at the current version of the source file that executes the AJAX request:
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js
You will see it still uses the async field on the settings object, this field is passed directly into the Open method of the XMLHttpRequest object. So using the default implementation all you can do, is set "async: false".
if ( s.username ) {
xhr.open( s.type, s.url, s.async, s.username, s.password );
} else {
xhr.open( s.type, s.url, s.async );
}
Now assuming you are really stubborn and want to do this without setting "async:false", you could get really bold and write a custom ajaxTransport and register it with a custom data type.
Here is an example I wrote that creates a custom transport object with a send and abort method, and registers it with the dataType 'mine'. So when you specify dataType 'mine' in your ajaxSettings object it will use this custom transport instead of the one built into jQuery. http://jsfiddle.net/xrzc7/ Notice there are two ajax requests one with the 'mine' dataType that show the alert, and one without the data type that does not show the alert. My ajaxTransport in this example isn't fully functional, its just to illustrate that you can swap in your own send function.
I wouldn't advise writing your own ajaxTransport for jQuery because it really isn't neccessary in my opinion, but to answer your question I'm suggesting it as an option.
You should pay close attention to how the default ajaxTransport in jquery is written, and how it interacts with the settings object and callback methods when writing your custom ajaxTransport. Your send function would obviously force a "false" value as the async parameter of the XMLHttpRequest.open method.
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js - this is the current source code for the default ajaxTransport mechanism.
Hope this helps, or perhaps persuades you to always use async:true. :-D

Should be really simple Jquery jsonp

Why does this not work? anybody:
In my code I have:
$.getJSON("http://isp123.co.uk/cw/NorthWales/Test.txt?jsoncallback=?",
function(data){
//This never gets executed
alert('here');
});
The text file can be viewed here:
http://isp123.co.uk/cw/NorthWales/Test.txt
This is not a JSONP response:
({"name" : "hello world"});
If you had a proper JSONP response, then your code should work.
The question mark in the "callback=?" part of the URL is changed by jQuery before making the request, your JSONP server needs to be able to dynamically create the JSONP "function" in response to the unique jQuery request. If you can't dynamically create your JSONP, perhaps you could use YQL/Yahoo pipes to turn it into JSONP?
This pipe should do the trick, to see if it works, use this URL instead in your getJSON function: http://pipes.yahoo.com/pipes/pipe.run?u=http%3A%2F%2Fisp123.co.uk%2Fcw%2FNorthWales%2FTest.txt&_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&_callback=?
I just tried this and it worked:
$.getJSON("http://pipes.yahoo.com/pipes/pipe.run?u=http%3A%2F%2Fisp123.co.uk%2Fcw%2FNorthWales%2FTest.txt&_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&_callback=?", function(data){
//This always gets executed!!!
alert('here');
});
I don't know if you know enough about JSONP but this is not JSONP
?({"name" : "hello world"});
It really should be something like this http://isp123.co.uk/cw/NorthWales/Test.txt?jsoncallback=foo
foo({"name" : "hello world"});
From the jQuery.getJson manual page:
Important: As of jQuery 1.4, if the JSON file contains a syntax error, the request will usually fail silently. Avoid frequent hand-editing of JSON data for this reason. JSON is a data-interchange format with syntax rules that are stricter than those of JavaScript's object literal notation. For example, all strings represented in JSON, whether they are properties or values, must be enclosed in double-quotes. For details on the JSON format, see http://json.org/.
Your JSON is invalid according to http://jsonlint.com/
Here Clearly mentioned
As of jQuery 1.5, setting the jsonp
option to false prevents jQuery from
adding the "?callback" string to the
URL or attempting to use "=?" for
transformation. In this case, you
should also explicitly set the
jsonpCallback setting
and read jsonpCallback section
jsonpCallback,
Specify the callback function name for
a JSONP request. This value will be
used instead of the random name
automatically generated by jQuery. It
is preferable to let jQuery generate a
unique name as it'll make it easier to
manage the requests and provide
callbacks and error handling. You may
want to specify the callback when you
want to enable better browser caching
of GET requests. As of jQuery 1.5, you
can also use a function for this
setting, in which case the value of
jsonpCallback is set to the return
value of that function
Probably worth using jQuery.ajax() - http://api.jquery.com/jQuery.ajax/
You can pass in the dataType as "jsonp" and then jQuery takes care of all the callback business, but more importantly you can specify a function to run when there's an error, which may help you:
$.ajax({
dataType: "jsonp",
success: function(d) {console.log(d);},
error: function() { console.log("error") } //do your debugging in here
//add other parameters such as URL, etc
});
The error function you define can be passed 3 variables, read up on it on the ajax() page on the jQuery docs (linked at the beginning of my post) to find out more about that and how to use them.
Your problem lies with how your server is outputting the information. In the link you've supplied, the assumption is that any name placed in the ?jsonpcallback should result in wrapping the JSONP code in a function with that same name. It, however, is not the case.
So the next option is this: use a static function name in your server file and wrap the code. (e.g. use foo(<jsonp>) and stick with it) Then, you have to explicitly tell jQuery that we are going to use a specific function name (leave jQuery with the assumption it's supplying (and thus receiving) that name back, when in-fact you're just supplying it server side and filling in the blanks).
Once you have your file setup, use something like the following:
$.ajax({
// setup the request
url: 'http://isp123.co.uk/cw/NorthWales/Test.txt',
crossDomain: true,
dataType: 'jsonp',
jsonp: false,
jsonpCallback: 'foo', // "supply" the jsonp function (pseudo-defined)
// function to call when completed
complete: function(data){
alert(data);
}
// just in case, catch the error
error: function(j,t,e){
alert('AJAX Error');
}
});
So now when jQuery makes the call and it thinks it's supplying the callback, it's really just getting the server-defined callback in return. So, for the above to work, your text file should look something like this:
foo({name:"Hello, World!"});
Also, if you can, change your header to application/javascript, though this is some-what optional.

Categories

Resources