CSRF protection always failing when trying to upload file with ajax - javascript

Few days before i learned that we can make file uploads with ajax. So i tried to build an app that uploads selected file when other parts of form being filled by user.
my app has two models:
class Post(models.Model):
image = models.ImageField(...)
title = ...
desc = ...
class TempImg(models.Model):
image = models.ImageField(...)
posted_by = ...
posted_at = ...
That form used to make a post, here you can see temp_image as hidden input:
class PostForm(forms.ModelForm):
temp_image = forms.IntegerField(widget=forms.HiddenInput)
class Meta:
model = Post
When user selects image, this javascript code uploads it and puts returning id value to temp_image field of form:
// here is a function that gets csrftoken, [which is taken from docs
// https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
csrftoken = ...
form = new FormData();
form.append("image", dataURLToBlob(resizedImgData));
form.append("csrftoken", csrftoken)
$.ajax({
url: '/upload/',
data: form,
processData: false,
contentType: false,
dataType: 'json',
type: 'POST',
beforeSend: function() {
$("#uploadingIndicator").show()
},
success: function(data){
$("#id_temp_image").val(data['id'])
$("#uploadingIndicator").hide();
}
});
Everything seems OK to me but, there is a problem that my view always return 403. CSRF verification error.
Can anybody have an idea where should i look at? I am going to use csrf_exemt if i can not find solution...

You should use
form.append("csrfmiddlewaretoken", csrftoken)
While you were trying to do form.append("csrftoken", csrftoken)

Related

Sending Parameter with Dropzone 'ProcessQueue' event

