server side unable to capture append formdata files - javascript

I have a module where user can snap a picture (which will converted into a base64 string and then to a file), and I require to upload the file into our server, but after converted the base64 into file object and append it into formData and submit the form. I found that in my backend, it unable to read the $_FILES property (refer last image), the array is empty but which suppose to have my file in there.
And checking on my formData variable, the data is append into it.
html
<form id="form" method="POST" action="smth.php" enctype="multipart/form-data">
...
<!-- some other input information -->
</form>
js
$('#form').on('submit', function(){
...
var formData = new FormData($(this)[0]);
var base64 = $('#photo').attr('src');
console.log(...formData);
console.log('before checking');
if(base64 != 'default.png'){
var file = dataUrltoFile(base64, 'photo.png'); //external function to convert base64 into file object
formData.append('photo', file);
}
console.log('after checking');
console.log(...formData);
...
});
console
smth.php
<?php ... var_dump($_POST); var_dump($_FILES); exit(); ... ?>
result

You won't be able to attach your FormData instance to the existing <form> for a normal submit (I think).
If you want to mess with the normal submit, you'll need to add HTML elements into the <form> like <input type="file">.
Otherwise, submit the data via AJAX
document.getElementById('form').addEventListener('submit', async function(e) {
e.preventDefault()
const formData = new FormData(this)
// do stuff to formData
const res = await fetch(this.action, {
method: this.method,
body: formData // automatically sets Content-type: multipart/form-data
})
if (res.ok) {
// handle response
}
})

Related

Use javascript to rename file before upload

Let's say I have this list of forms like so:
var forms = document.getElementsByClassName('uploadImage');
each item in this list look like this:
<form method=​"post" action=​"/​upload" enctype=​"multipart/​form-data" id=​"f_x" class=​"uploadImage">
​ <input type=​"file" id=​"u_x">​
<input type=​"submit" value=​"Submit" id=​"s_x">​
</form>​
where x = [0,1,2,3,4,5]
How do I loop through this list and do two things:
1 - Rename the file name
2 - Submit the form for uploading the file
I looked for many resources online like this one: https://www.telerik.com/forums/change-file's-name-when-it's-uploaded-via-html-form, all of them are using Jquery , I need it in javascript
update :-
I figured out how to get to the input value of each form
forms[0].elements[0] this will return the first input of the first form on the list
forms[0].elements[0].value this output the value of the file input
So here is the code you linked to, and I will break it down a bit after. A lot of it is vanilla javascript.
$(document).ready(function() {
initImageUpload();
function initImageUpload() {
$("#btn-submit").click(function(e) {
e.preventDefault();
var everlive = new Everlive({
appId: "",
scheme: "https"
});
// construct the form data and apply new file name
var file = $('#image-file').get(0).files[0];
var newFileName = file.filename + "new";
var formData = new FormData();
formData.append('file', file, newFileName);
$.ajax({
url: everlive.files.getUploadUrl(), // get the upload URL for the server
success: function(fileData) {
alert('Created file with Id: ' + fileData.Result[0].Id); // access the result of the file upload for the created file
alert('The created file Uri is available at URL: ' + fileData.Result[0].Uri);
},
error: function(e) {
alert('error ' + e.message);
},
// Form data
data: formData,
type: 'POST',
cache: false,
contentType: false,
processData: false
});
return false;
});
}
});
As is mentioned, this uses jQuery $.ajax() to create an AJAX POST to the server with new FormData where the name of the file has been modified. The new FormData is then sent to the server instead of the HTML Form data.
So, when the button is clicked to submit the form, this event is prevented.
var file = $('#image-file').get(0).files[0];
This is then used to select the <input> element in jQuery and then collect the files info from the element.
var file = document.getElementById("image-file").files[0];
This can be done with JavaScript. Largely the rest of the script would be unchanged, except for the initialization and sending of POST Data via AJAX.
It might be best to create a function that you send the form to and it can then return the new form data with new name. As you did not want to provide an MCVE, it's hard to give you an example since it's not clear how the data for the new name would be create or gathered from.
function nameFile(inEl, newName){
var file = inEl.files[0];
var results = new FormData();
results.append('file', file, newName);
return results;
}
function sendFile(url, formData){
var request = new XMLHttpRequest();
request.open("POST", url);
request.send(formData);
}
sendFile("/​upload", nameFile(document.getElementById("file-image"), "UserFile-" + new Date().now() + ".jpg"));
Another issue is if you have multiple forms, and multiple submit buttons, which one will trigger all the items to get uploaded? Either way, you'd have to iterate each form (maybe with a for() loop) collect the form data from each, update the name, and submit each one, most likely via AJAX.
Hope this helps.