Heres my issue.
I'm currently building an application in Laravel and using DropZone for a user upload image. Now on a 'new user' page, I have both the user details and a dropzone dropbox, and these are both being processed separately.
I'm going to run the 'create user' method first, then if that goes ok, upload the images.
The issue comes with Dropzone not knowing the new user Id when its ready to upload (as it needs to assign to the correct user in the DB).
I somehow need to be able to pass the new user Id back to the dropzone 'processQueue' method, to use the new user id in the image upload, does anyone know if this is possible?
In a perfect world I would be able to pass the new id into the 'processQueue' function like processQueue(newUserId) and fetch it and add it into the form data to send with the image.
Here is my code so far
HTML
<div id="user_profile" class="dropzone dropzone-box">
<div class="dz-message needsclick">
<h3>Select Image</h3>
<hr>
<p>Click here or drag and drop image</p>
</div>
</div>
JS
//Bind dropzone to user profile image
var userProfile = new Dropzone('#user_profile',{
url: '/ajax/userProfileUpload',
autoProcessQueue:false,
maxFiles:1,
addRemoveLinks:true,
paramName: 'profile_pic', // The name that will be used to transfer the file
init: function(){
this.on("maxfilesexceeded", function(file) {
userProfile.removeFile(file);
});
this.on("success", function(file, returnedData, myEvent) {
console.log(returnedData);
});
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
});
Send new user request, when done, send images
$.ajax({
type: "POST",
url: '/users',
data: postData,
success: function(data){
userProfile.processQueue(/* pass user id from here */);
},
error: function(data){
//Didnt work
}
});
An option can be to add a custom attribute to the Dropzone object that holds the id, set this attribute when the ajax call succeeds and then access it on the sending event, the relevant part would be:
var userProfile = new Dropzone('#user_profile',{
...
userId: '', // Attribute to hold the user id
init: function(){
let thisDropzone = this; // Closure
...
this.on('sending', function(file, xhr, formData){
formData.append('userId', thisDropzone.userId);
});
}
});
ajax request:
$.ajax({
type: "POST",
url: '/users',
data: postData,
success: function(data){
userProfile.userId = 'yourId'; // set the id
userProfile.processQueue(); // process queue
},
error: function(data){
//Didnt work
}
});

Spring MVC set attribute to response/model/modelMap via Ajax

I would like to set some attributes to my session or modelAttribute in my page using Ajax, those values are needed to do some information proccesing later.
Without Ajax I was able to do this using:
model.addAttribute("currentComponent", "system.fileUpload");
model.addAttribute("status", uploadStatus);
model.addAttribute("prueba",generatedFile);
model.addAttribute("path", rutaLiquidacionesNetas);
model.addAttribute("dateFolder", dateAndTimeFolder);
return "file/upload";
I setted those values and then in my JSP I was able to access them but now using Ajax I cant get those values because they are not even being setted.
Here is my ajax function:
$("#load-file").click(function(){
var sappUrl = $("#uploadForm").attr( "action") + "/generateFile";
var formData = new FormData(document.getElementById("uploadForm"));
$.ajax({
url: sappUrl,
data: formData,
type: "POST",
processData: false,
contentType: false,
success: function(data) {
$("#results-files").html(data);
},
error: function() { $("#result").html("Ha ocurrido un pelon"); }
});
});
I hope somebody could help me because I´ve only found examples about setting attributes to the request

Set HTTPPassword via REST with #Password function

I am creating docs via Domino Access Service and I would like to add the HTTPPassword field.
This field normally is translated via the
#Password(HTTPPassword)
formula. How can I establish something via a HTTP post? Now the field is set as 'normal text'.
var newPersonObj = {Form: "Person", HTTPPassword: "lotusnotes"};
$.ajax({
url: '/tools/fakenames.nsf/api/data/documents',
type: 'POST',
data: JSON.stringify(newPersonObj),
dataType: 'xml',
accepts: {
xml: 'text/xml',
text: 'text/plain'
},
contentType: "application/json"
}).done(function(data, textStatus, jqXHR) {
var newPersonLocation = jqXHR.getResponseHeader("Location");
});
I found out I can include the &computewithform=true parameter in the URL so field translation is performed and the #password function is executed in the translation formula for the HTTPpassword field
I guess who want to get data submitted by a POST:
Set s = New NotesSession
Set doc = s.documentcontext
If doc.REQUEST_CONTENT(0)<>"" Then'it's a POST
Where REQUEST_CONTENT will contain all the data posted in url encoded format (var1=val1&var2=val2...)
If I misunderstood, sorry, and I will erase/edit this response

Django + Ajax | File Upload | Server doesn't recognise Ajax Request

I am trying to implement file upload using ajax with Django but facing some problem.
When the user tries to upload the files after selecting the file and submitting the form, then as per my understanding , an ajax request should be send to the server using POST method ,but in my case a POST request is being made to the server, but the server is not able to identify it as an ajax request and browser is redirected to http://<server>:<port>/upload/ and the contents on this page are as follows.
{"status": "error", "result": "Something went wrong.Try Again !!"}
Django Version: 1.6.2
Python Version: 2.7.5
Also, testing on Django Development Server.
views.py
def upload(request):
logging.info('Inside upload view')
response_data = {}
if request.is_ajax():
logging.info('Is_AJAX() returned True')
form = UploaderForm(request.POST, request.FILES)
if form.is_valid():
logging.info('Uploaded Data Validated')
upload = Upload( upload=request.FILES['upload'] )
upload.name = request.FILES['upload'].name
upload.save()
logging.info('Uploaded Data Saved in Database and link is %s' % upload.upload)
response_data['status'] = "success"
response_data['result'] = "Your file has been uploaded !!"
response_data['fileLink'] = "/%s" % upload.upload
return HttpResponse(json.dumps(response_data), content_type="application/json")
response_data['status'] = "error"
response_data['result'] = "Something went wrong.Try Again !!"
return HttpResponse(json.dumps(response_data), content_type='application/json')
Template
<form id="uploadForm" action="/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input id="fileInput" class="input-file" name="upload" type="file">
<input type="submit" value="Post Images/Files" />
</form>
Javascript 1:
$('#uploadForm').submit(function(){
var formData = new FormData($(this)[0]);
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
async: false,
success: function (data) {
alert(data)
},
cache: false,
contentType: false,
processData: false
});
return false;
});
Javascript 2
var options = {
url: '/upload/',
type: "POST",
error: function(response) {
alert('Something went Wrong. Try Again');
},
success: function(response) {
if ( response.status == 'success' ) {
alert('success');
}
}
};
$('#uploadForm').ajaxSubmit(options);
Question:
1) Why is Django not able to recognize the ajax request and value of request.is_ajax() is always False.
2) Even if the server doesn't recognize ajax request why is my browser getting redirected to another page ?
There is another similar question here but with no result.
This works for me. You need a jquery.form.js
$("#uploadForm").submit(function(event) {
$(this).ajaxSubmit({
url:'{% url upload_file %}',
type: 'post',
success: function(data) {
console.log(data)
},
error: function(jqXHR, exception) {
console.log("An error occurred while uploading your file!");
}
});
return false;
});
Here's the similar question here with answers.
Make sure that javascript code block
$('#uploadForm').submit(function(){
var formData = new FormData($(this)[0]);
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
async: false,
success: function (data) {
alert(data)
},
cache: false,
contentType: false,
processData: false
});
return false;
});
loaded after your uploadForm html form in DOM on page. In your case seems you trying to bind submit handler with form element which not yet loaded so when you click, it send simple POST request.
1) why is_ajax() not working?
Have you included the JQuery form plugin (jquery.form.js) ? ajaxSubmit() needs that plugin.
Take a look at http://jquery.malsup.com/form/
If it's already done, you might take a look at the HTTPRequest object
Django Documentation says HttpRequest.is_ajax()
Returns True if the request was made via an XMLHttpRequest. And if you are using some javascript libraries to make the ajax request, you dont have to bother about this matter. Still you can verify "HTTP_X_REQUESTED_WITH" header to see if Django received an XMLHttpRequest or not.
2) Why page redirects?
As I said above, JQuery form plugin is needed for handling the ajax request and its call back. Also, for ajaxSubmit() you need to override the $(#uploadForm).submit()
$('#uploadForm').submit( function (){
$(this).ajaxSubmit(options);
return false;
});
Hope this was helpful :)

File Upload without Form

Without using any forms whatsoever, can I just send a file/files from <input type="file"> to 'upload.php' using POST method using jQuery. The input tag is not inside any form tag. It stands individually. So I don't want to use jQuery plugins like 'ajaxForm' or 'ajaxSubmit'.
You can use FormData to submit your data by a POST request. Here is a simple example:
var myFormData = new FormData();
myFormData.append('pictureFile', pictureInput.files[0]);
$.ajax({
url: 'upload.php',
type: 'POST',
processData: false, // important
contentType: false, // important
dataType : 'json',
data: myFormData
});
You don't have to use a form to make an ajax request, as long as you know your request setting (like url, method and parameters data).
All answers here are still using the FormData API. It is like a "multipart/form-data" upload without a form. You can also upload the file directly as content inside the body of the POST request using xmlHttpRequest like this:
var xmlHttpRequest = new XMLHttpRequest();
var file = ...file handle...
var fileName = ...file name...
var target = ...target...
var mimeType = ...mime type...
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('Content-Disposition', 'attachment; filename="' + fileName + '"');
xmlHttpRequest.send(file);
Content-Type and Content-Disposition headers are used for explaining what we are sending (mime-type and file name).
I posted similar answer also here.
UPDATE (January 2023):
You can also use the Fetch API to upload a file directly as binary content (as also was suggested in the comments).
const file = ...file handle...
const fileName = ...file name...
const target = ...target...
const mimeType = ...mime type...
const promise = fetch(target, {
method: 'POST',
body: file,
headers: {
'Content-Type': mimeType,
'Content-Disposition', `attachment; filename="${fileName}"`,
},
},
});
promise.then(
(response) => { /*...do something with response*/ },
(error) => { /*...handle error*/ },
);
See also a related question here: https://stackoverflow.com/a/48568899/1697459
Step 1: Create HTML Page where to place the HTML Code.
Step 2: In the HTML Code Page Bottom(footer)Create Javascript: and put Jquery Code in Script tag.
Step 3: Create PHP File and php code copy past. after Jquery Code in $.ajax Code url apply which one on your php file name.
JS
//$(document).on("change", "#avatar", function() { // If you want to upload without a submit button
$(document).on("click", "#upload", function() {
var file_data = $("#avatar").prop("files")[0]; // Getting the properties of file from file field
var form_data = new FormData(); // Creating object of FormData class
form_data.append("file", file_data) // Appending parameter named file with properties of file_field to form_data
form_data.append("user_id", 123) // Adding extra parameters to form_data
$.ajax({
url: "/upload_avatar", // Upload Script
dataType: 'script',
cache: false,
contentType: false,
processData: false,
data: form_data, // Setting the data attribute of ajax with file_data
type: 'post',
success: function(data) {
// Do something after Ajax completes
}
});
});
HTML
<input id="avatar" type="file" name="avatar" />
<button id="upload" value="Upload" />
Php
print_r($_FILES);
print_r($_POST);
Basing on this tutorial, here a very basic way to do that:
$('your_trigger_element_selector').on('click', function(){
var data = new FormData();
data.append('input_file_name', $('your_file_input_selector').prop('files')[0]);
// append other variables to data if you want: data.append('field_name_x', field_value_x);
$.ajax({
type: 'POST',
processData: false, // important
contentType: false, // important
data: data,
url: your_ajax_path,
dataType : 'json',
// in PHP you can call and process file in the same way as if it was submitted from a form:
// $_FILES['input_file_name']
success: function(jsonData){
...
}
...
});
});
Don't forget to add proper error handling
Try this puglin simpleUpload, no need form
Html:
<input type="file" name="arquivo" id="simpleUpload" multiple >
<button type="button" id="enviar">Enviar</button>
Javascript:
$('#simpleUpload').simpleUpload({
url: 'upload.php',
trigger: '#enviar',
success: function(data){
alert('Envio com sucesso');
}
});
A non-jquery (React) version:
JS:
function fileInputUpload(e){
let formData = new FormData();
formData.append(e.target.name, e.target.files[0]);
let response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
let result = await response.json();
console.log(result.message);
}
HTML/JSX:
<input type='file' name='fileInput' onChange={(e) => this.fileInput(e)} />
You might not want to use onChange, but you can attach the uploading part to any another function.
Sorry for being that guy but AngularJS offers a simple and elegant solution.
Here is the code I use:
ngApp.controller('ngController', ['$upload',
function($upload) {
$scope.Upload = function($files, index) {
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
$scope.upload = $upload.upload({
file: file,
url: '/File/Upload',
data: {
id: 1 //some data you want to send along with the file,
name: 'ABC' //some data you want to send along with the file,
},
}).progress(function(evt) {
}).success(function(data, status, headers, config) {
alert('Upload done');
}
})
.error(function(message) {
alert('Upload failed');
});
}
};
}]);
.Hidden {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-controller="ngController">
<input type="button" value="Browse" onclick="$(this).next().click();" />
<input type="file" ng-file-select="Upload($files, 1)" class="Hidden" />
</div>
On the server side I have an MVC controller with an action the saves the files uploaded found in the Request.Files collection and returning a JsonResult.
If you use AngularJS try this out, if you don't... sorry mate :-)

Categories

Resources