Submit HTML form data as a file / Combine form data + file and send as single file in Javascript

I have a form with input field like some textfields ,textareas,dropdowns and a file upload field which the user will upload while filling the form i want to send form contents (both form field values + uploaded file) as one file to the server below is a very simplified version of my problem .Say i have the following markup
<form id="myForm" method="post" action="something">
<input type="text" name="username" id="username">
<input type="text" name="email" id="email">
<input type="file" name="myFile" id="myFile">
</form>
So now what i want is instead of sending above 2 text fields and a file separately i want them to get embedded in a file and then get sent as a whole.
example
Note that the server where i am sending is third party and only excepts files also file format is proprietary but nonetheless it still a ASCII plain/text.I realize that it's only possible by AJAX and fileReader API so here is what i have tried
var file;
$('#myFile').change(function(e){
file = this.files[0];
var fr = new FileReader();
fr.onload = function(event){
fileData = fr.result;
};
fr.readAsDataURL(file);
$('#myForm').submit(function(e){
e.preventDefault();//prevent submit
var myFile= [$('#username').val(),$('#email').val(),fileData];
$.ajax({
url : "some url",
type: "POST",
contentType:false,
processData:false,
data: myFile;
success:function(data){ }
});
});
Issue is that upon form submission no file gets sent .Any help would be greatly appreciated , thanks.
In form submit you can do as mentioned below for send file with AJAX request
$('#myform').submit(function(e){
e.preventDefault();//prevent submit
var form_data = new FormData();
form_data.append('file', $('#myfile').prop('files')[0]);
form_data.append('username', $("#username").val());
form_data.append('phone', $("#phone").val());
$.ajax({
url : "some url",
type: "POST",
contentType:false,
processData:false,
data: form_data;
success:function(data){ }
});
});
There are 2 parts
Convert file to string format or serialize it on client side using FileReader API
Combine your form values with this string and send them as a file.
Part one
I don't know if you have noticed or not but when you use readAsDataURL() you don't get the original file byte-stream but its base64 encoded version so keeping that in mind change you code to
var fileData;
$('#myFile').change(function(e){
file = this.files[0];
var fr = new FileReader();
fr.onload = function(event) {
encfileData = fr.result;
startInx = encfileData.indexOf('base64');
startInx += 7;
tmp = encfileData.substr(startInx);
//removes the file MIME header part ie. "data:text/plain;base64," before decoding
//regex may be preferable
fileData = atob(tmp); //DECODE
};
fr.readAsDataURL(file);
});
So now you have a string containing your file's byte-stream now as you have said there is some format so depending on that you do whatever manipulation you may need to make it align with the format, since you have mentioned it's plain text format so basic string function are sufficient here.For next part i assume simple colon based CSV format key1:value1,key2:value2
Part Two
Now to truly create a file out of thin air you can use either File or Blob but i would suggest using Blob due to its better support.To contain the file you require FormData simply append your blob to it and send
$('#myForm').submit(function(e){
e.preventDefault();
var txtData = "\n username:"+$("#username").val()+","+"email:"+$("#email").val();
// NOTE: windows uses \r\n instead of \n for newlines
var payLoad = fileData + txtData; //append text field data to the file data
var blob = new Blob([payLoad], {type : 'plain/txt'});
var form = new FormData();
var fileName = 'combined.txt'; //filename that will be used on server
form.append('something', blob, fileName);
$.ajax({
url: "some url",
type: "POST",
cache: false,
contentType: false,
processData: false,
data: form,
success: function(response){alert(response);}
});
});
If using php on linux your $_FILES should look something like this
Array
(
[something] => Array
(
[name] => combined.txt
[type] => plain/txt
[tmp_name] => /tmp/phpJvSJ94
[error] => 0
[size] => 95
)
)
It seems that you're passing sending the wrong variable in your AJAX payload - shouldn't you be sending fileData instead of file?
You can upload data and files:
HTML
<form id="data" method="post" enctype="multipart/form-data">
<input type="text" name="username" id="username">
<input type="text" name="email" id="email">
<input type="file" name="myFile" id="myFile">
</form>
Jquery
$("form#data").submit(function(){
var formData = new FormData($(this)[0]);
$.ajax({
url: 'your_url',
type: 'POST',
data: formData,
async: false,
success: function (data) {
alert(data)
},
cache: false,
contentType: false,
processData: false
});
return false;
});

Form not submitting file / Undefined index: FileInput - PHP/AJAX/jQuery

I am trying to use jQuery to trigger a form submission and then use AJAX to call a PHP script that will handle the file and return a response. The issue, though, is that the file is not being uploaded upon submitting the form.
HTML:
<div id="browseButton" class="step1Button" onclick="browseFile()">Browse</div>
<form method="post" id="fileForm" style="display:inline-block;">
<input id="browseInput" type="file" name="FileInput" style="display: none"/>
<label for="upload-click-handler"></label>
<input id="upload-click-handler" type="text" readonly />
<input id="submitForm" type="submit" style="display: none"/>
</form>
<div id="previewButton" class="step1Button pull-right" onclick="uploadFile()" style="background-color: #57a957">
Preview
</div>
jQuery:
function uploadFile() {
submitForm();
parseExcel();
}
var submitForm = function() {
$('#previewButton').click(function(){
$('#submitForm').click();
});
};
var parseExcel = function() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET",'default/ParseExcel',true);
xmlhttp.send();
console.log("made it past excel parse");
};
The PHP that's called:
public function actionParseExcel() {
print "made it to parse".PHP_EOL;
print "File:";
if($_FILES['FileInput']['tmp_name']) {
print_r($_FILES['FileInput']['tmp_name']);
}
else {
print "Not found";
}
print "Done.";
}
I know the issue is that my form isn't submitting the chosen file because that's typically why the "Undefined index" error is thrown. But I can't understand why.
First, if you don't want your page to refresh, you better use <input type="button">
or else call your JavaScript via <form onSubmit="uploadFile()"> and return false at the end of your function uploadFile().
Second, you'll need to put enctype="multipart/form-data" in your <form>.
I see you're using JQuery, you should use it to send your AJAX request too :
// This code supports multiple type="file" inputs
// Variable to store your files
var files;
// Add events
$('input[type=file]').on('change', prepareUpload);
// Grab the files and set them to our variable
function prepareUpload(event)
{
files = event.target.files;
}
// Create a formdata object and add the file
var data = new FormData();
// In case you want to upload more than one file
$.each(files, function(key, value)
{
data.append(key, value);
});
$.ajax({
url: 'your.php?FileInput',
type: 'POST',
data: data,
cache: false,
dataType: 'json',
processData: false, // Prevent the file from beeing converted to string
contentType: false, // Set the content file to false prevent JQuery from using 'application/x-www-form-urlencoded; charset=UTF-8' as default type
...
});
I hope this will lead you to the solution...
Edited : var files declaration + files processing
To send forms with files you need to use enctype="multipart/form-data".
BUT, as far as I know, you can't send files using ajax.
So, the solution for that is to use a hidden iFrame:
Create a hidden iFrame (outside of your form) and assing it an ID
Create the form pointing to yout PHP file, and using the attribute enctype="multipart/form-data" and target="ID_OF_THE_IFRAME" (so the form, when submitted, will be sent to that iframe)
When the PHP finish procesing the file, you could output a javascript that calls parent.YOURFUNCTION(), so you can do whatever you want when the process is done.
Good luck!

Access file upload field from ajax

I have a problem with accessing file upload field
//HTML
<input type='file' name='images' id="images" multiple>
//////////////////
$('.bt-add-com').click(function(){
var formdata = new FormData();
var sessionID = 8;
var theCom = $('.the-new-com');
var theName = $('#name-com');
var theMail = $('#mail-com');
var theFile = formdata.append("images", sessionID);
if( !theCom.val()){
alert('You need to write a comment!');
}else{
$.ajax({
type: "POST",
url: "ajax/add-comment.php",
data: 'act=add-com&id_post='+<?php echo $id_post; ?>+'&name='+theName.val()+'&email='+theMail.val()+'&comment='+theCom.val()+'&file='+formdata.append("images[]", sessionID),
success: function(html){
theCom.val('');
theMail.val('');
theName.val('');
$('.new-com-cnt').hide('fast', function(){
$('.new-com-bt').show('fast');
$('.new-com-bt').before(html);
})
}
});
}
});
////RESULT
array (size=6)
'file' => string 'undefined' (length=9)
problem is when i access file upload field using formdata as code below. it display value as undefined. can't get uploaded file details
You're taking the form data object and appending it to a string. That won't work.
Don't try to build a string to pass to data, use the FormData API for all your fields, then pass the FormData object itself.
You also need to append the file data form the input instead of the number 8.
formdata.append("images", sessionID);
formdata.append("images[]", sessionID)
Don't use images and images[]. If you're using PHP, then use just images[]
Don't use sessionID, use the file.
formdata.append("images[]", document.getElementById('images').files[0]);

File upload into database is empty

I want to upload an array of files, send it to javascript formData object and then via ajax to some php script which will put the file into database. It works fine when I upload one file, send it to formData object in javascript and send it to php.
Problem is when I send an array of files via formData object, my php script will insert an empty file into database (BLOB - 0B). What do I do wrong?
Example:
<form method="post" action="javascript:sendPHP()" enctype="multipart/form-data">
<input type="file" onchange = 'handleFiles(this.files)' name="pics[]" />
<input type="file" onchange = 'handleFiles(this.files)' name="pics[]" />
<input type="file" onchange = 'handleFiles(this.files)' name="pics[]" />
<input type="submit" value="Upload" />
//Javascript
var formData = new FormData();
function handleFiles(files) {
var file = files[0];
formData.append('pics[]', file, file.name);
}
function sendPHP() {
$.ajax({
type: "POST",
url: "../php/haus.php",
data: formData,
processData: false,
contentType: false,
success: function(data){}
})}
//php
if(strtolower($_SERVER['REQUEST_METHOD']) == 'post' && !empty($_FILES))
{
foreach($_FILES['pics']['tmp_name'] as $index => $tmpName )
{
if(!empty($tmpName) && is_uploaded_file($tmpName))
{
$imgData= addslashes(file_get_contents($_FILES['pics']['tmp_name']));
$resultPics = $dbConnection->query("INSERT INTO picture (pic, text, id) VALUES ('".$imgData."', 'Hi','1')");
}
}
}
You are missing this attribute multiple="multiple" in your <input>
Do it this way ,
<input type="file" onchange = 'handleFiles(this.files)' name="pics[]" multiple="multiple" />
This function handles only single file upload
function handleFiles(files) {
var file = files[0];
formData.append('pics[]', file, file.name);
}
For multiple uploads you need to use a loop inside to append to each file.
Something Like this ,
function handleFiles(files) {
for(var file in files)
{
formData.append('pics[]', file, file.name);
}
The PHP part , you need to use a loop there as well to loop through each file and use json_encode() to convert the array of files into json string , so that you can insert the record as a string in the database and use json_decode() when retrieving the data back from DB.
Hope this helps.

Categories

Resources